mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
elf: add riscv dynamic relocs
This commit is contained in:
parent
601aa10b82
commit
975862aca9
@ -1891,6 +1891,7 @@ pub const R_X86_64 = enum(u32) {
|
||||
R_X86_64_GOTPCRELX = 41,
|
||||
/// Load from 32 bit signed PC relative offset to GOT entry with REX prefix, relaxable
|
||||
R_X86_64_REX_GOTPCRELX = 42,
|
||||
_,
|
||||
};
|
||||
|
||||
/// AArch64 relocs.
|
||||
@ -2163,6 +2164,7 @@ pub const R_AARCH64 = enum(u32) {
|
||||
R_AARCH64_TLSDESC = 1031,
|
||||
/// STT_GNU_IFUNC relocation.
|
||||
R_AARCH64_IRELATIVE = 1032,
|
||||
_,
|
||||
};
|
||||
|
||||
/// RISC-V relocations.
|
||||
@ -2225,6 +2227,7 @@ pub const R_RISCV = enum(u32) {
|
||||
R_RISCV_PLT32 = 59,
|
||||
R_RISCV_SET_ULEB128 = 60,
|
||||
R_RISCV_SUB_ULEB128 = 61,
|
||||
_,
|
||||
};
|
||||
|
||||
pub const STV = enum(u2) {
|
||||
|
||||
@ -43,9 +43,10 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
|
||||
// Add relocation to the decl.
|
||||
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.R_X86_64_PLT32);
|
||||
try atom_ptr.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | std.elf.R_X86_64_PLT32,
|
||||
.r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
|
||||
.r_addend = -4,
|
||||
});
|
||||
} else if (emit.lower.bin_file.cast(link.File.MachO)) |macho_file| {
|
||||
@ -88,18 +89,20 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
.linker_tlsld => |data| {
|
||||
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
|
||||
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.R_X86_64_TLSLD);
|
||||
try atom.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_TLSLD,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||
.r_addend = -4,
|
||||
});
|
||||
},
|
||||
.linker_dtpoff => |data| {
|
||||
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
|
||||
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.R_X86_64_DTPOFF32);
|
||||
try atom.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_DTPOFF32,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||
.r_addend = 0,
|
||||
});
|
||||
},
|
||||
@ -119,9 +122,9 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
|
||||
link.File.Elf.R_X86_64_ZIG_GOTPCREL
|
||||
else if (sym.flags.needs_got)
|
||||
std.elf.R_X86_64_GOTPCREL
|
||||
@intFromEnum(std.elf.R_X86_64.R_X86_64_GOTPCREL)
|
||||
else
|
||||
std.elf.R_X86_64_PC32;
|
||||
@intFromEnum(std.elf.R_X86_64.R_X86_64_PC32);
|
||||
try atom.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||
@ -129,20 +132,21 @@ pub fn emitMir(emit: *Emit) Error!void {
|
||||
});
|
||||
} else {
|
||||
if (lowered_inst.encoding.mnemonic == .call and sym.flags.needs_zig_got and is_obj_or_static_lib) {
|
||||
const r_type = @intFromEnum(std.elf.R_X86_64.R_X86_64_PC32);
|
||||
try atom.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_PC32,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||
.r_addend = -4,
|
||||
});
|
||||
} else {
|
||||
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)
|
||||
link.File.Elf.R_X86_64_ZIG_GOT32
|
||||
else if (sym.flags.needs_got)
|
||||
std.elf.R_X86_64_GOT32
|
||||
@intFromEnum(std.elf.R_X86_64.R_X86_64_GOT32)
|
||||
else if (sym.flags.is_tls)
|
||||
std.elf.R_X86_64_TPOFF32
|
||||
@intFromEnum(std.elf.R_X86_64.R_X86_64_TPOFF32)
|
||||
else
|
||||
std.elf.R_X86_64_32;
|
||||
@intFromEnum(std.elf.R_X86_64.R_X86_64_32);
|
||||
try atom.addReloc(elf_file, .{
|
||||
.r_offset = end_offset - 4,
|
||||
.r_info = (@as(u64, @intCast(data.sym_index)) << 32) | r_type,
|
||||
|
||||
@ -6065,8 +6065,8 @@ const RelaSection = struct {
|
||||
};
|
||||
const RelaSectionTable = std.AutoArrayHashMapUnmanaged(u32, RelaSection);
|
||||
|
||||
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;
|
||||
pub const R_X86_64_ZIG_GOT32: u32 = 0xff00;
|
||||
pub const R_X86_64_ZIG_GOTPCREL: u32 = 0xff01;
|
||||
|
||||
fn defaultEntrySymbolName(cpu_arch: std.Target.Cpu.Arch) []const u8 {
|
||||
return switch (cpu_arch) {
|
||||
|
||||
@ -384,7 +384,10 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
|
||||
const cpu_arch = elf_file.getTarget().cpu.arch;
|
||||
for (self.relocs(elf_file)) |rel| {
|
||||
switch (cpu_arch) {
|
||||
.x86_64 => if (rel.r_type() == elf.R_X86_64_GOTTPOFF) return true,
|
||||
.x86_64 => {
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
if (r_type == .R_X86_64_GOTTPOFF) return true;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
@ -836,8 +839,9 @@ const x86_64 = struct {
|
||||
var i: usize = 0;
|
||||
while (i < rels.len) : (i += 1) {
|
||||
const rel = rels[i];
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
|
||||
if (rel.r_type() == elf.R_X86_64_NONE) continue;
|
||||
if (r_type == .R_X86_64_NONE) continue;
|
||||
|
||||
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
||||
|
||||
@ -869,41 +873,41 @@ const x86_64 = struct {
|
||||
|
||||
// While traversing relocations, mark symbols that require special handling such as
|
||||
// pointer indirection via GOT, or a stub trampoline via PLT.
|
||||
switch (rel.r_type()) {
|
||||
elf.R_X86_64_64 => {
|
||||
switch (r_type) {
|
||||
.R_X86_64_64 => {
|
||||
try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
|
||||
},
|
||||
|
||||
elf.R_X86_64_32,
|
||||
elf.R_X86_64_32S,
|
||||
.R_X86_64_32,
|
||||
.R_X86_64_32S,
|
||||
=> {
|
||||
try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOT32,
|
||||
elf.R_X86_64_GOTPC32,
|
||||
elf.R_X86_64_GOTPC64,
|
||||
elf.R_X86_64_GOTPCREL,
|
||||
elf.R_X86_64_GOTPCREL64,
|
||||
elf.R_X86_64_GOTPCRELX,
|
||||
elf.R_X86_64_REX_GOTPCRELX,
|
||||
.R_X86_64_GOT32,
|
||||
.R_X86_64_GOTPC32,
|
||||
.R_X86_64_GOTPC64,
|
||||
.R_X86_64_GOTPCREL,
|
||||
.R_X86_64_GOTPCREL64,
|
||||
.R_X86_64_GOTPCRELX,
|
||||
.R_X86_64_REX_GOTPCRELX,
|
||||
=> {
|
||||
symbol.flags.needs_got = true;
|
||||
},
|
||||
|
||||
elf.R_X86_64_PLT32,
|
||||
elf.R_X86_64_PLTOFF64,
|
||||
.R_X86_64_PLT32,
|
||||
.R_X86_64_PLTOFF64,
|
||||
=> {
|
||||
if (symbol.flags.import) {
|
||||
symbol.flags.needs_plt = true;
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_PC32 => {
|
||||
.R_X86_64_PC32 => {
|
||||
try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
|
||||
},
|
||||
|
||||
elf.R_X86_64_TLSGD => {
|
||||
.R_X86_64_TLSGD => {
|
||||
// TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr
|
||||
|
||||
if (is_static or (!symbol.flags.import and !is_dyn_lib)) {
|
||||
@ -918,7 +922,7 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_TLSLD => {
|
||||
.R_X86_64_TLSLD => {
|
||||
// TODO verify followed by appropriate relocation such as PLT32 __tls_get_addr
|
||||
|
||||
if (is_static or !is_dyn_lib) {
|
||||
@ -930,7 +934,7 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTTPOFF => {
|
||||
.R_X86_64_GOTTPOFF => {
|
||||
const should_relax = blk: {
|
||||
if (is_dyn_lib or symbol.flags.import) break :blk false;
|
||||
if (!x86_64.canRelaxGotTpOff(code.?[r_offset - 3 ..])) break :blk false;
|
||||
@ -941,35 +945,37 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTPC32_TLSDESC => {
|
||||
.R_X86_64_GOTPC32_TLSDESC => {
|
||||
const should_relax = is_static or (!is_dyn_lib and !symbol.flags.import);
|
||||
if (!should_relax) {
|
||||
symbol.flags.needs_tlsdesc = true;
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_TPOFF32,
|
||||
elf.R_X86_64_TPOFF64,
|
||||
.R_X86_64_TPOFF32,
|
||||
.R_X86_64_TPOFF64,
|
||||
=> {
|
||||
if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTOFF64,
|
||||
elf.R_X86_64_DTPOFF32,
|
||||
elf.R_X86_64_DTPOFF64,
|
||||
elf.R_X86_64_SIZE32,
|
||||
elf.R_X86_64_SIZE64,
|
||||
elf.R_X86_64_TLSDESC_CALL,
|
||||
.R_X86_64_GOTOFF64,
|
||||
.R_X86_64_DTPOFF32,
|
||||
.R_X86_64_DTPOFF64,
|
||||
.R_X86_64_SIZE32,
|
||||
.R_X86_64_SIZE64,
|
||||
.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 => |x| switch (@intFromEnum(x)) {
|
||||
// Zig custom relocations
|
||||
Elf.R_X86_64_ZIG_GOT32,
|
||||
Elf.R_X86_64_ZIG_GOTPCREL,
|
||||
=> {
|
||||
assert(symbol.flags.has_zig_got);
|
||||
},
|
||||
|
||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||
else => try atom.reportUnhandledRelocError(rel, elf_file),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -983,8 +989,8 @@ const x86_64 = struct {
|
||||
var i: usize = 0;
|
||||
while (i < rels.len) : (i += 1) {
|
||||
const rel = rels[i];
|
||||
const r_type = rel.r_type();
|
||||
if (r_type == elf.R_X86_64_NONE) continue;
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
if (r_type == .R_X86_64_NONE) continue;
|
||||
|
||||
const target = switch (file_ptr) {
|
||||
.zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
|
||||
@ -1022,7 +1028,7 @@ const x86_64 = struct {
|
||||
const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
|
||||
|
||||
relocs_log.debug(" {s}: {x}: [{x} => {x}] G({x}) ZG({x}) ({s})", .{
|
||||
relocation.fmtRelocType(r_type, .x86_64),
|
||||
@tagName(r_type),
|
||||
r_offset,
|
||||
P,
|
||||
S + A,
|
||||
@ -1033,10 +1039,10 @@ const x86_64 = struct {
|
||||
|
||||
try stream.seekTo(r_offset);
|
||||
|
||||
switch (rel.r_type()) {
|
||||
elf.R_X86_64_NONE => unreachable,
|
||||
switch (r_type) {
|
||||
.R_X86_64_NONE => unreachable,
|
||||
|
||||
elf.R_X86_64_64 => {
|
||||
.R_X86_64_64 => {
|
||||
try atom.resolveDynAbsReloc(
|
||||
target,
|
||||
rel,
|
||||
@ -1046,15 +1052,15 @@ const x86_64 = struct {
|
||||
);
|
||||
},
|
||||
|
||||
elf.R_X86_64_PLT32,
|
||||
elf.R_X86_64_PC32,
|
||||
.R_X86_64_PLT32,
|
||||
.R_X86_64_PC32,
|
||||
=> try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little),
|
||||
|
||||
elf.R_X86_64_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
|
||||
elf.R_X86_64_GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
|
||||
elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
|
||||
.R_X86_64_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little),
|
||||
.R_X86_64_GOTPC32 => try cwriter.writeInt(i32, @as(i32, @intCast(GOT + A - P)), .little),
|
||||
.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A - P, .little),
|
||||
|
||||
elf.R_X86_64_GOTPCRELX => {
|
||||
.R_X86_64_GOTPCRELX => {
|
||||
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
|
||||
x86_64.relaxGotpcrelx(code[r_offset - 2 ..]) catch break :blk;
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
|
||||
@ -1063,7 +1069,7 @@ const x86_64 = struct {
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
|
||||
},
|
||||
|
||||
elf.R_X86_64_REX_GOTPCRELX => {
|
||||
.R_X86_64_REX_GOTPCRELX => {
|
||||
if (!target.flags.import and !target.isIFunc(elf_file) and !target.isAbs(elf_file)) blk: {
|
||||
x86_64.relaxRexGotpcrelx(code[r_offset - 3 ..]) catch break :blk;
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S + A - P)), .little);
|
||||
@ -1072,16 +1078,16 @@ const x86_64 = struct {
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A - P)), .little);
|
||||
},
|
||||
|
||||
elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
|
||||
elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
|
||||
.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @truncate(@as(u64, @intCast(S + A)))), .little),
|
||||
.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @truncate(S + A)), .little),
|
||||
|
||||
elf.R_X86_64_TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
|
||||
elf.R_X86_64_TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
|
||||
.R_X86_64_TPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - TP)), .little),
|
||||
.R_X86_64_TPOFF64 => try cwriter.writeInt(i64, S + A - TP, .little),
|
||||
|
||||
elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
|
||||
elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
|
||||
.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @truncate(S + A - DTP)), .little),
|
||||
.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
|
||||
|
||||
elf.R_X86_64_TLSGD => {
|
||||
.R_X86_64_TLSGD => {
|
||||
if (target.flags.has_tlsgd) {
|
||||
const S_ = @as(i64, @intCast(target.tlsGdAddress(elf_file)));
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
@ -1101,7 +1107,7 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_TLSLD => {
|
||||
.R_X86_64_TLSLD => {
|
||||
if (elf_file.got.tlsld_index) |entry_index| {
|
||||
const tlsld_entry = elf_file.got.entries.items[entry_index];
|
||||
const S_ = @as(i64, @intCast(tlsld_entry.address(elf_file)));
|
||||
@ -1118,7 +1124,7 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTPC32_TLSDESC => {
|
||||
.R_X86_64_GOTPC32_TLSDESC => {
|
||||
if (target.flags.has_tlsdesc) {
|
||||
const S_ = @as(i64, @intCast(target.tlsDescAddress(elf_file)));
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
@ -1128,12 +1134,12 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
|
||||
.R_X86_64_TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
|
||||
// call -> nop
|
||||
try cwriter.writeAll(&.{ 0x66, 0x90 });
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTTPOFF => {
|
||||
.R_X86_64_GOTTPOFF => {
|
||||
if (target.flags.has_gottp) {
|
||||
const S_ = @as(i64, @intCast(target.gotTpAddress(elf_file)));
|
||||
try cwriter.writeInt(i32, @as(i32, @intCast(S_ + A - P)), .little);
|
||||
@ -1143,13 +1149,15 @@ const x86_64 = struct {
|
||||
}
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
|
||||
.R_X86_64_GOT32 => try cwriter.writeInt(i32, @as(i32, @intCast(G + GOT + A)), .little),
|
||||
|
||||
// Zig custom relocations
|
||||
Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
|
||||
Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
|
||||
else => |x| switch (@intFromEnum(x)) {
|
||||
// Zig custom relocations
|
||||
Elf.R_X86_64_ZIG_GOT32 => try cwriter.writeInt(u32, @as(u32, @intCast(ZIG_GOT + A)), .little),
|
||||
Elf.R_X86_64_ZIG_GOTPCREL => try cwriter.writeInt(i32, @as(i32, @intCast(ZIG_GOT + A - P)), .little),
|
||||
|
||||
else => {},
|
||||
else => {},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1163,8 +1171,8 @@ const x86_64 = struct {
|
||||
var i: usize = 0;
|
||||
while (i < rels.len) : (i += 1) {
|
||||
const rel = rels[i];
|
||||
const r_type = rel.r_type();
|
||||
if (r_type == elf.R_X86_64_NONE) continue;
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
if (r_type == .R_X86_64_NONE) continue;
|
||||
|
||||
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
|
||||
|
||||
@ -1211,7 +1219,7 @@ const x86_64 = struct {
|
||||
const DTP = @as(i64, @intCast(elf_file.dtpAddress()));
|
||||
|
||||
relocs_log.debug(" {s}: {x}: [{x} => {x}] ({s})", .{
|
||||
relocation.fmtRelocType(r_type, .x86_64),
|
||||
@tagName(r_type),
|
||||
rel.r_offset,
|
||||
P,
|
||||
S + A,
|
||||
@ -1221,21 +1229,21 @@ const x86_64 = struct {
|
||||
try stream.seekTo(r_offset);
|
||||
|
||||
switch (r_type) {
|
||||
elf.R_X86_64_NONE => unreachable,
|
||||
elf.R_X86_64_8 => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),
|
||||
elf.R_X86_64_16 => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
|
||||
elf.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
|
||||
elf.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
|
||||
elf.R_X86_64_64 => try cwriter.writeInt(i64, S + A, .little),
|
||||
elf.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
|
||||
elf.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
|
||||
elf.R_X86_64_GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),
|
||||
elf.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
|
||||
elf.R_X86_64_SIZE32 => {
|
||||
.R_X86_64_NONE => unreachable,
|
||||
.R_X86_64_8 => try cwriter.writeInt(u8, @as(u8, @bitCast(@as(i8, @intCast(S + A)))), .little),
|
||||
.R_X86_64_16 => try cwriter.writeInt(u16, @as(u16, @bitCast(@as(i16, @intCast(S + A)))), .little),
|
||||
.R_X86_64_32 => try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(S + A)))), .little),
|
||||
.R_X86_64_32S => try cwriter.writeInt(i32, @as(i32, @intCast(S + A)), .little),
|
||||
.R_X86_64_64 => try cwriter.writeInt(i64, S + A, .little),
|
||||
.R_X86_64_DTPOFF32 => try cwriter.writeInt(i32, @as(i32, @intCast(S + A - DTP)), .little),
|
||||
.R_X86_64_DTPOFF64 => try cwriter.writeInt(i64, S + A - DTP, .little),
|
||||
.R_X86_64_GOTOFF64 => try cwriter.writeInt(i64, S + A - GOT, .little),
|
||||
.R_X86_64_GOTPC64 => try cwriter.writeInt(i64, GOT + A, .little),
|
||||
.R_X86_64_SIZE32 => {
|
||||
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
|
||||
try cwriter.writeInt(u32, @as(u32, @bitCast(@as(i32, @intCast(size + A)))), .little);
|
||||
},
|
||||
elf.R_X86_64_SIZE64 => {
|
||||
.R_X86_64_SIZE64 => {
|
||||
const size = @as(i64, @intCast(target.elfSym(elf_file).st_size));
|
||||
try cwriter.writeInt(i64, @as(i64, @intCast(size + A)), .little);
|
||||
},
|
||||
@ -1283,9 +1291,11 @@ const x86_64 = struct {
|
||||
) !void {
|
||||
assert(rels.len == 2);
|
||||
const writer = stream.writer();
|
||||
switch (rels[1].r_type()) {
|
||||
elf.R_X86_64_PC32,
|
||||
elf.R_X86_64_PLT32,
|
||||
const rel_0: elf.R_X86_64 = @enumFromInt(rels[0].r_type());
|
||||
const rel_1: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
|
||||
switch (rel_1) {
|
||||
.R_X86_64_PC32,
|
||||
.R_X86_64_PLT32,
|
||||
=> {
|
||||
var insts = [_]u8{
|
||||
0x64, 0x48, 0x8b, 0x04, 0x25, 0, 0, 0, 0, // movq %fs:0,%rax
|
||||
@ -1298,9 +1308,9 @@ const x86_64 = struct {
|
||||
|
||||
else => {
|
||||
var err = try elf_file.addErrorWithNotes(1);
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{
|
||||
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
|
||||
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {s} when followed by {s}", .{
|
||||
@tagName(rel_0),
|
||||
@tagName(rel_1),
|
||||
});
|
||||
try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{
|
||||
self.file(elf_file).?.fmtPath(),
|
||||
@ -1320,9 +1330,11 @@ const x86_64 = struct {
|
||||
) !void {
|
||||
assert(rels.len == 2);
|
||||
const writer = stream.writer();
|
||||
switch (rels[1].r_type()) {
|
||||
elf.R_X86_64_PC32,
|
||||
elf.R_X86_64_PLT32,
|
||||
const rel_0: elf.R_X86_64 = @enumFromInt(rels[0].r_type());
|
||||
const rel_1: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
|
||||
switch (rel_1) {
|
||||
.R_X86_64_PC32,
|
||||
.R_X86_64_PLT32,
|
||||
=> {
|
||||
var insts = [_]u8{
|
||||
0x31, 0xc0, // xor %eax, %eax
|
||||
@ -1334,8 +1346,8 @@ const x86_64 = struct {
|
||||
try writer.writeAll(&insts);
|
||||
},
|
||||
|
||||
elf.R_X86_64_GOTPCREL,
|
||||
elf.R_X86_64_GOTPCRELX,
|
||||
.R_X86_64_GOTPCREL,
|
||||
.R_X86_64_GOTPCRELX,
|
||||
=> {
|
||||
var insts = [_]u8{
|
||||
0x31, 0xc0, // xor %eax, %eax
|
||||
@ -1350,9 +1362,9 @@ const x86_64 = struct {
|
||||
|
||||
else => {
|
||||
var err = try elf_file.addErrorWithNotes(1);
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{
|
||||
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
|
||||
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {s} when followed by {s}", .{
|
||||
@tagName(rel_0),
|
||||
@tagName(rel_1),
|
||||
});
|
||||
try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{
|
||||
self.file(elf_file).?.fmtPath(),
|
||||
@ -1419,11 +1431,13 @@ const x86_64 = struct {
|
||||
) !void {
|
||||
assert(rels.len == 2);
|
||||
const writer = stream.writer();
|
||||
switch (rels[1].r_type()) {
|
||||
elf.R_X86_64_PC32,
|
||||
elf.R_X86_64_PLT32,
|
||||
elf.R_X86_64_GOTPCREL,
|
||||
elf.R_X86_64_GOTPCRELX,
|
||||
const rel_0: elf.R_X86_64 = @enumFromInt(rels[0].r_type());
|
||||
const rel_1: elf.R_X86_64 = @enumFromInt(rels[1].r_type());
|
||||
switch (rel_1) {
|
||||
.R_X86_64_PC32,
|
||||
.R_X86_64_PLT32,
|
||||
.R_X86_64_GOTPCREL,
|
||||
.R_X86_64_GOTPCRELX,
|
||||
=> {
|
||||
var insts = [_]u8{
|
||||
0x64, 0x48, 0x8b, 0x04, 0x25, 0, 0, 0, 0, // movq %fs:0,%rax
|
||||
@ -1432,17 +1446,14 @@ const x86_64 = struct {
|
||||
std.mem.writeInt(i32, insts[12..][0..4], value, .little);
|
||||
try stream.seekBy(-4);
|
||||
try writer.writeAll(&insts);
|
||||
relocs_log.debug(" relaxing {} and {}", .{
|
||||
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
|
||||
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
|
||||
});
|
||||
relocs_log.debug(" relaxing {s} and {s}", .{ @tagName(rel_0), @tagName(rel_1) });
|
||||
},
|
||||
|
||||
else => {
|
||||
var err = try elf_file.addErrorWithNotes(1);
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {} when followed by {}", .{
|
||||
relocation.fmtRelocType(rels[0].r_type(), .x86_64),
|
||||
relocation.fmtRelocType(rels[1].r_type(), .x86_64),
|
||||
try err.addMsg(elf_file, "fatal linker error: rewrite {s} when followed by {s}", .{
|
||||
@tagName(rel_0),
|
||||
@tagName(rel_1),
|
||||
});
|
||||
try err.addNote(elf_file, "in {}:{s} at offset 0x{x}", .{
|
||||
self.file(elf_file).?.fmtPath(),
|
||||
|
||||
@ -541,11 +541,12 @@ const EH_PE = struct {
|
||||
|
||||
const x86_64 = struct {
|
||||
fn resolveReloc(rel: elf.Elf64_Rela, source: i64, target: i64, data: []u8) void {
|
||||
switch (rel.r_type()) {
|
||||
elf.R_X86_64_32 => std.mem.writeInt(i32, data[0..4], @as(i32, @truncate(target)), .little),
|
||||
elf.R_X86_64_64 => std.mem.writeInt(i64, data[0..8], target, .little),
|
||||
elf.R_X86_64_PC32 => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little),
|
||||
elf.R_X86_64_PC64 => std.mem.writeInt(i64, data[0..8], target - source, .little),
|
||||
const r_type: elf.R_X86_64 = @enumFromInt(rel.r_type());
|
||||
switch (r_type) {
|
||||
.R_X86_64_32 => std.mem.writeInt(i32, data[0..4], @as(i32, @truncate(target)), .little),
|
||||
.R_X86_64_64 => std.mem.writeInt(i64, data[0..8], target, .little),
|
||||
.R_X86_64_PC32 => std.mem.writeInt(i32, data[0..4], @as(i32, @intCast(target - source)), .little),
|
||||
.R_X86_64_PC64 => std.mem.writeInt(i64, data[0..8], target - source, .little),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,25 @@ pub const Kind = enum {
|
||||
tlsdesc,
|
||||
};
|
||||
|
||||
const x86_64_relocs = [_]struct { Kind, elf.R_X86_64 }{
|
||||
fn Table(comptime len: comptime_int, comptime RelType: type, comptime mapping: [len]struct { Kind, RelType }) type {
|
||||
return struct {
|
||||
fn decode(r_type: u32) ?Kind {
|
||||
inline for (mapping) |entry| {
|
||||
if (@intFromEnum(entry[1]) == r_type) return entry[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
fn encode(comptime kind: Kind) u32 {
|
||||
inline for (mapping) |entry| {
|
||||
if (entry[0] == kind) return @intFromEnum(entry[1]);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const x86_64_relocs = Table(10, elf.R_X86_64, .{
|
||||
.{ .abs, .R_X86_64_64 },
|
||||
.{ .copy, .R_X86_64_COPY },
|
||||
.{ .rel, .R_X86_64_RELATIVE },
|
||||
@ -22,9 +40,9 @@ const x86_64_relocs = [_]struct { Kind, elf.R_X86_64 }{
|
||||
.{ .dtpoff, .R_X86_64_DTPOFF64 },
|
||||
.{ .tpoff, .R_X86_64_TPOFF64 },
|
||||
.{ .tlsdesc, .R_X86_64_TLSDESC },
|
||||
};
|
||||
});
|
||||
|
||||
const aarch64_relocs = [_]struct { Kind, elf.R_AARCH64 }{
|
||||
const aarch64_relocs = Table(10, elf.R_AARCH64, .{
|
||||
.{ .abs, .R_AARCH64_ABS64 },
|
||||
.{ .copy, .R_AARCH64_COPY },
|
||||
.{ .rel, .R_AARCH64_RELATIVE },
|
||||
@ -35,9 +53,9 @@ const aarch64_relocs = [_]struct { Kind, elf.R_AARCH64 }{
|
||||
.{ .dtpoff, .R_AARCH64_TLS_DTPREL },
|
||||
.{ .tpoff, .R_AARCH64_TLS_TPREL },
|
||||
.{ .tlsdesc, .R_AARCH64_TLSDESC },
|
||||
};
|
||||
});
|
||||
|
||||
const riscv64_relocs = [_]struct { Kind, elf.R_RISCV }{
|
||||
const riscv64_relocs = Table(8, elf.R_RISCV, .{
|
||||
.{ .abs, .R_RISCV_64 },
|
||||
.{ .copy, .R_RISCV_COPY },
|
||||
.{ .rel, .R_RISCV_RELATIVE },
|
||||
@ -46,31 +64,24 @@ const riscv64_relocs = [_]struct { Kind, elf.R_RISCV }{
|
||||
.{ .dtpmod, .R_RISCV_TLS_DTPMOD64 },
|
||||
.{ .dtpoff, .R_RISCV_TLS_DTPREL64 },
|
||||
.{ .tpoff, .R_RISCV_TLS_TPREL64 },
|
||||
.{ .tpoff, .R_RISCV_TLS_TPREL64 },
|
||||
};
|
||||
});
|
||||
|
||||
pub fn decode(r_type: u32, cpu_arch: std.Target.Cpu.Arch) ?Kind {
|
||||
const relocs = switch (cpu_arch) {
|
||||
.x86_64 => &x86_64_relocs,
|
||||
.aarch64 => &aarch64_relocs,
|
||||
return switch (cpu_arch) {
|
||||
.x86_64 => x86_64_relocs.decode(r_type),
|
||||
.aarch64 => aarch64_relocs.decode(r_type),
|
||||
.riscv64 => riscv64_relocs.decode(r_type),
|
||||
else => @panic("TODO unhandled cpu arch"),
|
||||
};
|
||||
inline for (relocs) |entry| {
|
||||
if (entry[1] == r_type) return entry[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 {
|
||||
const relocs = switch (cpu_arch) {
|
||||
.x86_64 => &x86_64_relocs,
|
||||
.aarch64 => &aarch64_relocs,
|
||||
return switch (cpu_arch) {
|
||||
.x86_64 => x86_64_relocs.encode(kind),
|
||||
.aarch64 => aarch64_relocs.encode(kind),
|
||||
.riscv64 => riscv64_relocs.encode(kind),
|
||||
else => @panic("TODO unhandled cpu arch"),
|
||||
};
|
||||
inline for (relocs) |entry| {
|
||||
if (entry[0] == kind) return entry[1];
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
const FormatRelocTypeCtx = struct {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user