diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 4e568e294f..c488209366 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -9190,14 +9190,19 @@ fn genCall(self: *Self, info: union(enum) { const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl); const sym = elf_file.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); - _ = try self.addInst(.{ - .tag = .call, - .ops = .direct_got_reloc, - .data = .{ .reloc = .{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, - } }, - }); + if (self.bin_file.options.pic) { + try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym.esym_index }); + try self.asmRegister(.{ ._, .call }, .rax); + } else { + _ = 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().?; @@ -11637,34 +11642,48 @@ fn genLazySymbolRef( return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym = elf_file.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); - const reloc = Mir.Reloc{ - .atom_index = try self.owner.getSymbolIndex(self), - .sym_index = sym.esym_index, - }; - switch (tag) { - .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) { - .lea, .call => {}, - .mov => try self.asmRegisterMemory( - .{ ._, tag }, - reg.to64(), - Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), - ), - else => unreachable, + + if (self.bin_file.options.pic) { + switch (tag) { + .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym.esym_index }), + .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym.esym_index }), + else => unreachable, + } + switch (tag) { + .lea, .mov => {}, + .call => try self.asmRegister(.{ ._, .call }, reg), + else => unreachable, + } + } else { + const reloc = Mir.Reloc{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = sym.esym_index, + }; + switch (tag) { + .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) { + .lea, .call => {}, + .mov => try self.asmRegisterMemory( + .{ ._, tag }, + reg.to64(), + Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), + ), + else => unreachable, + } } } else if (self.bin_file.cast(link.File.Plan9)) |p9_file| { const atom_index = p9_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index d2a199da42..3347460eb8 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -85,14 +85,21 @@ pub fn emitMir(emit: *Emit) Error!void { .linker_tlv, => |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, + .linker_direct_got => link.File.Elf.R_X86_64_ZIG_GOT32, + .linker_got => link.File.Elf.R_X86_64_ZIG_GOTPCREL, + .linker_direct => std.elf.R_X86_64_PC32, + else => unreachable, + }; + const r_addend: i64 = switch (lowered_relocs[0].target) { + .linker_direct_got => 0, + .linker_got, .linker_direct => -4, 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, + .r_addend = r_addend, }); } else if (emit.bin_file.cast(link.File.MachO)) |macho_file| { const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = symbol.atom_index }).?; diff --git a/src/codegen.zig b/src/codegen.zig index e2ebcecee2..b5f7f3885e 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -890,7 +890,11 @@ fn genDeclRef( const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index); const sym = elf_file.symbol(sym_index); _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); - return GenResult.mcv(.{ .memory = sym.zigGotAddress(elf_file) }); + if (bin_file.options.pic) { + return GenResult.mcv(.{ .load_got = sym.esym_index }); + } else { + return GenResult.mcv(.{ .memory = sym.zigGotAddress(elf_file) }); + } } else if (bin_file.cast(link.File.MachO)) |macho_file| { const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; @@ -925,7 +929,12 @@ fn genUnnamedConst( return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); }; if (bin_file.cast(link.File.Elf)) |elf_file| { - return GenResult.mcv(.{ .memory = elf_file.symbol(local_sym_index).value }); + const local = elf_file.symbol(local_sym_index); + if (bin_file.options.pic) { + return GenResult.mcv(.{ .load_direct = local.esym_index }); + } else { + return GenResult.mcv(.{ .memory = local.value }); + } } else if (bin_file.cast(link.File.MachO)) |_| { return GenResult.mcv(.{ .load_direct = local_sym_index }); } else if (bin_file.cast(link.File.Coff)) |_| { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index f89f303c6a..5659bfc858 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -6074,6 +6074,9 @@ const SystemLib = struct { path: []const u8, }; +pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1; +pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2; + const std = @import("std"); const build_options = @import("build_options"); const builtin = @import("builtin"); diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index fae96dec5e..b0d780c0c3 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -370,16 +370,6 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype try self.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); }, - // TODO I have temporarily repurposed those for handling .zig.got indirection - // but we should probably claim unused custom values for incremental linking - // that get rewritten to standard relocs when lowering to a relocatable object - // file. - elf.R_X86_64_GOT32, - elf.R_X86_64_GOT64, - => { - assert(symbol.flags.has_zig_got); - }, - elf.R_X86_64_GOTPC32, elf.R_X86_64_GOTPC64, elf.R_X86_64_GOTPCREL, @@ -461,6 +451,13 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype elf.R_X86_64_TLSDESC_CALL, => {}, + // Zig custom relocations + Elf.R_X86_64_ZIG_GOT32, + Elf.R_X86_64_ZIG_GOTPCREL, + => { + assert(symbol.flags.has_zig_got); + }, + else => try self.reportUnhandledRelocError(rel, elf_file), } } @@ -813,13 +810,6 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { elf.R_X86_64_32 => try cwriter.writeIntLittle(u32, @as(u32, @truncate(@as(u64, @intCast(S + A))))), elf.R_X86_64_32S => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A))), - // TODO I have temporarily repurposed those for handling .zig.got indirection - // but we should probably claim unused custom values for incremental linking - // that get rewritten to standard relocs when lowering to a relocatable object - // file. - elf.R_X86_64_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(ZIG_GOT + A))), - elf.R_X86_64_GOT64 => try cwriter.writeIntLittle(u64, @as(u64, @intCast(ZIG_GOT + A))), - elf.R_X86_64_TPOFF32 => try cwriter.writeIntLittle(i32, @as(i32, @truncate(S + A - TP))), elf.R_X86_64_TPOFF64 => try cwriter.writeIntLittle(i64, S + A - TP), @@ -888,6 +878,10 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void { } }, + // Zig custom relocations + Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeIntLittle(u32, @as(u32, @intCast(ZIG_GOT + A))), + Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeIntLittle(i32, @as(i32, @intCast(ZIG_GOT + A - P))), + else => {}, } } @@ -1136,6 +1130,9 @@ fn formatRelocType( elf.R_X86_64_GOTPCRELX => "R_X86_64_GOTPCRELX", elf.R_X86_64_REX_GOTPCRELX => "R_X86_64_REX_GOTPCRELX", elf.R_X86_64_NUM => "R_X86_64_NUM", + // Zig custom relocations + Elf.R_X86_64_ZIG_GOT32 => "R_X86_64_ZIG_GOT32", + Elf.R_X86_64_ZIG_GOTPCREL => "R_X86_64_ZIG_GOTPCREL", else => "R_X86_64_UNKNOWN", }; try writer.print("{s}", .{str});