diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-03-08 14:30:06 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-03-08 22:46:17 +0100 |
| commit | d9069cbe2cf88634eb556b3063ede5af4a5cced4 (patch) | |
| tree | 9f31a51a05820db7ec5b680c562227f24c4c296d /src/link/Elf | |
| parent | 310cef09724067f4df38b42c928cb120fdc09df8 (diff) | |
| download | zig-d9069cbe2cf88634eb556b3063ede5af4a5cced4.tar.gz zig-d9069cbe2cf88634eb556b3063ede5af4a5cced4.zip | |
elf+aarch64: relax TLSDESC for executables
Diffstat (limited to 'src/link/Elf')
| -rw-r--r-- | src/link/Elf/Atom.zig | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/src/link/Elf/Atom.zig b/src/link/Elf/Atom.zig index 00cf419f60..fca2fbef27 100644 --- a/src/link/Elf/Atom.zig +++ b/src/link/Elf/Atom.zig @@ -1633,7 +1633,7 @@ const aarch64 = struct { .TLSDESC_ADD_LO12, => { const should_relax = elf_file.base.isStatic() or (!is_dyn_lib and !symbol.flags.import); - if (!should_relax and true) { // TODO + if (!should_relax) { symbol.flags.needs_tlsdesc = true; } }, @@ -1659,7 +1659,7 @@ const aarch64 = struct { target: *const Symbol, args: ResolveArgs, it: *RelocsIterator, - code: []u8, + code_buffer: []u8, stream: anytype, ) (error{ UnexpectedRemainder, DivisionByZero } || RelocError)!void { _ = it; @@ -1667,6 +1667,7 @@ const aarch64 = struct { const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type()); const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow; const cwriter = stream.writer(); + const code = code_buffer[rel.r_offset..][0..4]; const P, const A, const S, const GOT, const G, const TP, const DTP, const ZIG_GOT = args; _ = DTP; @@ -1700,7 +1701,7 @@ const aarch64 = struct { }); return; }; - aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]); + aarch64_util.writeBranchImm(disp, code); }, .ADR_PREL_PG_HI21 => { @@ -1708,14 +1709,14 @@ const aarch64 = struct { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(S + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code); }, .ADR_GOT_PAGE => if (target.flags.has_got) { const saddr = @as(u64, @intCast(P)); const taddr = @as(u64, @intCast(G + GOT + A)); const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr))); - aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]); + aarch64_util.writeAdrpInst(pages, code); } else { // TODO: relax var err = try elf_file.addErrorWithNotes(1); @@ -1730,12 +1731,12 @@ const aarch64 = struct { .LD64_GOT_LO12_NC => { assert(target.flags.has_got); const taddr = @as(u64, @intCast(G + GOT + A)); - aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code[rel.r_offset..][0..4]); + aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code); }, .ADD_ABS_LO12_NC => { const taddr = @as(u64, @intCast(S + A)); - aarch64_util.writeAddImmInst(@truncate(taddr), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@truncate(taddr), code); }, .LDST8_ABS_LO12_NC, @@ -1754,48 +1755,79 @@ const aarch64 = struct { .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16), else => unreachable, }; - aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); + aarch64_util.writeLoadStoreRegInst(offset, code); }, .TLSLE_ADD_TPREL_HI12 => { const value = math.cast(i12, (S + A - TP) >> 12) orelse return error.Overflow; - aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code); }, .TLSLE_ADD_TPREL_LO12_NC => { const value: i12 = @truncate(S + A - TP); - aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]); + aarch64_util.writeAddImmInst(@bitCast(value), code); }, .TLSDESC_ADR_PAGE21 => { - assert(target.flags.has_tlsdesc); // TODO relax - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const saddr: u64 = @intCast(P); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); - aarch64_util.writeAdrpInst(pages, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const saddr: u64 = @intCast(P); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const pages: u21 = @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)); + aarch64_util.writeAdrpInst(pages, code); + } else { + relocs_log.debug(" relaxing adrp => nop", .{}); + mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + } }, .TLSDESC_LD64_LO12 => { - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); - aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = try math.divExact(u12, @truncate(taddr), 8); + aarch64_util.writeLoadStoreRegInst(offset, code); + } else { + relocs_log.debug(" relaxing ldr => nop", .{}); + mem.writeInt(u32, code, Instruction.nop().toU32(), .little); + } }, .TLSDESC_ADD_LO12 => { - const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); - const taddr: u64 = @intCast(S_ + A); - relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); - const offset: u12 = @truncate(taddr); - aarch64_util.writeAddImmInst(offset, code[rel.r_offset..][0..4]); + if (target.flags.has_tlsdesc) { + const S_: i64 = @intCast(target.tlsDescAddress(elf_file)); + const taddr: u64 = @intCast(S_ + A); + relocs_log.debug(" [{x} => {x}]", .{ P, taddr }); + const offset: u12 = @truncate(taddr); + aarch64_util.writeAddImmInst(offset, code); + } else { + const old_inst = Instruction{ + .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload( + Instruction, + Instruction.add_subtract_immediate, + ), code), + }; + const rd: Register = @enumFromInt(old_inst.add_subtract_immediate.rd); + relocs_log.debug(" relaxing add({s}) => movz(x0, {x})", .{ @tagName(rd), S + A - TP }); + const value: u16 = @bitCast(math.cast(i16, (S + A - TP) >> 16) orelse return error.Overflow); + mem.writeInt(u32, code, Instruction.movz(.x0, value, 16).toU32(), .little); + } }, .TLSDESC_CALL => if (!target.flags.has_tlsdesc) { - mem.writeInt(u32, code[rel.r_offset..][0..4], aarch64_util.Instruction.nop().toU32(), .little); + const old_inst = Instruction{ + .unconditional_branch_register = mem.bytesToValue(std.meta.TagPayload( + Instruction, + Instruction.unconditional_branch_register, + ), code), + }; + const rn: Register = @enumFromInt(old_inst.unconditional_branch_register.rn); + relocs_log.debug(" relaxing br({s}) => movk(x0, {x})", .{ @tagName(rn), S + A - TP }); + const value: u16 = @bitCast(@as(i16, @truncate(S + A - TP))); + mem.writeInt(u32, code, Instruction.movk(.x0, value, 0).toU32(), .little); }, else => try atom.reportUnhandledRelocError(rel, elf_file), @@ -1830,6 +1862,8 @@ const aarch64 = struct { } const aarch64_util = @import("../aarch64.zig"); + const Instruction = aarch64_util.Instruction; + const Register = aarch64_util.Register; }; const riscv = struct { |
