authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-05 08:23:46+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-13 11:47:51+02:00
logeba280ce20d308ec0abb17719ab4cc43a27901eb
treeb9bbac734e4c82bb2487f0921e26fce627291578
parent1795b8eb4e8db95cb639349c6c1bc4b0b82741bb

macho: refactor relocation type in incremental linker


5 files changed, 118 insertions(+), 190 deletions(-)

src/arch/aarch64/Emit.zig+10-19
...@@ -673,7 +673,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -673,7 +673,7 @@ fn mirCallExtern(emit: *Emit, inst: Mir.Inst.Index) !void {
673 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;673 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?;
674 const target = macho_file.getGlobalByIndex(relocation.sym_index);674 const target = macho_file.getGlobalByIndex(relocation.sym_index);
675 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{675 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
676 .type = @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),676 .type = .branch,
677 .target = target,677 .target = target,
678 .offset = offset,678 .offset = offset,
679 .addend = 0,679 .addend = 0,
...@@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
883 }883 }
884884
885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {885 if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
886 const Atom = link.File.MachO.Atom;
887 const Relocation = Atom.Relocation;
886 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;888 const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
887 // TODO this causes segfault in stage1889 try Atom.addRelocations(macho_file, atom_index, &[_]Relocation{ .{
888 // try atom.addRelocations(macho_file, 2, .{
889 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
890 .target = .{ .sym_index = data.sym_index, .file = null },890 .target = .{ .sym_index = data.sym_index, .file = null },
891 .offset = offset,891 .offset = offset,
892 .addend = 0,892 .addend = 0,
893 .pcrel = true,893 .pcrel = true,
894 .length = 2,894 .length = 2,
895 .type = switch (tag) {895 .type = switch (tag) {
896 .load_memory_got,896 .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_page,
897 .load_memory_ptr_got,897 .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.page,
898 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
899 .load_memory_direct,
900 .load_memory_ptr_direct,
901 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
902 else => unreachable,898 else => unreachable,
903 },899 },
904 });900 }, .{
905 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
906 .target = .{ .sym_index = data.sym_index, .file = null },901 .target = .{ .sym_index = data.sym_index, .file = null },
907 .offset = offset + 4,902 .offset = offset + 4,
908 .addend = 0,903 .addend = 0,
909 .pcrel = false,904 .pcrel = false,
910 .length = 2,905 .length = 2,
911 .type = switch (tag) {906 .type = switch (tag) {
912 .load_memory_got,907 .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_pageoff,
913 .load_memory_ptr_got,908 .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.pageoff,
914 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),
915 .load_memory_direct,
916 .load_memory_ptr_direct,
917 => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),
918 else => unreachable,909 else => unreachable,
919 },910 },
920 });911 } });
921 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {912 } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| {
922 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;913 const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?;
923 const target = switch (tag) {914 const target = switch (tag) {
src/arch/x86_64/Emit.zig+6-7
...@@ -42,7 +42,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -42,7 +42,7 @@ pub fn emitMir(emit: *Emit) Error!void {
42 ).?;42 ).?;
43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);43 const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index);
44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{44 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
45 .type = @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),45 .type = .branch,
46 .target = target,46 .target = target,
47 .offset = end_offset - 4,47 .offset = end_offset - 4,
48 .addend = 0,48 .addend = 0,
...@@ -68,17 +68,16 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -68,17 +68,16 @@ pub fn emitMir(emit: *Emit) Error!void {
68 .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {68 .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
69 const metadata =69 const metadata =
70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;70 emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
71 const reloc_type = switch (inst.ops) {
72 .got_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_GOT),
73 .direct_reloc => @enumToInt(std.macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),
74 else => unreachable,
75 };
76 const atom_index = macho_file.getAtomIndexForSymbol(.{71 const atom_index = macho_file.getAtomIndexForSymbol(.{
77 .sym_index = metadata.atom_index,72 .sym_index = metadata.atom_index,
78 .file = null,73 .file = null,
79 }).?;74 }).?;
80 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{75 try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{
81 .type = reloc_type,76 .type = switch (inst.ops) {
77 .got_reloc => .got,
78 .direct_reloc => .signed,
79 else => unreachable,
80 },
82 .target = .{ .sym_index = metadata.sym_index, .file = null },81 .target = .{ .sym_index = metadata.sym_index, .file = null },
83 .offset = @intCast(u32, end_offset - 4),82 .offset = @intCast(u32, end_offset - 4),
84 .addend = 0,83 .addend = 0,
src/link/MachO.zig+17-51
...@@ -1250,11 +1250,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {...@@ -1250,11 +1250,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1250 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});1250 log.debug("allocated GOT atom at 0x{x}", .{sym.n_value});
12511251
1252 try Atom.addRelocation(self, atom_index, .{1252 try Atom.addRelocation(self, atom_index, .{
1253 .type = switch (self.base.options.target.cpu.arch) {1253 .type = .unsigned,
1254 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1255 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1256 else => unreachable,
1257 },
1258 .target = target,1254 .target = target,
1259 .offset = 0,1255 .offset = 0,
1260 .addend = 0,1256 .addend = 0,
...@@ -1336,15 +1332,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1336,15 +1332,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
1336 code[9] = 0xff;1332 code[9] = 0xff;
1337 code[10] = 0x25;1333 code[10] = 0x25;
13381334
1339 try Atom.addRelocations(self, atom_index, 2, .{ .{1335 try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{
1340 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED),1336 .type = .signed,
1341 .target = dyld_private,1337 .target = dyld_private,
1342 .offset = 3,1338 .offset = 3,
1343 .addend = 0,1339 .addend = 0,
1344 .pcrel = true,1340 .pcrel = true,
1345 .length = 2,1341 .length = 2,
1346 }, .{1342 }, .{
1347 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT),1343 .type = .got,
1348 .target = dyld_stub_binder,1344 .target = dyld_stub_binder,
1349 .offset = 11,1345 .offset = 11,
1350 .addend = 0,1346 .addend = 0,
...@@ -1376,29 +1372,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1376,29 +1372,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
1376 // br x161372 // br x16
1377 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());1373 mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32());
13781374
1379 try Atom.addRelocations(self, atom_index, 4, .{ .{1375 try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{
1380 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1376 .type = .page,
1381 .target = dyld_private,1377 .target = dyld_private,
1382 .offset = 0,1378 .offset = 0,
1383 .addend = 0,1379 .addend = 0,
1384 .pcrel = true,1380 .pcrel = true,
1385 .length = 2,1381 .length = 2,
1386 }, .{1382 }, .{
1387 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),1383 .type = .pageoff,
1388 .target = dyld_private,1384 .target = dyld_private,
1389 .offset = 4,1385 .offset = 4,
1390 .addend = 0,1386 .addend = 0,
1391 .pcrel = false,1387 .pcrel = false,
1392 .length = 2,1388 .length = 2,
1393 }, .{1389 }, .{
1394 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),1390 .type = .got_page,
1395 .target = dyld_stub_binder,1391 .target = dyld_stub_binder,
1396 .offset = 12,1392 .offset = 12,
1397 .addend = 0,1393 .addend = 0,
1398 .pcrel = true,1394 .pcrel = true,
1399 .length = 2,1395 .length = 2,
1400 }, .{1396 }, .{
1401 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),1397 .type = .got_pageoff,
1402 .target = dyld_stub_binder,1398 .target = dyld_stub_binder,
1403 .offset = 16,1399 .offset = 16,
1404 .addend = 0,1400 .addend = 0,
...@@ -1456,7 +1452,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {...@@ -1456,7 +1452,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
1456 code[5] = 0xe9;1452 code[5] = 0xe9;
14571453
1458 try Atom.addRelocation(self, atom_index, .{1454 try Atom.addRelocation(self, atom_index, .{
1459 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1455 .type = .branch,
1460 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },1456 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
1461 .offset = 6,1457 .offset = 6,
1462 .addend = 0,1458 .addend = 0,
...@@ -1479,7 +1475,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {...@@ -1479,7 +1475,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index {
1479 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.1475 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
14801476
1481 try Atom.addRelocation(self, atom_index, .{1477 try Atom.addRelocation(self, atom_index, .{
1482 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26),1478 .type = .branch,
1483 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },1479 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null },
1484 .offset = 4,1480 .offset = 4,
1485 .addend = 0,1481 .addend = 0,
...@@ -1507,11 +1503,7 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo...@@ -1507,11 +1503,7 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo
1507 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;1503 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;
15081504
1509 try Atom.addRelocation(self, atom_index, .{1505 try Atom.addRelocation(self, atom_index, .{
1510 .type = switch (self.base.options.target.cpu.arch) {1506 .type = .unsigned,
1511 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
1512 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
1513 else => unreachable,
1514 },
1515 .target = .{ .sym_index = stub_sym_index, .file = null },1507 .target = .{ .sym_index = stub_sym_index, .file = null },
1516 .offset = 0,1508 .offset = 0,
1517 .addend = 0,1509 .addend = 0,
...@@ -1565,7 +1557,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1565,7 +1557,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1565 code[1] = 0x25;1557 code[1] = 0x25;
15661558
1567 try Atom.addRelocation(self, atom_index, .{1559 try Atom.addRelocation(self, atom_index, .{
1568 .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH),1560 .type = .branch,
1569 .target = .{ .sym_index = laptr_sym_index, .file = null },1561 .target = .{ .sym_index = laptr_sym_index, .file = null },
1570 .offset = 2,1562 .offset = 2,
1571 .addend = 0,1563 .addend = 0,
...@@ -1585,9 +1577,9 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1585,9 +1577,9 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1585 // br x161577 // br x16
1586 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());1578 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
15871579
1588 try Atom.addRelocations(self, atom_index, 2, .{1580 try Atom.addRelocations(self, atom_index, &[_]Relocation{
1589 .{1581 .{
1590 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21),1582 .type = .page,
1591 .target = .{ .sym_index = laptr_sym_index, .file = null },1583 .target = .{ .sym_index = laptr_sym_index, .file = null },
1592 .offset = 0,1584 .offset = 0,
1593 .addend = 0,1585 .addend = 0,
...@@ -1595,7 +1587,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {...@@ -1595,7 +1587,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1595 .length = 2,1587 .length = 2,
1596 },1588 },
1597 .{1589 .{
1598 .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),1590 .type = .pageoff,
1599 .target = .{ .sym_index = laptr_sym_index, .file = null },1591 .target = .{ .sym_index = laptr_sym_index, .file = null },
1600 .offset = 4,1592 .offset = 4,
1601 .addend = 0,1593 .addend = 0,
...@@ -2663,11 +2655,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2663,11 +2655,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2663 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;2655 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
2664 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;2656 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
2665 try Atom.addRelocation(self, atom_index, .{2657 try Atom.addRelocation(self, atom_index, .{
2666 .type = switch (self.base.options.target.cpu.arch) {2658 .type = .unsigned,
2667 .aarch64 => @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_UNSIGNED),
2668 .x86_64 => @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_UNSIGNED),
2669 else => unreachable,
2670 },
2671 .target = .{ .sym_index = sym_index, .file = null },2659 .target = .{ .sym_index = sym_index, .file = null },
2672 .offset = @intCast(u32, reloc_info.offset),2660 .offset = @intCast(u32, reloc_info.offset),
2673 .addend = reloc_info.addend,2661 .addend = reloc_info.addend,
...@@ -3115,28 +3103,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm...@@ -3115,28 +3103,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm
3115 return vaddr;3103 return vaddr;
3116}3104}
31173105
3118fn getSectionPrecedence(header: macho.section_64) u4 {
3119 if (header.isCode()) {
3120 if (mem.eql(u8, "__text", header.sectName())) return 0x0;
3121 if (header.type() == macho.S_SYMBOL_STUBS) return 0x1;
3122 return 0x2;
3123 }
3124 switch (header.type()) {
3125 macho.S_NON_LAZY_SYMBOL_POINTERS,
3126 macho.S_LAZY_SYMBOL_POINTERS,
3127 => return 0x0,
3128 macho.S_MOD_INIT_FUNC_POINTERS => return 0x1,
3129 macho.S_MOD_TERM_FUNC_POINTERS => return 0x2,
3130 macho.S_ZEROFILL => return 0xf,
3131 macho.S_THREAD_LOCAL_REGULAR => return 0xd,
3132 macho.S_THREAD_LOCAL_ZEROFILL => return 0xe,
3133 else => if (mem.eql(u8, "__eh_frame", header.sectName()))
3134 return 0xf
3135 else
3136 return 0x3,
3137 }
3138}
3139
3140pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {3106pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 {
3141 _ = lib_name;3107 _ = lib_name;
3142 const gpa = self.base.allocator;3108 const gpa = self.base.allocator;
src/link/MachO/Atom.zig+5-11
...@@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace;...@@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace;
14const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
15const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
16const MachO = @import("../MachO.zig");16const MachO = @import("../MachO.zig");
17const Relocation = @import("Relocation.zig");17pub const Relocation = @import("Relocation.zig");
18const SymbolWithLoc = MachO.SymbolWithLoc;18const SymbolWithLoc = MachO.SymbolWithLoc;
1919
20/// Each decl always gets a local symbol with the fully qualified name.20/// Each decl always gets a local symbol with the fully qualified name.
...@@ -113,25 +113,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {...@@ -113,25 +113,19 @@ pub fn freeListEligible(self: Atom, macho_file: *MachO) bool {
113}113}
114114
115pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {115pub fn addRelocation(macho_file: *MachO, atom_index: Index, reloc: Relocation) !void {
116 return addRelocations(macho_file, atom_index, 1, .{reloc});116 return addRelocations(macho_file, atom_index, &[_]Relocation{reloc});
117}117}
118118
119pub fn addRelocations(119pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation) !void {
120 macho_file: *MachO,
121 atom_index: Index,
122 comptime count: comptime_int,
123 relocs: [count]Relocation,
124) !void {
125 const gpa = macho_file.base.allocator;120 const gpa = macho_file.base.allocator;
126 const target = macho_file.base.options.target;
127 const gop = try macho_file.relocs.getOrPut(gpa, atom_index);121 const gop = try macho_file.relocs.getOrPut(gpa, atom_index);
128 if (!gop.found_existing) {122 if (!gop.found_existing) {
129 gop.value_ptr.* = .{};123 gop.value_ptr.* = .{};
130 }124 }
131 try gop.value_ptr.ensureUnusedCapacity(gpa, count);125 try gop.value_ptr.ensureUnusedCapacity(gpa, relocs.len);
132 for (relocs) |reloc| {126 for (relocs) |reloc| {
133 log.debug(" (adding reloc of type {s} to target %{d})", .{127 log.debug(" (adding reloc of type {s} to target %{d})", .{
134 reloc.fmtType(target),128 @tagName(reloc.type),
135 reloc.target.sym_index,129 reloc.target.sym_index,
136 });130 });
137 gop.value_ptr.appendAssumeCapacity(reloc);131 gop.value_ptr.appendAssumeCapacity(reloc);
src/link/MachO/Relocation.zig+80-102
...@@ -1,19 +1,7 @@...@@ -1,19 +1,7 @@
1const Relocation = @This();1//! Relocation used by the self-hosted backends to instruct the linker where and how to
22//! fixup the values when flushing the contents to file and/or memory.
3const std = @import("std");
4const aarch64 = @import("../../arch/aarch64/bits.zig");
5const assert = std.debug.assert;
6const log = std.log.scoped(.link);
7const macho = std.macho;
8const math = std.math;
9const mem = std.mem;
10const meta = std.meta;
11
12const Atom = @import("Atom.zig");
13const MachO = @import("../MachO.zig");
14const SymbolWithLoc = MachO.SymbolWithLoc;
153
16type: u4,4type: Type,
17target: SymbolWithLoc,5target: SymbolWithLoc,
18offset: u32,6offset: u32,
19addend: i64,7addend: i64,
...@@ -21,36 +9,46 @@ pcrel: bool,...@@ -21,36 +9,46 @@ pcrel: bool,
21length: u2,9length: u2,
22dirty: bool = true,10dirty: bool = true,
2311
12pub const Type = enum {
13 // x86, x86_64
14 /// RIP-relative displacement to a GOT pointer
15 got,
16 /// RIP-relative displacement
17 signed,
18 /// RIP-relative displacemen to threadlocal variable descriptor
19 tlv,
20
21 // aarch64
22 /// PC-relative distance to target page in GOT section
23 got_page,
24 /// Offset to a GOT pointer relative to the start of a page in GOT section
25 got_pageoff,
26 /// PC-relative distance to target page in a section
27 page,
28 /// Offset to a pointer relative to the start of a page in a section
29 pageoff,
30 /// PC-relative distance to target page in TLV section
31 tlv_page,
32 /// Offset to a pointer relative to the start of a page in TLV section
33 tlv_pageoff,
34
35 // common
36 /// PC/RIP-relative displacement B/BL/CALL
37 branch,
38 /// Absolute pointer value
39 unsigned,
40};
41
24/// Returns true if and only if the reloc is dirty AND the target address is available.42/// Returns true if and only if the reloc is dirty AND the target address is available.
25pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {43pub fn isResolvable(self: Relocation, macho_file: *MachO) bool {
26 _ = self.getTargetAtomIndex(macho_file) orelse return false;44 _ = self.getTargetAtomIndex(macho_file) orelse return false;
27 return self.dirty;45 return self.dirty;
28}46}
2947
30pub fn fmtType(self: Relocation, target: std.Target) []const u8 {
31 switch (target.cpu.arch) {
32 .aarch64 => return @tagName(@intToEnum(macho.reloc_type_arm64, self.type)),
33 .x86_64 => return @tagName(@intToEnum(macho.reloc_type_x86_64, self.type)),
34 else => unreachable,
35 }
36}
37
38pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {48pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index {
39 switch (macho_file.base.options.target.cpu.arch) {49 switch (self.type) {
40 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) {50 .got, .got_page, .got_pageoff => return macho_file.getGotAtomIndexForSymbol(self.target),
41 .ARM64_RELOC_GOT_LOAD_PAGE21,51 else => {},
42 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
43 .ARM64_RELOC_POINTER_TO_GOT,
44 => return macho_file.getGotAtomIndexForSymbol(self.target),
45 else => {},
46 },
47 .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.type)) {
48 .X86_64_RELOC_GOT,
49 .X86_64_RELOC_GOT_LOAD,
50 => return macho_file.getGotAtomIndexForSymbol(self.target),
51 else => {},
52 },
53 else => unreachable,
54 }52 }
55 if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;53 if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom;
56 return macho_file.getAtomIndexForSymbol(self.target);54 return macho_file.getAtomIndexForSymbol(self.target);
...@@ -70,7 +68,7 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -70,7 +68,7 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
70 source_addr,68 source_addr,
71 target_addr,69 target_addr,
72 macho_file.getSymbolName(self.target),70 macho_file.getSymbolName(self.target),
73 self.fmtType(macho_file.base.options.target),71 @tagName(self.type),
74 });72 });
7573
76 switch (arch) {74 switch (arch) {
...@@ -81,18 +79,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod...@@ -81,18 +79,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod
81}79}
8280
83fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {81fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
84 const rel_type = @intToEnum(macho.reloc_type_arm64, self.type);82 var buffer = code[self.offset..];
85 if (rel_type == .ARM64_RELOC_UNSIGNED) {83 switch (self.type) {
86 return switch (self.length) {84 .branch => {
87 2 => mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr))),
88 3 => mem.writeIntLittle(u64, code[self.offset..][0..8], @bitCast(u64, target_addr)),
89 else => unreachable,
90 };
91 }
92
93 var buffer = code[self.offset..][0..4];
94 switch (rel_type) {
95 .ARM64_RELOC_BRANCH26 => {
96 const displacement = math.cast(85 const displacement = math.cast(
97 i28,86 i28,
98 @intCast(i64, target_addr) - @intCast(i64, source_addr),87 @intCast(i64, target_addr) - @intCast(i64, source_addr),
...@@ -101,15 +90,12 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -101,15 +90,12 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
101 .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(90 .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload(
102 aarch64.Instruction,91 aarch64.Instruction,
103 aarch64.Instruction.unconditional_branch_immediate,92 aarch64.Instruction.unconditional_branch_immediate,
104 ), buffer),93 ), buffer[0..4]),
105 };94 };
106 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));95 inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2));
107 mem.writeIntLittle(u32, buffer, inst.toU32());96 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
108 },97 },
109 .ARM64_RELOC_PAGE21,98 .page, .got_page, .tlv_page => {
110 .ARM64_RELOC_GOT_LOAD_PAGE21,
111 .ARM64_RELOC_TLVP_LOAD_PAGE21,
112 => {
113 const source_page = @intCast(i32, source_addr >> 12);99 const source_page = @intCast(i32, source_addr >> 12);
114 const target_page = @intCast(i32, target_addr >> 12);100 const target_page = @intCast(i32, target_addr >> 12);
115 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));101 const pages = @bitCast(u21, @intCast(i21, target_page - source_page));
...@@ -117,31 +103,29 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -117,31 +103,29 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
117 .pc_relative_address = mem.bytesToValue(meta.TagPayload(103 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
118 aarch64.Instruction,104 aarch64.Instruction,
119 aarch64.Instruction.pc_relative_address,105 aarch64.Instruction.pc_relative_address,
120 ), buffer),106 ), buffer[0..4]),
121 };107 };
122 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);108 inst.pc_relative_address.immhi = @truncate(u19, pages >> 2);
123 inst.pc_relative_address.immlo = @truncate(u2, pages);109 inst.pc_relative_address.immlo = @truncate(u2, pages);
124 mem.writeIntLittle(u32, buffer, inst.toU32());110 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
125 },111 },
126 .ARM64_RELOC_PAGEOFF12,112 .pageoff, .got_pageoff => {
127 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
128 => {
129 const narrowed = @truncate(u12, @intCast(u64, target_addr));113 const narrowed = @truncate(u12, @intCast(u64, target_addr));
130 if (isArithmeticOp(buffer)) {114 if (isArithmeticOp(buffer[0..4])) {
131 var inst = aarch64.Instruction{115 var inst = aarch64.Instruction{
132 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(116 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
133 aarch64.Instruction,117 aarch64.Instruction,
134 aarch64.Instruction.add_subtract_immediate,118 aarch64.Instruction.add_subtract_immediate,
135 ), buffer),119 ), buffer[0..4]),
136 };120 };
137 inst.add_subtract_immediate.imm12 = narrowed;121 inst.add_subtract_immediate.imm12 = narrowed;
138 mem.writeIntLittle(u32, buffer, inst.toU32());122 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
139 } else {123 } else {
140 var inst = aarch64.Instruction{124 var inst = aarch64.Instruction{
141 .load_store_register = mem.bytesToValue(meta.TagPayload(125 .load_store_register = mem.bytesToValue(meta.TagPayload(
142 aarch64.Instruction,126 aarch64.Instruction,
143 aarch64.Instruction.load_store_register,127 aarch64.Instruction.load_store_register,
144 ), buffer),128 ), buffer[0..4]),
145 };129 };
146 const offset: u12 = blk: {130 const offset: u12 = blk: {
147 if (inst.load_store_register.size == 0) {131 if (inst.load_store_register.size == 0) {
...@@ -157,21 +141,21 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -157,21 +141,21 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
157 }141 }
158 };142 };
159 inst.load_store_register.offset = offset;143 inst.load_store_register.offset = offset;
160 mem.writeIntLittle(u32, buffer, inst.toU32());144 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
161 }145 }
162 },146 },
163 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {147 .tlv_pageoff => {
164 const RegInfo = struct {148 const RegInfo = struct {
165 rd: u5,149 rd: u5,
166 rn: u5,150 rn: u5,
167 size: u2,151 size: u2,
168 };152 };
169 const reg_info: RegInfo = blk: {153 const reg_info: RegInfo = blk: {
170 if (isArithmeticOp(buffer)) {154 if (isArithmeticOp(buffer[0..4])) {
171 const inst = mem.bytesToValue(meta.TagPayload(155 const inst = mem.bytesToValue(meta.TagPayload(
172 aarch64.Instruction,156 aarch64.Instruction,
173 aarch64.Instruction.add_subtract_immediate,157 aarch64.Instruction.add_subtract_immediate,
174 ), buffer);158 ), buffer[0..4]);
175 break :blk .{159 break :blk .{
176 .rd = inst.rd,160 .rd = inst.rd,
177 .rn = inst.rn,161 .rn = inst.rn,
...@@ -181,7 +165,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -181,7 +165,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
181 const inst = mem.bytesToValue(meta.TagPayload(165 const inst = mem.bytesToValue(meta.TagPayload(
182 aarch64.Instruction,166 aarch64.Instruction,
183 aarch64.Instruction.load_store_register,167 aarch64.Instruction.load_store_register,
184 ), buffer);168 ), buffer[0..4]);
185 break :blk .{169 break :blk .{
186 .rd = inst.rt,170 .rd = inst.rt,
187 .rn = inst.rn,171 .rn = inst.rn,
...@@ -201,45 +185,24 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []...@@ -201,45 +185,24 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []
201 .sf = @truncate(u1, reg_info.size),185 .sf = @truncate(u1, reg_info.size),
202 },186 },
203 };187 };
204 mem.writeIntLittle(u32, buffer, inst.toU32());188 mem.writeIntLittle(u32, buffer[0..4], inst.toU32());
205 },189 },
206 .ARM64_RELOC_POINTER_TO_GOT => {190 .unsigned => switch (self.length) {
207 const result = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr));191 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))),
208 mem.writeIntLittle(i32, buffer, result);192 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)),
193 else => unreachable,
209 },194 },
210 .ARM64_RELOC_SUBTRACTOR => unreachable,195 .got, .signed, .tlv => unreachable, // Invalid target architecture.
211 .ARM64_RELOC_ADDEND => unreachable,
212 .ARM64_RELOC_UNSIGNED => unreachable,
213 }196 }
214}197}
215198
216fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {199fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void {
217 const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type);200 switch (self.type) {
218 switch (rel_type) {201 .branch, .got, .tlv, .signed => {
219 .X86_64_RELOC_BRANCH,
220 .X86_64_RELOC_GOT,
221 .X86_64_RELOC_GOT_LOAD,
222 .X86_64_RELOC_TLV,
223 => {
224 const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);202 const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4);
225 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));203 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
226 },204 },
227 .X86_64_RELOC_SIGNED,205 .unsigned => {
228 .X86_64_RELOC_SIGNED_1,
229 .X86_64_RELOC_SIGNED_2,
230 .X86_64_RELOC_SIGNED_4,
231 => {
232 const correction: u3 = switch (rel_type) {
233 .X86_64_RELOC_SIGNED => 0,
234 .X86_64_RELOC_SIGNED_1 => 1,
235 .X86_64_RELOC_SIGNED_2 => 2,
236 .X86_64_RELOC_SIGNED_4 => 4,
237 else => unreachable,
238 };
239 const displacement = @intCast(i32, target_addr - @intCast(i64, source_addr + correction + 4));
240 mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement));
241 },
242 .X86_64_RELOC_UNSIGNED => {
243 switch (self.length) {206 switch (self.length) {
244 2 => {207 2 => {
245 mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));208 mem.writeIntLittle(u32, code[self.offset..][0..4], @truncate(u32, @bitCast(u64, target_addr)));
...@@ -250,7 +213,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8...@@ -250,7 +213,7 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
250 else => unreachable,213 else => unreachable,
251 }214 }
252 },215 },
253 .X86_64_RELOC_SUBTRACTOR => unreachable,216 .got_page, .got_pageoff, .page, .pageoff, .tlv_page, .tlv_pageoff => unreachable, // Invalid target architecture.
254 }217 }
255}218}
256219
...@@ -258,3 +221,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool {...@@ -258,3 +221,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool {
258 const group_decode = @truncate(u5, inst[3]);221 const group_decode = @truncate(u5, inst[3]);
259 return ((group_decode >> 2) == 4);222 return ((group_decode >> 2) == 4);
260}223}
224
225const Relocation = @This();
226
227const std = @import("std");
228const aarch64 = @import("../../arch/aarch64/bits.zig");
229const assert = std.debug.assert;
230const log = std.log.scoped(.link);
231const macho = std.macho;
232const math = std.math;
233const mem = std.mem;
234const meta = std.meta;
235
236const Atom = @import("Atom.zig");
237const MachO = @import("../MachO.zig");
238const SymbolWithLoc = MachO.SymbolWithLoc;