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> ¶ms, 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