Commit dbe13200f1

Jakub Konka <kubkon@jakubkonka.com>
2023-11-02 01:33:06
elf: emit STT_SECTION symbols
1 parent 8055f68
Changed files (4)
src/link/Elf/file.zig
@@ -136,7 +136,8 @@ pub const File = union(enum) {
             if (local.atom(elf_file)) |atom| if (!atom.flags.alive) continue;
             const esym = local.elfSym(elf_file);
             switch (esym.st_type()) {
-                elf.STT_SECTION, elf.STT_NOTYPE => continue,
+                elf.STT_SECTION => if (!elf_file.isObject()) continue,
+                elf.STT_NOTYPE => continue,
                 else => {},
             }
             local.flags.output_symtab = true;
src/link/Elf/Symbol.zig
@@ -223,6 +223,8 @@ pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
     const st_shndx = blk: {
         if (symbol.flags.has_copy_rel) break :blk elf_file.copy_rel_section_index.?;
         if (file_ptr == .shared_object or esym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
+        // TODO I think this is wrong and obsolete
+        if (elf_file.isObject() and st_type == elf.STT_SECTION) break :blk symbol.outputShndx().?;
         if (symbol.atom(elf_file) == null and file_ptr != .linker_defined)
             break :blk elf.SHN_ABS;
         break :blk symbol.outputShndx() orelse elf.SHN_UNDEF;
src/link/Elf/ZigObject.zig
@@ -87,7 +87,7 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
     const esym_index = try self.addLocalEsym(gpa);
     const esym = &self.local_esyms.items(.elf_sym)[esym_index];
     esym.st_name = name_off;
-    esym.st_info |= elf.STT_FILE;
+    esym.st_info = elf.STT_FILE;
     esym.st_shndx = elf.SHN_ABS;
     symbol_ptr.esym_index = esym_index;
 
@@ -284,6 +284,22 @@ pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
     return symbol_index;
 }
 
+pub fn addSectionSymbol(self: *ZigObject, shndx: u16, elf_file: *Elf) !void {
+    assert(elf_file.isObject());
+    const gpa = elf_file.base.allocator;
+    const symbol_index = try elf_file.addSymbol();
+    try self.local_symbols.append(gpa, symbol_index);
+    const symbol_ptr = elf_file.symbol(symbol_index);
+    symbol_ptr.file_index = self.index;
+    symbol_ptr.output_section_index = shndx;
+
+    const esym_index = try self.addLocalEsym(gpa);
+    const esym = &self.local_esyms.items(.elf_sym)[esym_index];
+    esym.st_info = elf.STT_SECTION;
+    esym.st_shndx = shndx;
+    symbol_ptr.esym_index = esym_index;
+}
+
 /// TODO actually create fake input shdrs and return that instead.
 pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
     _ = self;
@@ -435,6 +451,16 @@ pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
 pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
     const gpa = elf_file.base.allocator;
 
+    // const getSectionSymbol = struct {
+    //     fn getSectionSymbol(zig_object: ZigObject, shndx: u16, ctx: *Elf) Symbol.Index {
+    //         for (zig_object.locals()) |local_index| {
+    //             const local = ctx.symbol(local_index);
+    //             if (local.type(ctx) == elf.STT_SECTION and local.output_section_index == shndx)
+    //                 return local.esym_index;
+    //         } else unreachable;
+    //     }
+    // }.getSectionSymbol;
+
     for (&[_]?u16{
         elf_file.zig_text_rela_section_index,
         elf_file.zig_data_rel_ro_rela_section_index,
@@ -453,8 +479,13 @@ pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
 
         while (true) {
             for (atom.relocs(elf_file)) |rel| {
-                var r_sym = rel.r_sym() & symbol_mask;
-                if (self.isGlobal(rel.r_sym())) r_sym += @intCast(self.local_esyms.slice().len + 1);
+                const target = elf_file.symbol(self.symbol(rel.r_sym()));
+                const r_offset = target.value + rel.r_offset;
+                const r_sym: u32 = if (target.flags.global)
+                    (target.esym_index & symbol_mask) + @as(u32, @intCast(self.local_esyms.slice().len))
+                else
+                    target.esym_index;
+                // getSectionSymbol(self, target.outputShndx().?, elf_file);
                 const r_type = switch (rel.r_type()) {
                     Elf.R_X86_64_ZIG_GOT32,
                     Elf.R_X86_64_ZIG_GOTPCREL,
@@ -462,9 +493,9 @@ pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
                     else => |r_type| r_type,
                 };
                 relocs.appendAssumeCapacity(.{
-                    .r_offset = rel.r_offset,
+                    .r_offset = r_offset,
                     .r_addend = rel.r_addend,
-                    .r_info = (@as(u64, @intCast(r_sym)) << 32) | r_type,
+                    .r_info = (@as(u64, @intCast(r_sym + 1)) << 32) | r_type,
                 });
             }
             if (elf_file.atom(atom.prev_index)) |prev| {
@@ -485,28 +516,27 @@ pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
     }
 }
 
-pub fn isGlobal(self: ZigObject, index: Symbol.Index) bool {
-    _ = self;
+inline fn isGlobal(index: Symbol.Index) bool {
     return index & global_symbol_bit != 0;
 }
 
-pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
+pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
     const actual_index = index & symbol_mask;
-    if (self.isGlobal(index)) return self.global_symbols.items[actual_index];
+    if (isGlobal(index)) return self.global_symbols.items[actual_index];
     return self.local_symbols.items[actual_index];
 }
 
 pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
     const actual_index = index & symbol_mask;
-    if (self.isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
+    if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
     return &self.local_esyms.items(.elf_sym)[actual_index];
 }
 
-pub fn locals(self: *ZigObject) []const Symbol.Index {
+pub fn locals(self: ZigObject) []const Symbol.Index {
     return self.local_symbols.items;
 }
 
-pub fn globals(self: *ZigObject) []const Symbol.Index {
+pub fn globals(self: ZigObject) []const Symbol.Index {
     return self.global_symbols.items;
 }
 
src/link/Elf.zig
@@ -494,6 +494,7 @@ pub fn initMetadata(self: *Elf) !void {
     const ptr_size = self.ptrWidthBytes();
     const ptr_bit_width = self.base.options.target.ptrBitWidth();
     const is_linux = self.base.options.target.os.tag == .linux;
+    const zig_object = self.zigObjectPtr().?;
 
     const fillSection = struct {
         fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {
@@ -597,6 +598,7 @@ pub fn initMetadata(self: *Elf) !void {
         const shdr = &self.shdrs.items[self.zig_text_section_index.?];
         fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
         if (self.isObject()) {
+            try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
             self.zig_text_rela_section_index = try self.addRelaShdr(
                 ".rela.text.zig",
                 self.zig_text_section_index.?,
@@ -643,6 +645,7 @@ pub fn initMetadata(self: *Elf) !void {
         const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
         fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
         if (self.isObject()) {
+            try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
             self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
                 ".rela.data.rel.ro.zig",
                 self.zig_data_rel_ro_section_index.?,
@@ -668,6 +671,7 @@ pub fn initMetadata(self: *Elf) !void {
         const shdr = &self.shdrs.items[self.zig_data_section_index.?];
         fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
         if (self.isObject()) {
+            try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
             self.zig_data_rela_section_index = try self.addRelaShdr(
                 ".rela.data.zig",
                 self.zig_data_section_index.?,
@@ -697,12 +701,12 @@ pub fn initMetadata(self: *Elf) !void {
             shdr.sh_size = phdr.p_memsz;
             try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
         } else {
+            try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
             shdr.sh_size = 1024;
         }
         try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
     }
 
-    const zig_object = self.zigObjectPtr().?;
     if (zig_object.dwarf) |*dw| {
         if (self.debug_str_section_index == null) {
             assert(dw.strtab.buffer.items.len == 0);
@@ -3801,23 +3805,19 @@ fn sortShdrs(self: *Elf) !void {
     if (self.zigObjectPtr()) |zig_object| {
         for (zig_object.atoms.items) |atom_index| {
             const atom_ptr = self.atom(atom_index) orelse continue;
-            if (!atom_ptr.flags.alive) continue;
-            const out_shndx = atom_ptr.outputShndx() orelse continue;
-            atom_ptr.output_section_index = backlinks[out_shndx];
+            atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
         }
 
         for (zig_object.locals()) |local_index| {
             const local = self.symbol(local_index);
-            const atom_ptr = local.atom(self) orelse continue;
-            if (!atom_ptr.flags.alive) continue;
-            const out_shndx = local.outputShndx() orelse continue;
-            local.output_section_index = backlinks[out_shndx];
+            local.output_section_index = backlinks[local.output_section_index];
         }
 
         for (zig_object.globals()) |global_index| {
             const global = self.symbol(global_index);
             const atom_ptr = global.atom(self) orelse continue;
             if (!atom_ptr.flags.alive) continue;
+            // TODO claim unresolved for objects
             if (global.file(self).?.index() != zig_object.index) continue;
             const out_shndx = global.outputShndx() orelse continue;
             global.output_section_index = backlinks[out_shndx];