1 // Copyright 2019 Wouter van Oortmerssen. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef WASM_BINARY_WRITER_H
16 #define WASM_BINARY_WRITER_H
17 
18 #include "assert.h"
19 #include "cstring"
20 #include "vector"
21 #include "string"
22 #include "string_view"
23 
24 // Stand-alone single header WASM module writer class.
25 // Takes care of the "heavy lifting" of generating the binary format
26 // correctly, and provide a friendly code generation API, that may
27 // be useful outside of Lobster as well.
28 
29 // Documentation and example of the API in this file:
30 // http://aardappel.github.io/lobster/implementation_wasm.html
31 // (and see also test cases in wasm_binary_writer_test.h)
32 // Main use of this API in towasm.cpp.
33 
34 namespace WASM {
35 
36 enum class Section {
37     None = -1,
38     Custom = 0,
39     Type,
40     Import,
41     Function,
42     Table,
43     Memory,
44     Global,
45     Export,
46     Start,
47     Element,
48     Code,
49     Data,
50 };
51 
52 enum {
53     I32 = 0x7F,
54     I64 = 0x7E,
55     F32 = 0x7D,
56     F64 = 0x7C,
57     ANYFUNC = 0x70,
58     FUNC = 0x60,
59     VOID = 0x40,
60 };
61 
62 class BinaryWriter {
63     std::vector<uint8_t> &buf;
64     Section cur_section = Section::None;
65     Section last_known_section = Section::None;
66     size_t section_size = 0;
67     size_t section_count = 0;
68     size_t section_data = 0;
69     size_t section_index_in_file = 0;
70     size_t section_index_in_file_code = 0;
71     size_t section_index_in_file_data = 0;
72     size_t segment_payload_start = 0;
73     size_t num_function_imports = 0;
74     size_t num_global_imports = 0;
75     size_t num_function_decls = 0;
76     struct Function {
77         std::string name;
78         bool import;
79         bool local;
80     };
81     std::vector<Function> function_symbols;
82     size_t function_body_start = 0;
83     size_t data_section_size = 0;
84     struct DataSegment {
85         std::string name;
86         size_t align;
87         size_t size;
88         bool local;
89     };
90     std::vector<DataSegment> data_segments;
91     struct Reloc {
92         uint8_t type;
93         size_t src_offset;    // Where we are doing the relocation.
94         size_t sym_index;     // If is_function.
95         size_t target_index;  // Index inside thing we're referring to, e.g. addend.
96         bool is_function;
97     };
98     std::vector<Reloc> code_relocs;
99     std::vector<Reloc> data_relocs;
100 
UInt8(T v)101     template<typename T> void UInt8(T v) {
102         buf.push_back(static_cast<uint8_t>(v));
103     }
104 
UInt16(T v)105     template<typename T> void UInt16(T v) {
106         UInt8(v & 0xFF);
107         UInt8(v >> 8);
108     }
109 
UInt32(T v)110     template<typename T> void UInt32(T v) {
111         UInt16(v & 0xFFFF);
112         UInt16(v >> 16);
113     }
114 
UInt64(T v)115     template<typename T> void UInt64(T v) {
116         UInt32(v & 0xFFFFFFFF);
117         UInt32(v >> 32);
118     }
119 
Bits(T v)120     template<typename T, typename U> U Bits(T v) {
121         static_assert(sizeof(T) == sizeof(U), "");
122         U u;
123         memcpy(&u, &v, sizeof(T));
124         return u;
125     }
126 
ULEB(T v)127     template<typename T> void ULEB(T v) {
128         for (;;) {
129             UInt8(v & 0x7F);
130             v = (T)(v >> 7);
131             if (!v) break;
132             buf.back() |= 0x80;
133         }
134     }
135 
SLEB(T v)136     template<typename T> void SLEB(T v) {
137         auto negative = v < 0;
138         for (;;) {
139             UInt8(v & 0x7F);
140             auto sign = v & 0x40;
141             v = (T)(v >> 7);
142             if (negative) v |= T(0x7F) << (sizeof(T) * 8 - 7);
143             if ((!v && !sign) || (v == -1 && sign)) break;
144             buf.back() |= 0x80;
145         }
146     }
147 
148     enum { PATCHABLE_ULEB_SIZE = 5 };
149 
PatchableLEB()150     size_t PatchableLEB() {
151         auto pos = buf.size();
152         for (size_t i = 0; i < PATCHABLE_ULEB_SIZE - 1; i++) UInt8(0x80);
153         UInt8(0x00);
154         return pos;
155     }
156 
PatchULEB(size_t pos,size_t v)157     void PatchULEB(size_t pos, size_t v) {
158         for (size_t i = 0; i < PATCHABLE_ULEB_SIZE; i++) {
159             buf[pos + i] |= v & 0x7F;
160             v >>= 7;
161         }
162         assert(!v);
163     }
164 
Chars(std::string_view chars)165     void Chars(std::string_view chars) {
166         for (auto c : chars) UInt8(c);
167     }
168 
LenChars(std::string_view chars)169     size_t LenChars(std::string_view chars) {
170         ULEB(chars.size());
171         auto pos = buf.size();
172         Chars(chars);
173         return pos;
174     }
175 
StartsWithCount()176     bool StartsWithCount() {
177         return cur_section != Section::Custom &&
178                cur_section != Section::Start;
179     }
180 
181     enum {
182         R_WASM_FUNCTION_INDEX_LEB = 0,
183         R_WASM_TABLE_INDEX_SLEB = 1,
184         R_WASM_TABLE_INDEX_I32 = 2,
185         R_WASM_MEMORY_ADDR_LEB = 3,
186         R_WASM_MEMORY_ADDR_SLEB = 4,
187         R_WASM_MEMORY_ADDR_I32 = 5,
188         R_WASM_TYPE_INDEX_LEB = 6,
189         R_WASM_GLOBAL_INDEX_LEB = 7,
190         R_WASM_FUNCTION_OFFSET_I32 = 8,
191         R_WASM_SECTION_OFFSET_I32 = 9,
192         R_WASM_EVENT_INDEX_LEB = 10,
193     };
194 
195 
RelocULEB(uint8_t reloc_type,size_t sym_index,size_t target_index,bool is_function)196     void RelocULEB(uint8_t reloc_type, size_t sym_index, size_t target_index, bool is_function) {
197         code_relocs.push_back({ reloc_type,
198                                 buf.size() - section_data,
199                                 sym_index,
200                                 target_index,
201                                 is_function });
202         // A relocatable LEB typically can be 0, since all information about
203         // this value is stored in the relocation itself. But putting
204         // a meaningful value here will help with reading the output of
205         // objdump.
206         PatchULEB(PatchableLEB(), is_function ? sym_index : target_index);
207     }
208 
209   public:
210 
BinaryWriter(std::vector<uint8_t> & dest)211     explicit BinaryWriter(std::vector<uint8_t> &dest) : buf(dest) {
212         Chars(std::string_view("\0asm", 4));
213         UInt32(1);
214     }
215 
216     // Call Begin/EndSection pairs for each segment type, in order.
217     // In between, call the Add functions below corresponding to the section
218     // type.
219     void BeginSection(Section st, std::string_view name = "") {
220         // Call EndSection before calling another BeginSection.
221         assert(cur_section == Section::None);
222         cur_section = st;
223         if (st == Section::Code)
224             section_index_in_file_code = section_index_in_file;
225         if (st == Section::Data)
226             section_index_in_file_data = section_index_in_file;
227         UInt8(st);
228         section_size = PatchableLEB();
229         if (st == Section::Custom) {
230             LenChars(name);
231         } else {
232             // Known sections must be created in order and only once.
233             assert(st > last_known_section);
234             last_known_section = st;
235         }
236         section_count = 0;
237         section_data = buf.size();
238         if (StartsWithCount()) PatchableLEB();
239     }
240 
EndSection(Section st)241     void EndSection(Section st) {
242         assert(cur_section == st);
243         (void)st;
244         // Most sections start with a "count" field.
245         if (StartsWithCount()) {
246             PatchULEB(section_data, section_count);
247         }
248         // Patch up the size of this section.
249         PatchULEB(section_size, buf.size() - section_size - PATCHABLE_ULEB_SIZE);
250         cur_section = Section::None;
251         section_index_in_file++;
252     }
253 
AddType(const std::vector<unsigned> & params,const std::vector<unsigned> & returns)254     size_t AddType(const std::vector<unsigned> &params, const std::vector<unsigned> &returns) {
255         assert(cur_section == Section::Type);
256         ULEB(FUNC);
257         ULEB(params.size());
258         for (auto p : params) ULEB(p);
259         ULEB(returns.size());
260         for (auto r : returns) ULEB(r);
261         return section_count++;
262     }
263 
264     enum {
265         EXTERNAL_FUNCTION,
266         EXTERNAL_TABLE,
267         EXTERNAL_MEMORY,
268         EXTERNAL_GLOBAL,
269     };
270 
AddImportLinkFunction(std::string_view name,size_t tidx)271     size_t AddImportLinkFunction(std::string_view name, size_t tidx) {
272         LenChars("");  // Module, unused.
273         LenChars(name);
274         ULEB(EXTERNAL_FUNCTION);
275         ULEB(tidx);
276         function_symbols.push_back({ std::string(name), true, true });
277         section_count++;
278         return num_function_imports++;
279     }
280 
AddImportGlobal(std::string_view name,uint8_t type,bool is_mutable)281     size_t AddImportGlobal(std::string_view name, uint8_t type, bool is_mutable) {
282         LenChars("");  // Module, unused.
283         LenChars(name);
284         ULEB(EXTERNAL_GLOBAL);
285         UInt8(type);
286         ULEB<unsigned>(is_mutable);
287         section_count++;
288         return num_global_imports++;
289     }
290 
GetNumFunctionImports()291     size_t GetNumFunctionImports() { return num_function_imports; }
GetNumGlobalImports()292     size_t GetNumGlobalImports() { return num_global_imports; }
293 
AddFunction(size_t tidx)294     void AddFunction(size_t tidx) {
295         assert(cur_section == Section::Function);
296         ULEB(tidx);
297         num_function_decls++;
298         section_count++;
299     }
300 
GetNumDefinedFunctions()301     size_t GetNumDefinedFunctions() { return num_function_decls; }
302 
AddTable()303     void AddTable() {
304         assert(cur_section == Section::Table);
305         UInt8(WASM::ANYFUNC);  // Currently only option.
306         ULEB(0);  // Flags: no maximum.
307         ULEB(0);  // Initial length.
308         section_count++;
309     }
310 
AddMemory(size_t initial_pages)311     void AddMemory(size_t initial_pages) {
312         assert(cur_section == Section::Memory);
313         ULEB(0);  // Flags: no maximum.
314         ULEB(initial_pages);
315         section_count++;
316     }
317 
318     // You MUST emit an init exp after calling this, e.g. EmitI32Const(0); EmitEnd();
AddGlobal(uint8_t type,bool is_mutable)319     void AddGlobal(uint8_t type, bool is_mutable) {
320       assert(cur_section == Section::Global);
321       UInt8(type);
322       ULEB<unsigned>(is_mutable);
323       section_count++;
324     }
325 
AddExportFunction(std::string_view name,size_t fidx)326     void AddExportFunction(std::string_view name, size_t fidx) {
327         assert(cur_section == Section::Export);
328         LenChars(name);
329         ULEB(EXTERNAL_FUNCTION);
330         ULEB(fidx);
331     }
332 
AddExportGlobal(std::string_view name,size_t gidx)333     void AddExportGlobal(std::string_view name, size_t gidx) {
334         assert(cur_section == Section::Export);
335         LenChars(name);
336         ULEB(EXTERNAL_GLOBAL);
337         ULEB(gidx);
338     }
339 
AddStart(size_t fidx)340     void AddStart(size_t fidx) {
341         assert(cur_section == Section::Start);
342         ULEB(fidx);
343     }
344 
345     // Simple 1:1 mapping of function ids.
346     // TODO: add more flexible Element functions later.
AddElementAllFunctions()347     void AddElementAllFunctions() {
348         assert(cur_section == Section::Element);
349         ULEB(0);  // Table index, always 0 for now.
350         EmitI32Const(0);  // Offset.
351         EmitEnd();
352         auto total_funs = num_function_imports + num_function_decls;
353         ULEB(total_funs);
354         for (size_t i = 0; i < total_funs; i++) ULEB(i);
355         section_count++;
356     }
357 
358     // After calling this, use the Emit Functions below to add to the function body,
359     // and be sure to end with EmitEndFunction.
AddCode(const std::vector<unsigned> & locals,std::string_view name,bool local)360     void AddCode(const std::vector<unsigned> &locals, std::string_view name,
361                  bool local) {
362         assert(cur_section == Section::Code);
363         assert(!function_body_start);
364         function_body_start = PatchableLEB();
365         std::vector<std::pair<unsigned, unsigned>> entries;
366         for (auto l : locals) {
367             if (entries.empty() || entries.back().second != l) {
368                 entries.emplace_back(std::pair { 1, l });
369             } else {
370                 entries.back().first++;
371             }
372         }
373         ULEB(entries.size());
374         for (auto &e : entries) {
375             ULEB(e.first);
376             ULEB(e.second);
377         }
378         function_symbols.push_back({ std::string(name), false, local });
379         section_count++;
380     }
381 
382     // --- CONTROL FLOW ---
383 
EmitUnreachable()384     void EmitUnreachable() { UInt8(0x00); }
EmitNop()385     void EmitNop() { UInt8(0x01); }
EmitBlock(uint8_t block_type)386     void EmitBlock(uint8_t block_type) { UInt8(0x02); UInt8(block_type); }
EmitLoop(uint8_t block_type)387     void EmitLoop(uint8_t block_type) { UInt8(0x03); UInt8(block_type); }
EmitIf(uint8_t block_type)388     void EmitIf(uint8_t block_type) { UInt8(0x04); UInt8(block_type); }
EmitElse()389     void EmitElse() { UInt8(0x05); }
EmitEnd()390     void EmitEnd() { UInt8(0x0B); }
EmitBr(size_t relative_depth)391     void EmitBr(size_t relative_depth) { UInt8(0x0C); ULEB(relative_depth); }
EmitBrIf(size_t relative_depth)392     void EmitBrIf(size_t relative_depth) { UInt8(0x0D); ULEB(relative_depth); }
EmitBrTable(const std::vector<size_t> & targets,size_t default_target)393     void EmitBrTable(const std::vector<size_t> &targets, size_t default_target) {
394         UInt8(0x0E);
395         ULEB(targets.size());
396         for (auto t : targets) ULEB(t);
397         ULEB(default_target);
398     }
EmitReturn()399     void EmitReturn() { UInt8(0x0F); }
400 
401     // --- CALL OPERATORS ---
402 
403     // fun_idx is 0..N-1 imports followed by N..M-1 defined functions.
EmitCall(size_t fun_idx)404     void EmitCall(size_t fun_idx) {
405         UInt8(0x10);
406         RelocULEB(R_WASM_FUNCTION_INDEX_LEB, fun_idx, 0, true);
407     }
408 
EmitCallIndirect(size_t type_index)409     void EmitCallIndirect(size_t type_index) {
410         UInt8(0x11);
411         RelocULEB(R_WASM_TYPE_INDEX_LEB, 0, type_index, false);
412         ULEB(0);
413     }
414 
415     // --- PARAMETRIC OPERATORS
416 
EmitDrop()417     void EmitDrop() { UInt8(0x1A); }
EmitSelect()418     void EmitSelect() { UInt8(0x1B); }
419 
420     // --- VARIABLE ACCESS ---
421 
EmitGetLocal(size_t local)422     void EmitGetLocal(size_t local) { UInt8(0x20); ULEB(local); }
EmitSetLocal(size_t local)423     void EmitSetLocal(size_t local) { UInt8(0x21); ULEB(local); }
EmitTeeLocal(size_t local)424     void EmitTeeLocal(size_t local) { UInt8(0x22); ULEB(local); }
EmitGetGlobal(size_t global)425     void EmitGetGlobal(size_t global) { UInt8(0x23); ULEB(global); }
EmitSetGlobal(size_t global)426     void EmitSetGlobal(size_t global) { UInt8(0x24); ULEB(global); }
427 
428     // --- MEMORY ACCESS ---
429 
430     void EmitI32Load(size_t off, size_t flags = 2) { UInt8(0x28); ULEB(flags); ULEB(off); }
431     void EmitI64Load(size_t off, size_t flags = 3) { UInt8(0x29); ULEB(flags); ULEB(off); }
432     void EmitF32Load(size_t off, size_t flags = 2) { UInt8(0x2A); ULEB(flags); ULEB(off); }
433     void EmitF64Load(size_t off, size_t flags = 3) { UInt8(0x2B); ULEB(flags); ULEB(off); }
434     void EmitI32Load8S(size_t off, size_t flags = 0) { UInt8(0x2C); ULEB(flags); ULEB(off); }
435     void EmitI32Load8U(size_t off, size_t flags = 0) { UInt8(0x2D); ULEB(flags); ULEB(off); }
436     void EmitI32Load16S(size_t off, size_t flags = 1) { UInt8(0x2E); ULEB(flags); ULEB(off); }
437     void EmitI32Load16U(size_t off, size_t flags = 1) { UInt8(0x2F); ULEB(flags); ULEB(off); }
438     void EmitI64Load8S(size_t off, size_t flags = 0) { UInt8(0x30); ULEB(flags); ULEB(off); }
439     void EmitI64Load8U(size_t off, size_t flags = 0) { UInt8(0x31); ULEB(flags); ULEB(off); }
440     void EmitI64Load16S(size_t off, size_t flags = 1) { UInt8(0x32); ULEB(flags); ULEB(off); }
441     void EmitI64Load16U(size_t off, size_t flags = 1) { UInt8(0x33); ULEB(flags); ULEB(off); }
442     void EmitI64Load32S(size_t off, size_t flags = 2) { UInt8(0x34); ULEB(flags); ULEB(off); }
443     void EmitI64Load32U(size_t off, size_t flags = 2) { UInt8(0x35); ULEB(flags); ULEB(off); }
444 
445     void EmitI32Store(size_t off, size_t flags = 2) { UInt8(0x36); ULEB(flags); ULEB(off); }
446     void EmitI64Store(size_t off, size_t flags = 3) { UInt8(0x37); ULEB(flags); ULEB(off); }
447     void EmitF32Store(size_t off, size_t flags = 2) { UInt8(0x38); ULEB(flags); ULEB(off); }
448     void EmitF64Store(size_t off, size_t flags = 3) { UInt8(0x39); ULEB(flags); ULEB(off); }
449     void EmitI32Store8(size_t off, size_t flags = 0) { UInt8(0x3A); ULEB(flags); ULEB(off); }
450     void EmitI32Store16(size_t off, size_t flags = 1) { UInt8(0x3B); ULEB(flags); ULEB(off); }
451     void EmitI64Store8(size_t off, size_t flags = 0) { UInt8(0x3C); ULEB(flags); ULEB(off); }
452     void EmitI64Store16(size_t off, size_t flags = 1) { UInt8(0x3D); ULEB(flags); ULEB(off); }
453     void EmitI64Store32(size_t off, size_t flags = 2) { UInt8(0x3E); ULEB(flags); ULEB(off); }
454 
EmitCurrentMemory()455     void EmitCurrentMemory() { UInt8(0x3F); ULEB(0); }
EmitGrowMemory()456     void EmitGrowMemory() { UInt8(0x40); ULEB(0); }
457 
458     // --- CONSTANTS ---
459 
EmitI32Const(int32_t v)460     void EmitI32Const(int32_t v) { UInt8(0x41); SLEB(v); }
EmitI64Const(int64_t v)461     void EmitI64Const(int64_t v) { UInt8(0x42); SLEB(v); }
EmitF32Const(float v)462     void EmitF32Const(float v) { UInt8(0x43); UInt32(Bits<float, uint32_t>(v)); }
EmitF64Const(double v)463     void EmitF64Const(double v) { UInt8(0x44); UInt64(Bits<double, uint64_t>(v)); }
464 
465     // Getting the address of data in a data segment, encoded as a i32.const + reloc.
EmitI32ConstDataRef(size_t segment,size_t addend)466     void EmitI32ConstDataRef(size_t segment, size_t addend) {
467         UInt8(0x41);
468         RelocULEB(R_WASM_MEMORY_ADDR_SLEB, segment, addend, false );
469     }
470 
471     // fun_idx is 0..N-1 imports followed by N..M-1 defined functions.
EmitI32ConstFunctionRef(size_t fun_idx)472     void EmitI32ConstFunctionRef(size_t fun_idx) {
473         UInt8(0x41);
474         RelocULEB(R_WASM_TABLE_INDEX_SLEB, fun_idx, 0, true);
475     }
476 
477     // --- COMPARISON OPERATORS ---
478 
EmitI32Eqz()479     void EmitI32Eqz() { UInt8(0x45); }
EmitI32Eq()480     void EmitI32Eq() { UInt8(0x46); }
EmitI32Ne()481     void EmitI32Ne() { UInt8(0x47); }
EmitI32LtS()482     void EmitI32LtS() { UInt8(0x48); }
EmitI32LtU()483     void EmitI32LtU() { UInt8(0x49); }
EmitI32GtS()484     void EmitI32GtS() { UInt8(0x4A); }
EmitI32GtU()485     void EmitI32GtU() { UInt8(0x4B); }
EmitI32LeS()486     void EmitI32LeS() { UInt8(0x4C); }
EmitI32LeU()487     void EmitI32LeU() { UInt8(0x4D); }
EmitI32GeS()488     void EmitI32GeS() { UInt8(0x4E); }
EmitI32GeU()489     void EmitI32GeU() { UInt8(0x4F); }
490 
EmitI64Eqz()491     void EmitI64Eqz() { UInt8(0x50); }
EmitI64Eq()492     void EmitI64Eq() { UInt8(0x51); }
EmitI64Ne()493     void EmitI64Ne() { UInt8(0x52); }
EmitI64LtS()494     void EmitI64LtS() { UInt8(0x53); }
EmitI64LtU()495     void EmitI64LtU() { UInt8(0x54); }
EmitI64GtS()496     void EmitI64GtS() { UInt8(0x55); }
EmitI64GtU()497     void EmitI64GtU() { UInt8(0x56); }
EmitI64LeS()498     void EmitI64LeS() { UInt8(0x57); }
EmitI64LeU()499     void EmitI64LeU() { UInt8(0x58); }
EmitI64GeS()500     void EmitI64GeS() { UInt8(0x59); }
EmitI64GeU()501     void EmitI64GeU() { UInt8(0x5A); }
502 
EmitF32Eq()503     void EmitF32Eq() { UInt8(0x5B); }
EmitF32Ne()504     void EmitF32Ne() { UInt8(0x5C); }
EmitF32Lt()505     void EmitF32Lt() { UInt8(0x5D); }
EmitF32Gt()506     void EmitF32Gt() { UInt8(0x5E); }
EmitF32Le()507     void EmitF32Le() { UInt8(0x5F); }
EmitF32Ge()508     void EmitF32Ge() { UInt8(0x60); }
509 
EmitF64Eq()510     void EmitF64Eq() { UInt8(0x61); }
EmitF64Ne()511     void EmitF64Ne() { UInt8(0x62); }
EmitF64Lt()512     void EmitF64Lt() { UInt8(0x63); }
EmitF64Gt()513     void EmitF64Gt() { UInt8(0x64); }
EmitF64Le()514     void EmitF64Le() { UInt8(0x65); }
EmitF64Ge()515     void EmitF64Ge() { UInt8(0x66); }
516 
517     // --- NUMERIC OPERATORS
518 
EmitI32Clz()519     void EmitI32Clz() { UInt8(0x67); }
EmitI32Ctz()520     void EmitI32Ctz() { UInt8(0x68); }
EmitI32PopCnt()521     void EmitI32PopCnt() { UInt8(0x69); }
EmitI32Add()522     void EmitI32Add() { UInt8(0x6A); }
EmitI32Sub()523     void EmitI32Sub() { UInt8(0x6B); }
EmitI32Mul()524     void EmitI32Mul() { UInt8(0x6C); }
EmitI32DivS()525     void EmitI32DivS() { UInt8(0x6D); }
EmitI32DivU()526     void EmitI32DivU() { UInt8(0x6E); }
EmitI32RemS()527     void EmitI32RemS() { UInt8(0x6F); }
EmitI32RemU()528     void EmitI32RemU() { UInt8(0x70); }
EmitI32And()529     void EmitI32And() { UInt8(0x71); }
EmitI32Or()530     void EmitI32Or() { UInt8(0x72); }
EmitI32Xor()531     void EmitI32Xor() { UInt8(0x73); }
EmitI32Shl()532     void EmitI32Shl() { UInt8(0x74); }
EmitI32ShrS()533     void EmitI32ShrS() { UInt8(0x75); }
EmitI32ShrU()534     void EmitI32ShrU() { UInt8(0x76); }
EmitI32RotL()535     void EmitI32RotL() { UInt8(0x77); }
EmitI32RotR()536     void EmitI32RotR() { UInt8(0x78); }
537 
EmitI64Clz()538     void EmitI64Clz() { UInt8(0x79); }
EmitI64Ctz()539     void EmitI64Ctz() { UInt8(0x7A); }
EmitI64PopCnt()540     void EmitI64PopCnt() { UInt8(0x7B); }
EmitI64Add()541     void EmitI64Add() { UInt8(0x7C); }
EmitI64Sub()542     void EmitI64Sub() { UInt8(0x7D); }
EmitI64Mul()543     void EmitI64Mul() { UInt8(0x7E); }
EmitI64DivS()544     void EmitI64DivS() { UInt8(0x7F); }
EmitI64DivU()545     void EmitI64DivU() { UInt8(0x80); }
EmitI64RemS()546     void EmitI64RemS() { UInt8(0x81); }
EmitI64RemU()547     void EmitI64RemU() { UInt8(0x82); }
EmitI64And()548     void EmitI64And() { UInt8(0x83); }
EmitI64Or()549     void EmitI64Or() { UInt8(0x84); }
EmitI64Xor()550     void EmitI64Xor() { UInt8(0x85); }
EmitI64Shl()551     void EmitI64Shl() { UInt8(0x86); }
EmitI64ShrS()552     void EmitI64ShrS() { UInt8(0x87); }
EmitI64ShrU()553     void EmitI64ShrU() { UInt8(0x88); }
EmitI64RotL()554     void EmitI64RotL() { UInt8(0x89); }
EmitI64RotR()555     void EmitI64RotR() { UInt8(0x8A); }
556 
EmitF32Abs()557     void EmitF32Abs() { UInt8(0x8B); }
EmitF32Neg()558     void EmitF32Neg() { UInt8(0x8C); }
EmitF32Ceil()559     void EmitF32Ceil() { UInt8(0x8D); }
EmitF32Floor()560     void EmitF32Floor() { UInt8(0x8E); }
EmitF32Trunc()561     void EmitF32Trunc() { UInt8(0x8F); }
EmitF32Nearest()562     void EmitF32Nearest() { UInt8(0x90); }
EmitF32Sqrt()563     void EmitF32Sqrt() { UInt8(0x91); }
EmitF32Add()564     void EmitF32Add() { UInt8(0x92); }
EmitF32Sub()565     void EmitF32Sub() { UInt8(0x93); }
EmitF32Mul()566     void EmitF32Mul() { UInt8(0x94); }
EmitF32Div()567     void EmitF32Div() { UInt8(0x95); }
EmitF32Min()568     void EmitF32Min() { UInt8(0x96); }
EmitF32Max()569     void EmitF32Max() { UInt8(0x97); }
EmitF32CopySign()570     void EmitF32CopySign() { UInt8(0x98); }
571 
EmitF64Abs()572     void EmitF64Abs() { UInt8(0x99); }
EmitF64Neg()573     void EmitF64Neg() { UInt8(0x9A); }
EmitF64Ceil()574     void EmitF64Ceil() { UInt8(0x9B); }
EmitF64Floor()575     void EmitF64Floor() { UInt8(0x9C); }
EmitF64Trunc()576     void EmitF64Trunc() { UInt8(0x9D); }
EmitF64Nearest()577     void EmitF64Nearest() { UInt8(0x9E); }
EmitF64Sqrt()578     void EmitF64Sqrt() { UInt8(0x9F); }
EmitF64Add()579     void EmitF64Add() { UInt8(0xA0); }
EmitF64Sub()580     void EmitF64Sub() { UInt8(0xA1); }
EmitF64Mul()581     void EmitF64Mul() { UInt8(0xA2); }
EmitF64Div()582     void EmitF64Div() { UInt8(0xA3); }
EmitF64Min()583     void EmitF64Min() { UInt8(0xA4); }
EmitF64Max()584     void EmitF64Max() { UInt8(0xA5); }
EmitF64CopySign()585     void EmitF64CopySign() { UInt8(0xA6); }
586 
587     // --- CONVERSION OPERATORS ---
588 
EmitI32WrapI64()589     void EmitI32WrapI64() { UInt8(0xA7); }
EmitI32TruncSF32()590     void EmitI32TruncSF32() { UInt8(0xA8); }
EmitI32TruncUF32()591     void EmitI32TruncUF32() { UInt8(0xA9); }
EmitI32TruncSF64()592     void EmitI32TruncSF64() { UInt8(0xAA); }
EmitI32TruncUF64()593     void EmitI32TruncUF64() { UInt8(0xAB); }
EmitI64ExtendSI32()594     void EmitI64ExtendSI32() { UInt8(0xAC); }
EmitI64ExtendUI32()595     void EmitI64ExtendUI32() { UInt8(0xAD); }
EmitI64TruncSF32()596     void EmitI64TruncSF32() { UInt8(0xAE); }
EmitI64TruncUF32()597     void EmitI64TruncUF32() { UInt8(0xAF); }
EmitI64TruncSF64()598     void EmitI64TruncSF64() { UInt8(0xB0); }
EmitI64TruncUF64()599     void EmitI64TruncUF64() { UInt8(0xB1); }
EmitF32ConvertSI32()600     void EmitF32ConvertSI32() { UInt8(0xB2); }
EmitF32ConvertUI32()601     void EmitF32ConvertUI32() { UInt8(0xB3); }
EmitF32ConvertSI64()602     void EmitF32ConvertSI64() { UInt8(0xB4); }
EmitF32ConvertUI64()603     void EmitF32ConvertUI64() { UInt8(0xB5); }
EmitF32DemoteF64()604     void EmitF32DemoteF64() { UInt8(0xB6); }
EmitF64ConvertSI32()605     void EmitF64ConvertSI32() { UInt8(0xB7); }
EmitF64ConvertUI32()606     void EmitF64ConvertUI32() { UInt8(0xB8); }
EmitF64ConvertSI64()607     void EmitF64ConvertSI64() { UInt8(0xB9); }
EmitF64ConvertUI64()608     void EmitF64ConvertUI64() { UInt8(0xBA); }
EmitF64PromoteF32()609     void EmitF64PromoteF32() { UInt8(0xBB); }
610 
611     // --- REINTERPRETATIONS ---
612 
EmitI32ReinterpretF32()613     void EmitI32ReinterpretF32() { UInt8(0xBC); }
EmitI64ReinterpretF64()614     void EmitI64ReinterpretF64() { UInt8(0xBD); }
EmitF32ReinterpretI32()615     void EmitF32ReinterpretI32() { UInt8(0xBE); }
EmitF64ReinterpretI64()616     void EmitF64ReinterpretI64() { UInt8(0xBF); }
617 
618     // --- END FUNCTION ---
619 
EmitEndFunction()620     void EmitEndFunction() {
621         assert(cur_section == Section::Code);
622         EmitEnd();
623         assert(function_body_start);
624         PatchULEB(function_body_start,
625             buf.size() - function_body_start - PATCHABLE_ULEB_SIZE);
626         function_body_start = 0;
627     }
628 
629     void AddData(std::string_view data, std::string_view symbol, size_t align,
630                  bool local = true) {
631         assert(cur_section == Section::Data);
632         ULEB(0);  // Linear memory index.
633         // Init exp: must use 32-bit for wasm32 target.
634         EmitI32Const(static_cast<int32_t>(data_section_size));
635         EmitEnd();
636         segment_payload_start = LenChars(data);
637         data_section_size += data.size();
638         data_segments.push_back({ std::string(symbol), align, data.size(), local });
639         section_count++;
640     }
641 
642     // "off" is relative to the data in the last AddData call.
DataFunctionRef(size_t fid,size_t off)643     void DataFunctionRef(size_t fid, size_t off) {
644         assert(segment_payload_start);
645         data_relocs.push_back({ R_WASM_TABLE_INDEX_I32,
646                                 off + (segment_payload_start - section_data),
647                                 fid,
648                                 0,
649                                 true });
650     }
651 
652     // Call this last, to finalize the buffer into a valid WASM module,
653     // and to add linking/reloc sections based on the previous sections.
Finish()654     void Finish() {
655         assert(cur_section == Section::None);
656         // If this assert fails, you likely have not matched the number of
657         // AddFunction calls in a Function section with the number of AddCode
658         // calls in a Code section.
659         assert(num_function_imports + num_function_decls == function_symbols.size());
660         // Linking section.
661         {
662             BeginSection(Section::Custom, "linking");
663             ULEB(2);  // Version.
664             enum {
665                 WASM_SEGMENT_INFO = 5,
666                 WASM_INIT_FUNCS = 6,
667                 WASM_COMDAT_INFO = 7,
668                 WASM_SYMBOL_TABLE = 8,
669             };
670             // Segment Info.
671             {
672                 UInt8(WASM_SEGMENT_INFO);
673                 auto sisize = PatchableLEB();
674                 ULEB(data_segments.size());
675                 for (auto &ds : data_segments) {
676                     LenChars(ds.name);
677                     ULEB(ds.align);
678                     ULEB(0);  // Flags. FIXME: any valid values?
679                 }
680                 PatchULEB(sisize, buf.size() - sisize - PATCHABLE_ULEB_SIZE);
681             }
682             // Symbol Table.
683             {
684                 UInt8(WASM_SYMBOL_TABLE);
685                 auto stsize = PatchableLEB();
686                 enum {
687                     SYMTAB_FUNCTION = 0,
688                     SYMTAB_DATA = 1,
689                     SYMTAB_GLOBAL = 2,
690                     SYMTAB_SECTION = 3,
691                     SYMTAB_EVENT = 4,
692                 };
693                 enum {
694                     WASM_SYM_BINDING_WEAK = 1,
695                     WASM_SYM_BINDING_LOCAL = 2,
696                     WASM_SYM_VISIBILITY_HIDDEN = 4,
697                     WASM_SYM_UNDEFINED = 16,
698                     WASM_SYM_EXPORTED = 32,
699                 };
700                 ULEB(data_segments.size() + function_symbols.size());
701                 size_t segi = 0;
702                 for (auto &ds : data_segments) {
703                     UInt8(SYMTAB_DATA);
704                     ULEB(ds.local ? WASM_SYM_BINDING_LOCAL : WASM_SYM_EXPORTED);
705                     LenChars(ds.name);
706                     ULEB(segi++);
707                     ULEB(0);  // Offset in segment, always 0 (1 seg per sym).
708                     ULEB(ds.size);
709                 }
710                 size_t wasm_function = 0;
711                 for (auto &fs : function_symbols) {
712                     UInt8(SYMTAB_FUNCTION);
713                     ULEB(fs.import
714                          ? WASM_SYM_UNDEFINED
715                          : (fs.local ? WASM_SYM_BINDING_LOCAL
716                                      : WASM_SYM_EXPORTED));
717                     ULEB(wasm_function++);
718                     if (!fs.import) {
719                         LenChars(fs.name);
720                     }
721                 }
722                 PatchULEB(stsize, buf.size() - stsize - PATCHABLE_ULEB_SIZE);
723             }
724             EndSection(Section::Custom);  // linking
725         }
726         // Reloc sections
727         {
728             auto EncodeReloc = [&](Reloc &r) {
729                 UInt8(r.type);
730                 ULEB(r.src_offset);
731                 ULEB(r.sym_index + (r.is_function ? data_segments.size() : 0));
732                 if (r.type == R_WASM_MEMORY_ADDR_LEB ||
733                     r.type == R_WASM_MEMORY_ADDR_SLEB ||
734                     r.type == R_WASM_MEMORY_ADDR_I32 ||
735                     r.type == R_WASM_FUNCTION_OFFSET_I32 ||
736                     r.type == R_WASM_SECTION_OFFSET_I32)
737                     SLEB((ptrdiff_t)r.target_index);
738             };
739 
740             BeginSection(Section::Custom, "reloc.CODE");
741             ULEB(section_index_in_file_code);
742             ULEB(code_relocs.size());
743             for (auto &r : code_relocs) EncodeReloc(r);
744             EndSection(Section::Custom);  // reloc.CODE
745 
746             BeginSection(Section::Custom, "reloc.DATA");
747             ULEB(section_index_in_file_data);
748             ULEB(data_relocs.size());
749             for (auto &r : data_relocs) EncodeReloc(r);
750             EndSection(Section::Custom);  // reloc.DATA
751         }
752     }
753 
754 };
755 
756 }  // namespace WASM
757 
758 #endif  // WASM_BINARY_WRITER_H
759