| ... | @@ -110,6 +110,10 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, | ... | @@ -110,6 +110,10 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{}, |
| 110 | /// List of all symbol locations which have been resolved by the linker and will be emit | 110 | /// List of all symbol locations which have been resolved by the linker and will be emit |
| 111 | /// into the final binary. | 111 | /// into the final binary. |
| 112 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, | 112 | resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .{}, |
| | 113 | /// Maps a symbol's location to an atom. This can be used to find meta |
| | 114 | /// data of a symbol, such as its size, or its offset to perform a relocation. |
| | 115 | /// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped. |
| | 116 | symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, |
| 113 | | 117 | |
| 114 | pub const Segment = struct { | 118 | pub const Segment = struct { |
| 115 | alignment: u32, | 119 | alignment: u32, |
| ... | @@ -170,6 +174,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option | ... | @@ -170,6 +174,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option |
| 170 | .flags = 0, | 174 | .flags = 0, |
| 171 | .index = 0, | 175 | .index = 0, |
| 172 | }; | 176 | }; |
| | 177 | const loc: SymbolLoc = .{ .file = null, .index = 0 }; |
| | 178 | try wasm_bin.resolved_symbols.putNoClobber(allocator, loc, {}); |
| | 179 | try wasm_bin.globals.putNoClobber(allocator, "__stack_pointer", loc); |
| | 180 | |
| 173 | // For object files we will import the stack pointer symbol | 181 | // For object files we will import the stack pointer symbol |
| 174 | if (options.output_mode == .Obj) { | 182 | if (options.output_mode == .Obj) { |
| 175 | symbol.setUndefined(true); | 183 | symbol.setUndefined(true); |
| ... | @@ -336,6 +344,7 @@ pub fn deinit(self: *Wasm) void { | ... | @@ -336,6 +344,7 @@ pub fn deinit(self: *Wasm) void { |
| 336 | self.globals.deinit(gpa); | 344 | self.globals.deinit(gpa); |
| 337 | self.resolved_symbols.deinit(gpa); | 345 | self.resolved_symbols.deinit(gpa); |
| 338 | self.discarded.deinit(gpa); | 346 | self.discarded.deinit(gpa); |
| | 347 | self.symbol_atom.deinit(gpa); |
| 339 | self.atoms.deinit(gpa); | 348 | self.atoms.deinit(gpa); |
| 340 | self.managed_atoms.deinit(gpa); | 349 | self.managed_atoms.deinit(gpa); |
| 341 | self.segments.deinit(gpa); | 350 | self.segments.deinit(gpa); |
| ... | @@ -506,6 +515,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 { | ... | @@ -506,6 +515,10 @@ pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 { |
| 506 | atom.sym_index = @intCast(u32, self.symbols.items.len); | 515 | atom.sym_index = @intCast(u32, self.symbols.items.len); |
| 507 | self.symbols.appendAssumeCapacity(symbol); | 516 | self.symbols.appendAssumeCapacity(symbol); |
| 508 | } | 517 | } |
| | 518 | try self.resolved_symbols.putNoClobber(self.base.allocator, .{ |
| | 519 | .file = null, |
| | 520 | .index = atom.sym_index, |
| | 521 | }, {}); |
| 509 | | 522 | |
| 510 | try decl.link.wasm.locals.append(self.base.allocator, atom); | 523 | try decl.link.wasm.locals.append(self.base.allocator, atom); |
| 511 | return atom.sym_index; | 524 | return atom.sym_index; |
| ... | @@ -614,12 +627,13 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { | ... | @@ -614,12 +627,13 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { |
| 614 | const symbol: *Symbol = &self.symbols.items[symbol_index]; | 627 | const symbol: *Symbol = &self.symbols.items[symbol_index]; |
| 615 | symbol.name = decl.name; | 628 | symbol.name = decl.name; |
| 616 | symbol.setUndefined(true); | 629 | symbol.setUndefined(true); |
| 617 | // also add it as a global so it can be resolved | | |
| 618 | try self.globals.putNoClobber( | 630 | try self.globals.putNoClobber( |
| 619 | self.base.allocator, | 631 | self.base.allocator, |
| 620 | mem.sliceTo(symbol.name, 0), | 632 | mem.sliceTo(symbol.name, 0), |
| 621 | .{ .file = null, .index = symbol_index }, | 633 | .{ .file = null, .index = symbol_index }, |
| 622 | ); | 634 | ); |
| | 635 | try self.resolved_symbols.put(self.base.allocator, .{ .file = null, .index = symbol_index }, {}); |
| | 636 | |
| 623 | switch (decl.ty.zigTypeTag()) { | 637 | switch (decl.ty.zigTypeTag()) { |
| 624 | .Fn => { | 638 | .Fn => { |
| 625 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); | 639 | const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); |
| ... | @@ -730,20 +744,22 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { | ... | @@ -730,20 +744,22 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 730 | } | 744 | } |
| 731 | | 745 | |
| 732 | fn allocateAtoms(self: *Wasm) !void { | 746 | fn allocateAtoms(self: *Wasm) !void { |
| 733 | var it = self.atoms.iterator(); | 747 | var it = self.atoms.valueIterator(); |
| 734 | while (it.next()) |entry| { | 748 | while (it.next()) |current_atom| { |
| 735 | var atom: *Atom = entry.value_ptr.*.getFirst(); | 749 | var atom: *Atom = current_atom.*.getFirst(); |
| 736 | var offset: u32 = 0; | 750 | var offset: u32 = 0; |
| 737 | while (true) { | 751 | while (true) { |
| 738 | offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment); | 752 | offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment); |
| 739 | atom.offset = offset; | 753 | atom.offset = offset; |
| | 754 | const symbol_loc = atom.symbolLoc(); |
| 740 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ | 755 | log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{ |
| 741 | (SymbolLoc{ .file = atom.file, .index = atom.sym_index }).getSymbol(self).name, | 756 | symbol_loc.getSymbol(self).name, |
| 742 | offset, | 757 | offset, |
| 743 | offset + atom.size, | 758 | offset + atom.size, |
| 744 | atom.size, | 759 | atom.size, |
| 745 | }); | 760 | }); |
| 746 | offset += atom.size; | 761 | offset += atom.size; |
| | 762 | try self.symbol_atom.putNoClobber(self.base.allocator, symbol_loc, atom); |
| 747 | atom = atom.next orelse break; | 763 | atom = atom.next orelse break; |
| 748 | } | 764 | } |
| 749 | } | 765 | } |
| ... | @@ -1295,7 +1311,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1295,7 +1311,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1295 | } | 1311 | } |
| 1296 | | 1312 | |
| 1297 | // Global section (used to emit stack pointer) | 1313 | // Global section (used to emit stack pointer) |
| 1298 | { | 1314 | if (self.wasm_globals.items.len > 0) { |
| 1299 | const header_offset = try reserveVecSectionHeader(file); | 1315 | const header_offset = try reserveVecSectionHeader(file); |
| 1300 | const writer = file.writer(); | 1316 | const writer = file.writer(); |
| 1301 | | 1317 | |
| ... | @@ -1480,7 +1496,13 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1480,7 +1496,13 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1480 | } | 1496 | } |
| 1481 | | 1497 | |
| 1482 | if (is_obj) { | 1498 | if (is_obj) { |
| 1483 | try self.emitLinkSection(file, arena); | 1499 | // relocations need to point to the index of a symbol in the final symbol table. To save memory, |
| | 1500 | // we never store all symbols in a single table, but store a location reference instead. |
| | 1501 | // This means that for a relocatable object file, we need to generate one and provide it to the relocation sections. |
| | 1502 | var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena); |
| | 1503 | try self.emitLinkSection(file, arena, &symbol_table); |
| | 1504 | try self.emitCodeRelocations(file, arena, 6, symbol_table); |
| | 1505 | try self.emitDataRelocations(file, arena, 7, symbol_table); |
| 1484 | } else { | 1506 | } else { |
| 1485 | try self.emitNameSection(file, arena); | 1507 | try self.emitNameSection(file, arena); |
| 1486 | } | 1508 | } |
| ... | @@ -1498,7 +1520,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -1498,7 +1520,7 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 1498 | }; | 1520 | }; |
| 1499 | | 1521 | |
| 1500 | var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.items.len + self.imported_functions_count); | 1522 | var funcs = try std.ArrayList(Name).initCapacity(arena, self.functions.items.len + self.imported_functions_count); |
| 1501 | var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len); | 1523 | var globals = try std.ArrayList(Name).initCapacity(arena, self.wasm_globals.items.len + self.imported_globals_count); |
| 1502 | var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count()); | 1524 | var segments = try std.ArrayList(Name).initCapacity(arena, self.data_segments.count()); |
| 1503 | | 1525 | |
| 1504 | for (self.resolved_symbols.keys()) |sym_loc| { | 1526 | for (self.resolved_symbols.keys()) |sym_loc| { |
| ... | @@ -2069,7 +2091,7 @@ fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void { | ... | @@ -2069,7 +2091,7 @@ fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void { |
| 2069 | try file.pwriteAll(&buf, offset); | 2091 | try file.pwriteAll(&buf, offset); |
| 2070 | } | 2092 | } |
| 2071 | | 2093 | |
| 2072 | fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | 2094 | fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { |
| 2073 | const offset = try reserveCustomSectionHeader(file); | 2095 | const offset = try reserveCustomSectionHeader(file); |
| 2074 | const writer = file.writer(); | 2096 | const writer = file.writer(); |
| 2075 | // emit "linking" custom section name | 2097 | // emit "linking" custom section name |
| ... | @@ -2082,14 +2104,14 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2082,14 +2104,14 @@ fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2082 | | 2104 | |
| 2083 | // For each subsection type (found in types.Subsection) we can emit a section. | 2105 | // For each subsection type (found in types.Subsection) we can emit a section. |
| 2084 | // Currently, we only support emitting segment info and the symbol table. | 2106 | // Currently, we only support emitting segment info and the symbol table. |
| 2085 | try self.emitSymbolTable(file, arena); | 2107 | try self.emitSymbolTable(file, arena, symbol_table); |
| 2086 | try self.emitSegmentInfo(file, arena); | 2108 | try self.emitSegmentInfo(file, arena); |
| 2087 | | 2109 | |
| 2088 | const size = @intCast(u32, (try file.getPos()) - offset - 6); | 2110 | const size = @intCast(u32, (try file.getPos()) - offset - 6); |
| 2089 | try writeCustomSectionHeader(file, offset, size); | 2111 | try writeCustomSectionHeader(file, offset, size); |
| 2090 | } | 2112 | } |
| 2091 | | 2113 | |
| 2092 | fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator) !void { | 2114 | fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator, symbol_table: *std.AutoArrayHashMap(SymbolLoc, u32)) !void { |
| 2093 | // After emitting the subtype, we must emit the subsection's length | 2115 | // After emitting the subtype, we must emit the subsection's length |
| 2094 | // so first write it to a temporary arraylist to calculate the length | 2116 | // so first write it to a temporary arraylist to calculate the length |
| 2095 | // and then write all data at once. | 2117 | // and then write all data at once. |
| ... | @@ -2099,43 +2121,39 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2099,43 +2121,39 @@ fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2099 | try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE)); | 2121 | try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE)); |
| 2100 | | 2122 | |
| 2101 | var symbol_count: u32 = 0; | 2123 | var symbol_count: u32 = 0; |
| 2102 | var atom_it = self.atoms.valueIterator(); | 2124 | for (self.resolved_symbols.keys()) |sym_loc| { |
| 2103 | while (atom_it.next()) |next_atom| { | 2125 | const symbol = sym_loc.getSymbol(self).*; |
| 2104 | var atom: ?*Atom = next_atom.*.getFirst(); | 2126 | if (symbol.tag == .dead) continue; // Do not emit dead symbols |
| 2105 | while (atom) |current_atom| { | 2127 | try symbol_table.putNoClobber(sym_loc, symbol_count); |
| 2106 | const sym_loc: SymbolLoc = .{ .file = current_atom.file, .index = current_atom.sym_index }; | 2128 | symbol_count += 1; |
| 2107 | const symbol = sym_loc.getSymbol(self).*; | 2129 | log.debug("Emit symbol: {}", .{symbol}); |
| 2108 | if (symbol.tag == .dead) continue; // Do not emit dead symbols | 2130 | try leb.writeULEB128(writer, @enumToInt(symbol.tag)); |
| 2109 | symbol_count += 1; | 2131 | try leb.writeULEB128(writer, symbol.flags); |
| 2110 | log.debug("Emit symbol: {}", .{symbol}); | 2132 | |
| 2111 | try leb.writeULEB128(writer, @enumToInt(symbol.tag)); | 2133 | switch (symbol.tag) { |
| 2112 | try leb.writeULEB128(writer, symbol.flags); | 2134 | .data => { |
| 2113 | | 2135 | const name = mem.sliceTo(symbol.name, 0); |
| 2114 | switch (symbol.tag) { | 2136 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| 2115 | .data => { | 2137 | try writer.writeAll(name); |
| | 2138 | |
| | 2139 | if (symbol.isDefined()) { |
| | 2140 | try leb.writeULEB128(writer, symbol.index); |
| | 2141 | const atom = self.symbol_atom.get(sym_loc).?; |
| | 2142 | try leb.writeULEB128(writer, @as(u32, atom.offset)); |
| | 2143 | try leb.writeULEB128(writer, @as(u32, atom.size)); |
| | 2144 | } |
| | 2145 | }, |
| | 2146 | .section => { |
| | 2147 | try leb.writeULEB128(writer, symbol.index); |
| | 2148 | }, |
| | 2149 | else => { |
| | 2150 | try leb.writeULEB128(writer, symbol.index); |
| | 2151 | if (symbol.isDefined()) { |
| 2116 | const name = mem.sliceTo(symbol.name, 0); | 2152 | const name = mem.sliceTo(symbol.name, 0); |
| 2117 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | 2153 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| 2118 | try writer.writeAll(name); | 2154 | try writer.writeAll(name); |
| 2119 | | 2155 | } |
| 2120 | if (symbol.isDefined()) { | 2156 | }, |
| 2121 | try leb.writeULEB128(writer, symbol.index); | | |
| 2122 | try leb.writeULEB128(writer, @as(u32, current_atom.offset)); | | |
| 2123 | try leb.writeULEB128(writer, @as(u32, current_atom.size)); | | |
| 2124 | } | | |
| 2125 | }, | | |
| 2126 | .section => { | | |
| 2127 | try leb.writeULEB128(writer, symbol.index); | | |
| 2128 | }, | | |
| 2129 | else => { | | |
| 2130 | try leb.writeULEB128(writer, symbol.index); | | |
| 2131 | if (symbol.isDefined()) { | | |
| 2132 | const name = mem.sliceTo(symbol.name, 0); | | |
| 2133 | try leb.writeULEB128(writer, @intCast(u32, name.len)); | | |
| 2134 | try writer.writeAll(name); | | |
| 2135 | } | | |
| 2136 | }, | | |
| 2137 | } | | |
| 2138 | atom = current_atom.next orelse break; | | |
| 2139 | } | 2157 | } |
| 2140 | } | 2158 | } |
| 2141 | | 2159 | |
| ... | @@ -2176,6 +2194,109 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2176,6 +2194,109 @@ fn emitSegmentInfo(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2176 | try file.writevAll(&.{iovec}); | 2194 | try file.writevAll(&.{iovec}); |
| 2177 | } | 2195 | } |
| 2178 | | 2196 | |
| | 2197 | /// For each relocatable section, emits a custom "relocation.<section_name>" section |
| | 2198 | fn emitCodeRelocations( |
| | 2199 | self: *Wasm, |
| | 2200 | file: fs.File, |
| | 2201 | arena: Allocator, |
| | 2202 | section_index: u32, |
| | 2203 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| | 2204 | ) !void { |
| | 2205 | const code_index = self.code_section_index orelse return; |
| | 2206 | var payload = std.ArrayList(u8).init(arena); |
| | 2207 | const writer = payload.writer(); |
| | 2208 | |
| | 2209 | // write custom section information |
| | 2210 | const name = "reloc.CODE"; |
| | 2211 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| | 2212 | try writer.writeAll(name); |
| | 2213 | try leb.writeULEB128(writer, section_index); |
| | 2214 | const reloc_start = payload.items.len; |
| | 2215 | |
| | 2216 | var count: u32 = 0; |
| | 2217 | var atom: *Atom = self.atoms.get(code_index).?.getFirst(); |
| | 2218 | while (true) { |
| | 2219 | for (atom.relocs.items) |relocation| { |
| | 2220 | count += 1; |
| | 2221 | const sym_loc: SymbolLoc = .{ .file = atom.file, .index = relocation.index }; |
| | 2222 | const symbol_index = symbol_table.get(sym_loc).?; |
| | 2223 | try leb.writeULEB128(writer, @enumToInt(relocation.relocation_type)); |
| | 2224 | try leb.writeULEB128(writer, atom.offset + relocation.offset); |
| | 2225 | try leb.writeULEB128(writer, symbol_index); |
| | 2226 | if (relocation.relocation_type.addendIsPresent()) { |
| | 2227 | try leb.writeULEB128(writer, relocation.addend orelse 0); |
| | 2228 | } |
| | 2229 | } |
| | 2230 | atom = atom.next orelse break; |
| | 2231 | } |
| | 2232 | if (count == 0) return; |
| | 2233 | var buf: [5]u8 = undefined; |
| | 2234 | leb.writeUnsignedFixed(5, &buf, count); |
| | 2235 | try payload.insertSlice(reloc_start, &buf); |
| | 2236 | const iovec: std.os.iovec_const = .{ |
| | 2237 | .iov_base = payload.items.ptr, |
| | 2238 | .iov_len = payload.items.len, |
| | 2239 | }; |
| | 2240 | const header_offset = try reserveCustomSectionHeader(file); |
| | 2241 | try file.writevAll(&.{iovec}); |
| | 2242 | const size = @intCast(u32, payload.items.len); |
| | 2243 | try writeCustomSectionHeader(file, header_offset, size); |
| | 2244 | } |
| | 2245 | |
| | 2246 | fn emitDataRelocations( |
| | 2247 | self: *Wasm, |
| | 2248 | file: fs.File, |
| | 2249 | arena: Allocator, |
| | 2250 | section_index: u32, |
| | 2251 | symbol_table: std.AutoArrayHashMap(SymbolLoc, u32), |
| | 2252 | ) !void { |
| | 2253 | if (self.data_segments.count() == 0) return; |
| | 2254 | var payload = std.ArrayList(u8).init(arena); |
| | 2255 | const writer = payload.writer(); |
| | 2256 | |
| | 2257 | // write custom section information |
| | 2258 | const name = "reloc.DATA"; |
| | 2259 | try leb.writeULEB128(writer, @intCast(u32, name.len)); |
| | 2260 | try writer.writeAll(name); |
| | 2261 | try leb.writeULEB128(writer, section_index); |
| | 2262 | const reloc_start = payload.items.len; |
| | 2263 | |
| | 2264 | var count: u32 = 0; |
| | 2265 | for (self.data_segments.values()) |segment_index| { |
| | 2266 | var atom: *Atom = self.atoms.get(segment_index).?.getFirst(); |
| | 2267 | while (true) { |
| | 2268 | for (atom.relocs.items) |relocation| { |
| | 2269 | count += 1; |
| | 2270 | const sym_loc: SymbolLoc = .{ |
| | 2271 | .file = atom.file, |
| | 2272 | .index = relocation.index, |
| | 2273 | }; |
| | 2274 | const symbol_index = symbol_table.get(sym_loc).?; |
| | 2275 | try leb.writeULEB128(writer, @enumToInt(relocation.relocation_type)); |
| | 2276 | try leb.writeULEB128(writer, atom.offset + relocation.offset); |
| | 2277 | try leb.writeULEB128(writer, symbol_index); |
| | 2278 | if (relocation.relocation_type.addendIsPresent()) { |
| | 2279 | try leb.writeULEB128(writer, relocation.addend orelse 0); |
| | 2280 | } |
| | 2281 | } |
| | 2282 | atom = atom.next orelse break; |
| | 2283 | } |
| | 2284 | } |
| | 2285 | if (count == 0) return; |
| | 2286 | |
| | 2287 | var buf: [5]u8 = undefined; |
| | 2288 | leb.writeUnsignedFixed(5, &buf, count); |
| | 2289 | try payload.insertSlice(reloc_start, &buf); |
| | 2290 | const iovec: std.os.iovec_const = .{ |
| | 2291 | .iov_base = payload.items.ptr, |
| | 2292 | .iov_len = payload.items.len, |
| | 2293 | }; |
| | 2294 | const header_offset = try reserveCustomSectionHeader(file); |
| | 2295 | try file.writevAll(&.{iovec}); |
| | 2296 | const size = @intCast(u32, payload.items.len); |
| | 2297 | try writeCustomSectionHeader(file, header_offset, size); |
| | 2298 | } |
| | 2299 | |
| 2179 | /// Searches for an a matching function signature, when not found | 2300 | /// Searches for an a matching function signature, when not found |
| 2180 | /// a new entry will be made. The index of the existing/new signature will be returned. | 2301 | /// a new entry will be made. The index of the existing/new signature will be returned. |
| 2181 | pub fn putOrGetFuncType(self: *Wasm, func_type: wasm.Type) !u32 { | 2302 | pub fn putOrGetFuncType(self: *Wasm, func_type: wasm.Type) !u32 { |