├── .gitignore ├── .gitmodules ├── LICENSE ├── LICENSE-THIRD-PARTY ├── README.md ├── example ├── Knitfile ├── Makefile ├── hello.c └── hello.wasm ├── go.mod ├── go.sum ├── main.go ├── rt ├── uvwasi-main.c ├── uvwasi-rt.c ├── uvwasi-rt.h └── w2c2-main.c └── wasm2bin-clang └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | .knit 2 | a.out 3 | hello 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "w2c2"] 2 | path = w2c2 3 | url = https://github.com/turbolent/w2c2 4 | [submodule "wabt"] 5 | path = wabt 6 | url = https://github.com/zyedidia/wabt 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023: Zachary Yedidia. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /LICENSE-THIRD-PARTY: -------------------------------------------------------------------------------- 1 | Wasm2c runtime files were modified from wasm2native and wasm2c. 2 | 3 | wasm2native license: 4 | 5 | MIT License (https://github.com/vshymanskyy/wasm2native) 6 | 7 | Copyright (c) 2021 Volodymyr Shymanskyy 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | 27 | --- 28 | 29 | Wasm2c License (https://github.com/PLSysSec/wabt/tree/uvwasi_support) 30 | 31 | Modifications: changed function prefixes to link properly, changed preopens, 32 | named module based on template definition. 33 | 34 | Apache License 35 | Version 2.0, January 2004 36 | http://www.apache.org/licenses/ 37 | 38 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 39 | 40 | 1. Definitions. 41 | 42 | "License" shall mean the terms and conditions for use, reproduction, 43 | and distribution as defined by Sections 1 through 9 of this document. 44 | 45 | "Licensor" shall mean the copyright owner or entity authorized by 46 | the copyright owner that is granting the License. 47 | 48 | "Legal Entity" shall mean the union of the acting entity and all 49 | other entities that control, are controlled by, or are under common 50 | control with that entity. For the purposes of this definition, 51 | "control" means (i) the power, direct or indirect, to cause the 52 | direction or management of such entity, whether by contract or 53 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 54 | outstanding shares, or (iii) beneficial ownership of such entity. 55 | 56 | "You" (or "Your") shall mean an individual or Legal Entity 57 | exercising permissions granted by this License. 58 | 59 | "Source" form shall mean the preferred form for making modifications, 60 | including but not limited to software source code, documentation 61 | source, and configuration files. 62 | 63 | "Object" form shall mean any form resulting from mechanical 64 | transformation or translation of a Source form, including but 65 | not limited to compiled object code, generated documentation, 66 | and conversions to other media types. 67 | 68 | "Work" shall mean the work of authorship, whether in Source or 69 | Object form, made available under the License, as indicated by a 70 | copyright notice that is included in or attached to the work 71 | (an example is provided in the Appendix below). 72 | 73 | "Derivative Works" shall mean any work, whether in Source or Object 74 | form, that is based on (or derived from) the Work and for which the 75 | editorial revisions, annotations, elaborations, or other modifications 76 | represent, as a whole, an original work of authorship. For the purposes 77 | of this License, Derivative Works shall not include works that remain 78 | separable from, or merely link (or bind by name) to the interfaces of, 79 | the Work and Derivative Works thereof. 80 | 81 | "Contribution" shall mean any work of authorship, including 82 | the original version of the Work and any modifications or additions 83 | to that Work or Derivative Works thereof, that is intentionally 84 | submitted to Licensor for inclusion in the Work by the copyright owner 85 | or by an individual or Legal Entity authorized to submit on behalf of 86 | the copyright owner. For the purposes of this definition, "submitted" 87 | means any form of electronic, verbal, or written communication sent 88 | to the Licensor or its representatives, including but not limited to 89 | communication on electronic mailing lists, source code control systems, 90 | and issue tracking systems that are managed by, or on behalf of, the 91 | Licensor for the purpose of discussing and improving the Work, but 92 | excluding communication that is conspicuously marked or otherwise 93 | designated in writing by the copyright owner as "Not a Contribution." 94 | 95 | "Contributor" shall mean Licensor and any individual or Legal Entity 96 | on behalf of whom a Contribution has been received by Licensor and 97 | subsequently incorporated within the Work. 98 | 99 | 2. Grant of Copyright License. Subject to the terms and conditions of 100 | this License, each Contributor hereby grants to You a perpetual, 101 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 102 | copyright license to reproduce, prepare Derivative Works of, 103 | publicly display, publicly perform, sublicense, and distribute the 104 | Work and such Derivative Works in Source or Object form. 105 | 106 | 3. Grant of Patent License. Subject to the terms and conditions of 107 | this License, each Contributor hereby grants to You a perpetual, 108 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 109 | (except as stated in this section) patent license to make, have made, 110 | use, offer to sell, sell, import, and otherwise transfer the Work, 111 | where such license applies only to those patent claims licensable 112 | by such Contributor that are necessarily infringed by their 113 | Contribution(s) alone or by combination of their Contribution(s) 114 | with the Work to which such Contribution(s) was submitted. If You 115 | institute patent litigation against any entity (including a 116 | cross-claim or counterclaim in a lawsuit) alleging that the Work 117 | or a Contribution incorporated within the Work constitutes direct 118 | or contributory patent infringement, then any patent licenses 119 | granted to You under this License for that Work shall terminate 120 | as of the date such litigation is filed. 121 | 122 | 4. Redistribution. You may reproduce and distribute copies of the 123 | Work or Derivative Works thereof in any medium, with or without 124 | modifications, and in Source or Object form, provided that You 125 | meet the following conditions: 126 | 127 | (a) You must give any other recipients of the Work or 128 | Derivative Works a copy of this License; and 129 | 130 | (b) You must cause any modified files to carry prominent notices 131 | stating that You changed the files; and 132 | 133 | (c) You must retain, in the Source form of any Derivative Works 134 | that You distribute, all copyright, patent, trademark, and 135 | attribution notices from the Source form of the Work, 136 | excluding those notices that do not pertain to any part of 137 | the Derivative Works; and 138 | 139 | (d) If the Work includes a "NOTICE" text file as part of its 140 | distribution, then any Derivative Works that You distribute must 141 | include a readable copy of the attribution notices contained 142 | within such NOTICE file, excluding those notices that do not 143 | pertain to any part of the Derivative Works, in at least one 144 | of the following places: within a NOTICE text file distributed 145 | as part of the Derivative Works; within the Source form or 146 | documentation, if provided along with the Derivative Works; or, 147 | within a display generated by the Derivative Works, if and 148 | wherever such third-party notices normally appear. The contents 149 | of the NOTICE file are for informational purposes only and 150 | do not modify the License. You may add Your own attribution 151 | notices within Derivative Works that You distribute, alongside 152 | or as an addendum to the NOTICE text from the Work, provided 153 | that such additional attribution notices cannot be construed 154 | as modifying the License. 155 | 156 | You may add Your own copyright statement to Your modifications and 157 | may provide additional or different license terms and conditions 158 | for use, reproduction, or distribution of Your modifications, or 159 | for any such Derivative Works as a whole, provided Your use, 160 | reproduction, and distribution of the Work otherwise complies with 161 | the conditions stated in this License. 162 | 163 | 5. Submission of Contributions. Unless You explicitly state otherwise, 164 | any Contribution intentionally submitted for inclusion in the Work 165 | by You to the Licensor shall be under the terms and conditions of 166 | this License, without any additional terms or conditions. 167 | Notwithstanding the above, nothing herein shall supersede or modify 168 | the terms of any separate license agreement you may have executed 169 | with Licensor regarding such Contributions. 170 | 171 | 6. Trademarks. This License does not grant permission to use the trade 172 | names, trademarks, service marks, or product names of the Licensor, 173 | except as required for reasonable and customary use in describing the 174 | origin of the Work and reproducing the content of the NOTICE file. 175 | 176 | 7. Disclaimer of Warranty. Unless required by applicable law or 177 | agreed to in writing, Licensor provides the Work (and each 178 | Contributor provides its Contributions) on an "AS IS" BASIS, 179 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 180 | implied, including, without limitation, any warranties or conditions 181 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 182 | PARTICULAR PURPOSE. You are solely responsible for determining the 183 | appropriateness of using or redistributing the Work and assume any 184 | risks associated with Your exercise of permissions under this License. 185 | 186 | 8. Limitation of Liability. In no event and under no legal theory, 187 | whether in tort (including negligence), contract, or otherwise, 188 | unless required by applicable law (such as deliberate and grossly 189 | negligent acts) or agreed to in writing, shall any Contributor be 190 | liable to You for damages, including any direct, indirect, special, 191 | incidental, or consequential damages of any character arising as a 192 | result of this License or out of the use or inability to use the 193 | Work (including but not limited to damages for loss of goodwill, 194 | work stoppage, computer failure or malfunction, or any and all 195 | other commercial damages or losses), even if such Contributor 196 | has been advised of the possibility of such damages. 197 | 198 | 9. Accepting Warranty or Additional Liability. While redistributing 199 | the Work or Derivative Works thereof, You may choose to offer, 200 | and charge a fee for, acceptance of support, warranty, indemnity, 201 | or other liability obligations and/or rights consistent with this 202 | License. However, in accepting such obligations, You may act only 203 | on Your own behalf and on Your sole responsibility, not on behalf 204 | of any other Contributor, and only if You agree to indemnify, 205 | defend, and hold each Contributor harmless for any liability 206 | incurred by, or claims asserted against, such Contributor by reason 207 | of your accepting any such warranty or additional liability. 208 | 209 | END OF TERMS AND CONDITIONS 210 | 211 | APPENDIX: How to apply the Apache License to your work. 212 | 213 | To apply the Apache License to your work, attach the following 214 | boilerplate notice, with the fields enclosed by brackets "[]" 215 | replaced with your own identifying information. (Don't include 216 | the brackets!) The text should be enclosed in the appropriate 217 | comment syntax for the file format. We also recommend that a 218 | file or class name and description of purpose be included on the 219 | same "printed page" as the copyright notice for easier 220 | identification within third-party archives. 221 | 222 | Copyright [yyyy] [name of copyright owner] 223 | 224 | Licensed under the Apache License, Version 2.0 (the "License"); 225 | you may not use this file except in compliance with the License. 226 | You may obtain a copy of the License at 227 | 228 | http://www.apache.org/licenses/LICENSE-2.0 229 | 230 | Unless required by applicable law or agreed to in writing, software 231 | distributed under the License is distributed on an "AS IS" BASIS, 232 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 233 | See the License for the specific language governing permissions and 234 | limitations under the License. 235 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wasm2bin 2 | 3 | Wasm2bin is a tool that compiles Webassembly modules to native binaries. It 4 | uses either [w2c2](https://github.com/turbolent/w2c2) or 5 | [wasm2c](https://github.com/WebAssembly/wabt/tree/main/wasm2c) to compile 6 | Webassembly to C, and from there calls a C compiler and links the code with a 7 | WASI runtime to produce a native binary. For w2c2 it uses its internal WASI 8 | runtime, and for wasm2c it uses [uvwasi](https://github.com/nodejs/uvwasi). 9 | 10 | Example usage: 11 | 12 | ``` 13 | $ export WASM2BIN=/path/to/wasm2bin-src 14 | $ wasm2bin -n hello -o hello hello.wasm 15 | $ ./hello 16 | hello world! 17 | ``` 18 | 19 | # Installation 20 | 21 | First clone the repository and initialize submodules. 22 | 23 | ``` 24 | git clone https://github.com/zyedidia/wasm2bin 25 | cd wasm2bin 26 | git submodule update --init --recursive 27 | ``` 28 | 29 | Then build the wrapper tool: 30 | 31 | ``` 32 | go install 33 | ``` 34 | 35 | Now choose the backend you would like to use (w2c2 or wasm2c) and build it. 36 | 37 | ## w2c2 38 | 39 | Build w2c2: 40 | 41 | ``` 42 | cd w2c2 43 | cmake -B build 44 | cmake --build build 45 | 46 | cd wasi 47 | cmake -B build 48 | cmake --build build 49 | ``` 50 | 51 | ## Wasm2c 52 | 53 | Build Wasm2c: 54 | 55 | ``` 56 | cd wabt 57 | mkdir build 58 | cd build 59 | cmake .. -G Ninja -DWITH_WASI=ON 60 | ninja wasm2c libuvwasi_a.a 61 | ``` 62 | 63 | Note: uses version 1.0.33 of wasm2c. 64 | 65 | # Usage 66 | 67 | ``` 68 | Usage of wasm2bin: 69 | --cc string C compiler (default "clang") 70 | -f, --flags string C compiler flags (default "-O2") 71 | -n, --name string module name (default "main") 72 | -o, --output string output file (default "a.out") 73 | -V, --verbose verbose output 74 | --wasm2c Use Wasm2c instead of w2c2 75 | ``` 76 | 77 | ``` 78 | $ export WASM2BIN=/path/to/wasm2bin-src 79 | $ wasm2bin -n hello -o hello hello.wasm # compile with w2c2 80 | $ wasm2bin --wasm2c -n hello -o hello hello.wasm # compile with wasm2c 81 | ``` 82 | 83 | Note: 84 | 85 | The wasm2c runtime files have been adapted from the 86 | [wasm2native](https://github.com/vshymanskyy/wasm2native) project and this 87 | [pull request](https://github.com/WebAssembly/wabt/pull/2002). 88 | -------------------------------------------------------------------------------- /example/Knitfile: -------------------------------------------------------------------------------- 1 | local sysroot = "/opt/wasi-sysroot" 2 | 3 | return b{ 4 | $ hello: hello.wasm 5 | wasm2bin -n hello -o $output $input 6 | $ hello.wasm: hello.c 7 | clang -target wasm32-unknown-wasi -O3 $input --sysroot=$sysroot -o $output 8 | } 9 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | WASI_SYSROOT=/usr/share/wasi-sysroot 2 | 3 | hello: hello.wasm 4 | WASM2BIN=$(PWD)/.. wasm2bin --wasm2c --flags "-pthread -ldl" -n hello -o $@ $< 5 | hello.wasm: hello.c 6 | clang -target wasm32-unknown-wasi -O2 $< --sysroot=$(WASI_SYSROOT) -o $@ 7 | -------------------------------------------------------------------------------- /example/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | int main() { 3 | printf("%p\n", fopen("/home/zyedidia/wasm.txt", "rb")); 4 | printf("%p\n", fopen("hello.c", "rb")); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /example/hello.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zyedidia/wasm2bin/1a0c9f0868dd28f97209c41888703031e49e422c/example/hello.wasm -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/zyedidia/wasm2bin 2 | 3 | go 1.19 4 | 5 | require github.com/spf13/pflag v1.0.5 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= 2 | github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 3 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "embed" 5 | "fmt" 6 | "html/template" 7 | "log" 8 | "os" 9 | "os/exec" 10 | "path/filepath" 11 | 12 | "github.com/spf13/pflag" 13 | ) 14 | 15 | //go:embed rt/w2c2-main.c 16 | var w2c2data []byte 17 | 18 | //go:embed rt/uvwasi-main.c 19 | var wasm2cdata []byte 20 | 21 | var verbose = pflag.BoolP("verbose", "V", false, "verbose output") 22 | 23 | func temp(dir, name string) string { 24 | tmp, err := os.Create(filepath.Join(dir, name)) 25 | if err != nil { 26 | log.Fatal(err) 27 | } 28 | tmp.Close() 29 | return tmp.Name() 30 | } 31 | 32 | func run(c string) { 33 | cmd := exec.Command("sh", "-c", c) 34 | cmd.Stdout = os.Stdout 35 | cmd.Stderr = os.Stderr 36 | cmd.Stdin = os.Stdin 37 | cmd.Env = os.Environ() 38 | if *verbose { 39 | fmt.Fprintln(os.Stderr, cmd) 40 | } 41 | err := cmd.Run() 42 | if err != nil { 43 | log.Fatal(err) 44 | } 45 | } 46 | 47 | func main() { 48 | out := pflag.StringP("output", "o", "a.out", "output file") 49 | name := pflag.StringP("name", "n", "main", "module name") 50 | cc := pflag.String("cc", "clang", "C compiler") 51 | flags := pflag.StringP("flags", "f", "-O2", "C compiler flags") 52 | useWasm2c := pflag.Bool("wasm2c", false, "Use Wasm2c instead of w2c2") 53 | 54 | pflag.Parse() 55 | args := pflag.Args() 56 | if len(args) < 1 { 57 | log.Fatal("no input") 58 | } 59 | in := args[0] 60 | 61 | root := os.Getenv("WASM2BIN") 62 | pwd, err := os.Getwd() 63 | if err != nil { 64 | log.Fatal(err) 65 | } 66 | 67 | if *useWasm2c { 68 | wabt := filepath.Join(root, "wabt") 69 | dir, err := os.MkdirTemp("", "root") 70 | if err != nil { 71 | log.Fatal(err) 72 | } 73 | 74 | cwasm := temp(dir, fmt.Sprintf("%s.c", *name)) 75 | hwasm := temp(dir, fmt.Sprintf("%s.h", *name)) 76 | 77 | t, err := template.New("uvwas-main").Parse(string(wasm2cdata)) 78 | if err != nil { 79 | log.Fatal(err) 80 | } 81 | f, err := os.Create(filepath.Join(dir, "uvwasi-main.c")) 82 | if err != nil { 83 | log.Fatal(err) 84 | } 85 | err = t.Execute(f, struct { 86 | Hwasm string 87 | Name string 88 | }{ 89 | Hwasm: hwasm, 90 | Name: *name, 91 | }) 92 | if err != nil { 93 | log.Fatal(err) 94 | } 95 | f.Close() 96 | 97 | incwasm2c := filepath.Join(wabt, "wasm2c") 98 | uvwasirt := filepath.Join(root, "rt", "uvwasi-rt.c") 99 | incuvwasi := filepath.Join(wabt, "third_party", "uvwasi", "include") 100 | luvwasi := filepath.Join(wabt, "build", "third_party", "uvwasi") 101 | luv := filepath.Join(wabt, "build", "_deps", "libuv-build") 102 | wasmrt := filepath.Join(wabt, "wasm2c", "wasm-rt-impl.c") 103 | incrt := filepath.Join(root, "rt") 104 | incsimd := filepath.Join(wabt, "third_party", "simde") 105 | 106 | run(fmt.Sprintf("%s %s -o %s", filepath.Join(wabt, "build", "wasm2c"), in, cwasm)) 107 | run(fmt.Sprintf("%s %s -o %s -I%s -I%s %s -I%s -L%s -luvwasi_a -L%s -luv_a -lm %s %s -I%s %s", *cc, cwasm, *out, incsimd, incwasm2c, uvwasirt, incuvwasi, luvwasi, luv, wasmrt, f.Name(), incrt, *flags)) 108 | 109 | os.RemoveAll(dir) 110 | } else { 111 | w2c2 := filepath.Join(root, "w2c2") 112 | dir, err := os.MkdirTemp("", "root") 113 | if err != nil { 114 | log.Fatal(err) 115 | } 116 | 117 | cwasm := temp(dir, fmt.Sprintf("%s.c", *name)) 118 | hwasm := temp(dir, fmt.Sprintf("%s.h", *name)) 119 | incw2c2 := fmt.Sprintf("%s/w2c2", w2c2) 120 | incwasi := fmt.Sprintf("%s/wasi", w2c2) 121 | lwasi := fmt.Sprintf("%s/wasi/build", w2c2) 122 | t, err := template.New("w2c2-main").Parse(string(w2c2data)) 123 | if err != nil { 124 | log.Fatal(err) 125 | } 126 | f, err := os.Create(filepath.Join(dir, "w2c2-main.c")) 127 | if err != nil { 128 | log.Fatal(err) 129 | } 130 | err = t.Execute(f, struct { 131 | Hwasm string 132 | Name string 133 | }{ 134 | Hwasm: hwasm, 135 | Name: *name, 136 | }) 137 | if err != nil { 138 | log.Fatal(err) 139 | } 140 | f.Close() 141 | run(fmt.Sprintf("%s %s %s %s", filepath.Join(w2c2, "build", "w2c2", "w2c2"), in, cwasm, hwasm)) 142 | run(fmt.Sprintf("%s %s -c -o %s.o -I%s -I%s -I%s %s", *cc, cwasm, cwasm, incw2c2, incwasi, pwd, *flags)) 143 | run(fmt.Sprintf("%s %s -c -o %s.o -I%s -I%s -I%s %s", *cc, f.Name(), f.Name(), incw2c2, incwasi, pwd, *flags)) 144 | run(fmt.Sprintf("%s %s.o %s.o -L%s -lw2c2wasi -o %s -lm -static %s", *cc, cwasm, f.Name(), lwasi, *out, *flags)) 145 | 146 | os.RemoveAll(dir) 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /rt/uvwasi-main.c: -------------------------------------------------------------------------------- 1 | /* Link this with wasm2c output and uvwasi runtime to build a standalone app */ 2 | #include 3 | #include 4 | #include "uvwasi.h" 5 | #include "uvwasi-rt.h" 6 | 7 | #define MODULE_NAME {{ .Name }} 8 | #define MODULE_HEADER "{{ .Hwasm }}" 9 | #include MODULE_HEADER 10 | 11 | //force pre-processor expansion of m_name 12 | #define __module_init(m_name) Z_## m_name ##_init_module() 13 | #define module_init(m_name) __module_init(m_name) 14 | 15 | #define __module_instantiate(m_name, instance_p, wasi_p) wasm2c_## m_name ##_instantiate(instance_p, wasi_p) 16 | #define module_instantiate(m_name ,instance_p, wasi_p) __module_instantiate(m_name ,instance_p, wasi_p) 17 | 18 | #define __module_free(m_name, instance_p) wasm2c_## m_name ##_free(instance_p) 19 | #define module_free(m_name, instance_p) __module_free(m_name, instance_p) 20 | 21 | #define __module_start(m_name, instance_p) w2c_ ## m_name ## _0x5Fstart(instance_p) 22 | #define module_start(m_name, instance_p) __module_start(m_name, instance_p) 23 | 24 | int main(int argc, const char** argv) 25 | { 26 | w2c_{{ .Name }} local_instance; 27 | uvwasi_t local_uvwasi_state; 28 | 29 | struct w2c_wasi__snapshot__preview1 wasi_state = { 30 | .uvwasi = &local_uvwasi_state, 31 | .instance_memory = &local_instance.w2c_memory 32 | }; 33 | 34 | uvwasi_options_t init_options; 35 | 36 | //pass in standard descriptors 37 | init_options.in = 0; 38 | init_options.out = 1; 39 | init_options.err = 2; 40 | init_options.fd_table_size = 3; 41 | 42 | //pass in args and environement 43 | extern const char ** environ; 44 | init_options.argc = argc; 45 | init_options.argv = argv; 46 | init_options.envp = (const char **) environ; 47 | 48 | //no sandboxing enforced, binary has access to everything user does 49 | init_options.preopenc = 2; 50 | init_options.preopens = calloc(2, sizeof(uvwasi_preopen_t)); 51 | 52 | init_options.preopens[0].mapped_path = "/home"; 53 | init_options.preopens[0].real_path = "/home"; 54 | init_options.preopens[1].mapped_path = "./"; 55 | init_options.preopens[1].real_path = "."; 56 | 57 | init_options.allocator = NULL; 58 | 59 | wasm_rt_init(); 60 | uvwasi_errno_t ret = uvwasi_init(&local_uvwasi_state, &init_options); 61 | 62 | if (ret != UVWASI_ESUCCESS) { 63 | printf("uvwasi_init failed with error %d\n", ret); 64 | exit(1); 65 | } 66 | 67 | /* module_init(MODULE_NAME); */ 68 | module_instantiate(MODULE_NAME, &local_instance, (struct w2c_wasi__snapshot__preview1 *) &wasi_state); 69 | module_start(MODULE_NAME, &local_instance); 70 | module_free(MODULE_NAME, &local_instance); 71 | 72 | uvwasi_destroy(&local_uvwasi_state); 73 | wasm_rt_free(); 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /rt/uvwasi-rt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wasm-rt.h" 7 | #include "uvwasi.h" 8 | #include "uvwasi-rt.h" 9 | 10 | #define MEMACCESS(addr) ((void*)&wp->instance_memory->data[(addr)]) 11 | 12 | #define MEM_SET(addr, value, len) memset(MEMACCESS(addr), value, len) 13 | #define MEM_WRITE8(addr, value) (*(uint8_t*) MEMACCESS(addr)) = value 14 | #define MEM_WRITE16(addr, value) (*(uint16_t*)MEMACCESS(addr)) = value 15 | #define MEM_WRITE32(addr, value) (*(uint32_t*)MEMACCESS(addr)) = value 16 | #define MEM_WRITE64(addr, value) (*(uint64_t*)MEMACCESS(addr)) = value 17 | 18 | #define MEM_READ32(addr) (*(uint32_t*)MEMACCESS(addr)) 19 | #define READ32(x) (*(uint32_t*)(x)) 20 | 21 | // XXX TODO: Add linear memory boundary checks 22 | 23 | 24 | typedef uint32_t wasm_ptr; 25 | 26 | uint32_t w2c_wasi__snapshot__preview1_fd_prestat_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr buf) 27 | { 28 | uvwasi_prestat_t prestat; 29 | uvwasi_errno_t ret = uvwasi_fd_prestat_get(wp->uvwasi, fd, &prestat); 30 | if (ret == UVWASI_ESUCCESS) { 31 | MEM_WRITE32(buf+0, prestat.pr_type); 32 | MEM_WRITE32(buf+4, prestat.u.dir.pr_name_len); 33 | } 34 | return ret; 35 | } 36 | 37 | 38 | uint32_t w2c_wasi__snapshot__preview1_fd_prestat_dir_name(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr path, uint32_t path_len) 39 | { 40 | uvwasi_errno_t ret = uvwasi_fd_prestat_dir_name(wp->uvwasi, fd, (char*)MEMACCESS(path), path_len); 41 | return ret; 42 | } 43 | 44 | uint32_t w2c_wasi__snapshot__preview1_environ_sizes_get(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr env_count, wasm_ptr env_buf_size) 45 | { 46 | uvwasi_size_t uvcount; 47 | uvwasi_size_t uvbufsize; 48 | uvwasi_errno_t ret = uvwasi_environ_sizes_get(wp->uvwasi, &uvcount, &uvbufsize); 49 | if (ret == UVWASI_ESUCCESS) { 50 | MEM_WRITE32(env_count, uvcount); 51 | MEM_WRITE32(env_buf_size, uvbufsize); 52 | } 53 | return ret; 54 | } 55 | 56 | uint32_t w2c_wasi__snapshot__preview1_environ_get(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr env, wasm_ptr buf) 57 | { 58 | uvwasi_size_t uvcount; 59 | uvwasi_size_t uvbufsize; 60 | uvwasi_errno_t ret; 61 | ret = uvwasi_environ_sizes_get(wp->uvwasi, &uvcount, &uvbufsize); 62 | if (ret != UVWASI_ESUCCESS) { 63 | return ret; 64 | } 65 | 66 | // TODO XXX: check mem 67 | 68 | char** uvenv = calloc(uvcount, sizeof(char*)); 69 | if (uvenv == NULL) { 70 | return UVWASI_ENOMEM; 71 | } 72 | 73 | ret = uvwasi_environ_get(wp->uvwasi, uvenv, (char*)MEMACCESS(buf)); 74 | if (ret != UVWASI_ESUCCESS) { 75 | free(uvenv); 76 | return ret; 77 | } 78 | 79 | for (uint32_t i = 0; i < uvcount; ++i) 80 | { 81 | uint32_t offset = buf + (uvenv[i] - uvenv[0]); 82 | MEM_WRITE32(env+(i*sizeof(wasm_ptr)), offset); 83 | } 84 | 85 | free(uvenv); 86 | 87 | return ret; 88 | } 89 | 90 | uint32_t w2c_wasi__snapshot__preview1_args_sizes_get(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr argc, wasm_ptr argv_buf_size) 91 | { 92 | uvwasi_size_t uvcount; 93 | uvwasi_size_t uvbufsize; 94 | uvwasi_errno_t ret = uvwasi_args_sizes_get(wp->uvwasi, &uvcount, &uvbufsize); 95 | if (ret == UVWASI_ESUCCESS) { 96 | MEM_WRITE32(argc, uvcount); 97 | MEM_WRITE32(argv_buf_size, uvbufsize); 98 | } 99 | return ret; 100 | } 101 | 102 | uint32_t w2c_wasi__snapshot__preview1_args_get(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr argv, wasm_ptr buf) 103 | { 104 | uvwasi_size_t uvcount; 105 | uvwasi_size_t uvbufsize; 106 | uvwasi_errno_t ret; 107 | ret = uvwasi_args_sizes_get(wp->uvwasi, &uvcount, &uvbufsize); 108 | if (ret != UVWASI_ESUCCESS) { 109 | return ret; 110 | } 111 | 112 | // TODO XXX: check mem 113 | 114 | char** uvarg = calloc(uvcount, sizeof(char*)); 115 | if (uvarg == NULL) { 116 | return UVWASI_ENOMEM; 117 | } 118 | 119 | ret = uvwasi_args_get(wp->uvwasi, uvarg, (char*)MEMACCESS(buf)); 120 | if (ret != UVWASI_ESUCCESS) { 121 | free(uvarg); 122 | return ret; 123 | } 124 | 125 | for (uint32_t i = 0; i < uvcount; ++i) 126 | { 127 | uint32_t offset = buf + (uvarg[i] - uvarg[0]); 128 | MEM_WRITE32(argv+(i*sizeof(wasm_ptr)), offset); 129 | } 130 | 131 | free(uvarg); 132 | 133 | return ret; 134 | } 135 | 136 | uint32_t w2c_wasi__snapshot__preview1_fd_fdstat_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr stat) 137 | { 138 | uvwasi_fdstat_t uvstat; 139 | uvwasi_errno_t ret = uvwasi_fd_fdstat_get(wp->uvwasi, fd, &uvstat); 140 | if (ret == UVWASI_ESUCCESS) { 141 | MEM_SET(stat, 0, 24); 142 | MEM_WRITE8 (stat+0, uvstat.fs_filetype); 143 | MEM_WRITE16(stat+2, uvstat.fs_flags); 144 | MEM_WRITE64(stat+8, uvstat.fs_rights_base); 145 | MEM_WRITE64(stat+16, uvstat.fs_rights_inheriting); 146 | } 147 | return ret; 148 | } 149 | 150 | uint32_t w2c_wasi__snapshot__preview1_fd_fdstat_set_flags(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint32_t flags) 151 | { 152 | uvwasi_errno_t ret = uvwasi_fd_fdstat_set_flags(wp->uvwasi, fd, flags); 153 | return ret; 154 | } 155 | 156 | uint32_t w2c_wasi__snapshot__preview1_fd_fdstat_set_rights(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t fs_rights_base, uint64_t fs_rights_inheriting) 157 | { 158 | uvwasi_errno_t ret = uvwasi_fd_fdstat_set_rights(wp->uvwasi, fd, fs_rights_base, fs_rights_inheriting); 159 | return ret; 160 | } 161 | 162 | uint32_t w2c_wasi__snapshot__preview1_path_filestat_set_times(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint32_t flags, wasm_ptr path, uint32_t path_len, uint64_t atim, uint64_t mtim, uint32_t fst_flags) 163 | { 164 | uvwasi_errno_t ret = uvwasi_path_filestat_set_times(wp->uvwasi, fd, flags, (char*)MEMACCESS(path), path_len, atim, mtim, fst_flags); 165 | return ret; 166 | } 167 | 168 | uint32_t w2c_wasi__snapshot__preview1_path_filestat_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint32_t flags, wasm_ptr path, uint32_t path_len, wasm_ptr stat) 169 | { 170 | uvwasi_filestat_t uvstat; 171 | uvwasi_errno_t ret = uvwasi_path_filestat_get(wp->uvwasi, fd, flags, (char*)MEMACCESS(path), path_len, &uvstat); 172 | if (ret == UVWASI_ESUCCESS) { 173 | MEM_SET(stat, 0, 64); 174 | MEM_WRITE64(stat+0, uvstat.st_dev); 175 | MEM_WRITE64(stat+8, uvstat.st_ino); 176 | MEM_WRITE8 (stat+16, uvstat.st_filetype); 177 | MEM_WRITE64(stat+24, uvstat.st_nlink); 178 | MEM_WRITE64(stat+32, uvstat.st_size); 179 | MEM_WRITE64(stat+40, uvstat.st_atim); 180 | MEM_WRITE64(stat+48, uvstat.st_mtim); 181 | MEM_WRITE64(stat+56, uvstat.st_ctim); 182 | } 183 | return ret; 184 | } 185 | 186 | uint32_t w2c_wasi__snapshot__preview1_fd_filestat_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr stat) 187 | { 188 | uvwasi_filestat_t uvstat; 189 | uvwasi_errno_t ret = uvwasi_fd_filestat_get(wp->uvwasi, fd, &uvstat); 190 | if (ret == UVWASI_ESUCCESS) { 191 | MEM_SET(stat, 0, 64); 192 | MEM_WRITE64(stat+0, uvstat.st_dev); 193 | MEM_WRITE64(stat+8, uvstat.st_ino); 194 | MEM_WRITE8 (stat+16, uvstat.st_filetype); 195 | MEM_WRITE64(stat+24, uvstat.st_nlink); 196 | MEM_WRITE64(stat+32, uvstat.st_size); 197 | MEM_WRITE64(stat+40, uvstat.st_atim); 198 | MEM_WRITE64(stat+48, uvstat.st_mtim); 199 | MEM_WRITE64(stat+56, uvstat.st_ctim); 200 | } 201 | return ret; 202 | } 203 | 204 | uint32_t w2c_wasi__snapshot__preview1_fd_seek(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t offset, uint32_t wasi_whence, wasm_ptr pos) 205 | { 206 | uvwasi_whence_t whence = -1; 207 | switch (wasi_whence) { 208 | case 0: whence = UVWASI_WHENCE_SET; break; 209 | case 1: whence = UVWASI_WHENCE_CUR; break; 210 | case 2: whence = UVWASI_WHENCE_END; break; 211 | } 212 | 213 | uvwasi_filesize_t uvpos; 214 | uvwasi_errno_t ret = uvwasi_fd_seek(wp->uvwasi, fd, offset, whence, &uvpos); 215 | MEM_WRITE64(pos, uvpos); 216 | return ret; 217 | } 218 | 219 | uint32_t w2c_wasi__snapshot__preview1_fd_tell(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr pos) 220 | { 221 | uvwasi_filesize_t uvpos; 222 | uvwasi_errno_t ret = uvwasi_fd_tell(wp->uvwasi, fd, &uvpos); 223 | MEM_WRITE64(pos, uvpos); 224 | return ret; 225 | } 226 | 227 | 228 | uint32_t w2c_wasi__snapshot__preview1_fd_filestat_set_size(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t filesize) 229 | { 230 | uvwasi_errno_t ret = uvwasi_fd_filestat_set_size(wp->uvwasi, fd, filesize); 231 | return ret; 232 | } 233 | 234 | uint32_t w2c_wasi__snapshot__preview1_fd_filestat_set_times(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t atim, uint64_t mtim, uint32_t fst_flags) 235 | { 236 | uvwasi_errno_t ret = uvwasi_fd_filestat_set_times(wp->uvwasi, fd, atim, mtim, fst_flags); 237 | return ret; 238 | } 239 | 240 | 241 | uint32_t w2c_wasi__snapshot__preview1_fd_sync(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd) 242 | { 243 | uvwasi_errno_t ret = uvwasi_fd_sync(wp->uvwasi, fd); 244 | return ret; 245 | } 246 | 247 | uint32_t w2c_wasi__snapshot__preview1_fd_datasync(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd) 248 | { 249 | uvwasi_errno_t ret = uvwasi_fd_datasync(wp->uvwasi, fd); 250 | return ret; 251 | } 252 | 253 | uint32_t w2c_wasi__snapshot__preview1_fd_renumber(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd_from, uint32_t fd_to) 254 | { 255 | uvwasi_errno_t ret = uvwasi_fd_renumber(wp->uvwasi, fd_from, fd_to); 256 | return ret; 257 | } 258 | 259 | 260 | uint32_t w2c_wasi__snapshot__preview1_fd_allocate(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t offset, uint64_t len) 261 | { 262 | uvwasi_errno_t ret = uvwasi_fd_allocate(wp->uvwasi, fd, offset, len); 263 | return ret; 264 | } 265 | 266 | uint32_t w2c_wasi__snapshot__preview1_fd_advise(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, uint64_t offset, uint64_t len, uint32_t advice) 267 | { 268 | uvwasi_errno_t ret = uvwasi_fd_advise(wp->uvwasi, fd, offset, len, advice); 269 | return ret; 270 | } 271 | 272 | uint32_t w2c_wasi__snapshot__preview1_path_open(struct w2c_wasi__snapshot__preview1* wp, uint32_t dirfd, uint32_t dirflags, 273 | wasm_ptr path, uint32_t path_len, 274 | uint32_t oflags, uint64_t fs_rights_base, uint64_t fs_rights_inheriting, 275 | uint32_t fs_flags, wasm_ptr fd) 276 | { 277 | uvwasi_fd_t uvfd; 278 | uvwasi_errno_t ret = uvwasi_path_open(wp->uvwasi, 279 | dirfd, 280 | dirflags, 281 | (char*)MEMACCESS(path), 282 | path_len, 283 | oflags, 284 | fs_rights_base, 285 | fs_rights_inheriting, 286 | fs_flags, 287 | &uvfd); 288 | MEM_WRITE32(fd, uvfd); 289 | return ret; 290 | } 291 | 292 | uint32_t w2c_wasi__snapshot__preview1_fd_close(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd) 293 | { 294 | uvwasi_errno_t ret = uvwasi_fd_close(wp->uvwasi, fd); 295 | return ret; 296 | } 297 | 298 | uint32_t w2c_wasi__snapshot__preview1_path_symlink(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr old_path, uint32_t old_path_len, 299 | uint32_t fd, wasm_ptr new_path, uint32_t new_path_len) 300 | { 301 | uvwasi_errno_t ret = uvwasi_path_symlink(wp->uvwasi, (char*)MEMACCESS(old_path), old_path_len, 302 | fd, (char*)MEMACCESS(new_path), new_path_len); 303 | return ret; 304 | } 305 | 306 | uint32_t w2c_wasi__snapshot__preview1_path_rename(struct w2c_wasi__snapshot__preview1* wp, uint32_t old_fd, wasm_ptr old_path, 307 | uint32_t old_path_len, uint32_t new_fd, wasm_ptr new_path, uint32_t new_path_len) 308 | { 309 | uvwasi_errno_t ret = uvwasi_path_rename(wp->uvwasi, old_fd, (char*)MEMACCESS(old_path), old_path_len, 310 | new_fd, (char*)MEMACCESS(new_path), new_path_len); 311 | return ret; 312 | } 313 | 314 | uint32_t w2c_wasi__snapshot__preview1_path_link(struct w2c_wasi__snapshot__preview1* wp, uint32_t old_fd, uint32_t old_flags, 315 | wasm_ptr old_path, uint32_t old_path_len, uint32_t new_fd, wasm_ptr new_path, uint32_t new_path_len) 316 | { 317 | uvwasi_errno_t ret = uvwasi_path_link(wp->uvwasi, old_fd, old_flags, (char*)MEMACCESS(old_path), old_path_len, 318 | new_fd, (char*)MEMACCESS(new_path), new_path_len); 319 | return ret; 320 | } 321 | 322 | uint32_t w2c_wasi__snapshot__preview1_path_unlink_file(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr path, uint32_t path_len) 323 | { 324 | uvwasi_errno_t ret = uvwasi_path_unlink_file(wp->uvwasi, fd, (char*)MEMACCESS(path), path_len); 325 | return ret; 326 | } 327 | 328 | uint32_t w2c_wasi__snapshot__preview1_path_readlink(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr path, uint32_t path_len, wasm_ptr buf, uint32_t buf_len, wasm_ptr bufused) 329 | { 330 | uvwasi_size_t uvbufused; 331 | uvwasi_errno_t ret = uvwasi_path_readlink(wp->uvwasi, fd, (char*)MEMACCESS(path), path_len, MEMACCESS(buf), buf_len, &uvbufused); 332 | 333 | MEM_WRITE32(bufused, uvbufused); 334 | return ret; 335 | } 336 | 337 | uint32_t w2c_wasi__snapshot__preview1_path_create_directory(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr path, uint32_t path_len) 338 | { 339 | uvwasi_errno_t ret = uvwasi_path_create_directory(wp->uvwasi, fd, (char*)MEMACCESS(path), path_len); 340 | return ret; 341 | } 342 | 343 | uint32_t w2c_wasi__snapshot__preview1_path_remove_directory(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr path, uint32_t path_len) 344 | { 345 | uvwasi_errno_t ret = uvwasi_path_remove_directory(wp->uvwasi, fd, (char*)MEMACCESS(path), path_len); 346 | return ret; 347 | } 348 | 349 | uint32_t w2c_wasi__snapshot__preview1_fd_readdir(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr buf, uint32_t buf_len, uint64_t cookie, wasm_ptr bufused) 350 | { 351 | uvwasi_size_t uvbufused; 352 | uvwasi_errno_t ret = uvwasi_fd_readdir(wp->uvwasi, fd, MEMACCESS(buf), buf_len, cookie, &uvbufused); 353 | MEM_WRITE32(bufused, uvbufused); 354 | return ret; 355 | } 356 | 357 | typedef struct wasi_iovec_t 358 | { 359 | uvwasi_size_t buf; 360 | uvwasi_size_t buf_len; 361 | } wasi_iovec_t; 362 | 363 | uint32_t w2c_wasi__snapshot__preview1_fd_write(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr iovs_offset, uint32_t iovs_len, wasm_ptr nwritten) 364 | { 365 | wasi_iovec_t * wasi_iovs = (wasi_iovec_t *)MEMACCESS(iovs_offset); 366 | 367 | #if defined(_MSC_VER) 368 | if (iovs_len > 32) return UVWASI_EINVAL; 369 | uvwasi_ciovec_t iovs[32]; 370 | #else 371 | if (iovs_len > 128) return UVWASI_EINVAL; 372 | uvwasi_ciovec_t iovs[iovs_len]; 373 | #endif 374 | for (uvwasi_size_t i = 0; i < iovs_len; ++i) { 375 | iovs[i].buf = MEMACCESS(READ32(&wasi_iovs[i].buf)); 376 | iovs[i].buf_len = READ32(&wasi_iovs[i].buf_len); 377 | } 378 | 379 | uvwasi_size_t num_written; 380 | uvwasi_errno_t ret = uvwasi_fd_write(wp->uvwasi, fd, iovs, iovs_len, &num_written); 381 | MEM_WRITE32(nwritten, num_written); 382 | return ret; 383 | } 384 | 385 | 386 | uint32_t w2c_wasi__snapshot__preview1_fd_pwrite(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr iovs_offset, uint32_t iovs_len, uint64_t offset, wasm_ptr nwritten) 387 | { 388 | wasi_iovec_t * wasi_iovs = (wasi_iovec_t *)MEMACCESS(iovs_offset); 389 | 390 | #if defined(_MSC_VER) 391 | if (iovs_len > 32) return UVWASI_EINVAL; 392 | uvwasi_ciovec_t iovs[32]; 393 | #else 394 | if (iovs_len > 128) return UVWASI_EINVAL; 395 | uvwasi_ciovec_t iovs[iovs_len]; 396 | #endif 397 | for (uvwasi_size_t i = 0; i < iovs_len; ++i) { 398 | iovs[i].buf = MEMACCESS(READ32(&wasi_iovs[i].buf)); 399 | iovs[i].buf_len = READ32(&wasi_iovs[i].buf_len); 400 | } 401 | 402 | uvwasi_size_t num_written; 403 | uvwasi_errno_t ret = uvwasi_fd_pwrite(wp->uvwasi, fd, iovs, iovs_len, offset, &num_written); 404 | MEM_WRITE32(nwritten, num_written); 405 | return ret; 406 | } 407 | 408 | uint32_t w2c_wasi__snapshot__preview1_fd_read(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr iovs_offset, uint32_t iovs_len, wasm_ptr nread) 409 | { 410 | wasi_iovec_t * wasi_iovs = (wasi_iovec_t *)MEMACCESS(iovs_offset); 411 | 412 | #if defined(_MSC_VER) 413 | if (iovs_len > 32) return UVWASI_EINVAL; 414 | uvwasi_ciovec_t iovs[32]; 415 | #else 416 | if (iovs_len > 128) return UVWASI_EINVAL; 417 | uvwasi_ciovec_t iovs[iovs_len]; 418 | #endif 419 | 420 | for (uvwasi_size_t i = 0; i < iovs_len; ++i) { 421 | iovs[i].buf = MEMACCESS(READ32(&wasi_iovs[i].buf)); 422 | iovs[i].buf_len = READ32(&wasi_iovs[i].buf_len); 423 | } 424 | 425 | uvwasi_size_t num_read; 426 | uvwasi_errno_t ret = uvwasi_fd_read(wp->uvwasi, fd, (const uvwasi_iovec_t *)iovs, iovs_len, &num_read); 427 | MEM_WRITE32(nread, num_read); 428 | return ret; 429 | } 430 | 431 | uint32_t w2c_wasi__snapshot__preview1_fd_pread(struct w2c_wasi__snapshot__preview1* wp, uint32_t fd, wasm_ptr iovs_offset, uint32_t iovs_len, uint64_t offset, wasm_ptr nread) 432 | { 433 | wasi_iovec_t * wasi_iovs = (wasi_iovec_t *)MEMACCESS(iovs_offset); 434 | 435 | #if defined(_MSC_VER) 436 | if (iovs_len > 32) return UVWASI_EINVAL; 437 | uvwasi_ciovec_t iovs[32]; 438 | #else 439 | if (iovs_len > 128) return UVWASI_EINVAL; 440 | uvwasi_ciovec_t iovs[iovs_len]; 441 | #endif 442 | 443 | for (uvwasi_size_t i = 0; i < iovs_len; ++i) { 444 | iovs[i].buf = MEMACCESS(READ32(&wasi_iovs[i].buf)); 445 | iovs[i].buf_len = READ32(&wasi_iovs[i].buf_len); 446 | } 447 | 448 | uvwasi_size_t num_read; 449 | uvwasi_errno_t ret = uvwasi_fd_pread(wp->uvwasi, fd, (const uvwasi_iovec_t *)iovs, iovs_len, offset, &num_read); 450 | MEM_WRITE32(nread, num_read); 451 | return ret; 452 | } 453 | 454 | // TODO XXX: audit, compare with spec 455 | uint32_t w2c_wasi__snapshot__preview1_poll_oneoff(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr in, wasm_ptr out, uint32_t nsubscriptions, wasm_ptr nevents) 456 | { 457 | uvwasi_size_t uvnevents; 458 | uvwasi_errno_t ret = uvwasi_poll_oneoff(wp->uvwasi, MEMACCESS(in), MEMACCESS(out), nsubscriptions, &uvnevents); 459 | MEM_WRITE32(nevents, uvnevents); 460 | return ret; 461 | } 462 | 463 | 464 | uint32_t w2c_wasi__snapshot__preview1_clock_res_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t clk_id, wasm_ptr result) 465 | { 466 | uvwasi_timestamp_t t; 467 | uvwasi_errno_t ret = uvwasi_clock_res_get(wp->uvwasi, clk_id, &t); 468 | MEM_WRITE64(result, t); 469 | return ret; 470 | } 471 | 472 | uint32_t w2c_wasi__snapshot__preview1_clock_time_get(struct w2c_wasi__snapshot__preview1* wp, uint32_t clk_id, uint64_t precision, wasm_ptr result) 473 | { 474 | uvwasi_timestamp_t t; 475 | uvwasi_errno_t ret = uvwasi_clock_time_get(wp->uvwasi, clk_id, precision, &t); 476 | MEM_WRITE64(result, t); 477 | return ret; 478 | } 479 | 480 | uint32_t w2c_wasi__snapshot__preview1_random_get(struct w2c_wasi__snapshot__preview1* wp, wasm_ptr buf, uint32_t buf_len) 481 | { 482 | uvwasi_errno_t ret = uvwasi_random_get(wp->uvwasi, MEMACCESS(buf), buf_len); 483 | return ret; 484 | } 485 | 486 | uint32_t w2c_wasi__snapshot__preview1_sched_yield(struct w2c_wasi__snapshot__preview1* wp) 487 | { 488 | uvwasi_errno_t ret = uvwasi_sched_yield(wp->uvwasi); 489 | return ret; 490 | } 491 | 492 | uint32_t w2c_wasi__snapshot__preview1_proc_raise(struct w2c_wasi__snapshot__preview1* wp, uint32_t sig) 493 | { 494 | uvwasi_errno_t ret = uvwasi_proc_raise(wp->uvwasi, sig); 495 | return ret; 496 | } 497 | 498 | void w2c_wasi__snapshot__preview1_proc_exit(struct w2c_wasi__snapshot__preview1* wp, uint32_t code) 499 | { 500 | uvwasi_destroy(wp->uvwasi); 501 | exit(code); 502 | } 503 | 504 | -------------------------------------------------------------------------------- /rt/uvwasi-rt.h: -------------------------------------------------------------------------------- 1 | #ifndef UVWASI_RT_H 2 | #define UVWASI_RT_H 3 | 4 | #include "uvwasi.h" 5 | #include "wasm-rt.h" 6 | 7 | struct w2c_wasi__snapshot__preview1 { 8 | uvwasi_t * uvwasi; 9 | wasm_rt_memory_t * instance_memory; 10 | }; 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /rt/w2c2-main.c: -------------------------------------------------------------------------------- 1 | #include "w2c2_base.h" 2 | #include "wasi.h" 3 | #include "{{ .Hwasm }}" 4 | #include 5 | 6 | extern char** environ; 7 | 8 | void 9 | trap( 10 | Trap trap 11 | ) { 12 | fprintf(stderr, "TRAP: %s\n", trapDescription(trap)); 13 | abort(); 14 | } 15 | 16 | wasmMemory* wasiMemory(void* instance) { 17 | return {{ .Name }}_memory(({{ .Name }}Instance*)instance); 18 | } 19 | 20 | int 21 | main(int argc, char* argv[]) { 22 | {{ .Name }}Instance instance; 23 | {{ .Name }}Instantiate(&instance, NULL); 24 | if (!wasiInit(argc, argv, environ)) { 25 | fprintf(stderr, "failed to initialize WASI\n"); 26 | return 1; 27 | } 28 | 29 | if (!wasiFileDescriptorAdd(-1, "/home", NULL)) { 30 | fprintf(stderr, "failed to add preopen\n"); 31 | return 1; 32 | } 33 | if (!wasiFileDescriptorAdd(-1, ".", NULL)) { 34 | fprintf(stderr, "failed to add preopen\n"); 35 | return 1; 36 | } 37 | 38 | {{ .Name }}__start(&instance); 39 | {{ .Name }}FreeInstance(&instance); 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /wasm2bin-clang/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // This is a wrapper around clang that invokes a WebAssembly compiler after 4 | // building so that it produces an executable rather than a Wasm binary. 5 | 6 | import ( 7 | "fmt" 8 | "log" 9 | "os" 10 | "os/exec" 11 | "strings" 12 | ) 13 | 14 | func run(cmd string, args ...string) { 15 | c := exec.Command(cmd, args...) 16 | log.Println(c) 17 | c.Stdout = os.Stdout 18 | c.Stdin = os.Stdin 19 | c.Stderr = os.Stderr 20 | if err := c.Run(); err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | 25 | func main() { 26 | var out string 27 | clang := "clang" 28 | link := true 29 | args := make([]string, 0, len(os.Args)) 30 | for i := 1; i < len(os.Args); i++ { 31 | arg := os.Args[i] 32 | if strings.HasSuffix(arg, ".c") || 33 | strings.HasSuffix(arg, ".cc") || 34 | strings.HasSuffix(arg, ".cpp") || 35 | strings.HasSuffix(arg, ".cxx") || 36 | strings.HasSuffix(arg, ".c++") || 37 | strings.HasSuffix(arg, ".s") || 38 | strings.HasSuffix(arg, ".S") || 39 | strings.HasSuffix(arg, ".C") { 40 | link = false 41 | } 42 | switch arg { 43 | case "-compiler": 44 | if i+1 >= len(os.Args) { 45 | log.Fatal("-o needs an argument") 46 | } 47 | clang = os.Args[i+1] 48 | i++ 49 | case "-c": 50 | link = false 51 | args = append(args, arg) 52 | case "-o": 53 | if i+1 >= len(os.Args) { 54 | log.Fatal("-o needs an argument") 55 | } 56 | out = os.Args[i+1] 57 | i++ 58 | args = append(args, "-o", out) 59 | default: 60 | args = append(args, arg) 61 | } 62 | } 63 | 64 | if out == "" && link { 65 | out = "a.out" 66 | } 67 | 68 | run(clang, args...) 69 | if !link { 70 | return 71 | } 72 | 73 | postlink := os.Getenv("POSTLINKCMD") 74 | var flags string 75 | if strings.Contains(postlink, "wasm2c") { 76 | module := strings.ReplaceAll(out, "_", "__") + "__base" 77 | flags = fmt.Sprintf("-n %s", module) 78 | } else if strings.Contains(postlink, "wamrc") { 79 | flags = "--target=aarch64" 80 | } else if strings.Contains(postlink, "w2c2") { 81 | module := strings.ReplaceAll(out, "_", "") + "base" 82 | flags = fmt.Sprintf("-n %s", module) 83 | } else if strings.Contains(postlink, "wasmtime") { 84 | // nothing to do 85 | } 86 | in := out + "_base.wasm" 87 | opt := out + "_base.opt.wasm" 88 | run("cp", out, in) 89 | 90 | run("sh", "-c", fmt.Sprintf("wasm-opt -O3 %s -o %s; %s %s -o %s %s", in, opt, postlink, flags, out, in)) 91 | } 92 | --------------------------------------------------------------------------------