x86_64: add -fPIC support targeting ELF

This commit is contained in:
Jakub Konka 2023-10-14 09:04:08 +02:00
parent b3d98a4b88
commit 17635e4f2a
5 changed files with 92 additions and 57 deletions

View File

@ -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|

View File

@ -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 }).?;

View File

@ -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)) |_| {

View File

@ -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");

View File

@ -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});