authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 22:00:28+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-21 22:00:28+01:00
logee364d542a91293fc048ea47dd8530f824916e5a
treebcfb7fa83567e36ea4aafc42ab4f37e61c744422
parent60a8f9b989d64bb6dfbb9e85cd0dd4e1b41750e1

link: introduce common set of aarch64 abstractions


4 files changed, 24 insertions(+), 107 deletions(-)

src/link/MachO/Atom.zig+10-60
...@@ -699,14 +699,7 @@ fn resolveRelocInner(...@@ -699,14 +699,7 @@ fn resolveRelocInner(
699 const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file));699 const S_: i64 = @intCast(thunk.getTargetAddress(rel.target, macho_file));
700 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;700 break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
701 };701 };
702 var inst = aarch64.Instruction{702 try aarch64.writeBranchImm(disp, code[rel_offset..][0..4]);
703 .unconditional_branch_immediate = mem.bytesToValue(std.meta.TagPayload(
704 aarch64.Instruction,
705 aarch64.Instruction.unconditional_branch_immediate,
706 ), code[rel_offset..][0..4]),
707 };
708 inst.unconditional_branch_immediate.imm26 = @as(u26, @truncate(@as(u28, @bitCast(disp >> 2))));
709 try writer.writeInt(u32, inst.toU32(), .little);
710 },703 },
711 else => unreachable,704 else => unreachable,
712 }705 }
...@@ -776,16 +769,8 @@ fn resolveRelocInner(...@@ -776,16 +769,8 @@ fn resolveRelocInner(
776 };769 };
777 break :target math.cast(u64, target) orelse return error.Overflow;770 break :target math.cast(u64, target) orelse return error.Overflow;
778 };771 };
779 const pages = @as(u21, @bitCast(try Relocation.calcNumberOfPages(source, target)));772 const pages = @as(u21, @bitCast(try aarch64.calcNumberOfPages(source, target)));
780 var inst = aarch64.Instruction{773 try aarch64.writePages(pages, code[rel_offset..][0..4]);
781 .pc_relative_address = mem.bytesToValue(std.meta.TagPayload(
782 aarch64.Instruction,
783 aarch64.Instruction.pc_relative_address,
784 ), code[rel_offset..][0..4]),
785 };
786 inst.pc_relative_address.immhi = @as(u19, @truncate(pages >> 2));
787 inst.pc_relative_address.immlo = @as(u2, @truncate(pages));
788 try writer.writeInt(u32, inst.toU32(), .little);
789 },774 },
790775
791 .pageoff => {776 .pageoff => {
...@@ -794,35 +779,8 @@ fn resolveRelocInner(...@@ -794,35 +779,8 @@ fn resolveRelocInner(
794 assert(!rel.meta.pcrel);779 assert(!rel.meta.pcrel);
795 const target = math.cast(u64, S + A) orelse return error.Overflow;780 const target = math.cast(u64, S + A) orelse return error.Overflow;
796 const inst_code = code[rel_offset..][0..4];781 const inst_code = code[rel_offset..][0..4];
797 if (Relocation.isArithmeticOp(inst_code)) {782 const kind = aarch64.classifyInst(inst_code);
798 const off = try Relocation.calcPageOffset(target, .arithmetic);783 try aarch64.writePageOffset(kind, target, inst_code);
799 var inst = aarch64.Instruction{
800 .add_subtract_immediate = mem.bytesToValue(std.meta.TagPayload(
801 aarch64.Instruction,
802 aarch64.Instruction.add_subtract_immediate,
803 ), inst_code),
804 };
805 inst.add_subtract_immediate.imm12 = off;
806 try writer.writeInt(u32, inst.toU32(), .little);
807 } else {
808 var inst = aarch64.Instruction{
809 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
810 aarch64.Instruction,
811 aarch64.Instruction.load_store_register,
812 ), inst_code),
813 };
814 const off = try Relocation.calcPageOffset(target, switch (inst.load_store_register.size) {
815 0 => if (inst.load_store_register.v == 1)
816 Relocation.PageOffsetInstKind.load_store_128
817 else
818 Relocation.PageOffsetInstKind.load_store_8,
819 1 => .load_store_16,
820 2 => .load_store_32,
821 3 => .load_store_64,
822 });
823 inst.load_store_register.offset = off;
824 try writer.writeInt(u32, inst.toU32(), .little);
825 }
826 },784 },
827785
828 .got_load_pageoff => {786 .got_load_pageoff => {
...@@ -830,15 +788,7 @@ fn resolveRelocInner(...@@ -830,15 +788,7 @@ fn resolveRelocInner(
830 assert(rel.meta.length == 2);788 assert(rel.meta.length == 2);
831 assert(!rel.meta.pcrel);789 assert(!rel.meta.pcrel);
832 const target = math.cast(u64, G + A) orelse return error.Overflow;790 const target = math.cast(u64, G + A) orelse return error.Overflow;
833 const off = try Relocation.calcPageOffset(target, .load_store_64);791 try aarch64.writePageOffset(.load_store_64, target, code[rel_offset..][0..4]);
834 var inst: aarch64.Instruction = .{
835 .load_store_register = mem.bytesToValue(std.meta.TagPayload(
836 aarch64.Instruction,
837 aarch64.Instruction.load_store_register,
838 ), code[rel_offset..][0..4]),
839 };
840 inst.load_store_register.offset = off;
841 try writer.writeInt(u32, inst.toU32(), .little);
842 },792 },
843793
844 .tlvp_pageoff => {794 .tlvp_pageoff => {
...@@ -863,7 +813,7 @@ fn resolveRelocInner(...@@ -863,7 +813,7 @@ fn resolveRelocInner(
863813
864 const inst_code = code[rel_offset..][0..4];814 const inst_code = code[rel_offset..][0..4];
865 const reg_info: RegInfo = blk: {815 const reg_info: RegInfo = blk: {
866 if (Relocation.isArithmeticOp(inst_code)) {816 if (aarch64.isArithmeticOp(inst_code)) {
867 const inst = mem.bytesToValue(std.meta.TagPayload(817 const inst = mem.bytesToValue(std.meta.TagPayload(
868 aarch64.Instruction,818 aarch64.Instruction,
869 aarch64.Instruction.add_subtract_immediate,819 aarch64.Instruction.add_subtract_immediate,
...@@ -890,7 +840,7 @@ fn resolveRelocInner(...@@ -890,7 +840,7 @@ fn resolveRelocInner(
890 .load_store_register = .{840 .load_store_register = .{
891 .rt = reg_info.rd,841 .rt = reg_info.rd,
892 .rn = reg_info.rn,842 .rn = reg_info.rn,
893 .offset = try Relocation.calcPageOffset(target, .load_store_64),843 .offset = try aarch64.calcPageOffset(.load_store_64, target),
894 .opc = 0b01,844 .opc = 0b01,
895 .op1 = 0b01,845 .op1 = 0b01,
896 .v = 0,846 .v = 0,
...@@ -900,7 +850,7 @@ fn resolveRelocInner(...@@ -900,7 +850,7 @@ fn resolveRelocInner(
900 .add_subtract_immediate = .{850 .add_subtract_immediate = .{
901 .rd = reg_info.rd,851 .rd = reg_info.rd,
902 .rn = reg_info.rn,852 .rn = reg_info.rn,
903 .imm12 = try Relocation.calcPageOffset(target, .arithmetic),853 .imm12 = try aarch64.calcPageOffset(.arithmetic, target),
904 .sh = 0,854 .sh = 0,
905 .s = 0,855 .s = 0,
906 .op = 0,856 .op = 0,
...@@ -1183,7 +1133,7 @@ pub const Loc = struct {...@@ -1183,7 +1133,7 @@ pub const Loc = struct {
11831133
1184pub const Alignment = @import("../../InternPool.zig").Alignment;1134pub const Alignment = @import("../../InternPool.zig").Alignment;
11851135
1186const aarch64 = @import("../../arch/aarch64/bits.zig");1136const aarch64 = @import("../aarch64.zig");
1187const assert = std.debug.assert;1137const assert = std.debug.assert;
1188const bind = @import("dyld_info/bind.zig");1138const bind = @import("dyld_info/bind.zig");
1189const macho = std.macho;1139const macho = std.macho;
src/link/MachO/Relocation.zig-32
...@@ -60,38 +60,6 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {...@@ -60,38 +60,6 @@ pub fn lessThan(ctx: void, lhs: Relocation, rhs: Relocation) bool {
60 return lhs.offset < rhs.offset;60 return lhs.offset < rhs.offset;
61}61}
6262
63pub fn calcNumberOfPages(saddr: u64, taddr: u64) error{Overflow}!i21 {
64 const spage = math.cast(i32, saddr >> 12) orelse return error.Overflow;
65 const tpage = math.cast(i32, taddr >> 12) orelse return error.Overflow;
66 const pages = math.cast(i21, tpage - spage) orelse return error.Overflow;
67 return pages;
68}
69
70pub const PageOffsetInstKind = enum {
71 arithmetic,
72 load_store_8,
73 load_store_16,
74 load_store_32,
75 load_store_64,
76 load_store_128,
77};
78
79pub fn calcPageOffset(taddr: u64, kind: PageOffsetInstKind) !u12 {
80 const narrowed = @as(u12, @truncate(taddr));
81 return switch (kind) {
82 .arithmetic, .load_store_8 => narrowed,
83 .load_store_16 => try math.divExact(u12, narrowed, 2),
84 .load_store_32 => try math.divExact(u12, narrowed, 4),
85 .load_store_64 => try math.divExact(u12, narrowed, 8),
86 .load_store_128 => try math.divExact(u12, narrowed, 16),
87 };
88}
89
90pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
91 const group_decode = @as(u5, @truncate(inst[3]));
92 return ((group_decode >> 2) == 4);
93}
94
95pub const Type = enum {63pub const Type = enum {
96 // x86_6464 // x86_64
97 /// RIP-relative displacement (X86_64_RELOC_SIGNED)65 /// RIP-relative displacement (X86_64_RELOC_SIGNED)
src/link/MachO/synthetic.zig+11-12
...@@ -267,9 +267,9 @@ pub const StubsSection = struct {...@@ -267,9 +267,9 @@ pub const StubsSection = struct {
267 },267 },
268 .aarch64 => {268 .aarch64 => {
269 // TODO relax if possible269 // TODO relax if possible
270 const pages = try Relocation.calcNumberOfPages(source, target);270 const pages = try aarch64.calcNumberOfPages(source, target);
271 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);271 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
272 const off = try Relocation.calcPageOffset(target, .load_store_64);272 const off = try aarch64.calcPageOffset(.load_store_64, target);
273 try writer.writeInt(273 try writer.writeInt(
274 u32,274 u32,
275 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),275 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
...@@ -411,9 +411,9 @@ pub const StubsHelperSection = struct {...@@ -411,9 +411,9 @@ pub const StubsHelperSection = struct {
411 .aarch64 => {411 .aarch64 => {
412 {412 {
413 // TODO relax if possible413 // TODO relax if possible
414 const pages = try Relocation.calcNumberOfPages(sect.addr, dyld_private_addr);414 const pages = try aarch64.calcNumberOfPages(sect.addr, dyld_private_addr);
415 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);415 try writer.writeInt(u32, aarch64.Instruction.adrp(.x17, pages).toU32(), .little);
416 const off = try Relocation.calcPageOffset(dyld_private_addr, .arithmetic);416 const off = try aarch64.calcPageOffset(.arithmetic, dyld_private_addr);
417 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);417 try writer.writeInt(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32(), .little);
418 }418 }
419 try writer.writeInt(u32, aarch64.Instruction.stp(419 try writer.writeInt(u32, aarch64.Instruction.stp(
...@@ -424,9 +424,9 @@ pub const StubsHelperSection = struct {...@@ -424,9 +424,9 @@ pub const StubsHelperSection = struct {
424 ).toU32(), .little);424 ).toU32(), .little);
425 {425 {
426 // TODO relax if possible426 // TODO relax if possible
427 const pages = try Relocation.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr);427 const pages = try aarch64.calcNumberOfPages(sect.addr + 12, dyld_stub_binder_addr);
428 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);428 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
429 const off = try Relocation.calcPageOffset(dyld_stub_binder_addr, .load_store_64);429 const off = try aarch64.calcPageOffset(.load_store_64, dyld_stub_binder_addr);
430 try writer.writeInt(u32, aarch64.Instruction.ldr(430 try writer.writeInt(u32, aarch64.Instruction.ldr(
431 .x16,431 .x16,
432 .x16,432 .x16,
...@@ -679,9 +679,9 @@ pub const ObjcStubsSection = struct {...@@ -679,9 +679,9 @@ pub const ObjcStubsSection = struct {
679 {679 {
680 const target = sym.getObjcSelrefsAddress(macho_file);680 const target = sym.getObjcSelrefsAddress(macho_file);
681 const source = addr;681 const source = addr;
682 const pages = try Relocation.calcNumberOfPages(source, target);682 const pages = try aarch64.calcNumberOfPages(source, target);
683 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);683 try writer.writeInt(u32, aarch64.Instruction.adrp(.x1, pages).toU32(), .little);
684 const off = try Relocation.calcPageOffset(target, .load_store_64);684 const off = try aarch64.calcPageOffset(.load_store_64, target);
685 try writer.writeInt(685 try writer.writeInt(
686 u32,686 u32,
687 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),687 aarch64.Instruction.ldr(.x1, .x1, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
...@@ -692,9 +692,9 @@ pub const ObjcStubsSection = struct {...@@ -692,9 +692,9 @@ pub const ObjcStubsSection = struct {
692 const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);692 const target_sym = macho_file.getSymbol(macho_file.objc_msg_send_index.?);
693 const target = target_sym.getGotAddress(macho_file);693 const target = target_sym.getGotAddress(macho_file);
694 const source = addr + 2 * @sizeOf(u32);694 const source = addr + 2 * @sizeOf(u32);
695 const pages = try Relocation.calcNumberOfPages(source, target);695 const pages = try aarch64.calcNumberOfPages(source, target);
696 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);696 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
697 const off = try Relocation.calcPageOffset(target, .load_store_64);697 const off = try aarch64.calcPageOffset(.load_store_64, target);
698 try writer.writeInt(698 try writer.writeInt(
699 u32,699 u32,
700 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),700 aarch64.Instruction.ldr(.x16, .x16, aarch64.Instruction.LoadStoreOffset.imm(off)).toU32(),
...@@ -778,7 +778,7 @@ pub const WeakBindSection = bind.WeakBind;...@@ -778,7 +778,7 @@ pub const WeakBindSection = bind.WeakBind;
778pub const LazyBindSection = bind.LazyBind;778pub const LazyBindSection = bind.LazyBind;
779pub const ExportTrieSection = Trie;779pub const ExportTrieSection = Trie;
780780
781const aarch64 = @import("../../arch/aarch64/bits.zig");781const aarch64 = @import("../aarch64.zig");
782const assert = std.debug.assert;782const assert = std.debug.assert;
783const bind = @import("dyld_info/bind.zig");783const bind = @import("dyld_info/bind.zig");
784const math = std.math;784const math = std.math;
...@@ -788,6 +788,5 @@ const trace = @import("../../tracy.zig").trace;...@@ -788,6 +788,5 @@ const trace = @import("../../tracy.zig").trace;
788const Allocator = std.mem.Allocator;788const Allocator = std.mem.Allocator;
789const MachO = @import("../MachO.zig");789const MachO = @import("../MachO.zig");
790const Rebase = @import("dyld_info/Rebase.zig");790const Rebase = @import("dyld_info/Rebase.zig");
791const Relocation = @import("Relocation.zig");
792const Symbol = @import("Symbol.zig");791const Symbol = @import("Symbol.zig");
793const Trie = @import("dyld_info/Trie.zig");792const Trie = @import("dyld_info/Trie.zig");
src/link/MachO/thunks.zig+3-3
...@@ -99,9 +99,9 @@ pub const Thunk = struct {...@@ -99,9 +99,9 @@ pub const Thunk = struct {
99 const sym = macho_file.getSymbol(sym_index);99 const sym = macho_file.getSymbol(sym_index);
100 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;100 const saddr = thunk.getAddress(macho_file) + i * trampoline_size;
101 const taddr = sym.getAddress(.{}, macho_file);101 const taddr = sym.getAddress(.{}, macho_file);
102 const pages = try Relocation.calcNumberOfPages(saddr, taddr);102 const pages = try aarch64.calcNumberOfPages(saddr, taddr);
103 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);103 try writer.writeInt(u32, aarch64.Instruction.adrp(.x16, pages).toU32(), .little);
104 const off = try Relocation.calcPageOffset(taddr, .arithmetic);104 const off = try aarch64.calcPageOffset(.arithmetic, taddr);
105 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);105 try writer.writeInt(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32(), .little);
106 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);106 try writer.writeInt(u32, aarch64.Instruction.br(.x16).toU32(), .little);
107 }107 }
...@@ -164,7 +164,7 @@ const max_distance = (1 << (jump_bits - 1));...@@ -164,7 +164,7 @@ const max_distance = (1 << (jump_bits - 1));
164/// and assume margin to be 5MiB.164/// and assume margin to be 5MiB.
165const max_allowed_distance = max_distance - 0x500_000;165const max_allowed_distance = max_distance - 0x500_000;
166166
167const aarch64 = @import("../../arch/aarch64/bits.zig");167const aarch64 = @import("../aarch64.zig");
168const assert = std.debug.assert;168const assert = std.debug.assert;
169const log = std.log.scoped(.link);169const log = std.log.scoped(.link);
170const macho = std.macho;170const macho = std.macho;