diff options
| author | Luuk de Gram <luuk@degram.dev> | 2022-05-21 20:44:01 +0200 |
|---|---|---|
| committer | Luuk de Gram <luuk@degram.dev> | 2022-06-24 08:12:17 +0200 |
| commit | 8d03e4fc6b361e6cf96865acc05820556ae33863 (patch) | |
| tree | 1f6d431c2f2aef13df992f3d571f6291c66f5e7e /src/link | |
| parent | 359b61aec3494197aaca336dabaa39d0515706ff (diff) | |
| download | zig-8d03e4fc6b361e6cf96865acc05820556ae33863.tar.gz zig-8d03e4fc6b361e6cf96865acc05820556ae33863.zip | |
link: Implement API to get global symbol index
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/Wasm.zig | 64 | ||||
| -rw-r--r-- | src/link/Wasm/Atom.zig | 5 | ||||
| -rw-r--r-- | src/link/Wasm/Object.zig | 31 |
3 files changed, 69 insertions, 31 deletions
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 93240623ca..2e6a5dbc96 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -433,6 +433,13 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { continue; // Do not overwrite defined symbols with undefined symbols } + if (symbol.tag != existing_sym.tag) { + log.err("symbol '{s}' mismatching type '{s}", .{ sym_name, @tagName(symbol.tag) }); + log.err(" first definition in '{s}'", .{existing_file_path}); + log.err(" next definition in '{s}'", .{object.name}); + return error.SymbolMismatchingType; + } + // when both symbols are weak, we skip overwriting if (existing_sym.isWeak() and symbol.isWeak()) { continue; @@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In /// Returns the symbol index from the name of an intrinsic. /// If the symbol does not yet exist, creates a new one symbol instead /// and then returns the index to it. -pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { +pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 { const name_index = try self.string_table.put(self.base.allocator, name); const gop = try self.globals.getOrPut(self.base.allocator, name_index); if (gop.found_existing) { @@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { .tag = .function, }; symbol.setGlobal(true); - symbol.setFlag(.WASM_SYM_UNDEFINED); + symbol.setUndefined(true); const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: { var index = @intCast(u32, self.symbols.items.len); @@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 { }; self.symbols.items[sym_index] = symbol; gop.value_ptr.* = .{ .index = sym_index, .file = null }; - + try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {}); return sym_index; } @@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void { } } -pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { +/// Either creates a new import, or updates one if existing. +/// When `type_index` is non-null, we assume an external function. +/// In all other cases, a data-symbol will be created instead. +pub fn addOrUpdateImport( + self: *Wasm, + /// Name of the import + name: []const u8, + /// Symbol index that is external + symbol_index: u32, + /// Optional library name (i.e. `extern "c" fn foo() void` + lib_name: ?[*:0]const u8, + /// The index of the type that represents the function signature + /// when the extern is a function. When this is null, a data-symbol + /// is asserted instead. + type_index: ?u32, +) !void { // For the import name itself, we use the decl's name, rather than the fully qualified name - const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0)); - const symbol_index = decl.link.wasm.sym_index; + const decl_name_index = try self.string_table.put(self.base.allocator, name); const symbol: *Symbol = &self.symbols.items[symbol_index]; symbol.setUndefined(true); symbol.setGlobal(true); @@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void { try self.resolved_symbols.put(self.base.allocator, loc, {}); } - switch (decl.ty.zigTypeTag()) { - .Fn => { - const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); - const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: { - break :blk mem.sliceTo(lib_name, 0); - } else self.host_name; - if (!gop.found_existing) { - gop.value_ptr.* = .{ - .module_name = try self.string_table.put(self.base.allocator, module_name), - .name = decl_name_index, - .kind = .{ .function = decl.fn_link.wasm.type_index }, - }; - } - }, - else => @panic("TODO: Implement undefined symbols for non-function declarations"), - } + if (type_index) |ty_index| { + const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null }); + const module_name = if (lib_name) |l_name| blk: { + break :blk mem.sliceTo(l_name, 0); + } else self.host_name; + if (!gop.found_existing) { + gop.value_ptr.* = .{ + .module_name = try self.string_table.put(self.base.allocator, module_name), + .name = decl_name_index, + .kind = .{ .function = ty_index }, + }; + } + } else @panic("TODO: Implement undefined symbols for non-function declarations"); } const Kind = union(enum) { @@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void { symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count; try self.tables.append(self.base.allocator, original_table); }, - else => {}, + else => unreachable, } } diff --git a/src/link/Wasm/Atom.zig b/src/link/Wasm/Atom.zig index 6f65b1b83a..03b6fc6cf4 100644 --- a/src/link/Wasm/Atom.zig +++ b/src/link/Wasm/Atom.zig @@ -171,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa } std.debug.assert(symbol.tag == .data); const merge_segment = wasm_bin.base.options.output_mode != .Obj; - const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment); + const segment_info = if (self.file) |object_index| blk: { + break :blk wasm_bin.objects.items[object_index].segment_info; + } else wasm_bin.segment_info.items; + const segment_name = segment_info[symbol.index].outputName(merge_segment); const atom_index = wasm_bin.data_segments.get(segment_name).?; const target_atom = wasm_bin.symbol_atom.get(target_loc).?; const segment = wasm_bin.segments.items[atom_index]; diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index 8abf78d825..3a24fc6ccb 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -302,12 +302,16 @@ fn Parser(comptime ReaderType: type) type { } fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void { + errdefer self.object.deinit(gpa); try self.verifyMagicBytes(); const version = try self.reader.reader().readIntLittle(u32); self.object.version = version; var relocatable_data = std.ArrayList(RelocatableData).init(gpa); - defer relocatable_data.deinit(); + + errdefer while (relocatable_data.popOrNull()) |rel_data| { + gpa.free(rel_data.data[0..rel_data.size]); + } else relocatable_data.deinit(); var section_index: u32 = 0; while (self.reader.reader().readByte()) |byte| : (section_index += 1) { @@ -808,26 +812,29 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin kind: Symbol.Tag, index: u32, }; - var symbol_for_segment = std.AutoArrayHashMap(Key, u32).init(gpa); + var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa); defer symbol_for_segment.deinit(); for (self.symtable) |symbol, symbol_index| { switch (symbol.tag) { .function, .data => if (!symbol.isUndefined()) { - try symbol_for_segment.putNoClobber( - .{ .kind = symbol.tag, .index = symbol.index }, - @intCast(u32, symbol_index), - ); + const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index }); + const sym_idx = @intCast(u32, symbol_index); + if (!gop.found_existing) { + gop.value_ptr.* = std.ArrayList(u32).init(gpa); + } + try gop.value_ptr.*.append(sym_idx); }, else => continue, } } for (self.relocatable_data) |relocatable_data, index| { - const sym_index = symbol_for_segment.get(.{ + const symbols = symbol_for_segment.getPtr(.{ .kind = relocatable_data.getSymbolKind(), .index = @intCast(u32, relocatable_data.index), }) orelse continue; // encountered a segment we do not create an atom for + const sym_index = symbols.pop(); const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index)); const atom = try gpa.create(Atom); @@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin } try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]); + + // symbols referencing the same atom will be added as alias + // or as 'parent' when they are global. + while (symbols.popOrNull()) |idx| { + const alias_symbol = self.symtable[idx]; + const symbol = self.symtable[atom.sym_index]; + if (alias_symbol.isGlobal() and symbol.isLocal()) { + atom.sym_index = idx; + } + } try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom); const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index]; |
