| author | |
| committer | |
| log | 26af8d254af5277e36cc78e1ab99241dee199c37 |
| tree | effe8f6b663962ea5e2a06d389a4e93b5c97b71c |
| parent | 54854e2ab87e667751f2eae86f41b9d41bcfda9d |
3 files changed, 408 insertions(+), 1 deletions(-)
src/link/MachO.zig+85-1| ... | @@ -38,6 +38,8 @@ const LibStub = @import("tapi.zig").LibStub; | ... | @@ -38,6 +38,8 @@ const LibStub = @import("tapi.zig").LibStub; |
| 38 | const Liveness = @import("../Liveness.zig"); | 38 | const Liveness = @import("../Liveness.zig"); |
| 39 | const LlvmObject = @import("../codegen/llvm.zig").Object; | 39 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 40 | const Module = @import("../Module.zig"); | 40 | const Module = @import("../Module.zig"); |
| 41 | const Relocation = @import("MachO/Relocation.zig"); | ||
| 42 | const RelocationTable = Relocation.Table; | ||
| 41 | const StringTable = @import("strtab.zig").StringTable; | 43 | const StringTable = @import("strtab.zig").StringTable; |
| 42 | const Trie = @import("MachO/Trie.zig"); | 44 | const Trie = @import("MachO/Trie.zig"); |
| 43 | const Type = @import("../type.zig").Type; | 45 | const Type = @import("../type.zig").Type; |
| ... | @@ -193,6 +195,11 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, | ... | @@ -193,6 +195,11 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, *Atom) = .{}, |
| 193 | /// with `Decl` `main`, and lives as long as that `Decl`. | 195 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 194 | unnamed_const_atoms: UnnamedConstTable = .{}, | 196 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 195 | 197 | ||
| 198 | /// A table of relocations indexed by the owning them `Atom`. | ||
| 199 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, | ||
| 200 | /// this will be a table indexed by index into the list of Atoms. | ||
| 201 | relocs: RelocationTable = .{}, | ||
| 202 | |||
| 196 | /// Table of Decls that are currently alive. | 203 | /// Table of Decls that are currently alive. |
| 197 | /// We store them here so that we can properly dispose of any allocated | 204 | /// We store them here so that we can properly dispose of any allocated |
| 198 | /// memory within the atom in the incremental linker. | 205 | /// memory within the atom in the incremental linker. |
| ... | @@ -1854,11 +1861,80 @@ pub fn writeAtom(self: *MachO, atom: *Atom, sect_id: u8) !void { | ... | @@ -1854,11 +1861,80 @@ pub fn writeAtom(self: *MachO, atom: *Atom, sect_id: u8) !void { |
| 1854 | const section = self.sections.get(sect_id); | 1861 | const section = self.sections.get(sect_id); |
| 1855 | const sym = atom.getSymbol(self); | 1862 | const sym = atom.getSymbol(self); |
| 1856 | const file_offset = section.header.offset + sym.n_value - section.header.addr; | 1863 | const file_offset = section.header.offset + sym.n_value - section.header.addr; |
| 1857 | try atom.resolveRelocs(self); | ||
| 1858 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); | 1864 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ atom.getName(self), file_offset }); |
| 1859 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); | 1865 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 1860 | } | 1866 | } |
| 1861 | 1867 | ||
| 1868 | // fn markRelocsDirtyByTarget(self: *MachO, target: SymbolWithLoc) void { | ||
| 1869 | // // TODO: reverse-lookup might come in handy here | ||
| 1870 | // var it = self.relocs.valueIterator(); | ||
| 1871 | // while (it.next()) |relocs| { | ||
| 1872 | // for (relocs.items) |*reloc| { | ||
| 1873 | // if (!reloc.target.eql(target)) continue; | ||
| 1874 | // reloc.dirty = true; | ||
| 1875 | // } | ||
| 1876 | // } | ||
| 1877 | // } | ||
| 1878 | |||
| 1879 | // fn markRelocsDirtyByAddress(self: *MachO, addr: u32) void { | ||
| 1880 | // var it = self.relocs.valueIterator(); | ||
| 1881 | // while (it.next()) |relocs| { | ||
| 1882 | // for (relocs.items) |*reloc| { | ||
| 1883 | // const target_atom = reloc.getTargetAtom(self) orelse continue; | ||
| 1884 | // const target_sym = target_atom.getSymbol(self); | ||
| 1885 | // if (target_sym.value < addr) continue; | ||
| 1886 | // reloc.dirty = true; | ||
| 1887 | // } | ||
| 1888 | // } | ||
| 1889 | // } | ||
| 1890 | |||
| 1891 | // fn resolveRelocs(self: *MachO, atom: *Atom) !void { | ||
| 1892 | // const relocs = self.relocs.get(atom) orelse return; | ||
| 1893 | // const source_sym = atom.getSymbol(self); | ||
| 1894 | // const source_section = self.sections.get(@enumToInt(source_sym.section_number) - 1).header; | ||
| 1895 | // const file_offset = section.offset + source_sym.n_value - section.addr; | ||
| 1896 | |||
| 1897 | // log.debug("relocating '{s}'", .{atom.getName(self)}); | ||
| 1898 | |||
| 1899 | // for (relocs.items) |*reloc| { | ||
| 1900 | // if (!reloc.dirty) continue; | ||
| 1901 | |||
| 1902 | // const target_atom = reloc.getTargetAtom(self) orelse continue; | ||
| 1903 | // const target_vaddr = target_atom.getSymbol(self).value; | ||
| 1904 | // const target_vaddr_with_addend = target_vaddr + reloc.addend; | ||
| 1905 | |||
| 1906 | // log.debug(" ({x}: [() => 0x{x} ({s})) ({s}) (in file at 0x{x})", .{ | ||
| 1907 | // source_sym.value + reloc.offset, | ||
| 1908 | // target_vaddr_with_addend, | ||
| 1909 | // self.getSymbolName(reloc.target), | ||
| 1910 | // @tagName(reloc.@"type"), | ||
| 1911 | // file_offset + reloc.offset, | ||
| 1912 | // }); | ||
| 1913 | |||
| 1914 | // reloc.dirty = false; | ||
| 1915 | |||
| 1916 | // if (reloc.pcrel) { | ||
| 1917 | // const source_vaddr = source_sym.value + reloc.offset; | ||
| 1918 | // const disp = | ||
| 1919 | // @intCast(i32, target_vaddr_with_addend) - @intCast(i32, source_vaddr) - 4; | ||
| 1920 | // try self.base.file.?.pwriteAll(mem.asBytes(&disp), file_offset + reloc.offset); | ||
| 1921 | // continue; | ||
| 1922 | // } | ||
| 1923 | |||
| 1924 | // switch (reloc.length) { | ||
| 1925 | // 2 => try self.base.file.?.pwriteAll( | ||
| 1926 | // mem.asBytes(&@truncate(u32, target_vaddr_with_addend)), | ||
| 1927 | // file_offset + reloc.offset, | ||
| 1928 | // ), | ||
| 1929 | // 3 => try self.base.file.?.pwriteAll( | ||
| 1930 | // mem.asBytes(&(target_vaddr_with_addend)), | ||
| 1931 | // file_offset + reloc.offset, | ||
| 1932 | // ), | ||
| 1933 | // else => unreachable, | ||
| 1934 | // } | ||
| 1935 | // } | ||
| 1936 | // } | ||
| 1937 | |||
| 1862 | fn allocateSymbols(self: *MachO) !void { | 1938 | fn allocateSymbols(self: *MachO) !void { |
| 1863 | const slice = self.sections.slice(); | 1939 | const slice = self.sections.slice(); |
| 1864 | for (slice.items(.last_atom)) |last_atom, sect_id| { | 1940 | for (slice.items(.last_atom)) |last_atom, sect_id| { |
| ... | @@ -3069,6 +3145,14 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3069,6 +3145,14 @@ pub fn deinit(self: *MachO) void { |
| 3069 | } | 3145 | } |
| 3070 | 3146 | ||
| 3071 | self.atom_by_index_table.deinit(gpa); | 3147 | self.atom_by_index_table.deinit(gpa); |
| 3148 | |||
| 3149 | { | ||
| 3150 | var it = self.relocs.valueIterator(); | ||
| 3151 | while (it.next()) |relocs| { | ||
| 3152 | relocs.deinit(gpa); | ||
| 3153 | } | ||
| 3154 | self.relocs.deinit(gpa); | ||
| 3155 | } | ||
| 3072 | } | 3156 | } |
| 3073 | 3157 | ||
| 3074 | fn freeAtom(self: *MachO, atom: *Atom, sect_id: u8, owns_atom: bool) void { | 3158 | fn freeAtom(self: *MachO, atom: *Atom, sect_id: u8, owns_atom: bool) void { |
src/link/MachO/Atom.zig+46| ... | @@ -16,6 +16,7 @@ const Arch = std.Target.Cpu.Arch; | ... | @@ -16,6 +16,7 @@ const Arch = std.Target.Cpu.Arch; |
| 16 | const Dwarf = @import("../Dwarf.zig"); | 16 | const Dwarf = @import("../Dwarf.zig"); |
| 17 | const MachO = @import("../MachO.zig"); | 17 | const MachO = @import("../MachO.zig"); |
| 18 | const Object = @import("Object.zig"); | 18 | const Object = @import("Object.zig"); |
| 19 | const RelocationIncr = @import("Relocation.zig"); // temporary name until we clean up object-file relocation scanning | ||
| 19 | const SymbolWithLoc = MachO.SymbolWithLoc; | 20 | const SymbolWithLoc = MachO.SymbolWithLoc; |
| 20 | 21 | ||
| 21 | /// Each decl always gets a local symbol with the fully qualified name. | 22 | /// Each decl always gets a local symbol with the fully qualified name. |
| ... | @@ -894,3 +895,48 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool { | ... | @@ -894,3 +895,48 @@ inline fn isArithmeticOp(inst: *const [4]u8) bool { |
| 894 | const group_decode = @truncate(u5, inst[3]); | 895 | const group_decode = @truncate(u5, inst[3]); |
| 895 | return ((group_decode >> 2) == 4); | 896 | return ((group_decode >> 2) == 4); |
| 896 | } | 897 | } |
| 898 | |||
| 899 | pub fn addRelocation(self: *Atom, macho_file: *MachO, reloc: RelocationIncr) !void { | ||
| 900 | const gpa = macho_file.base.allocator; | ||
| 901 | log.debug(" (adding reloc of type {s} to target %{d})", .{ @tagName(reloc.@"type"), reloc.target.sym_index }); | ||
| 902 | const gop = try macho_file.relocs.getOrPut(gpa, self); | ||
| 903 | if (!gop.found_existing) { | ||
| 904 | gop.value_ptr.* = .{}; | ||
| 905 | } | ||
| 906 | try gop.value_ptr.append(gpa, reloc); | ||
| 907 | } | ||
| 908 | |||
| 909 | pub fn resolveRelocationsInCodeBuffer(self: *Atom, macho_file: *MachO, code: []u8) !void { | ||
| 910 | const relocs = macho_file.relocs.get(self) orelse return; | ||
| 911 | |||
| 912 | log.debug("relocating '{s}'", .{self.getName(macho_file)}); | ||
| 913 | |||
| 914 | for (relocs.items) |*reloc| { | ||
| 915 | // We don't check for dirty relocation as we resolve in memory so it's effectively free. | ||
| 916 | try reloc.resolve(self, macho_file, code); | ||
| 917 | reloc.dirty = false; | ||
| 918 | } | ||
| 919 | } | ||
| 920 | |||
| 921 | pub fn resolveRelocationsInFile(self: *Atom, macho_file: *MachO) !void { | ||
| 922 | const relocs = macho_file.relocs.get(self) orelse return; | ||
| 923 | const gpa = macho_file.base.allocator; | ||
| 924 | |||
| 925 | // No code available in a buffer; we need to read it in from the binary. | ||
| 926 | const source_sym = self.getSymbol(macho_file); | ||
| 927 | const source_section = macho_file.sections.get(source_sym.n_sect - 1).header; | ||
| 928 | const file_offset = source_section.offset + source_sym.value - source_section.addr; | ||
| 929 | const code = try gpa.alloc(u8, self.size); | ||
| 930 | try self.base.file.?.preadAll(code, file_offset); | ||
| 931 | defer gpa.free(code); | ||
| 932 | |||
| 933 | log.debug("relocating '{s}'", .{self.getName(macho_file)}); | ||
| 934 | |||
| 935 | for (relocs.items) |*reloc| { | ||
| 936 | if (!reloc.dirty) continue; | ||
| 937 | try reloc.resolve(self, macho_file, code); | ||
| 938 | reloc.dirty = false; | ||
| 939 | } | ||
| 940 | |||
| 941 | try self.base.file.?.pwriteAll(code, file_offset); | ||
| 942 | } |
src/link/MachO/Relocation.zig created+277| ... | @@ -0,0 +1,277 @@ | ||
| 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; | ||
| 15 | |||
| 16 | pub const Table = std.AutoHashMapUnmanaged(*Atom, std.ArrayListUnmanaged(Relocation)); | ||
| 17 | |||
| 18 | /// Offset within the atom's code buffer. | ||
| 19 | /// Note relocation size can be inferred by relocation's kind. | ||
| 20 | offset: u32, | ||
| 21 | target: SymbolWithLoc, | ||
| 22 | addend: i64, | ||
| 23 | pcrel: bool, | ||
| 24 | length: u2, | ||
| 25 | @"type": u4, | ||
| 26 | dirty: bool = true, | ||
| 27 | |||
| 28 | pub fn getTargetAtom(self: Relocation, macho_file: *MachO) ?*Atom { | ||
| 29 | switch (macho_file.base.options.target.cpu.arch) { | ||
| 30 | .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, self.@"type")) { | ||
| 31 | .ARM64_RELOC_GOT_LOAD_PAGE21, | ||
| 32 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12, | ||
| 33 | .ARM64_RELOC_POINTER_TO_GOT, | ||
| 34 | => return macho_file.getGotAtomForSymbol(self.target).?, | ||
| 35 | else => {}, | ||
| 36 | }, | ||
| 37 | .x86_64 => switch (@intToEnum(macho.reloc_type_x86_64, self.@"type")) { | ||
| 38 | .X86_64_RELOC_GOT, | ||
| 39 | .X86_64_RELOC_GOT_LOAD, | ||
| 40 | => return macho_file.getGotAtomForSymbol(self.target).?, | ||
| 41 | else => {}, | ||
| 42 | }, | ||
| 43 | else => unreachable, | ||
| 44 | } | ||
| 45 | if (macho_file.getStubsAtomForSymbol(self.target)) |stubs_atom| return stubs_atom; | ||
| 46 | if (macho_file.getTlvPtrAtomForSymbol(self.target)) |tlv_ptr_atom| return tlv_ptr_atom; | ||
| 47 | return macho_file.getAtomForSymbol(self.target); | ||
| 48 | } | ||
| 49 | |||
| 50 | pub fn resolve(self: Relocation, atom: *Atom, macho_file: *MachO, code: []u8) !void { | ||
| 51 | const arch = macho_file.base.options.target.cpu.arch; | ||
| 52 | const source_sym = atom.getSymbol(macho_file); | ||
| 53 | const source_addr = source_sym.n_value + self.offset; | ||
| 54 | |||
| 55 | const target_atom = self.getTargetAtom(macho_file) orelse return; | ||
| 56 | const target_addr = target_atom.getSymbol(macho_file).n_value + self.addend; | ||
| 57 | |||
| 58 | log.debug(" ({x}: [() => 0x{x} ({s})) ({s})", .{ | ||
| 59 | source_addr, | ||
| 60 | target_addr, | ||
| 61 | macho_file.getSymbolName(self.target), | ||
| 62 | switch (arch) { | ||
| 63 | .aarch64 => @tagName(@intToEnum(macho.reloc_type_arm64, self.@"type")), | ||
| 64 | .x86_64 => @tagName(@intToEnum(macho.reloc_type_x86_64, self.@"type")), | ||
| 65 | else => unreachable, | ||
| 66 | }, | ||
| 67 | }); | ||
| 68 | |||
| 69 | switch (arch) { | ||
| 70 | .aarch64 => return self.resolveAarch64(source_addr, target_addr, macho_file, code), | ||
| 71 | .x86_64 => return self.resolveX8664(source_addr, target_addr, code), | ||
| 72 | else => unreachable, | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | fn resolveAarch64(self: Relocation, source_addr: u64, target_addr: u64, macho_file: *MachO, code: []u8) !void { | ||
| 77 | const rel_type = @intToEnum(macho.reloc_type_arm64, self.@"type"); | ||
| 78 | switch (rel_type) { | ||
| 79 | .ARM64_RELOC_BRANCH26 => { | ||
| 80 | const displacement = math.cast(i28, @intCast(i64, target_addr) - @intCast(i64, source_addr)) orelse { | ||
| 81 | log.err("jump too big to encode as i28 displacement value", .{}); | ||
| 82 | log.err(" (target - source) = displacement => 0x{x} - 0x{x} = 0x{x}", .{ | ||
| 83 | target_addr, | ||
| 84 | source_addr, | ||
| 85 | @intCast(i64, target_addr) - @intCast(i64, source_addr), | ||
| 86 | }); | ||
| 87 | log.err(" TODO implement branch islands to extend jump distance for arm64", .{}); | ||
| 88 | return error.TODOImplementBranchIslands; | ||
| 89 | }; | ||
| 90 | var inst = aarch64.Instruction{ | ||
| 91 | .unconditional_branch_immediate = mem.bytesToValue(meta.TagPayload( | ||
| 92 | aarch64.Instruction, | ||
| 93 | aarch64.Instruction.unconditional_branch_immediate, | ||
| 94 | ), code), | ||
| 95 | }; | ||
| 96 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); | ||
| 97 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 98 | }, | ||
| 99 | .ARM64_RELOC_PAGE21, | ||
| 100 | .ARM64_RELOC_GOT_LOAD_PAGE21, | ||
| 101 | .ARM64_RELOC_TLVP_LOAD_PAGE21, | ||
| 102 | => { | ||
| 103 | const source_page = @intCast(i32, source_addr >> 12); | ||
| 104 | const target_page = @intCast(i32, target_addr >> 12); | ||
| 105 | const pages = @bitCast(u21, @intCast(i21, target_page - source_page)); | ||
| 106 | var inst = aarch64.Instruction{ | ||
| 107 | .pc_relative_address = mem.bytesToValue(meta.TagPayload( | ||
| 108 | aarch64.Instruction, | ||
| 109 | aarch64.Instruction.pc_relative_address, | ||
| 110 | ), code), | ||
| 111 | }; | ||
| 112 | inst.pc_relative_address.immhi = @truncate(u19, pages >> 2); | ||
| 113 | inst.pc_relative_address.immlo = @truncate(u2, pages); | ||
| 114 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 115 | }, | ||
| 116 | .ARM64_RELOC_PAGEOFF12 => { | ||
| 117 | const narrowed = @truncate(u12, @intCast(u64, target_addr)); | ||
| 118 | if (isArithmeticOp(code)) { | ||
| 119 | var inst = aarch64.Instruction{ | ||
| 120 | .add_subtract_immediate = mem.bytesToValue(meta.TagPayload( | ||
| 121 | aarch64.Instruction, | ||
| 122 | aarch64.Instruction.add_subtract_immediate, | ||
| 123 | ), code), | ||
| 124 | }; | ||
| 125 | inst.add_subtract_immediate.imm12 = narrowed; | ||
| 126 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 127 | } else { | ||
| 128 | var inst = aarch64.Instruction{ | ||
| 129 | .load_store_register = mem.bytesToValue(meta.TagPayload( | ||
| 130 | aarch64.Instruction, | ||
| 131 | aarch64.Instruction.load_store_register, | ||
| 132 | ), code), | ||
| 133 | }; | ||
| 134 | const offset: u12 = blk: { | ||
| 135 | if (inst.load_store_register.size == 0) { | ||
| 136 | if (inst.load_store_register.v == 1) { | ||
| 137 | // 128-bit SIMD is scaled by 16. | ||
| 138 | break :blk try math.divExact(u12, narrowed, 16); | ||
| 139 | } | ||
| 140 | // Otherwise, 8-bit SIMD or ldrb. | ||
| 141 | break :blk narrowed; | ||
| 142 | } else { | ||
| 143 | const denom: u4 = try math.powi(u4, 2, inst.load_store_register.size); | ||
| 144 | break :blk try math.divExact(u12, narrowed, denom); | ||
| 145 | } | ||
| 146 | }; | ||
| 147 | inst.load_store_register.offset = offset; | ||
| 148 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 149 | } | ||
| 150 | }, | ||
| 151 | .ARM64_RELOC_GOT_LOAD_PAGEOFF12 => { | ||
| 152 | const narrowed = @truncate(u12, @intCast(u64, target_addr)); | ||
| 153 | var inst: aarch64.Instruction = .{ | ||
| 154 | .load_store_register = mem.bytesToValue(meta.TagPayload( | ||
| 155 | aarch64.Instruction, | ||
| 156 | aarch64.Instruction.load_store_register, | ||
| 157 | ), code), | ||
| 158 | }; | ||
| 159 | const offset = try math.divExact(u12, narrowed, 8); | ||
| 160 | inst.load_store_register.offset = offset; | ||
| 161 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 162 | }, | ||
| 163 | .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => { | ||
| 164 | const RegInfo = struct { | ||
| 165 | rd: u5, | ||
| 166 | rn: u5, | ||
| 167 | size: u2, | ||
| 168 | }; | ||
| 169 | const reg_info: RegInfo = blk: { | ||
| 170 | if (isArithmeticOp(code)) { | ||
| 171 | const inst = mem.bytesToValue(meta.TagPayload( | ||
| 172 | aarch64.Instruction, | ||
| 173 | aarch64.Instruction.add_subtract_immediate, | ||
| 174 | ), code); | ||
| 175 | break :blk .{ | ||
| 176 | .rd = inst.rd, | ||
| 177 | .rn = inst.rn, | ||
| 178 | .size = inst.sf, | ||
| 179 | }; | ||
| 180 | } else { | ||
| 181 | const inst = mem.bytesToValue(meta.TagPayload( | ||
| 182 | aarch64.Instruction, | ||
| 183 | aarch64.Instruction.load_store_register, | ||
| 184 | ), code); | ||
| 185 | break :blk .{ | ||
| 186 | .rd = inst.rt, | ||
| 187 | .rn = inst.rn, | ||
| 188 | .size = inst.size, | ||
| 189 | }; | ||
| 190 | } | ||
| 191 | }; | ||
| 192 | const narrowed = @truncate(u12, @intCast(u64, target_addr)); | ||
| 193 | var inst = if (macho_file.tlv_ptr_entries_table.contains(self.target)) blk: { | ||
| 194 | const offset = try math.divExact(u12, narrowed, 8); | ||
| 195 | break :blk aarch64.Instruction{ | ||
| 196 | .load_store_register = .{ | ||
| 197 | .rt = reg_info.rd, | ||
| 198 | .rn = reg_info.rn, | ||
| 199 | .offset = offset, | ||
| 200 | .opc = 0b01, | ||
| 201 | .op1 = 0b01, | ||
| 202 | .v = 0, | ||
| 203 | .size = reg_info.size, | ||
| 204 | }, | ||
| 205 | }; | ||
| 206 | } else aarch64.Instruction{ | ||
| 207 | .add_subtract_immediate = .{ | ||
| 208 | .rd = reg_info.rd, | ||
| 209 | .rn = reg_info.rn, | ||
| 210 | .imm12 = narrowed, | ||
| 211 | .sh = 0, | ||
| 212 | .s = 0, | ||
| 213 | .op = 0, | ||
| 214 | .sf = @truncate(u1, reg_info.size), | ||
| 215 | }, | ||
| 216 | }; | ||
| 217 | mem.writeIntLittle(u32, code, inst.toU32()); | ||
| 218 | }, | ||
| 219 | .ARM64_RELOC_POINTER_TO_GOT => { | ||
| 220 | const result = math.cast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr)) orelse | ||
| 221 | return error.Overflow; | ||
| 222 | mem.writeIntLittle(u32, code, @bitCast(u32, result)); | ||
| 223 | }, | ||
| 224 | .ARM64_RELOC_UNSIGNED => { | ||
| 225 | switch (self.length) { | ||
| 226 | 2 => mem.writeIntLittle(u32, code, @truncate(u32, @bitCast(u64, target_addr))), | ||
| 227 | 3 => mem.writeIntLittle(u64, code, target_addr), | ||
| 228 | else => unreachable, | ||
| 229 | } | ||
| 230 | }, | ||
| 231 | .ARM64_RELOC_SUBTRACTOR => unreachable, | ||
| 232 | .ARM64_RELOC_ADDEND => unreachable, | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | fn resolveX8664(self: Relocation, source_addr: u64, target_addr: u64, code: []u8) !void { | ||
| 237 | const rel_type = @intToEnum(macho.reloc_type_x86_64, self.@"type"); | ||
| 238 | switch (rel_type) { | ||
| 239 | .X86_64_RELOC_BRANCH, | ||
| 240 | .X86_64_RELOC_GOT, | ||
| 241 | .X86_64_RELOC_GOT_LOAD, | ||
| 242 | .X86_64_RELOC_TLV, | ||
| 243 | => { | ||
| 244 | const displacement = math.cast(i32, @intCast(i64, target_addr) - @intCast(i64, source_addr) - 4) orelse | ||
| 245 | return error.Overflow; | ||
| 246 | mem.writeIntLittle(u32, code, @bitCast(u32, displacement)); | ||
| 247 | }, | ||
| 248 | .X86_64_RELOC_SIGNED, | ||
| 249 | .X86_64_RELOC_SIGNED_1, | ||
| 250 | .X86_64_RELOC_SIGNED_2, | ||
| 251 | .X86_64_RELOC_SIGNED_4, | ||
| 252 | => { | ||
| 253 | const correction: u3 = switch (rel_type) { | ||
| 254 | .X86_64_RELOC_SIGNED => 0, | ||
| 255 | .X86_64_RELOC_SIGNED_1 => 1, | ||
| 256 | .X86_64_RELOC_SIGNED_2 => 2, | ||
| 257 | .X86_64_RELOC_SIGNED_4 => 4, | ||
| 258 | else => unreachable, | ||
| 259 | }; | ||
| 260 | const displacement = math.cast(i32, target_addr - @intCast(i64, source_addr + correction + 4)) orelse | ||
| 261 | return error.Overflow; | ||
| 262 | mem.writeIntLittle(u32, code, @bitCast(u32, displacement)); | ||
| 263 | }, | ||
| 264 | .X86_64_RELOC_UNSIGNED => { | ||
| 265 | switch (self.length) { | ||
| 266 | 2 => mem.writeIntLittle(u32, code, @truncate(u32, @bitCast(u64, target_addr))), | ||
| 267 | 3 => mem.writeIntLittle(u64, code, target_addr), | ||
| 268 | } | ||
| 269 | }, | ||
| 270 | .X86_64_RELOC_SUBTRACTOR => unreachable, | ||
| 271 | } | ||
| 272 | } | ||
| 273 | |||
| 274 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | ||
| 275 | const group_decode = @truncate(u5, inst[3]); | ||
| 276 | return ((group_decode >> 2) == 4); | ||
| 277 | } | ||