Commit ae08f9bfe9

Jakub Konka <kubkon@jakubkonka.com>
2023-11-08 11:51:11
elf: claim unresolved dangling symbols as undef externs in -r mode
1 parent e87c751
Changed files (4)
src/link/Elf/Atom.zig
@@ -294,6 +294,8 @@ pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
 }
 
 pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.Elf64_Rela)) !void {
+    relocs_log.debug("0x{x}: {s}", .{ self.value, self.name(elf_file) });
+
     const file_ptr = self.file(elf_file).?;
     for (self.relocs(elf_file)) |rel| {
         const target_index = switch (file_ptr) {
@@ -302,15 +304,27 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
             else => unreachable,
         };
         const target = elf_file.symbol(target_index);
-        const r_sym = target.outputSymtabIndex(elf_file);
-        const r_offset = self.value + rel.r_offset;
-        const r_addend = rel.r_addend;
         const r_type = switch (rel.r_type()) {
             Elf.R_X86_64_ZIG_GOT32,
             Elf.R_X86_64_ZIG_GOTPCREL,
             => unreachable, // Sanity check if we accidentally emitted those.
             else => |r_type| r_type,
         };
+        const r_offset = self.value + rel.r_offset;
+        const r_addend = rel.r_addend;
+        const r_sym = switch (target.type(elf_file)) {
+            elf.STT_SECTION => elf_file.sectionSymbolOutputSymtabIndex(target.outputShndx().?),
+            else => target.outputSymtabIndex(elf_file),
+        };
+
+        relocs_log.debug("  {s}: [{x} => {d}({s})] + {x}", .{
+            fmtRelocType(r_type),
+            r_offset,
+            r_sym,
+            target.name(elf_file),
+            r_addend,
+        });
+
         out_relocs.appendAssumeCapacity(.{
             .r_offset = r_offset,
             .r_addend = r_addend,
src/link/Elf/Object.zig
@@ -491,6 +491,25 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
     }
 }
 
+pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
+    const first_global = self.first_global orelse return;
+    for (self.globals(), 0..) |index, i| {
+        const esym_index = @as(u32, @intCast(first_global + i));
+        const esym = self.symtab.items[esym_index];
+        if (esym.st_shndx != elf.SHN_UNDEF) continue;
+
+        const global = elf_file.symbol(index);
+        if (global.file(elf_file)) |file| {
+            if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
+        }
+
+        global.value = 0;
+        global.atom_index = 0;
+        global.esym_index = esym_index;
+        global.file_index = self.index;
+    }
+}
+
 pub fn markLive(self: *Object, elf_file: *Elf) void {
     const first_global = self.first_global orelse return;
     for (self.globals(), 0..) |index, i| {
src/link/Elf/ZigObject.zig
@@ -377,8 +377,7 @@ pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
 
         const global = elf_file.symbol(index);
         if (global.file(elf_file)) |file| {
-            if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or
-                file.index() <= self.index) continue;
+            if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
         }
 
         global.value = 0;
src/link/Elf.zig
@@ -2041,8 +2041,7 @@ fn claimUnresolved(self: *Elf) void {
         zig_object.claimUnresolved(self);
     }
     for (self.objects.items) |index| {
-        const object = self.file(index).?.object;
-        object.claimUnresolved(self);
+        self.file(index).?.object.claimUnresolved(self);
     }
 }
 
@@ -2050,6 +2049,9 @@ fn claimUnresolvedObject(self: *Elf) void {
     if (self.zigObjectPtr()) |zig_object| {
         zig_object.claimUnresolvedObject(self);
     }
+    for (self.objects.items) |index| {
+        self.file(index).?.object.claimUnresolvedObject(self);
+    }
 }
 
 /// In scanRelocs we will go over all live atoms and scan their relocs.
@@ -5083,6 +5085,10 @@ fn writeSectionSymbols(self: *Elf) void {
     }
 }
 
+pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 {
+    return @intCast(self.output_sections.getIndex(shndx).? + 1);
+}
+
 /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
 fn ptrWidthBytes(self: Elf) u8 {
     return switch (self.ptr_width) {