authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-03-08 14:13:30+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-03-08 22:46:17+01:00
log109d2321b0d92f20e75dcc0b7074026cefe1090e
tree428ff4af212fdabbe69c552b6358d351c851eb27
parentc1dbf01aa3e7ee1922762e6f9b86b2ad4c4a7e6f

link: refactor common aarch64 helpers


6 files changed, 71 insertions(+), 100 deletions(-)

src/link/Elf/Atom.zig+18-15
......@@ -1689,7 +1689,7 @@ const aarch64 = struct {
16891689 });
16901690 return;
16911691 };
1692 try aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]);
1692 aarch64_util.writeBranchImm(disp, code[r_offset..][0..4]);
16931693 },
16941694
16951695 .ADR_PREL_PG_HI21 => {
......@@ -1697,14 +1697,14 @@ const aarch64 = struct {
16971697 const saddr = @as(u64, @intCast(P));
16981698 const taddr = @as(u64, @intCast(S + A));
16991699 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)));
1700 try aarch64_util.writePages(pages, code[r_offset..][0..4]);
1700 aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]);
17011701 },
17021702
17031703 .ADR_GOT_PAGE => if (target.flags.has_got) {
17041704 const saddr = @as(u64, @intCast(P));
17051705 const taddr = @as(u64, @intCast(G + GOT + A));
17061706 const pages = @as(u21, @bitCast(try aarch64_util.calcNumberOfPages(saddr, taddr)));
1707 try aarch64_util.writePages(pages, code[r_offset..][0..4]);
1707 aarch64_util.writeAdrpInst(pages, code[r_offset..][0..4]);
17081708 } else {
17091709 // TODO: relax
17101710 var err = try elf_file.addErrorWithNotes(1);
......@@ -1719,10 +1719,14 @@ const aarch64 = struct {
17191719 .LD64_GOT_LO12_NC => {
17201720 assert(target.flags.has_got);
17211721 const taddr = @as(u64, @intCast(G + GOT + A));
1722 try aarch64_util.writePageOffset(.load_store_64, taddr, code[r_offset..][0..4]);
1722 aarch64_util.writeLoadStoreRegInst(@divExact(@as(u12, @truncate(taddr)), 8), code[rel.r_offset..][0..4]);
1723 },
1724
1725 .ADD_ABS_LO12_NC => {
1726 const taddr = @as(u64, @intCast(S + A));
1727 aarch64_util.writeAddImmInst(@truncate(taddr), code[rel.r_offset..][0..4]);
17231728 },
17241729
1725 .ADD_ABS_LO12_NC,
17261730 .LDST8_ABS_LO12_NC,
17271731 .LDST16_ABS_LO12_NC,
17281732 .LDST32_ABS_LO12_NC,
......@@ -1731,27 +1735,26 @@ const aarch64 = struct {
17311735 => {
17321736 // TODO: NC means no overflow check
17331737 const taddr = @as(u64, @intCast(S + A));
1734 const kind: aarch64_util.PageOffsetInstKind = switch (r_type) {
1735 .ADD_ABS_LO12_NC => .arithmetic,
1736 .LDST8_ABS_LO12_NC => .load_store_8,
1737 .LDST16_ABS_LO12_NC => .load_store_16,
1738 .LDST32_ABS_LO12_NC => .load_store_32,
1739 .LDST64_ABS_LO12_NC => .load_store_64,
1740 .LDST128_ABS_LO12_NC => .load_store_128,
1738 const offset: u12 = switch (r_type) {
1739 .LDST8_ABS_LO12_NC => @truncate(taddr),
1740 .LDST16_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 2),
1741 .LDST32_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 4),
1742 .LDST64_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 8),
1743 .LDST128_ABS_LO12_NC => @divExact(@as(u12, @truncate(taddr)), 16),
17411744 else => unreachable,
17421745 };
1743 try aarch64_util.writePageOffset(kind, taddr, code[r_offset..][0..4]);
1746 aarch64_util.writeLoadStoreRegInst(offset, code[rel.r_offset..][0..4]);
17441747 },
17451748
17461749 .TLSLE_ADD_TPREL_HI12 => {
17471750 const value = math.cast(i12, (S + A - TP) >> 12) orelse
17481751 return error.Overflow;
1749 try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]);
1752 aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]);
17501753 },
17511754
17521755 .TLSLE_ADD_TPREL_LO12_NC => {
17531756 const value: i12 = @truncate(S + A - TP);
1754 try aarch64_util.writeAddInst(@bitCast(value), code[rel.r_offset..][0..4]);
1757 aarch64_util.writeAddImmInst(@bitCast(value), code[rel.r_offset..][0..4]);
17551758 },
17561759
17571760 else => try atom.reportUnhandledRelocError(rel, elf_file),
src/link/Elf/synthetic_sections.zig+6-5
......@@ -1028,8 +1028,8 @@ pub const PltSection = struct {
10281028 // TODO: relax if possible
10291029 // .got.plt[2]
10301030 const pages = try aarch64_util.calcNumberOfPages(plt_addr + 4, got_plt_addr + 16);
1031 const ldr_off = try aarch64_util.calcPageOffset(.load_store_64, got_plt_addr + 16);
1032 const add_off = try aarch64_util.calcPageOffset(.arithmetic, got_plt_addr + 16);
1031 const ldr_off = try math.divExact(u12, @truncate(got_plt_addr + 16), 8);
1032 const add_off: u12 = @truncate(got_plt_addr + 16);
10331033
10341034 const preamble = &[_]Instruction{
10351035 Instruction.stp(
......@@ -1057,8 +1057,8 @@ pub const PltSection = struct {
10571057 const target_addr = sym.gotPltAddress(elf_file);
10581058 const source_addr = sym.pltAddress(elf_file);
10591059 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
1060 const ldr_off = try aarch64_util.calcPageOffset(.load_store_64, target_addr);
1061 const add_off = try aarch64_util.calcPageOffset(.arithmetic, target_addr);
1060 const ldr_off = try math.divExact(u12, @truncate(target_addr), 8);
1061 const add_off: u12 = @truncate(target_addr);
10621062 const insts = &[_]Instruction{
10631063 Instruction.adrp(.x16, pages),
10641064 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(ldr_off)),
......@@ -1202,7 +1202,7 @@ pub const PltGotSection = struct {
12021202 const target_addr = sym.gotAddress(elf_file);
12031203 const source_addr = sym.pltGotAddress(elf_file);
12041204 const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
1205 const off = try aarch64_util.calcPageOffset(.load_store_64, target_addr);
1205 const off = try math.divExact(u12, @truncate(target_addr), 8);
12061206 const insts = &[_]Instruction{
12071207 Instruction.adrp(.x16, pages),
12081208 Instruction.ldr(.x17, .x16, Instruction.LoadStoreOffset.imm(off)),
......@@ -1758,6 +1758,7 @@ fn writeInt(value: anytype, elf_file: *Elf, writer: anytype) !void {
17581758const assert = std.debug.assert;
17591759const builtin = @import("builtin");
17601760const elf = std.elf;
1761const math = std.math;
17611762const mem = std.mem;
17621763const log = std.log.scoped(.link);
17631764const relocation = @import("relocation.zig");
src/link/MachO/Atom.zig+25-7
......@@ -700,7 +700,7 @@ fn resolveRelocInner(
700700 const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file));
701701 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
702702 };
703 try aarch64.writeBranchImm(disp, code[rel_offset..][0..4]);
703 aarch64.writeBranchImm(disp, code[rel_offset..][0..4]);
704704 },
705705 else => unreachable,
706706 }
......@@ -771,7 +771,7 @@ fn resolveRelocInner(
771771 break :target math.cast(u64, target) orelse return error.Overflow;
772772 };
773773 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(source, target)));
774 try aarch64.writePages(pages, code[rel_offset..][0..4]);
774 aarch64.writeAdrpInst(pages, code[rel_offset..][0..4]);
775775 },
776776
777777 .pageoff => {
......@@ -780,8 +780,26 @@ fn resolveRelocInner(
780780 assert(!rel.meta.pcrel);
781781 const target = math.cast(u64, S + A) orelse return error.Overflow;
782782 const inst_code = code[rel_offset..][0..4];
783 const kind = aarch64.classifyInst(inst_code);
784 try aarch64.writePageOffset(kind, target, inst_code);
783 if (aarch64.isArithmeticOp(inst_code)) {
784 aarch64.writeAddImmInst(@truncate(target), inst_code);
785 } else {
786 var inst = aarch64.Instruction{
787 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
788 aarch64.Instruction,
789 aarch64.Instruction.load_store_register,
790 ), inst_code),
791 };
792 inst.load_store_register.offset = switch (inst.load_store_register.size) {
793 0 => if (inst.load_store_register.v == 1)
794 try math.divExact(u12, @truncate(target), 16)
795 else
796 @truncate(target),
797 1 => try math.divExact(u12, @truncate(target), 2),
798 2 => try math.divExact(u12, @truncate(target), 4),
799 3 => try math.divExact(u12, @truncate(target), 8),
800 };
801 try writer.writeInt(u32, inst.toU32(), .little);
802 }
785803 },
786804
787805 .got_load_pageoff => {
......@@ -789,7 +807,7 @@ fn resolveRelocInner(
789807 assert(rel.meta.length == 2);
790808 assert(!rel.meta.pcrel);
791809 const target = math.cast(u64, G + A) orelse return error.Overflow;
792 try aarch64.writePageOffset(.load_store_64, target, code[rel_offset..][0..4]);
810 aarch64.writeLoadStoreRegInst(try math.divExact(u12, @truncate(target), 8), code[rel_offset..][0..4]);
793811 },
794812
795813 .tlvp_pageoff => {
......@@ -841,7 +859,7 @@ fn resolveRelocInner(
841859 .load_store_register = .{
842860 .rt = reg_info.rd,
843861 .rn = reg_info.rn,
844 .offset = try aarch64.calcPageOffset(.load_store_64, target),
862 .offset = try math.divExact(u12, @truncate(target), 8),
845863 .opc = 0b01,
846864 .op1 = 0b01,
847865 .v = 0,
......@@ -851,7 +869,7 @@ fn resolveRelocInner(
851869 .add_subtract_immediate = .{
852870 .rd = reg_info.rd,
853871 .rn = reg_info.rn,
854 .imm12 = try aarch64.calcPageOffset(.arithmetic, target),
872 .imm12 = @truncate(target),
855873 .sh = 0,
856874 .s = 0,
857875 .op = 0,
src/link/MachO/synthetic.zig+5-5
......@@ -269,7 +269,7 @@ pub const StubsSection = struct {
269269 // TODO relax if possible
270270 const pages = try aarch64.calcNumberOfPages(source, target);
271271 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
272 const off = try aarch64.calcPageOffset(.load_store_64, target);
272 const off = try math.divExact(u12, @truncate(target), 8);
273273 try writer.writeInt(
274274 u32,
275275 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
......@@ -413,7 +413,7 @@ pub const StubsHelperSection = struct {
413413 // TODO relax if possible
414414 const pages = try aarch64.calcNumberOfPages(sect.addr, dyld_private_addr);
415415 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
416 const off = try aarch64.calcPageOffset(.arithmetic, dyld_private_addr);
416 const off: u12 = @truncate(dyld_private_addr);
417417 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
418418 }
419419 try writer.writeInt(u32, aarch64.Instruction.stp(
......@@ -426,7 +426,7 @@ pub const StubsHelperSection = struct {
426426 // TODO relax if possible
427427 const pages = try aarch64.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr);
428428 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
429 const off = try aarch64.calcPageOffset(.load_store_64, dyld_stub_binder_addr);
429 const off = try math.divExact(u12, @truncate(dyld_stub_binder_addr), 8);
430430 try writer.writeInt(u32, aarch64.Instruction.ldr(
431431 .x16,
432432 .x16,
......@@ -681,7 +681,7 @@ pub const ObjcStubsSection = struct {
681681 const source = addr;
682682 const pages = try aarch64.calcNumberOfPages(source, target);
683683 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
684 const off = try aarch64.calcPageOffset(.load_store_64, target);
684 const off = try math.divExact(u12, @truncate(target), 8);
685685 try writer.writeInt(
686686 u32,
687687 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
......@@ -694,7 +694,7 @@ pub const ObjcStubsSection = struct {
694694 const source = addr + 2 * @sizeOf(u32);
695695 const pages = try aarch64.calcNumberOfPages(source, target);
696696 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
697 const off = try aarch64.calcPageOffset(.load_store_64, target);
697 const off = try math.divExact(u12, @truncate(target), 8);
698698 try writer.writeInt(
699699 u32,
700700 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
src/link/MachO/thunks.zig+1-1
......@@ -101,7 +101,7 @@ pub const Thunk = struct {
101101 const taddr = sym.getAddress(.{}, macho_file);
102102 const pages = try aarch64.calcNumberOfPages(saddr, taddr);
103103 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
104 const off = try aarch64.calcPageOffset(.arithmetic, taddr);
104 const off: u12 = @truncate(taddr);
105105 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
106106 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
107107 }
src/link/aarch64.zig+16-67
......@@ -3,66 +3,26 @@ pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
33 return ((group_decode >> 2) == 4);
44}
55
6pub const PageOffsetInstKind = enum {
7 arithmetic,
8 load_store_8,
9 load_store_16,
10 load_store_32,
11 load_store_64,
12 load_store_128,
13};
14
15pub fn classifyInst(code: *const [4]u8) PageOffsetInstKind {
16 if (isArithmeticOp(code)) return .arithmetic;
17 const inst = Instruction{
18 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
6pub fn writeAddImmInst(value: u12, code: *[4]u8) void {
7 var inst = Instruction{
8 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
199 Instruction,
20 Instruction.load_store_register,
10 Instruction.add_subtract_immediate,
2111 ), code),
2212 };
23 return switch (inst.load_store_register.size) {
24 0 => if (inst.load_store_register.v == 1) .load_store_128 else .load_store_8,
25 1 => .load_store_16,
26 2 => .load_store_32,
27 3 => .load_store_64,
28 };
13 inst.add_subtract_immediate.imm12 = value;
14 mem.writeInt(u32, code, inst.toU32(), .little);
2915}
3016
31pub fn calcPageOffset(kind: PageOffsetInstKind, taddr: u64) !u12 {
32 const narrowed = @as(u12, @truncate(taddr));
33 return switch (kind) {
34 .arithmetic, .load_store_8 => narrowed,
35 .load_store_16 => try math.divExact(u12, narrowed, 2),
36 .load_store_32 => try math.divExact(u12, narrowed, 4),
37 .load_store_64 => try math.divExact(u12, narrowed, 8),
38 .load_store_128 => try math.divExact(u12, narrowed, 16),
17pub fn writeLoadStoreRegInst(value: u12, code: *[4]u8) void {
18 var inst: Instruction = .{
19 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
20 Instruction,
21 Instruction.load_store_register,
22 ), code),
3923 };
40}
41
42pub fn writePageOffset(kind: PageOffsetInstKind, taddr: u64, code: *[4]u8) !void {
43 const value = try calcPageOffset(kind, taddr);
44 switch (kind) {
45 .arithmetic => {
46 var inst = Instruction{
47 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
48 Instruction,
49 Instruction.add_subtract_immediate,
50 ), code),
51 };
52 inst.add_subtract_immediate.imm12 = value;
53 mem.writeInt(u32, code, inst.toU32(), .little);
54 },
55 else => {
56 var inst: Instruction = .{
57 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
58 Instruction,
59 Instruction.load_store_register,
60 ), code),
61 };
62 inst.load_store_register.offset = value;
63 mem.writeInt(u32, code, inst.toU32(), .little);
64 },
65 }
24 inst.load_store_register.offset = value;
25 mem.writeInt(u32, code, inst.toU32(), .little);
6626}
6727
6828pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {
......@@ -72,7 +32,7 @@ pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {
7232 return pages;
7333}
7434
75pub fn writePages(pages: u21, code: *[4]u8) !void {
35pub fn writeAdrpInst(pages: u21, code: *[4]u8) void {
7636 var inst = Instruction{
7737 .pc_relative_address = mem.bytesToValue(std.meta.TagPayload(
7838 Instruction,
......@@ -84,7 +44,7 @@ pub fn writePages(pages: u21, code: *[4]u8) !void {
8444 mem.writeInt(u32, code, inst.toU32(), .little);
8545}
8646
87pub fn writeBranchImm(disp: i28, code: *[4]u8) !void {
47pub fn writeBranchImm(disp: i28, code: *[4]u8) void {
8848 var inst = Instruction{
8949 .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload(
9050 Instruction,
......@@ -95,17 +55,6 @@ pub fn writeBranchImm(disp: i28, code: *[4]u8) !void {
9555 mem.writeInt(u32, code, inst.toU32(), .little);
9656}
9757
98pub fn writeAddInst(value: u12, code: *[4]u8) !void {
99 var inst = Instruction{
100 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
101 Instruction,
102 Instruction.add_subtract_immediate,
103 ), code),
104 };
105 inst.add_subtract_immediate.imm12 = value;
106 mem.writeInt(u32, code, inst.toU32(), .little);
107}
108
10958const assert = std.debug.assert;
11059const bits = @import("../arch/aarch64/bits.zig");
11160const builtin = @import("builtin");