| author | |
| committer | |
| log | eba280ce20d308ec0abb17719ab4cc43a27901eb |
| tree | b9bbac734e4c82bb2487f0921e26fce627291578 |
| parent | 1795b8eb4e8db95cb639349c6c1bc4b0b82741bb |
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 | 673 | const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = relocation.atom_index, .file = null }).?; |
| 674 | 674 | const target = macho_file.getGlobalByIndex(relocation.sym_index); |
| 675 | 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 | 677 | .target = target, |
| 678 | 678 | .offset = offset, |
| 679 | 679 | .addend = 0, |
| ... | ... | @@ -883,41 +883,32 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 883 | 883 | } |
| 884 | 884 | |
| 885 | 885 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 886 | const Atom = link.File.MachO.Atom; | |
| 887 | const Relocation = Atom.Relocation; | |
| 886 | 888 | const atom_index = macho_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; |
| 887 | // TODO this causes segfault in stage1 | |
| 888 | // try atom.addRelocations(macho_file, 2, .{ | |
| 889 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ | |
| 889 | try Atom.addRelocations(macho_file, atom_index, &[_]Relocation{ .{ | |
| 890 | 890 | .target = .{ .sym_index = data.sym_index, .file = null }, |
| 891 | 891 | .offset = offset, |
| 892 | 892 | .addend = 0, |
| 893 | 893 | .pcrel = true, |
| 894 | 894 | .length = 2, |
| 895 | 895 | .type = switch (tag) { |
| 896 | .load_memory_got, | |
| 897 | .load_memory_ptr_got, | |
| 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), | |
| 896 | .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_page, | |
| 897 | .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.page, | |
| 902 | 898 | else => unreachable, |
| 903 | 899 | }, |
| 904 | }); | |
| 905 | try link.File.MachO.Atom.addRelocation(macho_file, atom_index, .{ | |
| 900 | }, .{ | |
| 906 | 901 | .target = .{ .sym_index = data.sym_index, .file = null }, |
| 907 | 902 | .offset = offset + 4, |
| 908 | 903 | .addend = 0, |
| 909 | 904 | .pcrel = false, |
| 910 | 905 | .length = 2, |
| 911 | 906 | .type = switch (tag) { |
| 912 | .load_memory_got, | |
| 913 | .load_memory_ptr_got, | |
| 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), | |
| 907 | .load_memory_got, .load_memory_ptr_got => Relocation.Type.got_pageoff, | |
| 908 | .load_memory_direct, .load_memory_ptr_direct => Relocation.Type.pageoff, | |
| 918 | 909 | else => unreachable, |
| 919 | 910 | }, |
| 920 | }); | |
| 911 | } }); | |
| 921 | 912 | } else if (emit.bin_file.cast(link.File.Coff)) |coff_file| { |
| 922 | 913 | const atom_index = coff_file.getAtomIndexForSymbol(.{ .sym_index = data.atom_index, .file = null }).?; |
| 923 | 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 | 42 | ).?; |
| 43 | 43 | const target = macho_file.getGlobalByIndex(inst.data.relocation.sym_index); |
| 44 | 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 | 46 | .target = target, |
| 47 | 47 | .offset = end_offset - 4, |
| 48 | 48 | .addend = 0, |
| ... | ... | @@ -68,17 +68,16 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 68 | 68 | .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 69 | 69 | const metadata = |
| 70 | 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 | 71 | const atom_index = macho_file.getAtomIndexForSymbol(.{ |
| 77 | 72 | .sym_index = metadata.atom_index, |
| 78 | 73 | .file = null, |
| 79 | 74 | }).?; |
| 80 | 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 | 81 | .target = .{ .sym_index = metadata.sym_index, .file = null }, |
| 83 | 82 | .offset = @intCast(u32, end_offset - 4), |
| 84 | 83 | .addend = 0, |
src/link/MachO.zig+17-51| ... | ... | @@ -1250,11 +1250,7 @@ pub fn createGotAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { |
| 1250 | 1250 | log.debug("allocated GOT atom at 0x{x}", .{sym.n_value}); |
| 1251 | 1251 | |
| 1252 | 1252 | try Atom.addRelocation(self, atom_index, .{ |
| 1253 | .type = switch (self.base.options.target.cpu.arch) { | |
| 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 | }, | |
| 1253 | .type = .unsigned, | |
| 1258 | 1254 | .target = target, |
| 1259 | 1255 | .offset = 0, |
| 1260 | 1256 | .addend = 0, |
| ... | ... | @@ -1336,15 +1332,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1336 | 1332 | code[9] = 0xff; |
| 1337 | 1333 | code[10] = 0x25; |
| 1338 | 1334 | |
| 1339 | try Atom.addRelocations(self, atom_index, 2, .{ .{ | |
| 1340 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_SIGNED), | |
| 1335 | try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{ | |
| 1336 | .type = .signed, | |
| 1341 | 1337 | .target = dyld_private, |
| 1342 | 1338 | .offset = 3, |
| 1343 | 1339 | .addend = 0, |
| 1344 | 1340 | .pcrel = true, |
| 1345 | 1341 | .length = 2, |
| 1346 | 1342 | }, .{ |
| 1347 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_GOT), | |
| 1343 | .type = .got, | |
| 1348 | 1344 | .target = dyld_stub_binder, |
| 1349 | 1345 | .offset = 11, |
| 1350 | 1346 | .addend = 0, |
| ... | ... | @@ -1376,29 +1372,29 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 1376 | 1372 | // br x16 |
| 1377 | 1373 | mem.writeIntLittle(u32, code[20..][0..4], aarch64.Instruction.br(.x16).toU32()); |
| 1378 | 1374 | |
| 1379 | try Atom.addRelocations(self, atom_index, 4, .{ .{ | |
| 1380 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), | |
| 1375 | try Atom.addRelocations(self, atom_index, &[_]Relocation{ .{ | |
| 1376 | .type = .page, | |
| 1381 | 1377 | .target = dyld_private, |
| 1382 | 1378 | .offset = 0, |
| 1383 | 1379 | .addend = 0, |
| 1384 | 1380 | .pcrel = true, |
| 1385 | 1381 | .length = 2, |
| 1386 | 1382 | }, .{ |
| 1387 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), | |
| 1383 | .type = .pageoff, | |
| 1388 | 1384 | .target = dyld_private, |
| 1389 | 1385 | .offset = 4, |
| 1390 | 1386 | .addend = 0, |
| 1391 | 1387 | .pcrel = false, |
| 1392 | 1388 | .length = 2, |
| 1393 | 1389 | }, .{ |
| 1394 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), | |
| 1390 | .type = .got_page, | |
| 1395 | 1391 | .target = dyld_stub_binder, |
| 1396 | 1392 | .offset = 12, |
| 1397 | 1393 | .addend = 0, |
| 1398 | 1394 | .pcrel = true, |
| 1399 | 1395 | .length = 2, |
| 1400 | 1396 | }, .{ |
| 1401 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12), | |
| 1397 | .type = .got_pageoff, | |
| 1402 | 1398 | .target = dyld_stub_binder, |
| 1403 | 1399 | .offset = 16, |
| 1404 | 1400 | .addend = 0, |
| ... | ... | @@ -1456,7 +1452,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index { |
| 1456 | 1452 | code[5] = 0xe9; |
| 1457 | 1453 | |
| 1458 | 1454 | try Atom.addRelocation(self, atom_index, .{ |
| 1459 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), | |
| 1455 | .type = .branch, | |
| 1460 | 1456 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, |
| 1461 | 1457 | .offset = 6, |
| 1462 | 1458 | .addend = 0, |
| ... | ... | @@ -1479,7 +1475,7 @@ fn createStubHelperAtom(self: *MachO) !Atom.Index { |
| 1479 | 1475 | // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 1480 | 1476 | |
| 1481 | 1477 | try Atom.addRelocation(self, atom_index, .{ |
| 1482 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_BRANCH26), | |
| 1478 | .type = .branch, | |
| 1483 | 1479 | .target = .{ .sym_index = stub_helper_preamble_atom_sym_index, .file = null }, |
| 1484 | 1480 | .offset = 4, |
| 1485 | 1481 | .addend = 0, |
| ... | ... | @@ -1507,11 +1503,7 @@ fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLo |
| 1507 | 1503 | sym.n_sect = self.la_symbol_ptr_section_index.? + 1; |
| 1508 | 1504 | |
| 1509 | 1505 | try Atom.addRelocation(self, atom_index, .{ |
| 1510 | .type = switch (self.base.options.target.cpu.arch) { | |
| 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 | }, | |
| 1506 | .type = .unsigned, | |
| 1515 | 1507 | .target = .{ .sym_index = stub_sym_index, .file = null }, |
| 1516 | 1508 | .offset = 0, |
| 1517 | 1509 | .addend = 0, |
| ... | ... | @@ -1565,7 +1557,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1565 | 1557 | code[1] = 0x25; |
| 1566 | 1558 | |
| 1567 | 1559 | try Atom.addRelocation(self, atom_index, .{ |
| 1568 | .type = @enumToInt(macho.reloc_type_x86_64.X86_64_RELOC_BRANCH), | |
| 1560 | .type = .branch, | |
| 1569 | 1561 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1570 | 1562 | .offset = 2, |
| 1571 | 1563 | .addend = 0, |
| ... | ... | @@ -1585,9 +1577,9 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1585 | 1577 | // br x16 |
| 1586 | 1578 | mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32()); |
| 1587 | 1579 | |
| 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 | 1583 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1592 | 1584 | .offset = 0, |
| 1593 | 1585 | .addend = 0, |
| ... | ... | @@ -1595,7 +1587,7 @@ fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index { |
| 1595 | 1587 | .length = 2, |
| 1596 | 1588 | }, |
| 1597 | 1589 | .{ |
| 1598 | .type = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12), | |
| 1590 | .type = .pageoff, | |
| 1599 | 1591 | .target = .{ .sym_index = laptr_sym_index, .file = null }, |
| 1600 | 1592 | .offset = 4, |
| 1601 | 1593 | .addend = 0, |
| ... | ... | @@ -2663,11 +2655,7 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil |
| 2663 | 2655 | const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; |
| 2664 | 2656 | const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; |
| 2665 | 2657 | try Atom.addRelocation(self, atom_index, .{ |
| 2666 | .type = switch (self.base.options.target.cpu.arch) { | |
| 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 | }, | |
| 2658 | .type = .unsigned, | |
| 2671 | 2659 | .target = .{ .sym_index = sym_index, .file = null }, |
| 2672 | 2660 | .offset = @intCast(u32, reloc_info.offset), |
| 2673 | 2661 | .addend = reloc_info.addend, |
| ... | ... | @@ -3115,28 +3103,6 @@ fn allocateAtom(self: *MachO, atom_index: Atom.Index, new_atom_size: u64, alignm |
| 3115 | 3103 | return vaddr; |
| 3116 | 3104 | } |
| 3117 | 3105 | |
| 3118 | fn 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 | ||
| 3140 | 3106 | pub fn getGlobalSymbol(self: *MachO, name: []const u8, lib_name: ?[]const u8) !u32 { |
| 3141 | 3107 | _ = lib_name; |
| 3142 | 3108 | const gpa = self.base.allocator; |
src/link/MachO/Atom.zig+5-11| ... | ... | @@ -14,7 +14,7 @@ const trace = @import("../../tracy.zig").trace; |
| 14 | 14 | const Allocator = mem.Allocator; |
| 15 | 15 | const Arch = std.Target.Cpu.Arch; |
| 16 | 16 | const MachO = @import("../MachO.zig"); |
| 17 | const Relocation = @import("Relocation.zig"); | |
| 17 | pub const Relocation = @import("Relocation.zig"); | |
| 18 | 18 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 19 | 19 | |
| 20 | 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 | 113 | } |
| 114 | 114 | |
| 115 | 115 | pub 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 | } |
| 118 | 118 | |
| 119 | pub fn addRelocations( | |
| 120 | macho_file: *MachO, | |
| 121 | atom_index: Index, | |
| 122 | comptime count: comptime_int, | |
| 123 | relocs: [count]Relocation, | |
| 124 | ) !void { | |
| 119 | pub fn addRelocations(macho_file: *MachO, atom_index: Index, relocs: []Relocation) !void { | |
| 125 | 120 | const gpa = macho_file.base.allocator; |
| 126 | const target = macho_file.base.options.target; | |
| 127 | 121 | const gop = try macho_file.relocs.getOrPut(gpa, atom_index); |
| 128 | 122 | if (!gop.found_existing) { |
| 129 | 123 | gop.value_ptr.* = .{}; |
| 130 | 124 | } |
| 131 | try gop.value_ptr.ensureUnusedCapacity(gpa, count); | |
| 125 | try gop.value_ptr.ensureUnusedCapacity(gpa, relocs.len); | |
| 132 | 126 | for (relocs) |reloc| { |
| 133 | 127 | log.debug(" (adding reloc of type {s} to target %{d})", .{ |
| 134 | reloc.fmtType(target), | |
| 128 | @tagName(reloc.type), | |
| 135 | 129 | reloc.target.sym_index, |
| 136 | 130 | }); |
| 137 | 131 | gop.value_ptr.appendAssumeCapacity(reloc); |
src/link/MachO/Relocation.zig+80-102| ... | ... | @@ -1,19 +1,7 @@ |
| 1 | const Relocation = @This(); | |
| 2 | ||
| 3 | const std = @import("std"); | |
| 4 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | |
| 5 | const assert = std.debug.assert; | |
| 6 | const log = std.log.scoped(.link); | |
| 7 | const macho = std.macho; | |
| 8 | const math = std.math; | |
| 9 | const mem = std.mem; | |
| 10 | const meta = std.meta; | |
| 11 | ||
| 12 | const Atom = @import("Atom.zig"); | |
| 13 | const MachO = @import("../MachO.zig"); | |
| 14 | const SymbolWithLoc = MachO.SymbolWithLoc; | |
| 1 | //! Relocation used by the self-hosted backends to instruct the linker where and how to | |
| 2 | //! fixup the values when flushing the contents to file and/or memory. | |
| 15 | 3 | |
| 16 | type: u4, | |
| 4 | type: Type, | |
| 17 | 5 | target: SymbolWithLoc, |
| 18 | 6 | offset: u32, |
| 19 | 7 | addend: i64, |
| ... | ... | @@ -21,36 +9,46 @@ pcrel: bool, |
| 21 | 9 | length: u2, |
| 22 | 10 | dirty: bool = true, |
| 23 | 11 | |
| 12 | pub 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 | 42 | /// Returns true if and only if the reloc is dirty AND the target address is available. |
| 25 | 43 | pub fn isResolvable(self: Relocation, macho_file: *MachO) bool { |
| 26 | 44 | _ = self.getTargetAtomIndex(macho_file) orelse return false; |
| 27 | 45 | return self.dirty; |
| 28 | 46 | } |
| 29 | 47 | |
| 30 | pub 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 | ||
| 38 | 48 | pub fn getTargetAtomIndex(self: Relocation, macho_file: *MachO) ?Atom.Index { |
| 39 | switch (macho_file.base.options.target.cpu.arch) { | |
| 40 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.type)) { | |
| 41 | .ARM64_RELOC_GOT_LOAD_PAGE21, | |
| 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, | |
| 49 | switch (self.type) { | |
| 50 | .got, .got_page, .got_pageoff => return macho_file.getGotAtomIndexForSymbol(self.target), | |
| 51 | else => {}, | |
| 54 | 52 | } |
| 55 | 53 | if (macho_file.getStubsAtomIndexForSymbol(self.target)) |stubs_atom| return stubs_atom; |
| 56 | 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 | 68 | source_addr, |
| 71 | 69 | target_addr, |
| 72 | 70 | macho_file.getSymbolName(self.target), |
| 73 | self.fmtType(macho_file.base.options.target), | |
| 71 | @tagName(self.type), | |
| 74 | 72 | }); |
| 75 | 73 | |
| 76 | 74 | switch (arch) { |
| ... | ... | @@ -81,18 +79,9 @@ pub fn resolve(self: Relocation, macho_file: *MachO, atom_index: Atom.Index, cod |
| 81 | 79 | } |
| 82 | 80 | |
| 83 | 81 | fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void { |
| 84 | const rel_type = @intToEnum(macho.reloc_type_arm64, self.type); | |
| 85 | if (rel_type == .ARM64_RELOC_UNSIGNED) { | |
| 86 | return switch (self.length) { | |
| 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 => { | |
| 82 | var buffer = code[self.offset..]; | |
| 83 | switch (self.type) { | |
| 84 | .branch => { | |
| 96 | 85 | const displacement = math.cast( |
| 97 | 86 | i28, |
| 98 | 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 | 90 | .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload( |
| 102 | 91 | aarch64.Instruction, |
| 103 | 92 | aarch64.Instruction.unconditional_branch_immediate, |
| 104 | ), buffer), | |
| 93 | ), buffer[0..4]), | |
| 105 | 94 | }; |
| 106 | 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, | |
| 110 | .ARM64_RELOC_GOT_LOAD_PAGE21, | |
| 111 | .ARM64_RELOC_TLVP_LOAD_PAGE21, | |
| 112 | => { | |
| 98 | .page, .got_page, .tlv_page => { | |
| 113 | 99 | const source_page = @intCast(i32, source_addr >> 12); |
| 114 | 100 | const target_page = @intCast(i32, target_addr >> 12); |
| 115 | 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 | 103 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( |
| 118 | 104 | aarch64.Instruction, |
| 119 | 105 | aarch64.Instruction.pc_relative_address, |
| 120 | ), buffer), | |
| 106 | ), buffer[0..4]), | |
| 121 | 107 | }; |
| 122 | 108 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); |
| 123 | 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, | |
| 127 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | |
| 128 | => { | |
| 112 | .pageoff, .got_pageoff => { | |
| 129 | 113 | const narrowed = @truncate(u12, @intCast(u64, target_addr)); |
| 130 | if (isArithmeticOp(buffer)) { | |
| 114 | if (isArithmeticOp(buffer[0..4])) { | |
| 131 | 115 | var inst = aarch64.Instruction{ |
| 132 | 116 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( |
| 133 | 117 | aarch64.Instruction, |
| 134 | 118 | aarch64.Instruction.add_subtract_immediate, |
| 135 | ), buffer), | |
| 119 | ), buffer[0..4]), | |
| 136 | 120 | }; |
| 137 | 121 | inst.add_subtract_immediate.imm12 = narrowed; |
| 138 | mem.writeIntLittle(u32, buffer, inst.toU32()); | |
| 122 | mem.writeIntLittle(u32, buffer[0..4], inst.toU32()); | |
| 139 | 123 | } else { |
| 140 | 124 | var inst = aarch64.Instruction{ |
| 141 | 125 | .load_store_register = mem.bytesToValue(meta.TagPayload( |
| 142 | 126 | aarch64.Instruction, |
| 143 | 127 | aarch64.Instruction.load_store_register, |
| 144 | ), buffer), | |
| 128 | ), buffer[0..4]), | |
| 145 | 129 | }; |
| 146 | 130 | const offset: u12 = blk: { |
| 147 | 131 | if (inst.load_store_register.size == 0) { |
| ... | ... | @@ -157,21 +141,21 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: [] |
| 157 | 141 | } |
| 158 | 142 | }; |
| 159 | 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 | 148 | const RegInfo = struct { |
| 165 | 149 | rd: u5, |
| 166 | 150 | rn: u5, |
| 167 | 151 | size: u2, |
| 168 | 152 | }; |
| 169 | 153 | const reg_info: RegInfo = blk: { |
| 170 | if (isArithmeticOp(buffer)) { | |
| 154 | if (isArithmeticOp(buffer[0..4])) { | |
| 171 | 155 | const inst = mem.bytesToValue(meta.TagPayload( |
| 172 | 156 | aarch64.Instruction, |
| 173 | 157 | aarch64.Instruction.add_subtract_immediate, |
| 174 | ), buffer); | |
| 158 | ), buffer[0..4]); | |
| 175 | 159 | break :blk .{ |
| 176 | 160 | .rd = inst.rd, |
| 177 | 161 | .rn = inst.rn, |
| ... | ... | @@ -181,7 +165,7 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: [] |
| 181 | 165 | const inst = mem.bytesToValue(meta.TagPayload( |
| 182 | 166 | aarch64.Instruction, |
| 183 | 167 | aarch64.Instruction.load_store_register, |
| 184 | ), buffer); | |
| 168 | ), buffer[0..4]); | |
| 185 | 169 | break :blk .{ |
| 186 | 170 | .rd = inst.rt, |
| 187 | 171 | .rn = inst.rn, |
| ... | ... | @@ -201,45 +185,24 @@ fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: i64, code: [] |
| 201 | 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 => { | |
| 207 | const result = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr)); | |
| 208 | mem.writeIntLittle(i32, buffer, result); | |
| 190 | .unsigned => switch (self.length) { | |
| 191 | 2 => mem.writeIntLittle(u32, buffer[0..4], @truncate(u32, @bitCast(u64, target_addr))), | |
| 192 | 3 => mem.writeIntLittle(u64, buffer[0..8], @bitCast(u64, target_addr)), | |
| 193 | else => unreachable, | |
| 209 | 194 | }, |
| 210 | .ARM64_RELOC_SUBTRACTOR => unreachable, | |
| 211 | .ARM64_RELOC_ADDEND => unreachable, | |
| 212 | .ARM64_RELOC_UNSIGNED => unreachable, | |
| 195 | .got, .signed, .tlv => unreachable, // Invalid target architecture. | |
| 213 | 196 | } |
| 214 | 197 | } |
| 215 | 198 | |
| 216 | 199 | fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8) void { |
| 217 | const rel_type = @intToEnum(macho.reloc_type_x86_64, self.type); | |
| 218 | switch (rel_type) { | |
| 219 | .X86_64_RELOC_BRANCH, | |
| 220 | .X86_64_RELOC_GOT, | |
| 221 | .X86_64_RELOC_GOT_LOAD, | |
| 222 | .X86_64_RELOC_TLV, | |
| 223 | => { | |
| 200 | switch (self.type) { | |
| 201 | .branch, .got, .tlv, .signed => { | |
| 224 | 202 | const displacement = @intCast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4); |
| 225 | 203 | mem.writeIntLittle(u32, code[self.offset..][0..4], @bitCast(u32, displacement)); |
| 226 | 204 | }, |
| 227 | .X86_64_RELOC_SIGNED, | |
| 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 => { | |
| 205 | .unsigned => { | |
| 243 | 206 | switch (self.length) { |
| 244 | 207 | 2 => { |
| 245 | 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 | 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 | } |
| 256 | 219 | |
| ... | ... | @@ -258,3 +221,18 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool { |
| 258 | 221 | const group_decode = @truncate(u5, inst[3]); |
| 259 | 222 | return ((group_decode >> 2) == 4); |
| 260 | 223 | } |
| 224 | ||
| 225 | const Relocation = @This(); | |
| 226 | ||
| 227 | const std = @import("std"); | |
| 228 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | |
| 229 | const assert = std.debug.assert; | |
| 230 | const log = std.log.scoped(.link); | |
| 231 | const macho = std.macho; | |
| 232 | const math = std.math; | |
| 233 | const mem = std.mem; | |
| 234 | const meta = std.meta; | |
| 235 | ||
| 236 | const Atom = @import("Atom.zig"); | |
| 237 | const MachO = @import("../MachO.zig"); | |
| 238 | const SymbolWithLoc = MachO.SymbolWithLoc; |