authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-14 21:50:55+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-17 18:11:48+01:00
logf1cc5f33e88a64e30695c682177e00af4310a119
treef19af2ca6d49ba46d747bd5f1d91a08a3435d25b
parente7be0bef43e5fc7d19bbe184b9dc5209f52f745c

wasm-linker: Implement section merging

This implements the merging of all sections, to generate a valid wasm binary where all symbols have been resolved and their respective sections have been merged into the final binary.

4 files changed, 309 insertions(+), 47 deletions(-)

src/link/Wasm.zig+291-30
......@@ -45,20 +45,29 @@ host_name: []const u8 = "env",
4545/// This is ment for bookkeeping so we can safely cleanup all codegen memory
4646/// when calling `deinit`
4747decls: std.AutoHashMapUnmanaged(*Module.Decl, void) = .{},
48/// List of all symbols.
48/// List of all symbols generated by Zig code.
4949symbols: std.ArrayListUnmanaged(Symbol) = .{},
5050/// List of symbol indexes which are free to be used.
5151symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
5252/// Maps atoms to their segment index
5353atoms: std.AutoHashMapUnmanaged(u32, *Atom) = .{},
54/// Atoms managed and created by the linker. This contains atoms
55/// from object files, and not Atoms generated by a Decl.
56managed_atoms: std.ArrayListUnmanaged(*Atom) = .{},
5457/// Represents the index into `segments` where the 'code' section
5558/// lives.
5659code_section_index: ?u32 = null,
5760/// The count of imported functions. This number will be appended
5861/// to the function indexes as their index starts at the lowest non-extern function.
5962imported_functions_count: u32 = 0,
60/// Map of symbol indexes, represented by its `wasm.Import`
61imports: std.AutoHashMapUnmanaged(u32, wasm.Import) = .{},
63/// The count of imported wasm globals. This number will be appended
64/// to the global indexes when sections are merged.
65imported_globals_count: u32 = 0,
66/// The count of imported tables. This number will be appended
67/// to the table indexes when sections are merged.
68imported_tables_count: u32 = 0,
69/// Map of symbol locations, represented by its `wasm.Import`
70imports: std.AutoHashMapUnmanaged(SymbolLoc, wasm.Import) = .{},
6271/// Represents non-synthetic section entries.
6372/// Used for code, data and custom sections.
6473segments: std.ArrayListUnmanaged(Segment) = .{},
......@@ -77,6 +86,10 @@ functions: std.ArrayListUnmanaged(wasm.Func) = .{},
7786wasm_globals: std.ArrayListUnmanaged(wasm.Global) = .{},
7887/// Memory section
7988memories: wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
89/// Output table section
90tables: std.ArrayListUnmanaged(wasm.Table) = .{},
91/// Output export section
92exports: std.ArrayListUnmanaged(wasm.Export) = .{},
8093
8194/// Indirect function table, used to call function pointers
8295/// When this is non-zero, we must emit a table entry,
......@@ -87,14 +100,14 @@ function_table: std.AutoHashMapUnmanaged(u32, u32) = .{},
87100
88101/// All object files and their data which are linked into the final binary
89102objects: std.ArrayListUnmanaged(Object) = .{},
103/// A map of global names to their symbol location
104globals: std.StringHashMapUnmanaged(SymbolLoc) = .{},
90105/// Maps discarded symbols and their positions to the location of the symbol
91106/// it was resolved to
92107discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .{},
93/// Mapping between symbol names and their respective location.
94/// This map contains all symbols that will be written into the final binary
95/// and were either defined, or resolved.
96/// TODO: Use string interning and make the key an index, rather than a unique string.
97symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolLoc) = .{},
108/// List of all symbol locations which have been resolved by the linker and will be emit
109/// into the final binary.
110resolved_symbols: std.ArrayListUnmanaged(SymbolLoc) = .{},
98111
99112pub const Segment = struct {
100113 alignment: u32,
......@@ -116,6 +129,18 @@ pub const SymbolLoc = struct {
116129 /// The index of the object file where the symbol resides.
117130 /// When this is `null` the symbol comes from a non-object file.
118131 file: ?u16,
132
133 /// From a given location, returns the corresponding symbol in the wasm binary
134 pub fn getSymbol(self: SymbolLoc, wasm_bin: *const Wasm) *Symbol {
135 if (self.file) |object_index| {
136 if (wasm_bin.discarded.get(self)) |old_loc| {
137 return old_loc.getSymbol(wasm_bin);
138 }
139 const object = wasm_bin.objects.items[object_index];
140 return &object.symtable[self.index];
141 }
142 return &wasm_bin.symbols.items[self.index];
143 }
119144};
120145
121146pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Wasm {
......@@ -186,49 +211,118 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
186211 const file = try fs.cwd().openFile(path, .{});
187212 errdefer file.close();
188213
189 var object = Object.init(self.base.allocator, file, path) catch |err| {
190 if (err == error.InvalidMagicByte) {
214 var object = Object.create(self.base.allocator, file, path) catch |err| switch (err) {
215 error.InvalidMagicByte, error.NotObjectFile => {
191216 log.warn("Self hosted linker does not support non-object file parsing", .{});
192217 return false;
193 } else return err;
218 },
219 else => |e| return e,
194220 };
195221 errdefer object.deinit(self.base.allocator);
196222 try self.objects.append(self.base.allocator, object);
197223 return true;
198224}
199225
226fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
227 const object: Object = self.objects.items[object_index];
228 log.debug("Resolving symbols in object: '{s}'", .{object.name});
229
230 for (object.symtable) |symbol, i| {
231 const sym_index = @intCast(u32, i);
232 const location: SymbolLoc = .{
233 .file = object_index,
234 .index = sym_index,
235 };
236
237 if (symbol.isLocal()) {
238 if (symbol.isUndefined()) {
239 log.err("Local symbols are not allowed to reference imports", .{});
240 log.err(" symbol '{s}' defined in '{s}'", .{ symbol.name, object.name });
241 return error.undefinedLocal;
242 }
243 try self.resolved_symbols.append(self.base.allocator, location);
244 continue;
245 }
246
247 // TODO: locals are allowed to have duplicate symbol names
248 // TODO: Store undefined symbols so we can verify at the end if they've all been found
249 // if not, emit an error (unless --allow-undefined is enabled).
250 const maybe_existing = try self.globals.getOrPut(self.base.allocator, std.mem.sliceTo(symbol.name, 0));
251 if (!maybe_existing.found_existing) {
252 maybe_existing.value_ptr.* = location;
253
254 try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location);
255 continue;
256 }
257
258 const existing_loc = maybe_existing.value_ptr.*;
259 const existing_sym: *Symbol = existing_loc.getSymbol(self);
260
261 if (!existing_sym.isUndefined()) {
262 if (!symbol.isUndefined()) {
263 log.err("symbol '{s}' defined multiple times", .{existing_sym.name});
264 log.err(" first definition in '{s}'", .{self.objects.items[existing_loc.file.?].name});
265 log.err(" next definition in '{s}'", .{object.name});
266 return error.SymbolCollision;
267 }
268
269 continue; // Do not overwrite defined symbols with undefined symbols
270 }
271
272 // simply overwrite with the new symbol
273 log.info("Overwriting symbol '{s}'", .{symbol.name});
274 log.info(" first definition in '{s}'", .{self.objects.items[existing_loc.file.?].name});
275 log.info(" next definition in '{s}'", .{object.name});
276 try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location);
277 maybe_existing.value_ptr.* = location;
278 try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location);
279 }
280}
281
200282pub fn deinit(self: *Wasm) void {
283 const gpa = self.base.allocator;
201284 if (build_options.have_llvm) {
202 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
285 if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
203286 }
204287
205288 var decl_it = self.decls.keyIterator();
206289 while (decl_it.next()) |decl_ptr| {
207290 const decl = decl_ptr.*;
208 decl.link.wasm.deinit(self.base.allocator);
291 decl.link.wasm.deinit(gpa);
209292 }
210293
211294 for (self.func_types.items) |*func_type| {
212 func_type.deinit(self.base.allocator);
295 func_type.deinit(gpa);
213296 }
214297 for (self.segment_info.items) |segment_info| {
215 self.base.allocator.free(segment_info.name);
298 gpa.free(segment_info.name);
299 }
300 for (self.objects.items) |*object| {
301 object.file.?.close();
302 object.deinit(gpa);
216303 }
217304
218 self.decls.deinit(self.base.allocator);
219 self.symbols.deinit(self.base.allocator);
220 self.symbols_free_list.deinit(self.base.allocator);
221 self.atoms.deinit(self.base.allocator);
222 self.segments.deinit(self.base.allocator);
223 self.data_segments.deinit(self.base.allocator);
224 self.segment_info.deinit(self.base.allocator);
305 self.decls.deinit(gpa);
306 self.symbols.deinit(gpa);
307 self.symbols_free_list.deinit(gpa);
308 self.globals.deinit(gpa);
309 self.resolved_symbols.deinit(gpa);
310 self.discarded.deinit(gpa);
311 self.atoms.deinit(gpa);
312 self.managed_atoms.deinit(gpa);
313 self.segments.deinit(gpa);
314 self.data_segments.deinit(gpa);
315 self.segment_info.deinit(gpa);
316 self.objects.deinit(gpa);
225317
226318 // free output sections
227 self.imports.deinit(self.base.allocator);
228 self.func_types.deinit(self.base.allocator);
229 self.functions.deinit(self.base.allocator);
230 self.wasm_globals.deinit(self.base.allocator);
231 self.function_table.deinit(self.base.allocator);
319 self.imports.deinit(gpa);
320 self.func_types.deinit(gpa);
321 self.functions.deinit(gpa);
322 self.wasm_globals.deinit(gpa);
323 self.function_table.deinit(gpa);
324 self.tables.deinit(gpa);
325 self.exports.deinit(gpa);
232326}
233327
234328pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void {
......@@ -453,7 +547,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
453547 }
454548
455549 if (decl.isExtern()) {
456 const import = self.imports.fetchRemove(atom.sym_index).?.value;
550 const import = self.imports.fetchRemove(.{ .file = null, .index = atom.sym_index }).?.value;
457551 switch (import.kind) {
458552 .function => self.imported_functions_count -= 1,
459553 else => unreachable,
......@@ -469,6 +563,9 @@ pub fn addTableFunction(self: *Wasm, symbol_index: u32) !void {
469563 try self.function_table.put(self.base.allocator, symbol_index, index);
470564}
471565
566/// Assigns indexes to all indirect functions.
567/// Starts at offset 1, where the value `0` represents an unresolved function pointer
568/// or null-pointer
472569fn mapFunctionTable(self: *Wasm) void {
473570 var it = self.function_table.valueIterator();
474571 var index: u32 = 1;
......@@ -484,7 +581,7 @@ fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
484581 symbol.setUndefined(true);
485582 switch (decl.ty.zigTypeTag()) {
486583 .Fn => {
487 const gop = try self.imports.getOrPut(self.base.allocator, symbol_index);
584 const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
488585 const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: {
489586 break :blk std.mem.sliceTo(lib_name, 0);
490587 } else self.host_name;
......@@ -599,21 +696,176 @@ fn allocateAtoms(self: *Wasm) !void {
599696}
600697
601698fn setupImports(self: *Wasm) void {
699 for (self.resolved_symbols.items) |symbol_loc| {
700 if (symbol_loc.file == null) {
701 // imports generated by Zig code are already in the `import` section
702 continue;
703 }
704
705 const symbol = symbol_loc.getSymbol(self);
706 if (symbol.tag == .data or !symbol.requiresImport()) {
707 continue;
708 }
709
710 log.debug("Symbol '{s}' will be imported from the host", .{symbol.name});
711 const import = self.objects.items[symbol_loc.file.?].findImport(symbol.externalType(), symbol.index);
712 // TODO: De-duplicate imports
713 try self.imports.putNoClobber(self.base.allocator, symbol_loc, import);
714 }
715
716 // Assign all indexes of the imports to their representing symbols
602717 var function_index: u32 = 0;
718 var global_index: u32 = 0;
719 var table_index: u32 = 0;
603720 var it = self.imports.iterator();
604721 while (it.next()) |entry| {
605 const symbol = &self.symbols.items[entry.key_ptr.*];
722 const symbol = entry.key_ptr.*.getSymbol(self);
606723 const import: wasm.Import = entry.value_ptr.*;
607724 switch (import.kind) {
608725 .function => {
609726 symbol.index = function_index;
610727 function_index += 1;
611728 },
729 .global => {
730 symbol.index = global_index;
731 global_index += 1;
732 },
733 .table => {
734 symbol.index = table_index;
735 table_index += 1;
736 },
612737 else => unreachable,
613738 }
614739 }
615740}
616741
742/// Takes the global, function and table section from each linked object file
743/// and merges it into a single section for each.
744fn mergeSections(self: *Wasm) !void {
745 // append the indirect function table if initialized
746 if (self.globals.get("__indirect_function_table")) |sym_loc| {
747 const table: wasm.Table = .{
748 .limits = .{ .min = @intCast(u32, self.function_table.count()), .max = null },
749 .reftype = .funcref,
750 };
751 sym_loc.getSymbol(self).index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;
752 try self.tables.append(self.base.allocator, table);
753 }
754
755 for (self.resolved_symbols.items) |sym_loc| {
756 if (sym_loc.file == null) {
757 // Zig code-generated symbols are already within the sections and do not
758 // require to be merged
759 continue;
760 }
761
762 const object = self.objects.items[sym_loc.file.?];
763 const symbol = &object.symtable[sym_loc.index];
764 if (symbol.isUndefined()) {
765 // Skip undefined symbols as they go in the `import` section
766 continue;
767 }
768
769 const offset = object.importedCountByKind(symbol.externalType());
770 const index = symbol.index - offset;
771 switch (symbol.tag) {
772 .function => {
773 const original_func = object.functions[index];
774 symbol.index = @intCast(u32, self.functions.items.len) + self.imported_functions_count;
775 try self.functions.append(self.base.allocator, original_func);
776 },
777 .global => {
778 const original_global = object.globals[index];
779 symbol.index = @intCast(u32, self.globals.items.len) + self.imported_globals_count;
780 try self.wasm_globals.append(self.base.allocator, original_global);
781 },
782 .table => {
783 const original_table = object.tables[index];
784 symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;
785 try self.tables.append(self.base.allocator, original_table);
786 },
787 else => {},
788 }
789 }
790
791 log.debug("Merged ({d}) functions", .{self.functions.items.len});
792 log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len});
793 log.debug("Merged ({d}) tables", .{self.tables.tems.len});
794}
795
796/// Merges function types of all object files into the final
797/// 'types' section, while assigning the type index to the representing
798/// section (import, export, function).
799fn mergeTypes(self: *Wasm) !void {
800 for (self.resolved_symbols.items) |sym_loc| {
801 if (sym_loc.file == null) {
802 // zig code-generated symbols are already present in final type section
803 continue;
804 }
805 const object = self.objects.items[sym_loc.file.?];
806 const symbol = object.symtable[sym_loc.index];
807 if (symbol.tag != .function) {
808 // Only functions have types
809 continue;
810 }
811
812 if (symbol.isUndefined()) {
813 log.debug("Adding type from extern function '{s}'", .{symbol.name});
814 const import: *wasm.Import = self.imports.getPtr(sym_loc);
815 const original_type = object.types[import.kind.function];
816 import.kind.function = try self.putOrGetFuncType(original_type);
817 } else {
818 log.debug("Adding type from function '{s}'", .{symbol.name});
819 const func = &self.functions.items[symbol.index - self.imported_functions_count];
820 func.type_index = try self.putOrGetFuncType(object.types[func.type_index]);
821 }
822 }
823 log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len});
824}
825
826fn setupExports(self: *Wasm) !void {
827 log.debug("Building exports from symbols", .{});
828
829 // When importing memory option if false, we export it instead
830 if (!self.base.options.import_memory) {
831 try self.exports.append(self.base.allocator, .{ .name = "memory", .kind = .memory, .index = 0 });
832 }
833
834 for (self.resolved_symbols.items) |sym_loc| {
835 const symbol = sym_loc.getSymbol(self);
836 if (!symbol.isExported()) continue;
837
838 const exp: wasm.Export = .{ .name = symbol.name, .kind = symbol.externalType(), .index = symbol.index };
839 log.debug("Appending export for symbol '{s}' at index: ({d})", .{ exp.name, exp.index });
840 try self.exports.append(self.base.allocator, exp);
841 }
842
843 log.debug("Completed building exports. Total count: ({d})", .{self.exports.items.len});
844}
845
846fn setupStart(self: *Wasm) !void {
847 const entry_name = self.base.options.entry orelse "_start";
848
849 const symbol_loc = self.globals.get(entry_name) orelse {
850 if (self.base.options.output_mode == .Exe) {
851 if (self.base.options.wasi_exec_model == .reactor) return; // Not required for reactors
852 } else {
853 return; // No entry point needed for non-executable wasm files
854 }
855 log.err("Entry symbol '{s}' missing", .{entry_name});
856 return error.MissingSymbol;
857 };
858
859 const symbol = symbol_loc.getSymbol(self);
860 if (symbol.tag != .function) {
861 log.err("Entry symbol '{s}' is not a function", .{entry_name});
862 return error.InvalidEntryKind;
863 }
864
865 // Ensure the symbol is exported so host environment can access it
866 symbol.setFlag(.WASM_SYM_EXPORTED);
867}
868
617869/// Sets up the memory section of the wasm module, as well as the stack.
618870fn setupMemory(self: *Wasm) !void {
619871 log.debug("Setting up memory layout", .{});
......@@ -754,6 +1006,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
7541006 // TODO: Also link with other objects such as compiler-rt
7551007 try self.parseInputFiles(positionals.items);
7561008
1009 var object_index: u16 = 0;
1010 while (object_index < self.objects.items.len) : (object_index += 1) {
1011 try self.resolveSymbolsInObject(object_index);
1012 try self.objects.items[object_index].parseIntoAtoms(self.base.allocator, object_index, self);
1013 }
1014
7571015 // When we finish/error we reset the state of the linker
7581016 // So we can rebuild the binary file on each incremental update
7591017 defer self.resetState();
......@@ -777,6 +1035,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
7771035 try self.setupMemory();
7781036 try self.allocateAtoms();
7791037 self.mapFunctionTable();
1038 try self.mergeSections();
1039 try self.mergeTypes();
1040 try self.setupExports();
7801041
7811042 const file = self.base.file.?;
7821043 const header_size = 5 + 1;
src/link/Wasm/Atom.zig+4-4
......@@ -50,7 +50,7 @@ pub fn deinit(self: *Atom, gpa: Allocator) void {
5050 self.relocs.deinit(gpa);
5151 self.code.deinit(gpa);
5252
53 while (self.locals.items) |*local| {
53 for (self.locals.items) |*local| {
5454 local.deinit(gpa);
5555 }
5656 self.locals.deinit(gpa);
......@@ -93,7 +93,7 @@ pub fn symbolAtom(self: *Atom, symbol_index: u32) *Atom {
9393/// Resolves the relocations within the atom, writing the new value
9494/// at the calculated offset.
9595pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
96 const symbol: Symbol = wasm_bin.symbols.items[self.sym_index];
96 const symbol: Symbol = wasm_bin.managed_symbols.items[self.sym_index];
9797 log.debug("Resolving relocs in atom '{s}' count({d})", .{
9898 symbol.name,
9999 self.relocs.items.len,
......@@ -102,7 +102,7 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
102102 for (self.relocs.items) |reloc| {
103103 const value = try relocationValue(reloc, wasm_bin);
104104 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
105 wasm_bin.symbols.items[reloc.index].name,
105 wasm_bin.managed_symbols.items[reloc.index].name,
106106 symbol.name,
107107 reloc.offset,
108108 value,
......@@ -139,7 +139,7 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
139139/// All values will be represented as a `u64` as all values can fit within it.
140140/// The final value must be casted to the correct size.
141141fn relocationValue(relocation: types.Relocation, wasm_bin: *const Wasm) !u64 {
142 const symbol: Symbol = wasm_bin.symbols.items[relocation.index];
142 const symbol: Symbol = wasm_bin.managed_symbols.items[relocation.index];
143143 return switch (relocation.relocation_type) {
144144 .R_WASM_FUNCTION_INDEX_LEB => symbol.index,
145145 .R_WASM_TABLE_NUMBER_LEB => symbol.index,
src/link/Wasm/Object.zig+13-13
......@@ -6,14 +6,14 @@ const Object = @This();
66const Atom = @import("Atom.zig");
77const types = @import("types.zig");
88const std = @import("std");
9const Wasm = @import("Wasm.zig");
9const Wasm = @import("../Wasm.zig");
1010const Symbol = @import("Symbol.zig");
1111
1212const Allocator = std.mem.Allocator;
1313const leb = std.leb;
1414const meta = std.meta;
1515
16const log = std.log.scoped(.zwld);
16const log = std.log.scoped(.link);
1717
1818/// Wasm spec version used for this `Object`
1919version: u32 = 0,
......@@ -26,7 +26,7 @@ file: ?std.fs.File = null,
2626/// Name (read path) of the object file.
2727name: []const u8,
2828/// Parsed type section
29types: []const std.wasm.Type = &.{},
29func_types: []const std.wasm.Type = &.{},
3030/// A list of all imports for this module
3131imports: []std.wasm.Import = &.{},
3232/// Parsed function section
......@@ -104,7 +104,8 @@ const RelocatableData = struct {
104104pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadError;
105105
106106/// Initializes a new `Object` from a wasm object file.
107pub fn init(gpa: Allocator, file: std.fs.File, path: []const u8) InitError!Object {
107/// This also parses and verifies the object file.
108pub fn create(gpa: Allocator, file: std.fs.File, path: []const u8) InitError!Object {
108109 var object: Object = .{
109110 .file = file,
110111 .name = path,
......@@ -161,7 +162,7 @@ pub fn getTable(self: *const Object, id: u32) *std.wasm.Table {
161162/// we initialize a new table symbol that corresponds to that import and return that symbol.
162163///
163164/// When the object file is *NOT* MVP, we return `null`.
164fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
165fn checkLegacyIndirectFunctionTable(self: *Object, gpa: Allocator) !?Symbol {
165166 var table_count: usize = 0;
166167 for (self.symtable) |sym| {
167168 if (sym.tag == .table) table_count += 1;
......@@ -204,7 +205,7 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
204205
205206 var table_symbol: Symbol = .{
206207 .flags = 0,
207 .name = table_import.name,
208 .name = try gpa.dupeZ(u8, table_import.name),
208209 .tag = .table,
209210 .index = 0,
210211 };
......@@ -310,7 +311,7 @@ fn Parser(comptime ReaderType: type) type {
310311 }
311312 },
312313 .type => {
313 for (try readVec(&self.object.types, reader, gpa)) |*type_val| {
314 for (try readVec(&self.object.func_types, reader, gpa)) |*type_val| {
314315 if ((try reader.readByte()) != std.wasm.function_type) return error.ExpectedFuncType;
315316
316317 for (try readVec(&type_val.params, reader, gpa)) |*param| {
......@@ -636,7 +637,7 @@ fn Parser(comptime ReaderType: type) type {
636637
637638 // we found all symbols, check for indirect function table
638639 // in case of an MVP object file
639 if (try self.object.checkLegacyIndirectFunctionTable()) |symbol| {
640 if (try self.object.checkLegacyIndirectFunctionTable(gpa)) |symbol| {
640641 try symbols.append(symbol);
641642 log.debug("Found legacy indirect function table. Created symbol", .{});
642643 }
......@@ -662,7 +663,7 @@ fn Parser(comptime ReaderType: type) type {
662663 switch (tag) {
663664 .data => {
664665 const name_len = try leb.readULEB128(u32, reader);
665 const name = try gpa.alloc(u8, name_len);
666 const name = try gpa.allocSentinel(u8, name_len, 0);
666667 try reader.readNoEof(name);
667668 symbol.name = name;
668669
......@@ -684,16 +685,16 @@ fn Parser(comptime ReaderType: type) type {
684685
685686 const is_undefined = symbol.isUndefined();
686687 if (is_undefined) {
687 maybe_import = self.object.findImport(symbol.externalType(), symbol.index);
688 maybe_import = self.object.findImport(symbol.tag.externalType(), symbol.index);
688689 }
689690 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
690691 if (!(is_undefined and !explicit_name)) {
691692 const name_len = try leb.readULEB128(u32, reader);
692 const name = try gpa.alloc(u8, name_len);
693 const name = try gpa.allocSentinel(u8, name_len, 0);
693694 try reader.readNoEof(name);
694695 symbol.name = name;
695696 } else {
696 symbol.name = maybe_import.?.name;
697 symbol.name = try gpa.dupeZ(u8, maybe_import.?.name);
697698 }
698699 },
699700 }
......@@ -818,7 +819,6 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
818819 }
819820 }
820821
821 // TODO: Replace `atom.code` from an existing slice to a pointer to the data
822822 try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
823823
824824 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
src/link/Wasm/Symbol.zig+1
......@@ -38,6 +38,7 @@ pub const Tag = enum {
3838 .data => .memory,
3939 .section => unreachable, // Not an external type
4040 .event => unreachable, // Not an external type
41 .dead => unreachable, // Dead symbols should not be referenced
4142 .table => .table,
4243 };
4344 }