link.Elf: implement aarch64 relocation

This commit is contained in:
David Rubin 2025-11-29 19:16:11 -08:00 committed by Andrew Kelley
parent c4f5dda135
commit 85053a6a36
2 changed files with 13 additions and 32 deletions

View file

@ -1499,22 +1499,18 @@ const aarch64 = struct {
.ABS64 => { .ABS64 => {
try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file); try atom.scanReloc(symbol, rel, dynAbsRelocAction(symbol, elf_file), elf_file);
}, },
.ADR_PREL_PG_HI21 => { .ADR_PREL_PG_HI21 => {
try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file); try atom.scanReloc(symbol, rel, pcRelocAction(symbol, elf_file), elf_file);
}, },
.ADR_GOT_PAGE => { .ADR_GOT_PAGE => {
// TODO: relax if possible // TODO: relax if possible
symbol.flags.needs_got = true; symbol.flags.needs_got = true;
}, },
.LD64_GOT_LO12_NC, .LD64_GOT_LO12_NC,
.LD64_GOTPAGE_LO15, .LD64_GOTPAGE_LO15,
=> { => {
symbol.flags.needs_got = true; symbol.flags.needs_got = true;
}, },
.CALL26, .CALL26,
.JUMP26, .JUMP26,
=> { => {
@ -1522,25 +1518,21 @@ const aarch64 = struct {
symbol.flags.needs_plt = true; symbol.flags.needs_plt = true;
} }
}, },
.TLSLE_ADD_TPREL_HI12, .TLSLE_ADD_TPREL_HI12,
.TLSLE_ADD_TPREL_LO12_NC, .TLSLE_ADD_TPREL_LO12_NC,
=> { => {
if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file); if (is_dyn_lib) try atom.reportPicError(symbol, rel, elf_file);
}, },
.TLSIE_ADR_GOTTPREL_PAGE21, .TLSIE_ADR_GOTTPREL_PAGE21,
.TLSIE_LD64_GOTTPREL_LO12_NC, .TLSIE_LD64_GOTTPREL_LO12_NC,
=> { => {
symbol.flags.needs_gottp = true; symbol.flags.needs_gottp = true;
}, },
.TLSGD_ADR_PAGE21, .TLSGD_ADR_PAGE21,
.TLSGD_ADD_LO12_NC, .TLSGD_ADD_LO12_NC,
=> { => {
symbol.flags.needs_tlsgd = true; symbol.flags.needs_tlsgd = true;
}, },
.TLSDESC_ADR_PAGE21, .TLSDESC_ADR_PAGE21,
.TLSDESC_LD64_LO12, .TLSDESC_LD64_LO12,
.TLSDESC_ADD_LO12, .TLSDESC_ADD_LO12,
@ -1551,18 +1543,17 @@ const aarch64 = struct {
symbol.flags.needs_tlsdesc = true; symbol.flags.needs_tlsdesc = true;
} }
}, },
.ADD_ABS_LO12_NC, .ADD_ABS_LO12_NC,
.ADR_PREL_LO21, .ADR_PREL_LO21,
.LDST8_ABS_LO12_NC, .CONDBR19,
.LDST128_ABS_LO12_NC,
.LDST16_ABS_LO12_NC, .LDST16_ABS_LO12_NC,
.LDST32_ABS_LO12_NC, .LDST32_ABS_LO12_NC,
.LDST64_ABS_LO12_NC, .LDST64_ABS_LO12_NC,
.LDST128_ABS_LO12_NC, .LDST8_ABS_LO12_NC,
.PREL32, .PREL32,
.PREL64, .PREL64,
=> {}, => {},
else => try atom.reportUnhandledRelocError(rel, elf_file), else => try atom.reportUnhandledRelocError(rel, elf_file),
} }
} }
@ -1599,7 +1590,6 @@ const aarch64 = struct {
r_offset, r_offset,
); );
}, },
.CALL26, .CALL26,
.JUMP26, .JUMP26,
=> { => {
@ -1611,27 +1601,26 @@ const aarch64 = struct {
}; };
util.writeBranchImm(disp, code); util.writeBranchImm(disp, code);
}, },
.CONDBR19 => {
const value = math.cast(i19, S + A - P) orelse return error.Overflow;
util.writeCondBrImm(value, code);
},
.PREL32 => { .PREL32 => {
const value = math.cast(i32, S + A - P) orelse return error.Overflow; const value = math.cast(i32, S + A - P) orelse return error.Overflow;
mem.writeInt(u32, code, @bitCast(value), .little); mem.writeInt(u32, code, @bitCast(value), .little);
}, },
.PREL64 => { .PREL64 => {
const value = S + A - P; const value = S + A - P;
mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little); mem.writeInt(u64, code_buffer[r_offset..][0..8], @bitCast(value), .little);
}, },
.ADR_PREL_LO21 => { .ADR_PREL_LO21 => {
const value = math.cast(i21, S + A - P) orelse return error.Overflow; const value = math.cast(i21, S + A - P) orelse return error.Overflow;
util.writeAdrInst(value, code); util.writeAdrInst(value, code);
}, },
.ADR_PREL_PG_HI21 => { .ADR_PREL_PG_HI21 => {
// TODO: check for relaxation of ADRP+ADD // TODO: check for relaxation of ADRP+ADD
util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S + A), code);
}, },
.ADR_GOT_PAGE => if (target.flags.has_got) { .ADR_GOT_PAGE => if (target.flags.has_got) {
util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, G + GOT + A), code);
} else { } else {
@ -1644,18 +1633,15 @@ const aarch64 = struct {
r_offset, r_offset,
}); });
}, },
.LD64_GOT_LO12_NC => { .LD64_GOT_LO12_NC => {
assert(target.flags.has_got); assert(target.flags.has_got);
const taddr = @as(u64, @intCast(G + GOT + A)); const taddr = @as(u64, @intCast(G + GOT + A));
util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code);
}, },
.ADD_ABS_LO12_NC => { .ADD_ABS_LO12_NC => {
const taddr = @as(u64, @intCast(S + A)); const taddr = @as(u64, @intCast(S + A));
util.writeAddImmInst(@truncate(taddr), code); util.writeAddImmInst(@truncate(taddr), code);
}, },
.LDST8_ABS_LO12_NC, .LDST8_ABS_LO12_NC,
.LDST16_ABS_LO12_NC, .LDST16_ABS_LO12_NC,
.LDST32_ABS_LO12_NC, .LDST32_ABS_LO12_NC,
@ -1674,44 +1660,37 @@ const aarch64 = struct {
}; };
util.writeLoadStoreRegInst(off, code); util.writeLoadStoreRegInst(off, code);
}, },
.TLSLE_ADD_TPREL_HI12 => { .TLSLE_ADD_TPREL_HI12 => {
const value = math.cast(i12, (S + A - TP) >> 12) orelse const value = math.cast(i12, (S + A - TP) >> 12) orelse
return error.Overflow; return error.Overflow;
util.writeAddImmInst(@bitCast(value), code); util.writeAddImmInst(@bitCast(value), code);
}, },
.TLSLE_ADD_TPREL_LO12_NC => { .TLSLE_ADD_TPREL_LO12_NC => {
const value: i12 = @truncate(S + A - TP); const value: i12 = @truncate(S + A - TP);
util.writeAddImmInst(@bitCast(value), code); util.writeAddImmInst(@bitCast(value), code);
}, },
.TLSIE_ADR_GOTTPREL_PAGE21 => { .TLSIE_ADR_GOTTPREL_PAGE21 => {
const S_ = target.gotTpAddress(elf_file); const S_ = target.gotTpAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
}, },
.TLSIE_LD64_GOTTPREL_LO12_NC => { .TLSIE_LD64_GOTTPREL_LO12_NC => {
const S_ = target.gotTpAddress(elf_file); const S_ = target.gotTpAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8); const off: u12 = try math.divExact(u12, @truncate(@as(u64, @bitCast(S_ + A))), 8);
util.writeLoadStoreRegInst(off, code); util.writeLoadStoreRegInst(off, code);
}, },
.TLSGD_ADR_PAGE21 => { .TLSGD_ADR_PAGE21 => {
const S_ = target.tlsGdAddress(elf_file); const S_ = target.tlsGdAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code); util.writeAdrInst(try util.calcNumberOfPages(P, S_ + A), code);
}, },
.TLSGD_ADD_LO12_NC => { .TLSGD_ADD_LO12_NC => {
const S_ = target.tlsGdAddress(elf_file); const S_ = target.tlsGdAddress(elf_file);
relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A }); relocs_log.debug(" [{x} => {x}]", .{ P, S_ + A });
const off: u12 = @truncate(@as(u64, @bitCast(S_ + A))); const off: u12 = @truncate(@as(u64, @bitCast(S_ + A)));
util.writeAddImmInst(off, code); util.writeAddImmInst(off, code);
}, },
.TLSDESC_ADR_PAGE21 => { .TLSDESC_ADR_PAGE21 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1722,7 +1701,6 @@ const aarch64 = struct {
util.encoding.Instruction.nop().write(code); util.encoding.Instruction.nop().write(code);
} }
}, },
.TLSDESC_LD64_LO12 => { .TLSDESC_LD64_LO12 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1734,7 +1712,6 @@ const aarch64 = struct {
util.encoding.Instruction.nop().write(code); util.encoding.Instruction.nop().write(code);
} }
}, },
.TLSDESC_ADD_LO12 => { .TLSDESC_ADD_LO12 => {
if (target.flags.has_tlsdesc) { if (target.flags.has_tlsdesc) {
const S_ = target.tlsDescAddress(elf_file); const S_ = target.tlsDescAddress(elf_file);
@ -1747,13 +1724,11 @@ const aarch64 = struct {
util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code); util.encoding.Instruction.movz(.x0, value, .{ .lsl = .@"16" }).write(code);
} }
}, },
.TLSDESC_CALL => if (!target.flags.has_tlsdesc) { .TLSDESC_CALL => if (!target.flags.has_tlsdesc) {
relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP}); relocs_log.debug(" relaxing br => movk(x0, {x})", .{S + A - TP});
const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP)));
util.encoding.Instruction.movk(.x0, value, .{}).write(code); util.encoding.Instruction.movk(.x0, value, .{}).write(code);
}, },
else => try atom.reportUnhandledRelocError(rel, elf_file), else => try atom.reportUnhandledRelocError(rel, elf_file),
} }
} }

View file

@ -29,6 +29,12 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
inst.write(code); inst.write(code);
} }
pub fn writeCondBrImm(disp: i19, code: *[4]u8) void {
var inst: encoding.Instruction = .read(code);
inst.branch_exception_generating_system.conditional_branch_immediate.group.imm19 = @intCast(@shrExact(disp, 2));
inst.write(code);
}
const assert = std.debug.assert; const assert = std.debug.assert;
const builtin = @import("builtin"); const builtin = @import("builtin");
const math = std.math; const math = std.math;