Commit 7556b32840

Jakub Konka <kubkon@jakubkonka.com>
2024-08-08 23:21:52
elf: indirect via offset table in the linker away from backend
1 parent 97a65ea
Changed files (3)
src/link/Elf/Atom.zig
@@ -759,13 +759,14 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
         // Address of the dynamic thread pointer.
         const DTP = elf_file.dtpAddress();
 
-        relocs_log.debug("  {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
+        relocs_log.debug("  {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ZG2({x}) ({s})", .{
             relocation.fmtRelocType(rel.r_type(), cpu_arch),
             r_offset,
             P,
             S + A,
             G + GOT + A,
             ZIG_GOT + A,
+            target.zigOffsetTableAddress(elf_file) + A,
             target.name(elf_file),
         });
 
@@ -1224,9 +1225,12 @@ const x86_64 = struct {
                 );
             },
 
-            .PLT32,
-            .PC32,
-            => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
+            .PLT32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
+
+            .PC32 => {
+                const S_ = if (target.flags.zig_offset_table) target.zigOffsetTableAddress(elf_file) else S;
+                try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
+            },
 
             .GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
             .GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
src/link/Elf/Symbol.zig
@@ -236,6 +236,14 @@ pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
     return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
 }
 
+pub fn zigOffsetTableAddress(symbol: Symbol, elf_file: *Elf) i64 {
+    if (!symbol.flags.zig_offset_table) return 0;
+    const zo = elf_file.zigObjectPtr().?;
+    const offset_table = zo.offsetTablePtr().?;
+    const ot_index = symbol.extra(elf_file).zig_offset_table;
+    return offset_table.entryAddress(ot_index, zo, elf_file);
+}
+
 pub fn dsoAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
     const file_ptr = symbol.file(elf_file) orelse return 0;
     assert(file_ptr == .shared_object);
src/link/Elf/ZigObject.zig
@@ -760,7 +760,9 @@ pub fn getOrCreateMetadataForLazySymbol(
             const gpa = elf_file.base.comp.gpa;
             const symbol_index = try self.newSymbolWithAtom(gpa, 0);
             const sym = self.symbol(symbol_index);
-            sym.flags.needs_zig_got = true;
+            if (lazy_sym.kind != .code) {
+                sym.flags.needs_zig_got = true;
+            }
             symbol_index_ptr.* = symbol_index;
         },
         .pending_flush => return symbol_index_ptr.*,
@@ -816,7 +818,7 @@ pub fn getOrCreateMetadataForNav(
                 sym.flags.is_tls = true;
             }
         }
-        if (!sym.flags.is_tls) {
+        if (!sym.flags.is_tls and nav_val.typeOf(zcu).zigTypeTag(zcu) != .Fn) {
             sym.flags.needs_zig_got = true;
         }
         gop.value_ptr.* = .{ .symbol_index = symbol_index };
@@ -919,16 +921,19 @@ fn updateNavCode(
                 sym.value = 0;
                 esym.st_value = 0;
 
-                if (!elf_file.base.isRelocatable()) {
-                    log.debug("  (writing new offset table entry)", .{});
-                    assert(sym.flags.has_zig_got);
-                    const extra = sym.extra(elf_file);
-                    try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
-                    if (stt_bits == elf.STT_FUNC) {
-                        const offset_table = self.offsetTablePtr().?;
-                        offset_table.entries.items(.dirty)[extra.zig_offset_table] = true;
+                if (stt_bits != elf.STT_FUNC) {
+                    if (!elf_file.base.isRelocatable()) {
+                        log.debug("  (writing new offset table entry)", .{});
+                        assert(sym.flags.has_zig_got);
+                        const extra = sym.extra(elf_file);
+                        try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
                     }
                 }
+                if (stt_bits == elf.STT_FUNC) {
+                    const extra = sym.extra(elf_file);
+                    const offset_table = self.offsetTablePtr().?;
+                    offset_table.entries.items(.dirty)[extra.zig_offset_table] = true;
+                }
             }
         } else if (code.len < old_size) {
             atom_ptr.shrink(elf_file);
@@ -938,12 +943,13 @@ fn updateNavCode(
         errdefer self.freeNavMetadata(elf_file, sym_index);
 
         sym.value = 0;
-        sym.flags.needs_zig_got = true;
         esym.st_value = 0;
-
-        if (!elf_file.base.isRelocatable()) {
-            const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
-            try elf_file.zig_got.writeOne(elf_file, gop.index);
+        if (stt_bits != elf.STT_FUNC) {
+            sym.flags.needs_zig_got = true;
+            if (!elf_file.base.isRelocatable()) {
+                const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
+                try elf_file.zig_got.writeOne(elf_file, gop.index);
+            }
         }
     }
 
@@ -1061,7 +1067,12 @@ pub fn updateFunc(
             sym.flags.zig_offset_table = true;
             sym.addExtra(.{ .zig_offset_table = index }, elf_file);
             try offset_table.updateSize(self, elf_file);
+            const old_vaddr = offset_table.address(self, elf_file);
             try self.symbol(offset_table.sym_index).atom(elf_file).?.allocate(elf_file);
+            const new_vaddr = offset_table.address(self, elf_file);
+            if (old_vaddr != new_vaddr) {
+                offset_table.dirty = true;
+            }
         }
     }
 
@@ -1106,7 +1117,13 @@ pub fn updateFunc(
 
     // Exports will be updated by `Zcu.processExports` after the update.
 
-    {
+    if (offset_table.dirty) {
+        // TODO write in bulk
+        for (offset_table.entries.items(.dirty), 0..) |*dirty, i| {
+            try offset_table.writeEntry(@intCast(i), self, elf_file);
+            dirty.* = false;
+        }
+    } else {
         const sym = self.symbol(sym_index);
         const ot_index = sym.extra(elf_file).zig_offset_table;
         var ot_entry = offset_table.entries.get(ot_index);
@@ -1261,7 +1278,9 @@ fn updateLazySymbol(
     errdefer self.freeNavMetadata(elf_file, symbol_index);
 
     local_sym.value = 0;
-    local_sym.flags.needs_zig_got = true;
+    if (sym.kind != .code) {
+        local_sym.flags.needs_zig_got = true;
+    }
     local_esym.st_value = 0;
 
     if (!elf_file.base.isRelocatable()) {
@@ -1476,7 +1495,7 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
     return lookup_gop.value_ptr.*;
 }
 
-fn offsetTablePtr(self: *ZigObject) ?*OffsetTable {
+pub fn offsetTablePtr(self: *ZigObject) ?*OffsetTable {
     return if (self.offset_table) |*ot| ot else null;
 }
 
@@ -1747,6 +1766,7 @@ const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
 pub const OffsetTable = struct {
     sym_index: Symbol.Index,
     entries: std.MultiArrayList(Entry) = .{},
+    dirty: bool = false,
 
     pub fn deinit(ot: *OffsetTable, allocator: Allocator) void {
         ot.entries.deinit(allocator);