| ... | ... | @@ -177,8 +177,6 @@ has_stabs: bool = false, |
| 177 | 177 | |
| 178 | 178 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 179 | 179 | |
| 180 | | pending_updates: std.ArrayListUnmanaged(PendingUpdate) = .{}, |
| 181 | | |
| 182 | 180 | /// A list of text blocks that have surplus capacity. This list can have false |
| 183 | 181 | /// positives, as functions grow and shrink over time, only sometimes being added |
| 184 | 182 | /// or removed from the freelist. |
| ... | ... | @@ -384,6 +382,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 384 | 382 | try ds.writeLocalSymbol(0); |
| 385 | 383 | } |
| 386 | 384 | |
| 385 | { |
| 386 | const atom = try self.createDyldPrivateAtom(); |
| 387 | const match = MatchingSection{ |
| 388 | .seg = self.data_segment_cmd_index.?, |
| 389 | .sect = self.data_section_index.?, |
| 390 | }; |
| 391 | const vaddr = try self.allocateAtom(atom, match); |
| 392 | try self.writeAtom(atom, match); |
| 393 | } |
| 394 | |
| 395 | { |
| 396 | const atom = try self.createStubHelperPreambleAtom(); |
| 397 | const match = MatchingSection{ |
| 398 | .seg = self.text_segment_cmd_index.?, |
| 399 | .sect = self.stub_helper_section_index.?, |
| 400 | }; |
| 401 | const vaddr = try self.allocateAtom(atom, match); |
| 402 | try self.writeAtom(atom, match); |
| 403 | } |
| 404 | |
| 387 | 405 | return self; |
| 388 | 406 | } |
| 389 | 407 | |
| ... | ... | @@ -760,50 +778,42 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 760 | 778 | try self.parseLibs(libs.items, self.base.options.sysroot); |
| 761 | 779 | try self.resolveSymbols(); |
| 762 | 780 | try self.resolveDyldStubBinder(); |
| 763 | | try self.createDyldPrivateAtom(); |
| 764 | | try self.createStubHelperPreambleAtom(); |
| 765 | | |
| 766 | | if (!use_stage1) { |
| 767 | | // TODO just a temp |
| 768 | | const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 769 | | const sect = seg.sections.items[self.stub_helper_section_index.?]; |
| 770 | | self.stub_helper_stubs_start_off = sect.offset + switch (self.base.options.target.cpu.arch) { |
| 771 | | .x86_64 => @intCast(u64, 15), |
| 772 | | .aarch64 => @intCast(u64, 6 * @sizeOf(u32)), |
| 773 | | else => unreachable, |
| 774 | | }; |
| 775 | | } |
| 776 | | |
| 777 | | // Apply pending updates |
| 778 | | var still_pending = std.ArrayList(PendingUpdate).init(self.base.allocator); |
| 779 | | defer still_pending.deinit(); |
| 780 | | |
| 781 | | for (self.pending_updates.items) |update| { |
| 782 | | switch (update) { |
| 783 | | .add_stub_entry => |stub_index| { |
| 784 | | try self.writeStub(stub_index); |
| 785 | | try self.writeStubInStubHelper(stub_index); |
| 786 | | try self.writeLazySymbolPointer(stub_index); |
| 787 | | self.rebase_info_dirty = true; |
| 788 | | self.lazy_binding_info_dirty = true; |
| 789 | | }, |
| 790 | | else => unreachable, |
| 791 | | } |
| 792 | | } |
| 793 | | |
| 794 | | self.pending_updates.clearRetainingCapacity(); |
| 795 | | for (still_pending.items) |update| { |
| 796 | | self.pending_updates.appendAssumeCapacity(update); |
| 797 | | } |
| 798 | | |
| 799 | | try self.parseTextBlocks(); |
| 800 | 781 | try self.addRpathLCs(rpath_table.keys()); |
| 801 | 782 | try self.addLoadDylibLCs(); |
| 802 | 783 | try self.addDataInCodeLC(); |
| 803 | 784 | try self.addCodeSignatureLC(); |
| 804 | 785 | |
| 805 | 786 | if (use_stage1) { |
| 787 | try self.parseTextBlocks(); |
| 806 | 788 | try self.sortSections(); |
| 789 | { |
| 790 | const atom = try self.createDyldPrivateAtom(); |
| 791 | try self.allocateAtomStage1(atom, .{ |
| 792 | .seg = self.data_segment_cmd_index.?, |
| 793 | .sect = self.data_section_index.?, |
| 794 | }); |
| 795 | } |
| 796 | { |
| 797 | const atom = try self.createStubHelperPreambleAtom(); |
| 798 | try self.allocateAtomStage1(atom, .{ |
| 799 | .seg = self.text_segment_cmd_index.?, |
| 800 | .sect = self.stub_helper_section_index.?, |
| 801 | }); |
| 802 | |
| 803 | // TODO this is just a temp |
| 804 | // We already prealloc stub helper size in populateMissingMetadata(), but |
| 805 | // perhaps it's not needed after all? |
| 806 | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 807 | const sect = &seg.sections.items[self.stub_helper_section_index.?]; |
| 808 | sect.size -= atom.size; |
| 809 | } |
| 810 | for (self.stubs.items) |_| { |
| 811 | const atom = try self.createStubHelperAtom(); |
| 812 | try self.allocateAtomStage1(atom, .{ |
| 813 | .seg = self.text_segment_cmd_index.?, |
| 814 | .sect = self.stub_helper_section_index.?, |
| 815 | }); |
| 816 | } |
| 807 | 817 | try self.allocateTextSegment(); |
| 808 | 818 | try self.allocateDataConstSegment(); |
| 809 | 819 | try self.allocateDataSegment(); |
| ... | ... | @@ -1705,18 +1715,10 @@ fn allocateTextSegment(self: *MachO) !void { |
| 1705 | 1715 | seg.inner.fileoff = 0; |
| 1706 | 1716 | seg.inner.vmaddr = base_vmaddr; |
| 1707 | 1717 | |
| 1708 | | // Set stubs and stub_helper sizes |
| 1718 | // Set stubs sizes |
| 1709 | 1719 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 1710 | | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; |
| 1711 | 1720 | stubs.size += nstubs * stubs.reserved2; |
| 1712 | 1721 | |
| 1713 | | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 1714 | | .x86_64 => 10, |
| 1715 | | .aarch64 => 3 * @sizeOf(u32), |
| 1716 | | else => unreachable, |
| 1717 | | }; |
| 1718 | | stub_helper.size += nstubs * stub_size; |
| 1719 | | |
| 1720 | 1722 | var sizeofcmds: u64 = 0; |
| 1721 | 1723 | for (self.load_commands.items) |lc| { |
| 1722 | 1724 | sizeofcmds += lc.cmdsize(); |
| ... | ... | @@ -1947,41 +1949,81 @@ fn createEmptyAtom( |
| 1947 | 1949 | defer self.base.allocator.free(code); |
| 1948 | 1950 | mem.set(u8, code, 0); |
| 1949 | 1951 | |
| 1950 | | const block = try self.base.allocator.create(TextBlock); |
| 1951 | | errdefer self.base.allocator.destroy(block); |
| 1952 | | block.* = TextBlock.empty; |
| 1953 | | block.local_sym_index = local_sym_index; |
| 1954 | | block.size = size; |
| 1955 | | block.alignment = alignment; |
| 1956 | | try block.code.appendSlice(self.base.allocator, code); |
| 1952 | const atom = try self.base.allocator.create(TextBlock); |
| 1953 | errdefer self.base.allocator.destroy(atom); |
| 1954 | atom.* = TextBlock.empty; |
| 1955 | atom.local_sym_index = local_sym_index; |
| 1956 | atom.size = size; |
| 1957 | atom.alignment = alignment; |
| 1958 | try atom.code.appendSlice(self.base.allocator, code); |
| 1959 | try self.managed_blocks.append(self.base.allocator, atom); |
| 1957 | 1960 | |
| 1958 | | try self.managed_blocks.append(self.base.allocator, block); |
| 1961 | return atom; |
| 1962 | } |
| 1963 | |
| 1964 | fn allocateAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !u64 { |
| 1965 | // TODO converge with `allocateTextBlock` |
| 1966 | const seg = self.load_commands.items[match.seg].Segment; |
| 1967 | const sect = seg.sections.items[match.sect]; |
| 1968 | const base_addr = if (atom.prev) |prev| blk: { |
| 1969 | const prev_atom_sym = self.locals.items[prev.local_sym_index]; |
| 1970 | break :blk prev_atom_sym.n_value; |
| 1971 | } else sect.addr; |
| 1972 | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 1973 | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); |
| 1974 | |
| 1975 | // TODO we should check if we need to expand the section or not like we |
| 1976 | // do in `allocateTextBlock`. |
| 1977 | if (self.blocks.getPtr(match)) |last| { |
| 1978 | last.*.next = atom; |
| 1979 | atom.prev = last.*; |
| 1980 | last.* = atom; |
| 1981 | } else { |
| 1982 | try self.blocks.putNoClobber(self.base.allocator, match, atom); |
| 1983 | } |
| 1959 | 1984 | |
| 1985 | return vaddr; |
| 1986 | } |
| 1987 | |
| 1988 | fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1989 | const seg = self.load_commands.items[match.seg].Segment; |
| 1990 | const sect = seg.sections.items[match.sect]; |
| 1991 | |
| 1992 | const vaddr = try self.allocateAtom(atom, match); |
| 1993 | const sym = &self.locals.items[atom.local_sym_index]; |
| 1994 | sym.n_value = vaddr; |
| 1995 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 1996 | |
| 1997 | try atom.resolveRelocs(self); |
| 1998 | |
| 1999 | const file_offset = sect.offset + vaddr - sect.addr; |
| 2000 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 2001 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 2002 | try self.writeLocalSymbol(atom.local_sym_index); |
| 2003 | } |
| 2004 | |
| 2005 | fn allocateAtomStage1(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1960 | 2006 | // Update target section's metadata |
| 1961 | 2007 | // TODO should we update segment's size here too? |
| 1962 | 2008 | // How does it tie with incremental space allocs? |
| 1963 | 2009 | const tseg = &self.load_commands.items[match.seg].Segment; |
| 1964 | 2010 | const tsect = &tseg.sections.items[match.sect]; |
| 1965 | | const new_alignment = math.max(tsect.@"align", alignment); |
| 2011 | const new_alignment = math.max(tsect.@"align", atom.alignment); |
| 1966 | 2012 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); |
| 1967 | | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + size; |
| 2013 | const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + atom.size; |
| 1968 | 2014 | tsect.size = new_size; |
| 1969 | 2015 | tsect.@"align" = new_alignment; |
| 1970 | 2016 | |
| 1971 | 2017 | if (self.blocks.getPtr(match)) |last| { |
| 1972 | | last.*.next = block; |
| 1973 | | block.prev = last.*; |
| 1974 | | last.* = block; |
| 2018 | last.*.next = atom; |
| 2019 | atom.prev = last.*; |
| 2020 | last.* = atom; |
| 1975 | 2021 | } else { |
| 1976 | | try self.blocks.putNoClobber(self.base.allocator, match, block); |
| 2022 | try self.blocks.putNoClobber(self.base.allocator, match, atom); |
| 1977 | 2023 | } |
| 1978 | | |
| 1979 | | return block; |
| 1980 | 2024 | } |
| 1981 | 2025 | |
| 1982 | | fn createDyldPrivateAtom(self: *MachO) !void { |
| 1983 | | if (self.dyld_private_sym_index != null) return; |
| 1984 | | |
| 2026 | fn createDyldPrivateAtom(self: *MachO) !*TextBlock { |
| 1985 | 2027 | const match = MatchingSection{ |
| 1986 | 2028 | .seg = self.data_segment_cmd_index.?, |
| 1987 | 2029 | .sect = self.data_section_index.?, |
| ... | ... | @@ -1994,35 +2036,11 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 1994 | 2036 | .n_desc = 0, |
| 1995 | 2037 | .n_value = 0, |
| 1996 | 2038 | }); |
| 1997 | | const last = self.blocks.get(match); |
| 1998 | | const atom = try self.createEmptyAtom(match, local_sym_index, @sizeOf(u64), 3); |
| 1999 | | |
| 2000 | | if (!(build_options.is_stage1 and self.base.options.use_stage1)) { |
| 2001 | | const seg = self.load_commands.items[match.seg].Segment; |
| 2002 | | const sect = seg.sections.items[match.sect]; |
| 2003 | | const base_addr = if (last) |last_atom| blk: { |
| 2004 | | const last_atom_sym = self.locals.items[last_atom.local_sym_index]; |
| 2005 | | break :blk last_atom_sym.n_value; |
| 2006 | | } else sect.addr; |
| 2007 | | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2008 | | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 2009 | | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); |
| 2010 | | |
| 2011 | | const sym = &self.locals.items[local_sym_index]; |
| 2012 | | sym.n_value = vaddr; |
| 2013 | | sym.n_sect = n_sect; |
| 2014 | | |
| 2015 | | const file_offset = sect.offset + vaddr - sect.addr; |
| 2016 | | log.debug("writing code for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 2017 | | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 2018 | | try self.writeLocalSymbol(local_sym_index); |
| 2019 | | } |
| 2020 | | |
| 2021 | 2039 | self.dyld_private_sym_index = local_sym_index; |
| 2040 | return self.createEmptyAtom(match, local_sym_index, @sizeOf(u64), 3); |
| 2022 | 2041 | } |
| 2023 | 2042 | |
| 2024 | | fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2025 | | if (self.stub_preamble_sym_index != null) return; |
| 2043 | fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock { |
| 2026 | 2044 | const arch = self.base.options.target.cpu.arch; |
| 2027 | 2045 | const match = MatchingSection{ |
| 2028 | 2046 | .seg = self.text_segment_cmd_index.?, |
| ... | ... | @@ -2046,7 +2064,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2046 | 2064 | .n_desc = 0, |
| 2047 | 2065 | .n_value = 0, |
| 2048 | 2066 | }); |
| 2049 | | const last = self.blocks.get(match); |
| 2050 | 2067 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2051 | 2068 | switch (arch) { |
| 2052 | 2069 | .x86_64 => { |
| ... | ... | @@ -2157,36 +2174,71 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2157 | 2174 | else => unreachable, |
| 2158 | 2175 | } |
| 2159 | 2176 | self.stub_preamble_sym_index = local_sym_index; |
| 2177 | return atom; |
| 2178 | } |
| 2160 | 2179 | |
| 2161 | | if (!(build_options.is_stage1 and self.base.options.use_stage1)) { |
| 2162 | | const seg = self.load_commands.items[match.seg].Segment; |
| 2163 | | const sect = seg.sections.items[match.sect]; |
| 2164 | | const base_addr = if (last) |last_atom| blk: { |
| 2165 | | const last_atom_sym = self.locals.items[last_atom.local_sym_index]; |
| 2166 | | break :blk last_atom_sym.n_value; |
| 2167 | | } else sect.addr; |
| 2168 | | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2169 | | const atom_alignment = try math.powi(u32, 2, atom.alignment); |
| 2170 | | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); |
| 2171 | | |
| 2172 | | const sym = &self.locals.items[local_sym_index]; |
| 2173 | | sym.n_value = vaddr; |
| 2174 | | sym.n_sect = n_sect; |
| 2175 | | |
| 2176 | | try atom.resolveRelocs(self); |
| 2180 | fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 2181 | const arch = self.base.options.target.cpu.arch; |
| 2182 | const stub_size: u4 = switch (arch) { |
| 2183 | .x86_64 => 10, |
| 2184 | .aarch64 => 3 * @sizeOf(u32), |
| 2185 | else => unreachable, |
| 2186 | }; |
| 2187 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2188 | try self.locals.append(self.base.allocator, .{ |
| 2189 | .n_strx = try self.makeString("stub_in_stub_helper"), |
| 2190 | .n_type = macho.N_SECT, |
| 2191 | .n_sect = 0, |
| 2192 | .n_desc = 0, |
| 2193 | .n_value = 0, |
| 2194 | }); |
| 2195 | const atom = try self.createEmptyAtom(.{ |
| 2196 | .seg = self.text_segment_cmd_index.?, |
| 2197 | .sect = self.stub_helper_section_index.?, |
| 2198 | }, local_sym_index, stub_size, 2); |
| 2199 | try atom.relocs.ensureTotalCapacity(self.base.allocator, 1); |
| 2177 | 2200 | |
| 2178 | | const file_offset = sect.offset + vaddr - sect.addr; |
| 2179 | | log.debug("writing code for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 2180 | | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 2181 | | try self.writeLocalSymbol(local_sym_index); |
| 2201 | switch (arch) { |
| 2202 | .x86_64 => { |
| 2203 | // pushq |
| 2204 | atom.code.items[0] = 0x68; |
| 2205 | // Next 4 bytes 1..4 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 2206 | // jmpq |
| 2207 | atom.code.items[5] = 0xe9; |
| 2208 | atom.relocs.appendAssumeCapacity(.{ |
| 2209 | .offset = 6, |
| 2210 | .where = .local, |
| 2211 | .where_index = self.stub_preamble_sym_index.?, |
| 2212 | .payload = .{ |
| 2213 | .branch = .{ .arch = arch }, |
| 2214 | }, |
| 2215 | }); |
| 2216 | }, |
| 2217 | .aarch64 => { |
| 2218 | const literal = blk: { |
| 2219 | const div_res = try math.divExact(u64, stub_size - @sizeOf(u32), 4); |
| 2220 | break :blk try math.cast(u18, div_res); |
| 2221 | }; |
| 2222 | // ldr w16, literal |
| 2223 | mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.ldr(.w16, .{ |
| 2224 | .literal = literal, |
| 2225 | }).toU32()); |
| 2226 | // b disp |
| 2227 | mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.b(0).toU32()); |
| 2228 | atom.relocs.appendAssumeCapacity(.{ |
| 2229 | .offset = 4, |
| 2230 | .where = .local, |
| 2231 | .where_index = self.stub_preamble_sym_index.?, |
| 2232 | .payload = .{ |
| 2233 | .branch = .{ .arch = arch }, |
| 2234 | }, |
| 2235 | }); |
| 2236 | // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 2237 | }, |
| 2238 | else => unreachable, |
| 2182 | 2239 | } |
| 2183 | 2240 | |
| 2184 | | // TODO this needs to be fixed |
| 2185 | | // We already prealloc stub helper size in populateMissingMetadata(), but |
| 2186 | | // perhaps it's not needed after all? |
| 2187 | | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 2188 | | const sect = &seg.sections.items[self.stub_helper_section_index.?]; |
| 2189 | | sect.size -= size; |
| 2241 | return atom; |
| 2190 | 2242 | } |
| 2191 | 2243 | |
| 2192 | 2244 | fn resolveSymbolsInObject( |
| ... | ... | @@ -2681,7 +2733,6 @@ fn flushZld(self: *MachO) !void { |
| 2681 | 2733 | // TODO weak bound pointers |
| 2682 | 2734 | try self.writeLazySymbolPointer(index); |
| 2683 | 2735 | try self.writeStub(index); |
| 2684 | | try self.writeStubInStubHelper(index); |
| 2685 | 2736 | } |
| 2686 | 2737 | |
| 2687 | 2738 | if (self.common_section_index) |index| { |
| ... | ... | @@ -3173,7 +3224,6 @@ pub fn deinit(self: *MachO) void { |
| 3173 | 3224 | } |
| 3174 | 3225 | |
| 3175 | 3226 | self.section_ordinals.deinit(self.base.allocator); |
| 3176 | | self.pending_updates.deinit(self.base.allocator); |
| 3177 | 3227 | self.got_entries.deinit(self.base.allocator); |
| 3178 | 3228 | self.got_entries_map.deinit(self.base.allocator); |
| 3179 | 3229 | self.got_entries_free_list.deinit(self.base.allocator); |
| ... | ... | @@ -4404,11 +4454,7 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 { |
| 4404 | 4454 | try self.stubs.append(self.base.allocator, sym_index); |
| 4405 | 4455 | try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index); |
| 4406 | 4456 | |
| 4407 | | // TODO discuss this. The caller context expects codegen.InnerError{ OutOfMemory, CodegenFail }, |
| 4408 | | // which obviously doesn't include file writing op errors. So instead of trying to write the stub |
| 4409 | | // entry right here and now, queue it up and dispose of when updating decl. |
| 4410 | | try self.pending_updates.ensureUnusedCapacity(self.base.allocator, 1); |
| 4411 | | self.pending_updates.appendAssumeCapacity(.{ .add_stub_entry = stubs_index }); |
| 4457 | // TODO create and write stub, stub_helper and lazy_ptr atoms |
| 4412 | 4458 | |
| 4413 | 4459 | return sym_index; |
| 4414 | 4460 | } |
| ... | ... | @@ -4683,53 +4729,6 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 4683 | 4729 | try self.base.file.?.pwriteAll(code, stub_off); |
| 4684 | 4730 | } |
| 4685 | 4731 | |
| 4686 | | fn writeStubInStubHelper(self: *MachO, index: u32) !void { |
| 4687 | | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4688 | | const stub_helper = text_segment.sections.items[self.stub_helper_section_index.?]; |
| 4689 | | |
| 4690 | | const stub_size: u4 = switch (self.base.options.target.cpu.arch) { |
| 4691 | | .x86_64 => 10, |
| 4692 | | .aarch64 => 3 * @sizeOf(u32), |
| 4693 | | else => unreachable, |
| 4694 | | }; |
| 4695 | | const stub_off = self.stub_helper_stubs_start_off.? + index * stub_size; |
| 4696 | | |
| 4697 | | var code = try self.base.allocator.alloc(u8, stub_size); |
| 4698 | | defer self.base.allocator.free(code); |
| 4699 | | |
| 4700 | | switch (self.base.options.target.cpu.arch) { |
| 4701 | | .x86_64 => { |
| 4702 | | const displacement = try math.cast( |
| 4703 | | i32, |
| 4704 | | @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - stub_size, |
| 4705 | | ); |
| 4706 | | // pushq |
| 4707 | | code[0] = 0x68; |
| 4708 | | mem.writeIntLittle(u32, code[1..][0..4], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 4709 | | // jmpq |
| 4710 | | code[5] = 0xe9; |
| 4711 | | mem.writeIntLittle(u32, code[6..][0..4], @bitCast(u32, displacement)); |
| 4712 | | }, |
| 4713 | | .aarch64 => { |
| 4714 | | const literal = blk: { |
| 4715 | | const div_res = try math.divExact(u64, stub_size - @sizeOf(u32), 4); |
| 4716 | | break :blk try math.cast(u18, div_res); |
| 4717 | | }; |
| 4718 | | // ldr w16, literal |
| 4719 | | mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{ |
| 4720 | | .literal = literal, |
| 4721 | | }).toU32()); |
| 4722 | | const displacement = try math.cast(i28, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4); |
| 4723 | | // b disp |
| 4724 | | mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(displacement).toU32()); |
| 4725 | | // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`. |
| 4726 | | mem.writeIntLittle(u32, code[8..12], 0x0); |
| 4727 | | }, |
| 4728 | | else => unreachable, |
| 4729 | | } |
| 4730 | | try self.base.file.?.pwriteAll(code, stub_off); |
| 4731 | | } |
| 4732 | | |
| 4733 | 4732 | fn relocateSymbolTable(self: *MachO) !void { |
| 4734 | 4733 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 4735 | 4734 | const nlocals = self.locals.items.len; |