Commit 5698be3ef0

Jakub Konka <kubkon@jakubkonka.com>
2023-11-01 23:34:24
elf: write out contents of .rela sections
1 parent 3606b5d
Changed files (2)
src/link/Elf/ZigObject.zig
@@ -432,6 +432,60 @@ pub fn updateRelaSectionSizes(self: ZigObject, elf_file: *Elf) void {
     }
 }
 
+pub fn writeRelaSections(self: ZigObject, elf_file: *Elf) !void {
+    _ = self;
+    const gpa = elf_file.base.allocator;
+
+    for (&[_]?u16{
+        elf_file.zig_text_rela_section_index,
+        elf_file.zig_data_rel_ro_rela_section_index,
+        elf_file.zig_data_rela_section_index,
+    }) |maybe_index| {
+        const index = maybe_index orelse continue;
+        const shdr = elf_file.shdrs.items[index];
+        const meta = elf_file.last_atom_and_free_list_table.get(@intCast(shdr.sh_info)).?;
+        const last_atom_index = meta.last_atom_index;
+
+        var atom = elf_file.atom(last_atom_index) orelse continue;
+
+        var relocs = std.ArrayList(elf.Elf64_Rela).init(gpa);
+        defer relocs.deinit();
+        try relocs.ensureTotalCapacityPrecise(@divExact(shdr.sh_size, shdr.sh_entsize));
+
+        while (true) {
+            for (atom.relocs(elf_file)) |rel| {
+                relocs.appendAssumeCapacity(switch (rel.r_type()) {
+                    Elf.R_X86_64_ZIG_GOT32 => .{
+                        .r_offset = rel.r_offset,
+                        .r_addend = rel.r_addend,
+                        .r_info = (@as(u64, @intCast(rel.r_sym())) << 32) | elf.R_X86_64_32,
+                    },
+                    Elf.R_X86_64_ZIG_GOTPCREL => .{
+                        .r_offset = rel.r_offset,
+                        .r_addend = rel.r_addend,
+                        .r_info = (@as(u64, @intCast(rel.r_sym())) << 32) | elf.R_X86_64_PC32,
+                    },
+                    else => rel,
+                });
+            }
+            if (elf_file.atom(atom.prev_index)) |prev| {
+                atom = prev;
+            } else break;
+        }
+
+        const SortRelocs = struct {
+            pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
+                _ = ctx;
+                return lhs.r_offset < rhs.r_offset;
+            }
+        };
+
+        mem.sort(elf.Elf64_Rela, relocs.items, {}, SortRelocs.lessThan);
+
+        try elf_file.base.file.?.pwriteAll(mem.sliceAsBytes(relocs.items), shdr.sh_offset);
+    }
+}
+
 pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
     const is_global = index & global_symbol_bit != 0;
     const actual_index = index & symbol_mask;
src/link/Elf.zig
@@ -4400,6 +4400,10 @@ fn updateSymtabSize(self: *Elf) !void {
 fn writeSyntheticSections(self: *Elf) !void {
     const gpa = self.base.allocator;
 
+    if (self.zigObjectPtr()) |zig_object| {
+        try zig_object.writeRelaSections(self);
+    }
+
     if (self.interp_section_index) |shndx| {
         const shdr = self.shdrs.items[shndx];
         const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;