| ... | @@ -177,8 +177,6 @@ has_stabs: bool = false, | ... | @@ -177,8 +177,6 @@ has_stabs: bool = false, |
| 177 | | 177 | |
| 178 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, | 178 | section_ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}, |
| 179 | | 179 | |
| 180 | pending_updates: std.ArrayListUnmanaged(PendingUpdate) = .{}, | | |
| 181 | | | |
| 182 | /// A list of text blocks that have surplus capacity. This list can have false | 180 | /// A list of text blocks that have surplus capacity. This list can have false |
| 183 | /// positives, as functions grow and shrink over time, only sometimes being added | 181 | /// positives, as functions grow and shrink over time, only sometimes being added |
| 184 | /// or removed from the freelist. | 182 | /// or removed from the freelist. |
| ... | @@ -384,6 +382,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -384,6 +382,26 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 384 | try ds.writeLocalSymbol(0); | 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 | return self; | 405 | return self; |
| 388 | } | 406 | } |
| 389 | | 407 | |
| ... | @@ -760,50 +778,42 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -760,50 +778,42 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 760 | try self.parseLibs(libs.items, self.base.options.sysroot); | 778 | try self.parseLibs(libs.items, self.base.options.sysroot); |
| 761 | try self.resolveSymbols(); | 779 | try self.resolveSymbols(); |
| 762 | try self.resolveDyldStubBinder(); | 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 | try self.addRpathLCs(rpath_table.keys()); | 781 | try self.addRpathLCs(rpath_table.keys()); |
| 801 | try self.addLoadDylibLCs(); | 782 | try self.addLoadDylibLCs(); |
| 802 | try self.addDataInCodeLC(); | 783 | try self.addDataInCodeLC(); |
| 803 | try self.addCodeSignatureLC(); | 784 | try self.addCodeSignatureLC(); |
| 804 | | 785 | |
| 805 | if (use_stage1) { | 786 | if (use_stage1) { |
| | 787 | try self.parseTextBlocks(); |
| 806 | try self.sortSections(); | 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 | try self.allocateTextSegment(); | 817 | try self.allocateTextSegment(); |
| 808 | try self.allocateDataConstSegment(); | 818 | try self.allocateDataConstSegment(); |
| 809 | try self.allocateDataSegment(); | 819 | try self.allocateDataSegment(); |
| ... | @@ -1705,18 +1715,10 @@ fn allocateTextSegment(self: *MachO) !void { | ... | @@ -1705,18 +1715,10 @@ fn allocateTextSegment(self: *MachO) !void { |
| 1705 | seg.inner.fileoff = 0; | 1715 | seg.inner.fileoff = 0; |
| 1706 | seg.inner.vmaddr = base_vmaddr; | 1716 | seg.inner.vmaddr = base_vmaddr; |
| 1707 | | 1717 | |
| 1708 | // Set stubs and stub_helper sizes | 1718 | // Set stubs sizes |
| 1709 | const stubs = &seg.sections.items[self.stubs_section_index.?]; | 1719 | const stubs = &seg.sections.items[self.stubs_section_index.?]; |
| 1710 | const stub_helper = &seg.sections.items[self.stub_helper_section_index.?]; | | |
| 1711 | stubs.size += nstubs * stubs.reserved2; | 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 | var sizeofcmds: u64 = 0; | 1722 | var sizeofcmds: u64 = 0; |
| 1721 | for (self.load_commands.items) |lc| { | 1723 | for (self.load_commands.items) |lc| { |
| 1722 | sizeofcmds += lc.cmdsize(); | 1724 | sizeofcmds += lc.cmdsize(); |
| ... | @@ -1947,41 +1949,81 @@ fn createEmptyAtom( | ... | @@ -1947,41 +1949,81 @@ fn createEmptyAtom( |
| 1947 | defer self.base.allocator.free(code); | 1949 | defer self.base.allocator.free(code); |
| 1948 | mem.set(u8, code, 0); | 1950 | mem.set(u8, code, 0); |
| 1949 | | 1951 | |
| 1950 | const block = try self.base.allocator.create(TextBlock); | 1952 | const atom = try self.base.allocator.create(TextBlock); |
| 1951 | errdefer self.base.allocator.destroy(block); | 1953 | errdefer self.base.allocator.destroy(atom); |
| 1952 | block.* = TextBlock.empty; | 1954 | atom.* = TextBlock.empty; |
| 1953 | block.local_sym_index = local_sym_index; | 1955 | atom.local_sym_index = local_sym_index; |
| 1954 | block.size = size; | 1956 | atom.size = size; |
| 1955 | block.alignment = alignment; | 1957 | atom.alignment = alignment; |
| 1956 | try block.code.appendSlice(self.base.allocator, code); | 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 | // Update target section's metadata | 2006 | // Update target section's metadata |
| 1961 | // TODO should we update segment's size here too? | 2007 | // TODO should we update segment's size here too? |
| 1962 | // How does it tie with incremental space allocs? | 2008 | // How does it tie with incremental space allocs? |
| 1963 | const tseg = &self.load_commands.items[match.seg].Segment; | 2009 | const tseg = &self.load_commands.items[match.seg].Segment; |
| 1964 | const tsect = &tseg.sections.items[match.sect]; | 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 | const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment); | 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 | tsect.size = new_size; | 2014 | tsect.size = new_size; |
| 1969 | tsect.@"align" = new_alignment; | 2015 | tsect.@"align" = new_alignment; |
| 1970 | | 2016 | |
| 1971 | if (self.blocks.getPtr(match)) |last| { | 2017 | if (self.blocks.getPtr(match)) |last| { |
| 1972 | last.*.next = block; | 2018 | last.*.next = atom; |
| 1973 | block.prev = last.*; | 2019 | atom.prev = last.*; |
| 1974 | last.* = block; | 2020 | last.* = atom; |
| 1975 | } else { | 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 { | 2026 | fn createDyldPrivateAtom(self: *MachO) !*TextBlock { |
| 1983 | if (self.dyld_private_sym_index != null) return; | | |
| 1984 | | | |
| 1985 | const match = MatchingSection{ | 2027 | const match = MatchingSection{ |
| 1986 | .seg = self.data_segment_cmd_index.?, | 2028 | .seg = self.data_segment_cmd_index.?, |
| 1987 | .sect = self.data_section_index.?, | 2029 | .sect = self.data_section_index.?, |
| ... | @@ -1994,35 +2036,11 @@ fn createDyldPrivateAtom(self: *MachO) !void { | ... | @@ -1994,35 +2036,11 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 1994 | .n_desc = 0, | 2036 | .n_desc = 0, |
| 1995 | .n_value = 0, | 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 | self.dyld_private_sym_index = local_sym_index; | 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 { | 2043 | fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock { |
| 2025 | if (self.stub_preamble_sym_index != null) return; | | |
| 2026 | const arch = self.base.options.target.cpu.arch; | 2044 | const arch = self.base.options.target.cpu.arch; |
| 2027 | const match = MatchingSection{ | 2045 | const match = MatchingSection{ |
| 2028 | .seg = self.text_segment_cmd_index.?, | 2046 | .seg = self.text_segment_cmd_index.?, |
| ... | @@ -2046,7 +2064,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { | ... | @@ -2046,7 +2064,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2046 | .n_desc = 0, | 2064 | .n_desc = 0, |
| 2047 | .n_value = 0, | 2065 | .n_value = 0, |
| 2048 | }); | 2066 | }); |
| 2049 | const last = self.blocks.get(match); | | |
| 2050 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); | 2067 | const atom = try self.createEmptyAtom(match, local_sym_index, size, alignment); |
| 2051 | switch (arch) { | 2068 | switch (arch) { |
| 2052 | .x86_64 => { | 2069 | .x86_64 => { |
| ... | @@ -2157,36 +2174,71 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { | ... | @@ -2157,36 +2174,71 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2157 | else => unreachable, | 2174 | else => unreachable, |
| 2158 | } | 2175 | } |
| 2159 | self.stub_preamble_sym_index = local_sym_index; | 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)) { | 2180 | fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 2162 | const seg = self.load_commands.items[match.seg].Segment; | 2181 | const arch = self.base.options.target.cpu.arch; |
| 2163 | const sect = seg.sections.items[match.sect]; | 2182 | const stub_size: u4 = switch (arch) { |
| 2164 | const base_addr = if (last) |last_atom| blk: { | 2183 | .x86_64 => 10, |
| 2165 | const last_atom_sym = self.locals.items[last_atom.local_sym_index]; | 2184 | .aarch64 => 3 * @sizeOf(u32), |
| 2166 | break :blk last_atom_sym.n_value; | 2185 | else => unreachable, |
| 2167 | } else sect.addr; | 2186 | }; |
| 2168 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); | 2187 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2169 | const atom_alignment = try math.powi(u32, 2, atom.alignment); | 2188 | try self.locals.append(self.base.allocator, .{ |
| 2170 | const vaddr = mem.alignForwardGeneric(u64, base_addr, atom_alignment); | 2189 | .n_strx = try self.makeString("stub_in_stub_helper"), |
| 2171 | | 2190 | .n_type = macho.N_SECT, |
| 2172 | const sym = &self.locals.items[local_sym_index]; | 2191 | .n_sect = 0, |
| 2173 | sym.n_value = vaddr; | 2192 | .n_desc = 0, |
| 2174 | sym.n_sect = n_sect; | 2193 | .n_value = 0, |
| 2175 | | 2194 | }); |
| 2176 | try atom.resolveRelocs(self); | 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; | 2201 | switch (arch) { |
| 2179 | log.debug("writing code for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); | 2202 | .x86_64 => { |
| 2180 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); | 2203 | // pushq |
| 2181 | try self.writeLocalSymbol(local_sym_index); | 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 | 2241 | return atom; |
| 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; | | |
| 2190 | } | 2242 | } |
| 2191 | | 2243 | |
| 2192 | fn resolveSymbolsInObject( | 2244 | fn resolveSymbolsInObject( |
| ... | @@ -2681,7 +2733,6 @@ fn flushZld(self: *MachO) !void { | ... | @@ -2681,7 +2733,6 @@ fn flushZld(self: *MachO) !void { |
| 2681 | // TODO weak bound pointers | 2733 | // TODO weak bound pointers |
| 2682 | try self.writeLazySymbolPointer(index); | 2734 | try self.writeLazySymbolPointer(index); |
| 2683 | try self.writeStub(index); | 2735 | try self.writeStub(index); |
| 2684 | try self.writeStubInStubHelper(index); | | |
| 2685 | } | 2736 | } |
| 2686 | | 2737 | |
| 2687 | if (self.common_section_index) |index| { | 2738 | if (self.common_section_index) |index| { |
| ... | @@ -3173,7 +3224,6 @@ pub fn deinit(self: *MachO) void { | ... | @@ -3173,7 +3224,6 @@ pub fn deinit(self: *MachO) void { |
| 3173 | } | 3224 | } |
| 3174 | | 3225 | |
| 3175 | self.section_ordinals.deinit(self.base.allocator); | 3226 | self.section_ordinals.deinit(self.base.allocator); |
| 3176 | self.pending_updates.deinit(self.base.allocator); | | |
| 3177 | self.got_entries.deinit(self.base.allocator); | 3227 | self.got_entries.deinit(self.base.allocator); |
| 3178 | self.got_entries_map.deinit(self.base.allocator); | 3228 | self.got_entries_map.deinit(self.base.allocator); |
| 3179 | self.got_entries_free_list.deinit(self.base.allocator); | 3229 | self.got_entries_free_list.deinit(self.base.allocator); |
| ... | @@ -4404,11 +4454,7 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 { | ... | @@ -4404,11 +4454,7 @@ pub fn addExternFn(self: *MachO, name: []const u8) !u32 { |
| 4404 | try self.stubs.append(self.base.allocator, sym_index); | 4454 | try self.stubs.append(self.base.allocator, sym_index); |
| 4405 | try self.stubs_map.putNoClobber(self.base.allocator, sym_index, stubs_index); | 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 }, | 4457 | // TODO create and write stub, stub_helper and lazy_ptr atoms |
| 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 }); | | |
| 4412 | | 4458 | |
| 4413 | return sym_index; | 4459 | return sym_index; |
| 4414 | } | 4460 | } |
| ... | @@ -4683,53 +4729,6 @@ fn writeStub(self: *MachO, index: u32) !void { | ... | @@ -4683,53 +4729,6 @@ fn writeStub(self: *MachO, index: u32) !void { |
| 4683 | try self.base.file.?.pwriteAll(code, stub_off); | 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 | fn relocateSymbolTable(self: *MachO) !void { | 4732 | fn relocateSymbolTable(self: *MachO) !void { |
| 4734 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 4733 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 4735 | const nlocals = self.locals.items.len; | 4734 | const nlocals = self.locals.items.len; |