Commit af40bce08a

Jakub Konka <kubkon@jakubkonka.com>
2023-09-26 13:35:50
x86_64: emit R_X86_64_GOT32 for non-PIC GOT references
1 parent 8e1421f
Changed files (5)
src/arch/x86_64/CodeGen.zig
@@ -8223,11 +8223,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
                 const sym = elf_file.symbol(sym_index);
                 sym.flags.needs_got = true;
                 _ = try sym.getOrCreateGotEntry(sym_index, elf_file);
-                const got_addr = sym.gotAddress(elf_file);
-                try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
-                    .base = .{ .reg = .ds },
-                    .disp = @intCast(got_addr),
-                }));
+                _ = try self.addInst(.{
+                    .tag = .call,
+                    .ops = .direct_got_reloc,
+                    .data = .{ .reloc = .{
+                        .atom_index = try self.owner.getSymbolIndex(self),
+                        .sym_index = sym.esym_index,
+                    } },
+                });
             } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
                 const atom = try coff_file.getOrCreateAtomForDecl(owner_decl);
                 const sym_index = coff_file.getAtom(atom).getSymbolIndex().?;
@@ -10290,12 +10293,24 @@ fn genLazySymbolRef(
         const sym = elf_file.symbol(sym_index);
         sym.flags.needs_got = true;
         _ = try sym.getOrCreateGotEntry(sym_index, elf_file);
-        const got_addr = sym.gotAddress(elf_file);
-        const got_mem =
-            Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(got_addr) });
+        const reloc = Mir.Reloc{
+            .atom_index = try self.owner.getSymbolIndex(self),
+            .sym_index = sym.esym_index,
+        };
         switch (tag) {
-            .lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), got_mem),
-            .call => try self.asmMemory(.{ ._, .call }, got_mem),
+            .lea, .mov => _ = try self.addInst(.{
+                .tag = .mov,
+                .ops = .direct_got_reloc,
+                .data = .{ .rx = .{
+                    .r1 = reg.to64(),
+                    .payload = try self.addExtra(reloc),
+                } },
+            }),
+            .call => _ = try self.addInst(.{
+                .tag = .call,
+                .ops = .direct_got_reloc,
+                .data = .{ .reloc = reloc },
+            }),
             else => unreachable,
         }
         switch (tag) {
src/arch/x86_64/Emit.zig
@@ -80,9 +80,21 @@ pub fn emitMir(emit: *Emit) Error!void {
                 }),
                 .linker_got,
                 .linker_direct,
+                .linker_direct_got,
                 .linker_import,
                 .linker_tlv,
-                => |symbol| if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
+                => |symbol| if (emit.bin_file.cast(link.File.Elf)) |elf_file| {
+                    const r_type: u32 = switch (lowered_relocs[0].target) {
+                        .linker_direct_got => std.elf.R_X86_64_GOT32,
+                        else => unreachable,
+                    };
+                    const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
+                    try atom_ptr.addReloc(elf_file, .{
+                        .r_offset = end_offset - 4,
+                        .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
+                        .r_addend = 0,
+                    });
+                } else if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
                     const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?;
                     try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
                         .type = switch (lowered_relocs[0].target) {
src/arch/x86_64/Lower.zig
@@ -52,6 +52,7 @@ pub const Reloc = struct {
         linker_extern_fn: Mir.Reloc,
         linker_got: Mir.Reloc,
         linker_direct: Mir.Reloc,
+        linker_direct_got: Mir.Reloc,
         linker_import: Mir.Reloc,
         linker_tlv: Mir.Reloc,
     };
@@ -387,7 +388,7 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
         .rrmi_sib, .rrmi_rip => inst.data.rrix.fixes,
         .mi_sib_u, .mi_rip_u, .mi_sib_s, .mi_rip_s => inst.data.x.fixes,
         .m_sib, .m_rip, .rax_moffs, .moffs_rax => inst.data.x.fixes,
-        .extern_fn_reloc, .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ._,
+        .extern_fn_reloc, .got_reloc, .direct_reloc, .direct_got_reloc, .import_reloc, .tlv_reloc => ._,
         else => return lower.fail("TODO lower .{s}", .{@tagName(inst.ops)}),
     };
     try lower.emit(switch (fixes) {
@@ -511,6 +512,26 @@ fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
         .extern_fn_reloc => &.{
             .{ .imm = lower.reloc(.{ .linker_extern_fn = inst.data.reloc }) },
         },
+        .direct_got_reloc => ops: {
+            switch (inst.tag) {
+                .call => {
+                    _ = lower.reloc(.{ .linker_direct_got = inst.data.reloc });
+                    break :ops &.{
+                        .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
+                    };
+                },
+                .mov => {
+                    const reg = inst.data.rx.r1;
+                    const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
+                    _ = lower.reloc(.{ .linker_direct_got = extra });
+                    break :ops &.{
+                        .{ .reg = reg },
+                        .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = 0 }) },
+                    };
+                },
+                else => unreachable,
+            }
+        },
         .got_reloc, .direct_reloc, .import_reloc, .tlv_reloc => ops: {
             const reg = inst.data.rx.r1;
             const extra = lower.mir.extraData(Mir.Reloc, inst.data.rx.payload).data;
src/arch/x86_64/Mir.zig
@@ -783,6 +783,9 @@ pub const Inst = struct {
         /// Linker relocation - threadlocal variable via GOT indirection.
         /// Uses `rx` payload with extra data of type `Reloc`.
         tlv_reloc,
+        /// Linker relocation - non-PIC direct reference to GOT cell.
+        /// Uses `reloc` payload if tag is `call`, `rx` otherwise.
+        direct_got_reloc,
 
         // Pseudo instructions:
 
src/link/Elf/Atom.zig
@@ -518,6 +518,9 @@ pub fn resolveRelocs(self: Atom, elf_file: *Elf, code: []u8) !void {
             elf.R_X86_64_PC32,
             => try cwriter.writeIntLittle(i32, @as(i32, @intCast(S + A - P))),
 
+            elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(G + GOT + A))),
+            elf.R_X86_64_GOT64 => try cwriter.writeIntLittle(u64, @as(u64, @intCast(G + GOT + A))),
+
             elf.R_X86_64_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(G + GOT + A - P))),
             elf.R_X86_64_GOTPC32 => try cwriter.writeIntLittle(i32, @as(i32, @intCast(GOT + A - P))),
             elf.R_X86_64_GOTPC64 => try cwriter.writeIntLittle(i64, GOT + A - P),