diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2023-10-30 12:44:50 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2023-10-30 12:44:50 +0100 |
| commit | 324a93e673afcf1bcaac1163379d385952e52a27 (patch) | |
| tree | ec05a05cb590ebc5dcfebce9c92bd8e53db200de /src | |
| parent | 2e690f5c74cbfd16757cc301ac0d899caa8b2fb3 (diff) | |
| download | zig-324a93e673afcf1bcaac1163379d385952e52a27.tar.gz zig-324a93e673afcf1bcaac1163379d385952e52a27.zip | |
coff: implement enough of extern handling to pass comptime export tests
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 3 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 17 | ||||
| -rw-r--r-- | src/codegen.zig | 11 | ||||
| -rw-r--r-- | src/link/Coff.zig | 48 |
4 files changed, 61 insertions, 18 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index d6ac3fb36b..318b1bf670 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -13063,6 +13063,7 @@ fn genExternSymbolRef( } }, }); } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { + const global_index = try coff_file.getGlobalSymbol(callee, lib); _ = try self.addInst(.{ .tag = .mov, .ops = .import_reloc, @@ -13070,7 +13071,7 @@ fn genExternSymbolRef( .r1 = .rax, .payload = try self.addExtra(bits.Symbol{ .atom_index = atom_index, - .sym_index = try coff_file.getGlobalSymbol(callee, lib), + .sym_index = link.File.Coff.global_symbol_bit | global_index, }), } }, }); diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 8201eb4b9a..ca796a4d71 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -69,7 +69,10 @@ pub fn emitMir(emit: *Emit) Error!void { const atom_index = coff_file.getAtomIndexForSymbol( .{ .sym_index = symbol.atom_index, .file = null }, ).?; - const target = coff_file.getGlobalByIndex(symbol.sym_index); + const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + else + link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = .direct, .target = target, @@ -141,6 +144,10 @@ pub fn emitMir(emit: *Emit) Error!void { .sym_index = symbol.atom_index, .file = null, }).?; + const target = if (link.File.Coff.global_symbol_bit & symbol.sym_index != 0) + coff_file.getGlobalByIndex(link.File.Coff.global_symbol_mask & symbol.sym_index) + else + link.File.Coff.SymbolWithLoc{ .sym_index = symbol.sym_index, .file = null }; try link.File.Coff.Atom.addRelocation(coff_file, atom_index, .{ .type = switch (lowered_relocs[0].target) { .linker_got => .got, @@ -148,13 +155,7 @@ pub fn emitMir(emit: *Emit) Error!void { .linker_import => .import, else => unreachable, }, - .target = switch (lowered_relocs[0].target) { - .linker_got, - .linker_direct, - => .{ .sym_index = symbol.sym_index, .file = null }, - .linker_import => coff_file.getGlobalByIndex(symbol.sym_index), - else => unreachable, - }, + .target = target, .offset = @as(u32, @intCast(end_offset - 4)), .addend = 0, .pcrel = true, diff --git a/src/codegen.zig b/src/codegen.zig index cb7c2df55a..c46e41c6e6 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -927,6 +927,17 @@ fn genDeclRef( } return GenResult.mcv(.{ .load_got = sym_index }); } else if (bin_file.cast(link.File.Coff)) |coff_file| { + if (is_extern) { + const name = mod.intern_pool.stringToSlice(decl.name); + // TODO audit this + const lib_name = if (decl.getOwnedVariable(mod)) |ov| + mod.intern_pool.stringToSliceUnwrap(ov.lib_name) + else + null; + const global_index = try coff_file.getGlobalSymbol(name, lib_name); + try coff_file.need_got_table.put(bin_file.allocator, global_index, {}); // needs GOT + return GenResult.mcv(.{ .load_got = link.File.Coff.global_symbol_bit | global_index }); + } const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; return GenResult.mcv(.{ .load_got = sym_index }); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 4c56910cd4..340b60534d 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -28,6 +28,7 @@ locals: std.ArrayListUnmanaged(coff.Symbol) = .{}, globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{}, resolver: std.StringHashMapUnmanaged(u32) = .{}, unresolved: std.AutoArrayHashMapUnmanaged(u32, bool) = .{}, +need_got_table: std.AutoHashMapUnmanaged(u32, void) = .{}, locals_free_list: std.ArrayListUnmanaged(u32) = .{}, globals_free_list: std.ArrayListUnmanaged(u32) = .{}, @@ -1168,12 +1169,17 @@ pub fn updateDecl( const decl = mod.declPtr(decl_index); if (decl.val.getExternFunc(mod)) |_| { - return; // TODO Should we do more when front-end analyzed extern decl? + return; } - if (decl.val.getVariable(mod)) |variable| { - if (variable.is_extern) { - return; // TODO Should we do more when front-end analyzed extern decl? - } + + if (decl.isExtern(mod)) { + // TODO make this part of getGlobalSymbol + const variable = decl.getOwnedVariable(mod).?; + const name = mod.intern_pool.stringToSlice(decl.name); + const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); + const global_index = try self.getGlobalSymbol(name, lib_name); + try self.need_got_table.put(self.base.allocator, global_index, {}); + return; } const atom_index = try self.getOrCreateAtomForDecl(decl_index); @@ -1519,14 +1525,25 @@ pub fn updateExports( continue; } - const sym_index = metadata.getExport(self, mod.intern_pool.stringToSlice(exp.opts.name)) orelse blk: { - const sym_index = try self.allocateSymbol(); + const exp_name = mod.intern_pool.stringToSlice(exp.opts.name); + const sym_index = metadata.getExport(self, exp_name) orelse blk: { + const sym_index = if (self.getGlobalIndex(exp_name)) |global_index| ind: { + const global = self.globals.items[global_index]; + // TODO this is just plain wrong as it all should happen in a single `resolveSymbols` + // pass. This will go away once we abstact away Zig's incremental compilation into + // its own module. + if (global.file == null and self.getSymbol(global).section_number == .UNDEFINED) { + _ = self.unresolved.swapRemove(global_index); + break :ind global.sym_index; + } + break :ind try self.allocateSymbol(); + } else try self.allocateSymbol(); try metadata.exports.append(gpa, sym_index); break :blk sym_index; }; const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const sym = self.getSymbolPtr(sym_loc); - try self.setSymbolName(sym, mod.intern_pool.stringToSlice(exp.opts.name)); + try self.setSymbolName(sym, exp_name); sym.value = atom.getSymbol(self).value; sym.section_number = @as(coff.SectionNumber, @enumFromInt(metadata.section + 1)); sym.type = atom.getSymbol(self).type; @@ -1663,8 +1680,16 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; } + { + var it = self.need_got_table.iterator(); + while (it.next()) |entry| { + const global = self.globals.items[entry.key_ptr.*]; + try self.addGotEntry(global); + } + } + while (self.unresolved.popOrNull()) |entry| { - assert(entry.value); // We only expect imports generated by the incremental linker for now. + assert(entry.value); const global = self.globals.items[entry.key]; const sym = self.getSymbol(global); const res = try self.import_tables.getOrPut(gpa, sym.value); @@ -2459,6 +2484,11 @@ const GetOrPutGlobalPtrResult = struct { value_ptr: *SymbolWithLoc, }; +/// Used only for disambiguating local from global at relocation level. +/// TODO this must go away. +pub const global_symbol_bit: u32 = 0x80000000; +pub const global_symbol_mask: u32 = 0x7fffffff; + /// Return pointer to the global entry for `name` if one exists. /// Puts a new global entry for `name` if one doesn't exist, and /// returns a pointer to it. |
