Commit e99818c602

Jakub Konka <kubkon@jakubkonka.com>
2024-08-06 12:36:51
elf: start-stop resolution has to come after init output sections
1 parent 835f1fc
Changed files (3)
src/link/Elf/LinkerDefined.zig
@@ -42,30 +42,28 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
     try self.strtab.append(allocator, 0);
 }
 
-pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
-    const newSymbolAssumeCapacity = struct {
-        fn newSymbolAssumeCapacity(ld: *LinkerDefined, name_off: u32, ef: *Elf) Symbol.Index {
-            const esym_index: u32 = @intCast(ld.symtab.items.len);
-            const esym = ld.symtab.addOneAssumeCapacity();
-            esym.* = .{
-                .st_name = name_off,
-                .st_info = elf.STB_GLOBAL << 4,
-                .st_other = @intFromEnum(elf.STV.HIDDEN),
-                .st_shndx = elf.SHN_ABS,
-                .st_value = 0,
-                .st_size = 0,
-            };
-            const index = ld.addSymbolAssumeCapacity();
-            const symbol = &ld.symbols.items[index];
-            symbol.name_offset = name_off;
-            symbol.extra_index = ld.addSymbolExtraAssumeCapacity(.{});
-            symbol.ref = .{ .index = 0, .file = 0 };
-            symbol.esym_index = esym_index;
-            symbol.version_index = ef.default_sym_version;
-            return index;
-        }
-    }.newSymbolAssumeCapacity;
+fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) Symbol.Index {
+    const esym_index: u32 = @intCast(self.symtab.items.len);
+    const esym = self.symtab.addOneAssumeCapacity();
+    esym.* = .{
+        .st_name = name_off,
+        .st_info = elf.STB_GLOBAL << 4,
+        .st_other = @intFromEnum(elf.STV.HIDDEN),
+        .st_shndx = elf.SHN_ABS,
+        .st_value = 0,
+        .st_size = 0,
+    };
+    const index = self.addSymbolAssumeCapacity();
+    const symbol = &self.symbols.items[index];
+    symbol.name_offset = name_off;
+    symbol.extra_index = self.addSymbolExtraAssumeCapacity(.{});
+    symbol.ref = .{ .index = 0, .file = 0 };
+    symbol.esym_index = esym_index;
+    symbol.version_index = elf_file.default_sym_version;
+    return index;
+}
 
+pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
     const gpa = elf_file.base.comp.gpa;
 
     var nsyms: usize = 0;
@@ -93,18 +91,6 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
         nsyms += 1; // __global_pointer$
     }
 
-    var start_stop_count: usize = 0;
-    for (elf_file.objects.items) |index| {
-        const object = elf_file.file(index).?.object;
-        for (object.shdrs.items) |shdr| {
-            if (object.getStartStopBasename(shdr)) |_| {
-                start_stop_count += 2; // __start_, __stop_
-            }
-        }
-    }
-    nsyms += start_stop_count;
-
-    try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, start_stop_count);
     try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
     try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
     try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
@@ -113,44 +99,67 @@ pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
     @memset(self.symbols_resolver.items, 0);
 
     if (elf_file.entry_name) |name| {
-        self.entry_index = newSymbolAssumeCapacity(self, try self.addString(gpa, name), elf_file);
+        self.entry_index = self.newSymbolAssumeCapacity(try self.addString(gpa, name), elf_file);
     }
 
-    self.dynamic_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_DYNAMIC"), elf_file);
-    self.ehdr_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__ehdr_start"), elf_file);
-    self.init_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_start"), elf_file);
-    self.init_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__init_array_end"), elf_file);
-    self.fini_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_start"), elf_file);
-    self.fini_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__fini_array_end"), elf_file);
-    self.preinit_array_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_start"), elf_file);
-    self.preinit_array_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__preinit_array_end"), elf_file);
-    self.got_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file);
-    self.plt_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file);
-    self.end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "_end"), elf_file);
+    self.dynamic_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_DYNAMIC"), elf_file);
+    self.ehdr_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__ehdr_start"), elf_file);
+    self.init_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_start"), elf_file);
+    self.init_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_end"), elf_file);
+    self.fini_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_start"), elf_file);
+    self.fini_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_end"), elf_file);
+    self.preinit_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_start"), elf_file);
+    self.preinit_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_end"), elf_file);
+    self.got_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file);
+    self.plt_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file);
+    self.end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_end"), elf_file);
 
     if (elf_file.base.comp.link_eh_frame_hdr) {
-        self.gnu_eh_frame_hdr_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file);
+        self.gnu_eh_frame_hdr_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file);
     }
 
-    self.dso_handle_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__dso_handle"), elf_file);
-    self.rela_iplt_start_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_start"), elf_file);
-    self.rela_iplt_end_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__rela_iplt_end"), elf_file);
+    self.dso_handle_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__dso_handle"), elf_file);
+    self.rela_iplt_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_start"), elf_file);
+    self.rela_iplt_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_end"), elf_file);
 
     if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
-        self.global_pointer_index = newSymbolAssumeCapacity(self, try self.addString(gpa, "__global_pointer$"), elf_file);
+        self.global_pointer_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__global_pointer$"), elf_file);
+    }
+}
+
+pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
+    const gpa = elf_file.base.comp.gpa;
+
+    var nsyms: usize = 0;
+    for (elf_file.shdrs.items) |shdr| {
+        if (elf_file.getStartStopBasename(shdr)) |_| {
+            nsyms += 2; // __start_, __stop_
+        }
     }
 
-    for (elf_file.objects.items) |index| {
-        const object = elf_file.file(index).?.object;
-        for (object.shdrs.items) |shdr| {
-            if (object.getStartStopBasename(shdr)) |name| {
-                const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
-                defer gpa.free(start_name);
-                const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
-                defer gpa.free(stop_name);
-                const start = newSymbolAssumeCapacity(self, try self.addString(gpa, start_name), elf_file);
-                const stop = newSymbolAssumeCapacity(self, try self.addString(gpa, stop_name), elf_file);
-                self.start_stop_indexes.appendSliceAssumeCapacity(&.{ start, stop });
+    try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, nsyms);
+    try self.symtab.ensureUnusedCapacity(gpa, nsyms);
+    try self.symbols.ensureUnusedCapacity(gpa, nsyms);
+    try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra));
+    try self.symbols_resolver.ensureUnusedCapacity(gpa, nsyms);
+
+    for (elf_file.shdrs.items) |shdr| {
+        if (elf_file.getStartStopBasename(shdr)) |name| {
+            const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
+            defer gpa.free(start_name);
+            const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
+            defer gpa.free(stop_name);
+
+            for (&[_][]const u8{ start_name, stop_name }) |nn| {
+                const index = self.newSymbolAssumeCapacity(try self.addString(gpa, nn), elf_file);
+                self.start_stop_indexes.appendAssumeCapacity(index);
+                const gop = try elf_file.resolver.getOrPut(gpa, .{
+                    .index = index,
+                    .file = self.index,
+                }, elf_file);
+                assert(!gop.found_existing);
+                gop.ref.* = .{ .index = index, .file = self.index };
+                self.symbols_resolver.appendAssumeCapacity(gop.index);
             }
         }
     }
src/link/Elf/Object.zig
@@ -1399,14 +1399,6 @@ pub fn comdatGroup(self: *Object, index: Elf.ComdatGroup.Index) *Elf.ComdatGroup
     return &self.comdat_groups.items[index];
 }
 
-pub fn getStartStopBasename(self: Object, shdr: elf.Elf64_Shdr) ?[]const u8 {
-    const name = self.getString(shdr.sh_name);
-    if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
-        if (Elf.isCIdentifier(name)) return name;
-    }
-    return null;
-}
-
 pub fn format(
     self: *Object,
     comptime unused_fmt_string: []const u8,
src/link/Elf.zig
@@ -1282,6 +1282,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
     try self.finalizeMergeSections();
     try self.initOutputSections();
     try self.initMergeSections();
+    if (self.linkerDefinedPtr()) |obj| {
+        try obj.initStartStopSymbols(self);
+    }
     self.claimUnresolved();
 
     // Scan and create missing synthetic entries such as GOT indirection.
@@ -5247,6 +5250,14 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize {
     return count;
 }
 
+pub fn getStartStopBasename(self: Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
+    const name = self.getShString(shdr.sh_name);
+    if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
+        if (Elf.isCIdentifier(name)) return name;
+    }
+    return null;
+}
+
 pub fn isCIdentifier(name: []const u8) bool {
     if (name.len == 0) return false;
     const first_c = name[0];