Commit 324a93e673

Jakub Konka <kubkon@jakubkonka.com>
2023-10-30 12:44:50
coff: implement enough of extern handling to pass comptime export tests
1 parent 2e690f5
Changed files (4)
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,
                 }),
             } },
         });
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,
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.
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 });