]> git.proxmox.com Git - rustc.git/blob - src/binaryen/src/tools/s2wasm.cpp
New upstream version 1.23.0+dfsg1
[rustc.git] / src / binaryen / src / tools / s2wasm.cpp
1 /*
2 * Copyright 2015 WebAssembly Community Group participants
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //
18 // s2wasm console tool
19 //
20
21 #include <exception>
22
23 #include "ir/trapping.h"
24 #include "support/colors.h"
25 #include "support/command-line.h"
26 #include "support/file.h"
27 #include "s2wasm.h"
28 #include "wasm-emscripten.h"
29 #include "wasm-linker.h"
30 #include "wasm-printing.h"
31 #include "wasm-validator.h"
32
33 using namespace cashew;
34 using namespace wasm;
35
36 int main(int argc, const char *argv[]) {
37 bool ignoreUnknownSymbols = false;
38 bool generateEmscriptenGlue = false;
39 bool allowMemoryGrowth = false;
40 bool importMemory = false;
41 std::string startFunction;
42 std::vector<std::string> archiveLibraries;
43 TrapMode trapMode = TrapMode::Allow;
44 Options options("s2wasm", "Link .s file into .wast");
45 options.extra["validate"] = "wasm";
46 options
47 .add("--output", "-o", "Output file (stdout if not specified)",
48 Options::Arguments::One,
49 [](Options *o, const std::string &argument) {
50 o->extra["output"] = argument;
51 Colors::disable();
52 })
53 .add("--ignore-unknown", "", "Ignore unknown symbols",
54 Options::Arguments::Zero,
55 [&ignoreUnknownSymbols](Options *, const std::string &) {
56 ignoreUnknownSymbols = true;
57 })
58 .add("--start", "", "Generate the start method (default: main)",
59 Options::Arguments::Optional,
60 [&startFunction](Options *, const std::string &argument) {
61 startFunction = argument.size() ? argument : "main";
62 })
63 .add("--global-base", "-g", "Where to start to place globals",
64 Options::Arguments::One,
65 [](Options *o, const std::string &argument) {
66 o->extra["global-base"] = argument;
67 })
68 .add("--allocate-stack", "-s", "Size of the user stack in linear memory",
69 Options::Arguments::One,
70 [](Options *o, const std::string &argument) {
71 o->extra["stack-allocation"] = argument;
72 })
73 .add("--initial-memory", "-i", "Initial size of the linear memory",
74 Options::Arguments::One,
75 [](Options *o, const std::string &argument) {
76 o->extra["initial-memory"] = argument;
77 })
78 .add("--max-memory", "-m", "Maximum size of the linear memory",
79 Options::Arguments::One,
80 [](Options *o, const std::string &argument) {
81 o->extra["max-memory"] = argument;
82 })
83 .add("--allow-memory-growth", "", "Allow linear memory to grow at runtime",
84 Options::Arguments::Zero,
85 [&allowMemoryGrowth](Options *, const std::string &) {
86 allowMemoryGrowth = true;
87 })
88 .add("--trap-mode", "",
89 "Strategy for handling potentially trapping instructions. Valid "
90 "values are \"allow\", \"js\", and \"clamp\"",
91 Options::Arguments::One,
92 [&trapMode](Options *o, const std::string &argument) {
93 try {
94 trapMode = trapModeFromString(argument);
95 } catch (std::invalid_argument e) {
96 std::cerr << "Error: " << e.what() << "\n";
97 exit(EXIT_FAILURE);
98 }
99 })
100 .add("--emscripten-glue", "-e", "Generate emscripten glue",
101 Options::Arguments::Zero,
102 [&generateEmscriptenGlue](Options *, const std::string &) {
103 generateEmscriptenGlue = true;
104 })
105 .add("--import-memory", "", "Import the linear memory instead of exporting it",
106 Options::Arguments::Zero,
107 [&importMemory](Options *, const std::string &) {
108 importMemory = true;
109 })
110 .add("--library", "-l", "Add archive library",
111 Options::Arguments::N,
112 [&archiveLibraries](Options *o, const std::string &argument) {
113 archiveLibraries.push_back(argument);
114 })
115 .add("--validate", "-v", "Control validation of the output module",
116 Options::Arguments::One,
117 [](Options *o, const std::string &argument) {
118 if (argument != "web" && argument != "none" && argument != "wasm") {
119 std::cerr << "Valid arguments for --validate flag are 'wasm', 'web' and 'none'.\n";
120 exit(1);
121 }
122 o->extra["validate"] = argument;
123 })
124 .add_positional("INFILE", Options::Arguments::One,
125 [](Options *o, const std::string &argument) {
126 o->extra["infile"] = argument;
127 });
128 options.parse(argc, argv);
129
130 if (allowMemoryGrowth && !generateEmscriptenGlue) {
131 Fatal() << "Error: adding memory growth code without Emscripten glue. "
132 "This doesn't do anything.\n";
133 }
134
135 auto debugFlag = options.debug ? Flags::Debug : Flags::Release;
136 auto input(read_file<std::string>(options.extra["infile"], Flags::Text, debugFlag));
137
138 if (options.debug) std::cerr << "Parsing and wasming..." << std::endl;
139 uint64_t globalBase = options.extra.find("global-base") != options.extra.end()
140 ? std::stoull(options.extra["global-base"])
141 : 0;
142 uint64_t stackAllocation =
143 options.extra.find("stack-allocation") != options.extra.end()
144 ? std::stoull(options.extra["stack-allocation"])
145 : 0;
146 uint64_t initialMem =
147 options.extra.find("initial-memory") != options.extra.end()
148 ? std::stoull(options.extra["initial-memory"])
149 : 0;
150 uint64_t maxMem =
151 options.extra.find("max-memory") != options.extra.end()
152 ? std::stoull(options.extra["max-memory"])
153 : 0;
154 if (options.debug) std::cerr << "Global base " << globalBase << '\n';
155
156 Linker linker(globalBase, stackAllocation, initialMem, maxMem,
157 importMemory || generateEmscriptenGlue, ignoreUnknownSymbols, startFunction,
158 options.debug);
159
160 S2WasmBuilder mainbuilder(input.c_str(), options.debug);
161 linker.linkObject(mainbuilder);
162
163 if (trapMode != TrapMode::Allow) {
164 Module* wasm = &(linker.getOutput().wasm);
165 PassRunner runner(wasm);
166 addTrapModePass(runner, trapMode);
167 runner.run();
168 }
169
170 for (const auto& m : archiveLibraries) {
171 auto archiveFile(read_file<std::vector<char>>(m, Flags::Binary, debugFlag));
172 bool error;
173 Archive lib(archiveFile, error);
174 if (error) Fatal() << "Error opening archive " << m << "\n";
175 linker.linkArchive(lib);
176 }
177
178 linker.layout();
179
180 std::string metadata;
181 if (generateEmscriptenGlue) {
182 Module& wasm = linker.getOutput().wasm;
183 if (options.debug) {
184 std::cerr << "Emscripten gluing..." << std::endl;
185 WasmPrinter::printModule(&wasm, std::cerr);
186 }
187 metadata = emscriptenGlue(
188 wasm,
189 allowMemoryGrowth,
190 linker.getStackPointerAddress(),
191 linker.getStaticBump(),
192 linker.getOutput().getInitializerFunctions());
193 }
194
195 if (options.extra["validate"] != "none") {
196 if (options.debug) std::cerr << "Validating..." << std::endl;
197 Module* output = &linker.getOutput().wasm;
198 if (!wasm::WasmValidator().validate(*output,
199 WasmValidator::Globally | (options.extra["validate"] == "web" ? WasmValidator::Web : 0))) {
200 WasmPrinter::printModule(output);
201 Fatal() << "Error: linked module is not valid.\n";
202 }
203 }
204
205 if (options.debug) std::cerr << "Printing..." << std::endl;
206 Output output(options.extra["output"], Flags::Text, options.debug ? Flags::Debug : Flags::Release);
207 WasmPrinter::printModule(&linker.getOutput().wasm, output.getStream());
208 output << metadata;
209
210 if (options.debug) std::cerr << "Done." << std::endl;
211 return 0;
212 }