authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-15 22:27:58+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-02-17 18:11:48+01:00
loga4622501bdae96d43f26d1897c1f4de87b8daa31
treef6894652cc4dcafce3d367a81d9b1fee64f3d209
parentf1cc5f33e88a64e30695c682177e00af4310a119

wasm-linker: Allocate atoms and handle imports

We now correctly allocate and create atoms for symbols from other object files. Imports are now also resolved and appended when required. Besides those changes, we now duplicate all symbol names, so we can correctly generate unique names for unnamed constants. TODO: String interning

4 files changed, 136 insertions(+), 63 deletions(-)

src/link/Wasm.zig+100-41
......@@ -34,6 +34,8 @@ pub const base_tag = link.File.Tag.wasm;
3434pub const DeclBlock = Atom;
3535
3636base: link.File,
37/// Output name of the file
38name: []const u8,
3739/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
3840llvm_object: ?*LlvmObject = null,
3941/// When importing objects from the host environment, a name must be supplied.
......@@ -156,6 +158,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
156158 // TODO: read the file and keep valid parts instead of truncating
157159 const file = try options.emit.?.directory.handle.createFile(sub_path, .{ .truncate = true, .read = true });
158160 wasm_bin.base.file = file;
161 wasm_bin.name = sub_path;
159162
160163 try file.writeAll(&(wasm.magic ++ wasm.version));
161164
......@@ -170,7 +173,7 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
170173 };
171174 const symbol = try wasm_bin.symbols.addOne(allocator);
172175 symbol.* = .{
173 .name = "__stack_pointer",
176 .name = try allocator.dupeZ(u8, "__stack_pointer"),
174177 .tag = .global,
175178 .flags = 0,
176179 .index = 0,
......@@ -188,6 +191,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
188191 .file = null,
189192 .allocator = gpa,
190193 },
194 .name = undefined,
191195 };
192196 const use_llvm = build_options.have_llvm and options.use_llvm;
193197 const use_stage1 = build_options.is_stage1 and options.use_stage1;
......@@ -233,6 +237,7 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
233237 .file = object_index,
234238 .index = sym_index,
235239 };
240 const sym_name = std.mem.sliceTo(symbol.name, 0);
236241
237242 if (symbol.isLocal()) {
238243 if (symbol.isUndefined()) {
......@@ -247,21 +252,23 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
247252 // TODO: locals are allowed to have duplicate symbol names
248253 // TODO: Store undefined symbols so we can verify at the end if they've all been found
249254 // 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));
255 const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name);
251256 if (!maybe_existing.found_existing) {
252257 maybe_existing.value_ptr.* = location;
253
254 try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location);
255258 continue;
256259 }
257260
258261 const existing_loc = maybe_existing.value_ptr.*;
259262 const existing_sym: *Symbol = existing_loc.getSymbol(self);
260263
264 const existing_file_path = if (existing_loc.file) |file| blk: {
265 break :blk self.objects.items[file].name;
266 } else self.name;
267
261268 if (!existing_sym.isUndefined()) {
262269 if (!symbol.isUndefined()) {
263270 log.err("symbol '{s}' defined multiple times", .{existing_sym.name});
264 log.err(" first definition in '{s}'", .{self.objects.items[existing_loc.file.?].name});
271 log.err(" first definition in '{s}'", .{existing_file_path});
265272 log.err(" next definition in '{s}'", .{object.name});
266273 return error.SymbolCollision;
267274 }
......@@ -271,11 +278,11 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
271278
272279 // simply overwrite with the new symbol
273280 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});
281 log.info(" old definition in '{s}'", .{existing_file_path});
282 log.info(" new definition in '{s}'", .{object.name});
276283 try self.discarded.putNoClobber(self.base.allocator, maybe_existing.value_ptr.*, location);
277284 maybe_existing.value_ptr.* = location;
278 try self.globals.putNoClobber(self.base.allocator, std.mem.sliceTo(symbol.name, 0), location);
285 try self.globals.put(self.base.allocator, sym_name, location);
279286 }
280287}
281288
......@@ -302,6 +309,12 @@ pub fn deinit(self: *Wasm) void {
302309 object.deinit(gpa);
303310 }
304311
312 for (self.symbols.items) |symbol| {
313 if (symbol.tag != .dead) {
314 gpa.free(mem.sliceTo(symbol.name, 0));
315 }
316 }
317
305318 self.decls.deinit(gpa);
306319 self.symbols.deinit(gpa);
307320 self.symbols_free_list.deinit(gpa);
......@@ -441,7 +454,7 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
441454 const atom: *Atom = &decl.link.wasm;
442455 atom.size = @intCast(u32, code.len);
443456 atom.alignment = decl.ty.abiAlignment(self.base.options.target);
444 self.symbols.items[atom.sym_index].name = decl.name;
457 self.symbols.items[atom.sym_index].name = try self.base.allocator.dupeZ(u8, std.mem.sliceTo(decl.name, 0));
445458 try atom.code.appendSlice(self.base.allocator, code);
446459}
447460
......@@ -449,8 +462,10 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void {
449462/// and then append it as a 'contained' atom onto the Decl.
450463pub fn createLocalSymbol(self: *Wasm, decl: *Module.Decl, ty: Type) !u32 {
451464 assert(ty.zigTypeTag() != .Fn); // cannot create local symbols for functions
465 const local_index = decl.link.wasm.locals.items.len;
466 const name = try std.fmt.allocPrintZ(self.base.allocator, "__unnamed_{s}_{d}", .{ decl.name, local_index });
452467 var symbol: Symbol = .{
453 .name = "unnamed_local",
468 .name = name,
454469 .flags = 0,
455470 .tag = .data,
456471 .index = undefined,
......@@ -494,7 +509,7 @@ pub fn getDeclVAddr(
494509 const atom = decl.link.wasm.symbolAtom(symbol_index);
495510 const is_wasm32 = self.base.options.target.cpu.arch == .wasm32;
496511 if (ty.zigTypeTag() == .Fn) {
497 std.debug.assert(addend == 0); // addend not allowed for function relocations
512 assert(addend == 0); // addend not allowed for function relocations
498513 // We found a function pointer, so add it to our table,
499514 // as function pointers are not allowed to be stored inside the data section.
500515 // They are instead stored in a function table which are called by index.
......@@ -543,15 +558,13 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void {
543558 self.symbols.items[atom.sym_index].tag = .dead; // to ensure it does not end in the names section
544559 for (atom.locals.items) |local_atom| {
545560 self.symbols.items[local_atom.sym_index].tag = .dead; // also for any local symbol
561 // self.base.allocator.free(mem.sliceTo(self.symbols.items[local_atom.sym_index].name, 0));
546562 self.symbols_free_list.append(self.base.allocator, local_atom.sym_index) catch {};
547563 }
564 // self.base.allocator.free(mem.sliceTo(self.symbols.items[atom.sym_index].name, 0));
548565
549566 if (decl.isExtern()) {
550 const import = self.imports.fetchRemove(.{ .file = null, .index = atom.sym_index }).?.value;
551 switch (import.kind) {
552 .function => self.imported_functions_count -= 1,
553 else => unreachable,
554 }
567 assert(self.imports.remove(.{ .file = null, .index = atom.sym_index }));
555568 }
556569
557570 atom.deinit(self.base.allocator);
......@@ -577,16 +590,18 @@ fn mapFunctionTable(self: *Wasm) void {
577590fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
578591 const symbol_index = decl.link.wasm.sym_index;
579592 const symbol: *Symbol = &self.symbols.items[symbol_index];
580 symbol.name = decl.name;
593 const decl_name = mem.sliceTo(decl.name, 0);
594 symbol.name = try self.base.allocator.dupeZ(u8, decl_name);
581595 symbol.setUndefined(true);
596 // also add it as a global so it can be resolved
597 try self.globals.put(self.base.allocator, decl_name, .{ .file = null, .index = symbol_index });
582598 switch (decl.ty.zigTypeTag()) {
583599 .Fn => {
584600 const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
585601 const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: {
586 break :blk std.mem.sliceTo(lib_name, 0);
602 break :blk mem.sliceTo(lib_name, 0);
587603 } else self.host_name;
588604 if (!gop.found_existing) {
589 self.imported_functions_count += 1;
590605 gop.value_ptr.* = .{
591606 .module_name = module_name,
592607 .name = std.mem.span(symbol.name),
......@@ -608,9 +623,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
608623 const symbol: *Symbol = &self.symbols.items[atom.sym_index];
609624 const final_index: u32 = switch (kind) {
610625 .function => |fn_data| result: {
611 const type_index = fn_data.type_index;
612626 const index = @intCast(u32, self.functions.items.len + self.imported_functions_count);
613 try self.functions.append(self.base.allocator, .{ .type_index = type_index });
627 try self.functions.append(self.base.allocator, .{ .type_index = fn_data.type_index });
614628 symbol.tag = .function;
615629 symbol.index = index;
616630
......@@ -641,6 +655,7 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
641655 break :blk index;
642656 };
643657 const info_index = @intCast(u32, self.segment_info.items.len);
658 // TODO: Add mutables global decls to .bss section instead
644659 const segment_name = try std.mem.concat(self.base.allocator, u8, &.{
645660 ".rodata.",
646661 std.mem.span(symbol.name),
......@@ -684,7 +699,7 @@ fn allocateAtoms(self: *Wasm) !void {
684699 offset = std.mem.alignForwardGeneric(u32, offset, atom.alignment);
685700 atom.offset = offset;
686701 log.debug("Atom '{s}' allocated from 0x{x:0>8} to 0x{x:0>8} size={d}", .{
687 self.symbols.items[atom.sym_index].name,
702 (SymbolLoc{ .file = atom.file, .index = atom.sym_index }).getSymbol(self).name,
688703 offset,
689704 offset + atom.size,
690705 atom.size,
......@@ -695,7 +710,7 @@ fn allocateAtoms(self: *Wasm) !void {
695710 }
696711}
697712
698fn setupImports(self: *Wasm) void {
713fn setupImports(self: *Wasm) !void {
699714 for (self.resolved_symbols.items) |symbol_loc| {
700715 if (symbol_loc.file == null) {
701716 // imports generated by Zig code are already in the `import` section
......@@ -708,7 +723,7 @@ fn setupImports(self: *Wasm) void {
708723 }
709724
710725 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);
726 const import = self.objects.items[symbol_loc.file.?].findImport(symbol.tag.externalType(), symbol.index);
712727 // TODO: De-duplicate imports
713728 try self.imports.putNoClobber(self.base.allocator, symbol_loc, import);
714729 }
......@@ -737,6 +752,9 @@ fn setupImports(self: *Wasm) void {
737752 else => unreachable,
738753 }
739754 }
755 self.imported_functions_count = function_index;
756 self.imported_globals_count = global_index;
757 self.imported_tables_count = table_index;
740758}
741759
742760/// Takes the global, function and table section from each linked object file
......@@ -761,12 +779,13 @@ fn mergeSections(self: *Wasm) !void {
761779
762780 const object = self.objects.items[sym_loc.file.?];
763781 const symbol = &object.symtable[sym_loc.index];
764 if (symbol.isUndefined()) {
782 if (symbol.isUndefined() or (symbol.tag != .function and symbol.tag != .global and symbol.tag != .table)) {
765783 // Skip undefined symbols as they go in the `import` section
784 // Also skip symbols that do not need to have a section merged.
766785 continue;
767786 }
768787
769 const offset = object.importedCountByKind(symbol.externalType());
788 const offset = object.importedCountByKind(symbol.tag.externalType());
770789 const index = symbol.index - offset;
771790 switch (symbol.tag) {
772791 .function => {
......@@ -776,7 +795,7 @@ fn mergeSections(self: *Wasm) !void {
776795 },
777796 .global => {
778797 const original_global = object.globals[index];
779 symbol.index = @intCast(u32, self.globals.items.len) + self.imported_globals_count;
798 symbol.index = @intCast(u32, self.wasm_globals.items.len) + self.imported_globals_count;
780799 try self.wasm_globals.append(self.base.allocator, original_global);
781800 },
782801 .table => {
......@@ -790,7 +809,7 @@ fn mergeSections(self: *Wasm) !void {
790809
791810 log.debug("Merged ({d}) functions", .{self.functions.items.len});
792811 log.debug("Merged ({d}) globals", .{self.wasm_globals.items.len});
793 log.debug("Merged ({d}) tables", .{self.tables.tems.len});
812 log.debug("Merged ({d}) tables", .{self.tables.items.len});
794813}
795814
796815/// Merges function types of all object files into the final
......@@ -811,13 +830,13 @@ fn mergeTypes(self: *Wasm) !void {
811830
812831 if (symbol.isUndefined()) {
813832 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];
833 const import: *wasm.Import = self.imports.getPtr(sym_loc).?;
834 const original_type = object.func_types[import.kind.function];
816835 import.kind.function = try self.putOrGetFuncType(original_type);
817836 } else {
818837 log.debug("Adding type from function '{s}'", .{symbol.name});
819838 const func = &self.functions.items[symbol.index - self.imported_functions_count];
820 func.type_index = try self.putOrGetFuncType(object.types[func.type_index]);
839 func.type_index = try self.putOrGetFuncType(object.func_types[func.type_index]);
821840 }
822841 }
823842 log.debug("Completed merging and deduplicating types. Total count: ({d})", .{self.func_types.items.len});
......@@ -835,7 +854,11 @@ fn setupExports(self: *Wasm) !void {
835854 const symbol = sym_loc.getSymbol(self);
836855 if (!symbol.isExported()) continue;
837856
838 const exp: wasm.Export = .{ .name = symbol.name, .kind = symbol.externalType(), .index = symbol.index };
857 const exp: wasm.Export = .{
858 .name = mem.sliceTo(symbol.name, 0),
859 .kind = symbol.tag.externalType(),
860 .index = symbol.index,
861 };
839862 log.debug("Appending export for symbol '{s}' at index: ({d})", .{ exp.name, exp.index });
840863 try self.exports.append(self.base.allocator, exp);
841864 }
......@@ -948,6 +971,41 @@ fn setupMemory(self: *Wasm) !void {
948971 }
949972}
950973
974/// From a given object's index and the index of the segment, returns the corresponding
975/// index of the segment within the final data section. When the segment does not yet
976/// exist, a new one will be initialized and appended. The new index will be returned in that case.
977pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !u32 {
978 const object: Object = self.objects.items[object_index];
979 const relocatable_data = object.relocatable_data[relocatable_index];
980 const index = @intCast(u32, self.segments.items.len);
981
982 switch (relocatable_data.type) {
983 .data => {
984 const segment_info = object.segment_info[relocatable_data.index];
985 const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName());
986 if (!result.found_existing) {
987 result.value_ptr.* = index;
988 try self.segments.append(self.base.allocator, .{
989 .alignment = 1,
990 .size = 0,
991 .offset = 0,
992 });
993 return index;
994 } else return result.value_ptr.*;
995 },
996 .code => return self.code_section_index orelse blk: {
997 self.code_section_index = index;
998 try self.segments.append(self.base.allocator, .{
999 .alignment = 1,
1000 .size = 0,
1001 .offset = 0,
1002 });
1003 break :blk index;
1004 },
1005 .custom => return error.@"TODO: Custom section relocations for wasm",
1006 }
1007}
1008
9511009fn resetState(self: *Wasm) void {
9521010 for (self.segment_info.items) |*segment_info| {
9531011 self.base.allocator.free(segment_info.name);
......@@ -1015,7 +1073,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
10151073 // When we finish/error we reset the state of the linker
10161074 // So we can rebuild the binary file on each incremental update
10171075 defer self.resetState();
1018 self.setupImports();
1076 try self.setupImports();
10191077 var decl_it = self.decls.keyIterator();
10201078 while (decl_it.next()) |decl| {
10211079 if (decl.*.isExtern()) continue;
......@@ -1050,7 +1108,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
10501108 {
10511109 const header_offset = try reserveVecSectionHeader(file);
10521110 const writer = file.writer();
1053
1111 log.debug("Writing type section. Count: ({d})", .{self.func_types.items.len});
10541112 for (self.func_types.items) |func_type| {
10551113 try leb.writeULEB128(writer, wasm.function_type);
10561114 try leb.writeULEB128(writer, @intCast(u32, func_type.params.len));
......@@ -1095,8 +1153,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
10951153
10961154 var it = self.imports.iterator();
10971155 while (it.next()) |entry| {
1098 const import_symbol = self.symbols.items[entry.key_ptr.*];
1099 std.debug.assert(import_symbol.isUndefined());
1156 assert(entry.key_ptr.*.getSymbol(self).isUndefined());
11001157 const import = entry.value_ptr.*;
11011158 try emitImport(writer, import);
11021159 }
......@@ -1207,7 +1264,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
12071264 .Fn => {
12081265 const target = exprt.exported_decl.link.wasm.sym_index;
12091266 const target_symbol = self.symbols.items[target];
1210 std.debug.assert(target_symbol.tag == .function);
1267 assert(target_symbol.tag == .function);
12111268 // Type of the export
12121269 try writer.writeByte(wasm.externalKind(.function));
12131270 // Exported function index
......@@ -1323,8 +1380,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
13231380 try writer.writeByteNTimes(0, diff);
13241381 current_offset += diff;
13251382 }
1326 std.debug.assert(current_offset == atom.offset);
1327 std.debug.assert(atom.code.items.len == atom.size);
1383 assert(current_offset == atom.offset);
1384 assert(atom.code.items.len == atom.size);
13281385 try writer.writeAll(atom.code.items);
13291386
13301387 current_offset += atom.size;
......@@ -1335,10 +1392,12 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
13351392 // segments are aligned.
13361393 if (current_offset != segment.size) {
13371394 try writer.writeByteNTimes(0, segment.size - current_offset);
1395 current_offset += segment.size - current_offset;
13381396 }
13391397 break;
13401398 }
13411399 }
1400 assert(current_offset == segment.size);
13421401 }
13431402
13441403 try writeVecSectionHeader(
......@@ -1371,8 +1430,8 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
13711430
13721431 for (self.symbols.items) |symbol| {
13731432 switch (symbol.tag) {
1374 .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }),
1375 .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }),
1433 .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }),
1434 .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = mem.sliceTo(symbol.name, 0) }),
13761435 else => {},
13771436 }
13781437 }
src/link/Wasm/Atom.zig+11-5
......@@ -23,6 +23,9 @@ alignment: u32,
2323/// Offset into the section where the atom lives, this already accounts
2424/// for alignment.
2525offset: u32,
26/// Represents the index of the file this atom was generated from.
27/// This is 'null' when the atom was generated by a Decl from Zig code.
28file: ?u16,
2629
2730/// Next atom in relation to this atom.
2831/// When null, this atom is the last atom
......@@ -38,6 +41,7 @@ locals: std.ArrayListUnmanaged(Atom) = .{},
3841/// Represents a default empty wasm `Atom`
3942pub const empty: Atom = .{
4043 .alignment = 0,
44 .file = null,
4145 .next = null,
4246 .offset = 0,
4347 .prev = null,
......@@ -93,16 +97,17 @@ pub fn symbolAtom(self: *Atom, symbol_index: u32) *Atom {
9397/// Resolves the relocations within the atom, writing the new value
9498/// at the calculated offset.
9599pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
96 const symbol: Symbol = wasm_bin.managed_symbols.items[self.sym_index];
100 const loc: Wasm.SymbolLoc = .{ .file = self.file, .index = self.sym_index };
101 const symbol = loc.getSymbol(wasm_bin).*;
97102 log.debug("Resolving relocs in atom '{s}' count({d})", .{
98103 symbol.name,
99104 self.relocs.items.len,
100105 });
101106
102107 for (self.relocs.items) |reloc| {
103 const value = try relocationValue(reloc, wasm_bin);
108 const value = try self.relocationValue(reloc, wasm_bin);
104109 log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
105 wasm_bin.managed_symbols.items[reloc.index].name,
110 (Wasm.SymbolLoc{ .file = self.file, .index = reloc.index }).getSymbol(wasm_bin).name,
106111 symbol.name,
107112 reloc.offset,
108113 value,
......@@ -138,8 +143,9 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) !void {
138143/// From a given `relocation` will return the new value to be written.
139144/// All values will be represented as a `u64` as all values can fit within it.
140145/// The final value must be casted to the correct size.
141fn relocationValue(relocation: types.Relocation, wasm_bin: *const Wasm) !u64 {
142 const symbol: Symbol = wasm_bin.managed_symbols.items[relocation.index];
146fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) !u64 {
147 const target_loc: Wasm.SymbolLoc = .{ .file = self.file, .index = relocation.index };
148 const symbol = target_loc.getSymbol(wasm_bin).*;
143149 return switch (relocation.relocation_type) {
144150 .R_WASM_FUNCTION_INDEX_LEB => symbol.index,
145151 .R_WASM_TABLE_NUMBER_LEB => symbol.index,
src/link/Wasm/Object.zig+24-16
......@@ -131,9 +131,9 @@ pub fn deinit(self: *Object, gpa: Allocator) void {
131131
132132/// Finds the import within the list of imports from a given kind and index of that kind.
133133/// Asserts the import exists
134pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index: u32) *std.wasm.Import {
134pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index: u32) std.wasm.Import {
135135 var i: u32 = 0;
136 return for (self.imports) |*import| {
136 return for (self.imports) |import| {
137137 if (std.meta.activeTag(import.kind) == import_kind) {
138138 if (i == index) return import;
139139 i += 1;
......@@ -681,7 +681,7 @@ fn Parser(comptime ReaderType: type) type {
681681 },
682682 else => {
683683 symbol.index = try leb.readULEB128(u32, reader);
684 var maybe_import: ?*std.wasm.Import = null;
684 var maybe_import: ?std.wasm.Import = null;
685685
686686 const is_undefined = symbol.isUndefined();
687687 if (is_undefined) {
......@@ -791,10 +791,14 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
791791 .kind = relocatable_data.getSymbolKind(),
792792 .index = @intCast(u32, relocatable_data.index),
793793 }) orelse continue; // encountered a segment we do not create an atom for
794 const final_index = try wasm_bin.getMatchingSegment(gpa, object_index, @intCast(u32, index));
794 const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index));
795795
796 const atom = try Atom.create(gpa);
797 errdefer atom.deinit(gpa);
796 const atom = try gpa.create(Atom);
797 atom.* = Atom.empty;
798 errdefer {
799 atom.deinit(gpa);
800 gpa.destroy(atom);
801 }
798802
799803 try wasm_bin.managed_atoms.append(gpa, atom);
800804 atom.file = object_index;
......@@ -803,19 +807,23 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
803807 atom.sym_index = sym_index;
804808
805809 const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};
806 for (relocations) |*relocation| {
810 for (relocations) |relocation| {
807811 if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {
808812 // set the offset relative to the offset of the segment itself,
809813 // rather than within the entire section.
810 relocation.offset -= relocatable_data.offset;
811 try atom.relocs.append(gpa, relocation.*);
812
813 if (relocation.isTableIndex()) {
814 try wasm_bin.elements.appendSymbol(gpa, .{
815 .file = object_index,
816 .sym_index = relocation.index,
817 });
818 }
814 var reloc = relocation;
815 reloc.offset -= relocatable_data.offset;
816 try atom.relocs.append(gpa, reloc);
817
818 // TODO: Automatically append the target symbol to the indirect
819 // function table when the relocation is a table index.
820 //
821 // if (relocation.isTableIndex()) {
822 // try wasm_bin.elements.appendSymbol(gpa, .{
823 // .file = object_index,
824 // .sym_index = relocation.index,
825 // });
826 // }
819827 }
820828 }
821829
src/link/Wasm/Symbol.zig+1-1
......@@ -78,7 +78,7 @@ pub const Flag = enum(u32) {
7878pub fn requiresImport(self: Symbol) bool {
7979 if (!self.isUndefined()) return false;
8080 if (self.isWeak()) return false;
81 if (self.kind == .data) return false;
81 if (self.tag == .data) return false;
8282 // if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib
8383
8484 return true;