authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-19 16:38:44+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-04-21 22:44:27+02:00
logfa40267b04e29fa8e36e73cb54eb68d58d26fa8d
treec6f77455c305e37e13d66eda48da736c93b4c9d6
parentc55e821df6d6adca449720e052f40463eef8174b

macho: do not allocate atoms for stub entries


8 files changed, 408 insertions(+), 487 deletions(-)

src/link/MachO.zig+160-293
...@@ -19,6 +19,7 @@ const fat = @import("MachO/fat.zig");...@@ -19,6 +19,7 @@ const fat = @import("MachO/fat.zig");
19const link = @import("../link.zig");19const link = @import("../link.zig");
20const llvm_backend = @import("../codegen/llvm.zig");20const llvm_backend = @import("../codegen/llvm.zig");
21const load_commands = @import("MachO/load_commands.zig");21const load_commands = @import("MachO/load_commands.zig");
22const stubs = @import("MachO/stubs.zig");
22const target_util = @import("../target.zig");23const target_util = @import("../target.zig");
23const trace = @import("../tracy.zig").trace;24const trace = @import("../tracy.zig").trace;
24const zld = @import("MachO/zld.zig");25const zld = @import("MachO/zld.zig");
...@@ -156,7 +157,7 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,...@@ -156,7 +157,7 @@ stub_helper_preamble_atom_index: ?Atom.Index = null,
156strtab: StringTable(.strtab) = .{},157strtab: StringTable(.strtab) = .{},
157158
158got_table: TableSection(SymbolWithLoc) = .{},159got_table: TableSection(SymbolWithLoc) = .{},
159stubs_table: SectionTable = .{},160stub_table: TableSection(SymbolWithLoc) = .{},
160tlv_table: SectionTable = .{},161tlv_table: SectionTable = .{},
161162
162error_flags: File.ErrorFlags = File.ErrorFlags{},163error_flags: File.ErrorFlags = File.ErrorFlags{},
...@@ -164,6 +165,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},...@@ -164,6 +165,8 @@ error_flags: File.ErrorFlags = File.ErrorFlags{},
164segment_table_dirty: bool = false,165segment_table_dirty: bool = false,
165got_table_count_dirty: bool = false,166got_table_count_dirty: bool = false,
166got_table_contents_dirty: bool = false,167got_table_contents_dirty: bool = false,
168stub_table_count_dirty: bool = false,
169stub_table_contents_dirty: bool = false,
167170
168/// A helper var to indicate if we are at the start of the incremental updates, or171/// A helper var to indicate if we are at the start of the incremental updates, or
169/// already somewhere further along the update-and-run chain.172/// already somewhere further along the update-and-run chain.
...@@ -213,11 +216,6 @@ rebases: RebaseTable = .{},...@@ -213,11 +216,6 @@ rebases: RebaseTable = .{},
213/// this will be a table indexed by index into the list of Atoms.216/// this will be a table indexed by index into the list of Atoms.
214bindings: BindingTable = .{},217bindings: BindingTable = .{},
215218
216/// A table of lazy bindings indexed by the owning them `Atom`.
217/// Note that once we refactor `Atom`'s lifetime and ownership rules,
218/// this will be a table indexed by index into the list of Atoms.
219lazy_bindings: BindingTable = .{},
220
221/// Table of tracked LazySymbols.219/// Table of tracked LazySymbols.
222lazy_syms: LazySymbolTable = .{},220lazy_syms: LazySymbolTable = .{},
223221
...@@ -763,11 +761,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -763,11 +761,23 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
763 if (self.got_table_contents_dirty) {761 if (self.got_table_contents_dirty) {
764 for (self.got_table.entries.items, 0..) |entry, i| {762 for (self.got_table.entries.items, 0..) |entry, i| {
765 if (!self.got_table.lookup.contains(entry)) continue;763 if (!self.got_table.lookup.contains(entry)) continue;
764 // TODO: write all in one go rather than incrementally.
766 try self.writeOffsetTableEntry(i);765 try self.writeOffsetTableEntry(i);
767 }766 }
768 self.got_table_contents_dirty = false;767 self.got_table_contents_dirty = false;
769 }768 }
770769
770 // Update stubs if we moved any section in memory.
771 // TODO: we probably don't need to update all sections if only one got moved.
772 if (self.stub_table_contents_dirty) {
773 for (self.stub_table.entries.items, 0..) |entry, i| {
774 if (!self.stub_table.lookup.contains(entry)) continue;
775 // TODO: write all in one go rather than incrementally.
776 try self.writeStubTableEntry(i);
777 }
778 self.stub_table_contents_dirty = false;
779 }
780
771 if (build_options.enable_logging) {781 if (build_options.enable_logging) {
772 self.logSymtab();782 self.logSymtab();
773 self.logSections();783 self.logSections();
...@@ -1311,6 +1321,86 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1311,6 +1321,86 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1311 }1321 }
1312}1322}
13131323
1324fn writeStubTableEntry(self: *MachO, index: usize) !void {
1325 const stubs_sect_id = self.stubs_section_index.?;
1326 const stub_helper_sect_id = self.stub_helper_section_index.?;
1327 const laptr_sect_id = self.la_symbol_ptr_section_index.?;
1328
1329 const cpu_arch = self.base.options.target.cpu.arch;
1330 const stub_entry_size = stubs.calcStubEntrySize(cpu_arch);
1331 const stub_helper_entry_size = stubs.calcStubHelperEntrySize(cpu_arch);
1332 const stub_helper_preamble_size = stubs.calcStubHelperPreambleSize(cpu_arch);
1333
1334 if (self.stub_table_count_dirty) {
1335 // We grow all 3 sections one by one.
1336 {
1337 const needed_size = stub_entry_size * self.stub_table.entries.items.len;
1338 try self.growSection(stubs_sect_id, needed_size);
1339 }
1340 {
1341 const needed_size = stub_helper_preamble_size + stub_helper_entry_size * self.stub_table.entries.items.len;
1342 try self.growSection(stub_helper_sect_id, needed_size);
1343 }
1344 {
1345 const needed_size = @sizeOf(u64) * self.stub_table.entries.items.len;
1346 try self.growSection(laptr_sect_id, needed_size);
1347 }
1348 self.stub_table_count_dirty = false;
1349 }
1350
1351 const gpa = self.base.allocator;
1352
1353 const stubs_header = self.sections.items(.header)[stubs_sect_id];
1354 const stub_helper_header = self.sections.items(.header)[stub_helper_sect_id];
1355 const laptr_header = self.sections.items(.header)[laptr_sect_id];
1356
1357 const entry = self.stub_table.entries.items[index];
1358 const stub_addr: u64 = stubs_header.addr + stub_entry_size * index;
1359 const stub_helper_addr: u64 = stub_helper_header.addr + stub_helper_preamble_size + stub_helper_entry_size * index;
1360 const laptr_addr: u64 = laptr_header.addr + @sizeOf(u64) * index;
1361
1362 log.debug("writing stub entry {d}: @{x} => '{s}'", .{ index, stub_addr, self.getSymbolName(entry) });
1363
1364 {
1365 var buf = try std.ArrayList(u8).initCapacity(gpa, stub_entry_size);
1366 defer buf.deinit();
1367 try stubs.writeStubCode(.{
1368 .cpu_arch = cpu_arch,
1369 .source_addr = stub_addr,
1370 .target_addr = laptr_addr,
1371 }, buf.writer());
1372 const off = stubs_header.offset + stub_entry_size * index;
1373 try self.base.file.?.pwriteAll(buf.items, off);
1374 }
1375
1376 {
1377 var buf = try std.ArrayList(u8).initCapacity(gpa, stub_helper_entry_size);
1378 defer buf.deinit();
1379 try stubs.writeStubHelperCode(.{
1380 .cpu_arch = cpu_arch,
1381 .source_addr = stub_helper_addr,
1382 .target_addr = stub_helper_header.addr,
1383 }, buf.writer());
1384 const off = stub_helper_header.offset + stub_helper_preamble_size + stub_helper_entry_size * index;
1385 try self.base.file.?.pwriteAll(buf.items, off);
1386 }
1387
1388 {
1389 var buf: [@sizeOf(u64)]u8 = undefined;
1390 mem.writeIntLittle(u64, &buf, stub_helper_addr);
1391 const off = laptr_header.offset + @sizeOf(u64) * index;
1392 try self.base.file.?.pwriteAll(&buf, off);
1393 }
1394
1395 // TODO: generating new stub entry will require pulling the address of the symbol from the
1396 // target dylib when updating directly in memory.
1397 if (is_hot_update_compatible) {
1398 if (self.hot_state.mach_task) |_| {
1399 @panic("TODO: update a stub entry in memory");
1400 }
1401 }
1402}
1403
1314fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {1404fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void {
1315 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);1405 var buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
1316 try self.writeAtom(atom_index, &buffer);1406 try self.writeAtom(atom_index, &buffer);
...@@ -1339,12 +1429,16 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {...@@ -1339,12 +1429,16 @@ fn markRelocsDirtyByAddress(self: *MachO, addr: u64) void {
1339 }1429 }
13401430
1341 // Dirty synthetic table sections if necessary1431 // Dirty synthetic table sections if necessary
1342 for (&[_]u8{self.got_section_index.?}, &[_]*bool{&self.got_table_contents_dirty}) |sect_id, dirty| {1432 {
1343 if (dirty.*) continue;1433 const target_addr = self.getSegment(self.got_section_index.?).vmaddr;
1344 const segment_index = self.sections.items(.segment_index)[sect_id];1434 if (target_addr >= addr) self.got_table_contents_dirty = true;
1345 const segment = self.segments.items[segment_index];1435 }
1346 if (segment.vmaddr < addr) continue;1436 {
1347 dirty.* = true;1437 const stubs_addr = self.getSegment(self.stubs_section_index.?).vmaddr;
1438 const stub_helper_addr = self.getSegment(self.stub_helper_section_index.?).vmaddr;
1439 const laptr_addr = self.getSegment(self.la_symbol_ptr_section_index.?).vmaddr;
1440 if (stubs_addr >= addr or stub_helper_addr >= addr or laptr_addr >= addr)
1441 self.stub_table_contents_dirty = true;
1348 }1442 }
1349}1443}
13501444
...@@ -1525,200 +1619,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -1525,200 +1619,6 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
1525 try self.writeAtom(atom_index, code);1619 try self.writeAtom(atom_index, code);
1526}1620}
15271621
1528fn createStubHelperAtom(self: *MachO) !Atom.Index {
1529 const gpa = self.base.allocator;
1530 const arch = self.base.options.target.cpu.arch;
1531 const size: u4 = switch (arch) {
1532 .x86_64 => 10,
1533 .aarch64 => 3 * @sizeOf(u32),
1534 else => unreachable,
1535 };
1536 const atom_index = try self.createAtom();
1537 const atom = self.getAtomPtr(atom_index);
1538 atom.size = size;
1539
1540 const required_alignment: u32 = switch (arch) {
1541 .x86_64 => 1,
1542 .aarch64 => @alignOf(u32),
1543 else => unreachable,
1544 };
1545
1546 const sym = atom.getSymbolPtr(self);
1547 sym.n_type = macho.N_SECT;
1548 sym.n_sect = self.stub_helper_section_index.? + 1;
1549
1550 const code = try gpa.alloc(u8, size);
1551 defer gpa.free(code);
1552 mem.set(u8, code, 0);
1553
1554 const stub_helper_preamble_atom_sym_index = if (self.stub_helper_preamble_atom_index) |stub_index|
1555 self.getAtom(stub_index).getSymbolIndex().?
1556 else
1557 unreachable;
1558
1559 switch (arch) {
1560 .x86_64 => {
1561 // pushq
1562 code[0] = 0x68;
1563 // Next 4 bytes 1..4 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
1564 // jmpq
1565 code[5] = 0xe9;
1566
1567 try Atom.addRelocation(self, atom_index, .{
1568 .type = .branch,
1569 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
1570 .offset = 6,
1571 .addend = 0,
1572 .pcrel = true,
1573 .length = 2,
1574 });
1575 },
1576 .aarch64 => {
1577 const literal = blk: {
1578 const div_res = try math.divExact(u64, size - @sizeOf(u32), 4);
1579 break :blk math.cast(u18, div_res) orelse return error.Overflow;
1580 };
1581 // ldr w16, literal
1582 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldrLiteral(
1583 .w16,
1584 literal,
1585 ).toU32());
1586 // b disp
1587 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(0).toU32());
1588 // Next 4 bytes 8..12 are just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
1589
1590 try Atom.addRelocation(self, atom_index, .{
1591 .type = .branch,
1592 .target = .{ .sym_index = stub_helper_preamble_atom_sym_index },
1593 .offset = 4,
1594 .addend = 0,
1595 .pcrel = true,
1596 .length = 2,
1597 });
1598 },
1599 else => unreachable,
1600 }
1601
1602 sym.n_value = try self.allocateAtom(atom_index, size, required_alignment);
1603 log.debug("allocated stub helper atom at 0x{x}", .{sym.n_value});
1604 try self.writeAtom(atom_index, code);
1605
1606 return atom_index;
1607}
1608
1609fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, target: SymbolWithLoc) !Atom.Index {
1610 const atom_index = try self.createAtom();
1611 const atom = self.getAtomPtr(atom_index);
1612 atom.size = @sizeOf(u64);
1613
1614 const sym = atom.getSymbolPtr(self);
1615 sym.n_type = macho.N_SECT;
1616 sym.n_sect = self.la_symbol_ptr_section_index.? + 1;
1617
1618 try Atom.addRelocation(self, atom_index, .{
1619 .type = .unsigned,
1620 .target = .{ .sym_index = stub_sym_index },
1621 .offset = 0,
1622 .addend = 0,
1623 .pcrel = false,
1624 .length = 3,
1625 });
1626 try Atom.addRebase(self, atom_index, 0);
1627 try Atom.addLazyBinding(self, atom_index, .{
1628 .target = self.getGlobal(self.getSymbolName(target)).?,
1629 .offset = 0,
1630 });
1631
1632 sym.n_value = try self.allocateAtom(atom_index, atom.size, @alignOf(u64));
1633 log.debug("allocated lazy pointer atom at 0x{x} ({s})", .{ sym.n_value, self.getSymbolName(target) });
1634 try self.writePtrWidthAtom(atom_index);
1635
1636 return atom_index;
1637}
1638
1639fn createStubAtom(self: *MachO, laptr_sym_index: u32) !Atom.Index {
1640 const gpa = self.base.allocator;
1641 const arch = self.base.options.target.cpu.arch;
1642 const size: u4 = switch (arch) {
1643 .x86_64 => 6,
1644 .aarch64 => 3 * @sizeOf(u32),
1645 else => unreachable, // unhandled architecture type
1646 };
1647 const atom_index = try self.createAtom();
1648 const atom = self.getAtomPtr(atom_index);
1649 atom.size = size;
1650
1651 const required_alignment: u32 = switch (arch) {
1652 .x86_64 => 1,
1653 .aarch64 => @alignOf(u32),
1654 else => unreachable, // unhandled architecture type
1655
1656 };
1657
1658 const sym = atom.getSymbolPtr(self);
1659 sym.n_type = macho.N_SECT;
1660 sym.n_sect = self.stubs_section_index.? + 1;
1661
1662 const code = try gpa.alloc(u8, size);
1663 defer gpa.free(code);
1664 mem.set(u8, code, 0);
1665
1666 switch (arch) {
1667 .x86_64 => {
1668 // jmp
1669 code[0] = 0xff;
1670 code[1] = 0x25;
1671
1672 try Atom.addRelocation(self, atom_index, .{
1673 .type = .branch,
1674 .target = .{ .sym_index = laptr_sym_index },
1675 .offset = 2,
1676 .addend = 0,
1677 .pcrel = true,
1678 .length = 2,
1679 });
1680 },
1681 .aarch64 => {
1682 // adrp x16, pages
1683 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, 0).toU32());
1684 // ldr x16, x16, offset
1685 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(
1686 .x16,
1687 .x16,
1688 aarch64.Instruction.LoadStoreOffset.imm(0),
1689 ).toU32());
1690 // br x16
1691 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
1692
1693 try Atom.addRelocations(self, atom_index, &[_]Relocation{
1694 .{
1695 .type = .page,
1696 .target = .{ .sym_index = laptr_sym_index },
1697 .offset = 0,
1698 .addend = 0,
1699 .pcrel = true,
1700 .length = 2,
1701 },
1702 .{
1703 .type = .pageoff,
1704 .target = .{ .sym_index = laptr_sym_index },
1705 .offset = 4,
1706 .addend = 0,
1707 .pcrel = false,
1708 .length = 2,
1709 },
1710 });
1711 },
1712 else => unreachable,
1713 }
1714
1715 sym.n_value = try self.allocateAtom(atom_index, size, required_alignment);
1716 log.debug("allocated stub atom at 0x{x}", .{sym.n_value});
1717 try self.writeAtom(atom_index, code);
1718
1719 return atom_index;
1720}
1721
1722fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {1622fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index {
1723 const gpa = self.base.allocator;1623 const gpa = self.base.allocator;
1724 const size = 3 * @sizeOf(u64);1624 const size = 3 * @sizeOf(u64);
...@@ -1904,7 +1804,7 @@ pub fn deinit(self: *MachO) void {...@@ -1904,7 +1804,7 @@ pub fn deinit(self: *MachO) void {
1904 }1804 }
19051805
1906 self.got_table.deinit(gpa);1806 self.got_table.deinit(gpa);
1907 self.stubs_table.deinit(gpa);1807 self.stub_table.deinit(gpa);
1908 self.tlv_table.deinit(gpa);1808 self.tlv_table.deinit(gpa);
1909 self.strtab.deinit(gpa);1809 self.strtab.deinit(gpa);
19101810
...@@ -1968,11 +1868,6 @@ pub fn deinit(self: *MachO) void {...@@ -1968,11 +1868,6 @@ pub fn deinit(self: *MachO) void {
1968 bindings.deinit(gpa);1868 bindings.deinit(gpa);
1969 }1869 }
1970 self.bindings.deinit(gpa);1870 self.bindings.deinit(gpa);
1971
1972 for (self.lazy_bindings.values()) |*bindings| {
1973 bindings.deinit(gpa);
1974 }
1975 self.lazy_bindings.deinit(gpa);
1976}1871}
19771872
1978fn freeAtom(self: *MachO, atom_index: Atom.Index) void {1873fn freeAtom(self: *MachO, atom_index: Atom.Index) void {
...@@ -2124,16 +2019,10 @@ fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {...@@ -2124,16 +2019,10 @@ fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
2124}2019}
21252020
2126fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {2021fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
2127 if (self.stubs_table.lookup.contains(target)) return;2022 if (self.stub_table.lookup.contains(target)) return;
2128 const stub_index = try self.stubs_table.allocateEntry(self.base.allocator, target);2023 const stub_index = try self.stub_table.allocateEntry(self.base.allocator, target);
2129 const stub_helper_atom_index = try self.createStubHelperAtom();2024 try self.writeStubTableEntry(stub_index);
2130 const stub_helper_atom = self.getAtom(stub_helper_atom_index);2025 self.stub_table_count_dirty = true;
2131 const laptr_atom_index = try self.createLazyPointerAtom(stub_helper_atom.getSymbolIndex().?, target);
2132 const laptr_atom = self.getAtom(laptr_atom_index);
2133 const stub_atom_index = try self.createStubAtom(laptr_atom.getSymbolIndex().?);
2134 const stub_atom = self.getAtom(stub_atom_index);
2135 self.stubs_table.entries.items[stub_index].sym_index = stub_atom.getSymbolIndex().?;
2136 self.markRelocsDirtyByTarget(target);
2137}2026}
21382027
2139fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {2028fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void {
...@@ -2840,11 +2729,7 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -2840,11 +2729,7 @@ fn populateMissingMetadata(self: *MachO) !void {
2840 }2729 }
28412730
2842 if (self.stubs_section_index == null) {2731 if (self.stubs_section_index == null) {
2843 const stub_size: u32 = switch (cpu_arch) {2732 const stub_size = stubs.calcStubEntrySize(cpu_arch);
2844 .x86_64 => 6,
2845 .aarch64 => 3 * @sizeOf(u32),
2846 else => unreachable, // unhandled architecture type
2847 };
2848 self.stubs_section_index = try self.allocateSection("__TEXT2", "__stubs", .{2733 self.stubs_section_index = try self.allocateSection("__TEXT2", "__stubs", .{
2849 .size = stub_size,2734 .size = stub_size,
2850 .alignment = switch (cpu_arch) {2735 .alignment = switch (cpu_arch) {
...@@ -3377,45 +3262,35 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {...@@ -3377,45 +3262,35 @@ fn collectBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {
3377 try bind.finalize(gpa, self);3262 try bind.finalize(gpa, self);
3378}3263}
33793264
3380fn collectLazyBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void {3265fn collectLazyBindData(self: *MachO, bind: anytype) !void {
3381 const gpa = self.base.allocator;3266 const gpa = self.base.allocator;
3382 const slice = self.sections.slice();
33833267
3384 for (raw_bindings.keys(), 0..) |atom_index, i| {3268 try bind.entries.ensureUnusedCapacity(gpa, self.stub_table.entries.items.len);
3385 const atom = self.getAtom(atom_index);3269 const segment_index = self.sections.items(.segment_index)[self.la_symbol_ptr_section_index.?];
3386 log.debug(" ATOM(%{?d}, '{s}')", .{ atom.getSymbolIndex(), atom.getName(self) });3270 for (self.stub_table.entries.items, 0..) |entry, i| {
33873271 if (!self.stub_table.lookup.contains(entry)) continue;
3388 const sym = atom.getSymbol(self);3272 const bind_sym = self.getSymbol(entry);
3389 const segment_index = slice.items(.segment_index)[sym.n_sect - 1];3273 assert(bind_sym.undf());
3390 const seg = self.getSegment(sym.n_sect - 1);3274 const bind_sym_name = self.getSymbolName(entry);
33913275 const offset = i * @sizeOf(u64);
3392 const base_offset = sym.n_value - seg.vmaddr;3276 const dylib_ordinal = @divTrunc(
33933277 @bitCast(i16, bind_sym.n_desc),
3394 const bindings = raw_bindings.values()[i];3278 macho.N_SYMBOL_RESOLVER,
3395 try bind.entries.ensureUnusedCapacity(gpa, bindings.items.len);3279 );
33963280 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
3397 for (bindings.items) |binding| {3281 offset,
3398 const bind_sym = self.getSymbol(binding.target);3282 bind_sym_name,
3399 const bind_sym_name = self.getSymbolName(binding.target);3283 dylib_ordinal,
3400 const dylib_ordinal = @divTrunc(3284 });
3401 @bitCast(i16, bind_sym.n_desc),3285 if (bind_sym.weakRef()) {
3402 macho.N_SYMBOL_RESOLVER,3286 log.debug(" | marking as weak ref ", .{});
3403 );
3404 log.debug(" | bind at {x}, import('{s}') in dylib({d})", .{
3405 binding.offset + base_offset,
3406 bind_sym_name,
3407 dylib_ordinal,
3408 });
3409 if (bind_sym.weakRef()) {
3410 log.debug(" | marking as weak ref ", .{});
3411 }
3412 bind.entries.appendAssumeCapacity(.{
3413 .target = binding.target,
3414 .offset = binding.offset + base_offset,
3415 .segment_id = segment_index,
3416 .addend = 0,
3417 });
3418 }3287 }
3288 bind.entries.appendAssumeCapacity(.{
3289 .target = entry,
3290 .offset = offset,
3291 .segment_id = segment_index,
3292 .addend = 0,
3293 });
3419 }3294 }
34203295
3421 try bind.finalize(gpa, self);3296 try bind.finalize(gpa, self);
...@@ -3464,7 +3339,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -3464,7 +3339,7 @@ fn writeDyldInfoData(self: *MachO) !void {
34643339
3465 var lazy_bind = LazyBind{};3340 var lazy_bind = LazyBind{};
3466 defer lazy_bind.deinit(gpa);3341 defer lazy_bind.deinit(gpa);
3467 try self.collectLazyBindData(&lazy_bind, self.lazy_bindings);3342 try self.collectLazyBindData(&lazy_bind);
34683343
3469 var trie: Trie = .{};3344 var trie: Trie = .{};
3470 defer trie.deinit(gpa);3345 defer trie.deinit(gpa);
...@@ -3542,32 +3417,24 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void...@@ -3542,32 +3417,24 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
3542 const stub_helper_section_index = self.stub_helper_section_index.?;3417 const stub_helper_section_index = self.stub_helper_section_index.?;
3543 assert(self.stub_helper_preamble_atom_index != null);3418 assert(self.stub_helper_preamble_atom_index != null);
35443419
3545 const section = self.sections.get(stub_helper_section_index);3420 const header = self.sections.items(.header)[stub_helper_section_index];
35463421
3547 const stub_offset: u4 = switch (self.base.options.target.cpu.arch) {3422 const cpu_arch = self.base.options.target.cpu.arch;
3548 .x86_64 => 1,3423 const preamble_size = stubs.calcStubHelperPreambleSize(cpu_arch);
3549 .aarch64 => 2 * @sizeOf(u32),3424 const stub_size = stubs.calcStubHelperEntrySize(cpu_arch);
3550 else => unreachable,3425 const stub_offset = stubs.calcStubOffsetInStubHelper(cpu_arch);
3551 };3426 const base_offset = header.offset + preamble_size;
3552 const header = section.header;
3553 var atom_index = section.last_atom_index.?;
35543427
3555 var index: usize = lazy_bind.offsets.items.len;3428 for (lazy_bind.offsets.items, 0..) |bind_offset, index| {
3556 while (index > 0) : (index -= 1) {3429 const file_offset = base_offset + index * stub_size + stub_offset;
3557 const atom = self.getAtom(atom_index);
3558 const sym = atom.getSymbol(self);
3559 const file_offset = header.offset + sym.n_value - header.addr + stub_offset;
3560 const bind_offset = lazy_bind.offsets.items[index - 1];
35613430
3562 log.debug("writing lazy bind offset 0x{x} ({s}) in stub helper at 0x{x}", .{3431 log.debug("writing lazy bind offset 0x{x} ({s}) in stub helper at 0x{x}", .{
3563 bind_offset,3432 bind_offset,
3564 self.getSymbolName(lazy_bind.entries.items[index - 1].target),3433 self.getSymbolName(lazy_bind.entries.items[index].target),
3565 file_offset,3434 file_offset,
3566 });3435 });
35673436
3568 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);3437 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);
3569
3570 atom_index = atom.prev_index.?;
3571 }3438 }
3572}3439}
35733440
...@@ -3683,7 +3550,7 @@ const SymtabCtx = struct {...@@ -3683,7 +3550,7 @@ const SymtabCtx = struct {
36833550
3684fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {3551fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3685 const gpa = self.base.allocator;3552 const gpa = self.base.allocator;
3686 const nstubs = @intCast(u32, self.stubs_table.lookup.count());3553 const nstubs = @intCast(u32, self.stub_table.lookup.count());
3687 const ngot_entries = @intCast(u32, self.got_table.lookup.count());3554 const ngot_entries = @intCast(u32, self.got_table.lookup.count());
3688 const nindirectsyms = nstubs * 2 + ngot_entries;3555 const nindirectsyms = nstubs * 2 + ngot_entries;
3689 const iextdefsym = ctx.nlocalsym;3556 const iextdefsym = ctx.nlocalsym;
...@@ -3704,13 +3571,13 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {...@@ -3704,13 +3571,13 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3704 const writer = buf.writer();3571 const writer = buf.writer();
37053572
3706 if (self.stubs_section_index) |sect_id| {3573 if (self.stubs_section_index) |sect_id| {
3707 const stubs = &self.sections.items(.header)[sect_id];3574 const stubs_header = &self.sections.items(.header)[sect_id];
3708 stubs.reserved1 = 0;3575 stubs_header.reserved1 = 0;
3709 for (self.stubs_table.entries.items) |entry| {3576 for (self.stub_table.entries.items) |entry| {
3710 if (entry.sym_index == 0) continue;3577 if (!self.stub_table.lookup.contains(entry)) continue;
3711 const target_sym = self.getSymbol(entry.target);3578 const target_sym = self.getSymbol(entry);
3712 assert(target_sym.undf());3579 assert(target_sym.undf());
3713 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);3580 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
3714 }3581 }
3715 }3582 }
37163583
...@@ -3731,11 +3598,11 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {...@@ -3731,11 +3598,11 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3731 if (self.la_symbol_ptr_section_index) |sect_id| {3598 if (self.la_symbol_ptr_section_index) |sect_id| {
3732 const la_symbol_ptr = &self.sections.items(.header)[sect_id];3599 const la_symbol_ptr = &self.sections.items(.header)[sect_id];
3733 la_symbol_ptr.reserved1 = nstubs + ngot_entries;3600 la_symbol_ptr.reserved1 = nstubs + ngot_entries;
3734 for (self.stubs_table.entries.items) |entry| {3601 for (self.stub_table.entries.items) |entry| {
3735 if (entry.sym_index == 0) continue;3602 if (!self.stub_table.lookup.contains(entry)) continue;
3736 const target_sym = self.getSymbol(entry.target);3603 const target_sym = self.getSymbol(entry);
3737 assert(target_sym.undf());3604 assert(target_sym.undf());
3738 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);3605 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
3739 }3606 }
3740 }3607 }
37413608
...@@ -4422,7 +4289,7 @@ pub fn logSymtab(self: *MachO) void {...@@ -4422,7 +4289,7 @@ pub fn logSymtab(self: *MachO) void {
4422 log.debug("{}", .{self.got_table});4289 log.debug("{}", .{self.got_table});
44234290
4424 log.debug("stubs entries:", .{});4291 log.debug("stubs entries:", .{});
4425 log.debug("{}", .{self.stubs_table.fmtDebug(self)});4292 log.debug("{}", .{self.stub_table});
44264293
4427 log.debug("threadlocal entries:", .{});4294 log.debug("threadlocal entries:", .{});
4428 log.debug("{}", .{self.tlv_table.fmtDebug(self)});4295 log.debug("{}", .{self.tlv_table.fmtDebug(self)});
src/link/MachO/Atom.zig-17
...@@ -158,21 +158,6 @@ pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void...@@ -158,21 +158,6 @@ pub fn addBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void
158 try gop.value_ptr.append(gpa, binding);158 try gop.value_ptr.append(gpa, binding);
159}159}
160160
161pub fn addLazyBinding(macho_file: *MachO, atom_index: Index, binding: Binding) !void {
162 const gpa = macho_file.base.allocator;
163 const atom = macho_file.getAtom(atom_index);
164 log.debug(" (adding lazy binding to symbol {s} at offset 0x{x} in %{?d})", .{
165 macho_file.getSymbolName(binding.target),
166 binding.offset,
167 atom.getSymbolIndex(),
168 });
169 const gop = try macho_file.lazy_bindings.getOrPut(gpa, atom_index);
170 if (!gop.found_existing) {
171 gop.value_ptr.* = .{};
172 }
173 try gop.value_ptr.append(gpa, binding);
174}
175
176pub fn resolveRelocations(161pub fn resolveRelocations(
177 macho_file: *MachO,162 macho_file: *MachO,
178 atom_index: Index,163 atom_index: Index,
...@@ -193,6 +178,4 @@ pub fn freeRelocations(macho_file: *MachO, atom_index: Index) void {...@@ -193,6 +178,4 @@ pub fn freeRelocations(macho_file: *MachO, atom_index: Index) void {
193 if (removed_rebases) |*rebases| rebases.value.deinit(gpa);178 if (removed_rebases) |*rebases| rebases.value.deinit(gpa);
194 var removed_bindings = macho_file.bindings.fetchOrderedRemove(atom_index);179 var removed_bindings = macho_file.bindings.fetchOrderedRemove(atom_index);
195 if (removed_bindings) |*bindings| bindings.value.deinit(gpa);180 if (removed_bindings) |*bindings| bindings.value.deinit(gpa);
196 var removed_lazy_bindings = macho_file.lazy_bindings.fetchOrderedRemove(atom_index);
197 if (removed_lazy_bindings) |*lazy_bindings| lazy_bindings.value.deinit(gpa);
198}181}
src/link/MachO/Relocation.zig+44-5
...@@ -59,10 +59,12 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {...@@ -59,10 +59,12 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
59 return header.addr + got_index * @sizeOf(u64);59 return header.addr + got_index * @sizeOf(u64);
60 },60 },
61 .branch => {61 .branch => {
62 const atom_index = blk: {62 if (macho_file.stub_table.lookup.get(self.target)) |index| {
63 if (macho_file.stubs_table.getAtomIndex(macho_file, self.target)) |index| break :blk index;63 const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];
64 break :blk macho_file.getAtomIndexForSymbol(self.target) orelse return null;64 return header.addr +
65 };65 index * @import("stubs.zig").calcStubEntrySize(macho_file.base.options.target.cpu.arch);
66 }
67 const atom_index = macho_file.getAtomIndexForSymbol(self.target) orelse return null;
66 const atom = macho_file.getAtom(atom_index);68 const atom = macho_file.getAtom(atom_index);
67 return atom.getSymbol(macho_file).n_value;69 return atom.getSymbol(macho_file).n_value;
68 },70 },
...@@ -196,11 +198,48 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8...@@ -196,11 +198,48 @@ fn resolveX8664(self: Relocation, source_addr: u64, target_addr: i64, code: []u8
196 }198 }
197}199}
198200
199inline fn isArithmeticOp(inst: *const [4]u8) bool {201pub inline fn isArithmeticOp(inst: *const [4]u8) bool {
200 const group_decode = @truncate(u5, inst[3]);202 const group_decode = @truncate(u5, inst[3]);
201 return ((group_decode >> 2) == 4);203 return ((group_decode >> 2) == 4);
202}204}
203205
206pub fn calcPcRelativeDisplacementX86(source_addr: u64, target_addr: u64, correction: u3) error{Overflow}!i32 {
207 const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr + 4 + correction);
208 return math.cast(i32, disp) orelse error.Overflow;
209}
210
211pub fn calcPcRelativeDisplacementArm64(source_addr: u64, target_addr: u64) error{Overflow}!i28 {
212 const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr);
213 return math.cast(i28, disp) orelse error.Overflow;
214}
215
216pub fn calcNumberOfPages(source_addr: u64, target_addr: u64) i21 {
217 const source_page = @intCast(i32, source_addr >> 12);
218 const target_page = @intCast(i32, target_addr >> 12);
219 const pages = @intCast(i21, target_page - source_page);
220 return pages;
221}
222
223pub const PageOffsetInstKind = enum {
224 arithmetic,
225 load_store_8,
226 load_store_16,
227 load_store_32,
228 load_store_64,
229 load_store_128,
230};
231
232pub fn calcPageOffset(target_addr: u64, kind: PageOffsetInstKind) !u12 {
233 const narrowed = @truncate(u12, target_addr);
234 return switch (kind) {
235 .arithmetic, .load_store_8 => narrowed,
236 .load_store_16 => try math.divExact(u12, narrowed, 2),
237 .load_store_32 => try math.divExact(u12, narrowed, 4),
238 .load_store_64 => try math.divExact(u12, narrowed, 8),
239 .load_store_128 => try math.divExact(u12, narrowed, 16),
240 };
241}
242
204const Relocation = @This();243const Relocation = @This();
205244
206const std = @import("std");245const std = @import("std");
src/link/MachO/ZldAtom.zig+17-58
...@@ -21,6 +21,7 @@ const Allocator = mem.Allocator;...@@ -21,6 +21,7 @@ const Allocator = mem.Allocator;
21const Arch = std.Target.Cpu.Arch;21const Arch = std.Target.Cpu.Arch;
22const AtomIndex = @import("zld.zig").AtomIndex;22const AtomIndex = @import("zld.zig").AtomIndex;
23const Object = @import("Object.zig");23const Object = @import("Object.zig");
24const Relocation = @import("Relocation.zig");
24const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;25const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;
25const Zld = @import("zld.zig").Zld;26const Zld = @import("zld.zig").Zld;
2627
...@@ -571,7 +572,7 @@ fn resolveRelocsArm64(...@@ -571,7 +572,7 @@ fn resolveRelocsArm64(
571 zld.getAtom(getRelocTargetAtomIndex(zld, target, is_via_got).?).getFile(),572 zld.getAtom(getRelocTargetAtomIndex(zld, target, is_via_got).?).getFile(),
572 });573 });
573574
574 const displacement = if (calcPcRelativeDisplacementArm64(575 const displacement = if (Relocation.calcPcRelativeDisplacementArm64(
575 source_addr,576 source_addr,
576 zld.getSymbol(actual_target).n_value,577 zld.getSymbol(actual_target).n_value,
577 )) |disp| blk: {578 )) |disp| blk: {
...@@ -585,7 +586,7 @@ fn resolveRelocsArm64(...@@ -585,7 +586,7 @@ fn resolveRelocsArm64(
585 actual_target,586 actual_target,
586 ).?);587 ).?);
587 log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_sym.n_value});588 log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_sym.n_value});
588 break :blk try calcPcRelativeDisplacementArm64(source_addr, thunk_sym.n_value);589 break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_sym.n_value);
589 };590 };
590591
591 const code = atom_code[rel_offset..][0..4];592 const code = atom_code[rel_offset..][0..4];
...@@ -607,7 +608,7 @@ fn resolveRelocsArm64(...@@ -607,7 +608,7 @@ fn resolveRelocsArm64(
607608
608 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});609 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
609610
610 const pages = @bitCast(u21, calcNumberOfPages(source_addr, adjusted_target_addr));611 const pages = @bitCast(u21, Relocation.calcNumberOfPages(source_addr, adjusted_target_addr));
611 const code = atom_code[rel_offset..][0..4];612 const code = atom_code[rel_offset..][0..4];
612 var inst = aarch64.Instruction{613 var inst = aarch64.Instruction{
613 .pc_relative_address = mem.bytesToValue(meta.TagPayload(614 .pc_relative_address = mem.bytesToValue(meta.TagPayload(
...@@ -627,8 +628,8 @@ fn resolveRelocsArm64(...@@ -627,8 +628,8 @@ fn resolveRelocsArm64(
627 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});628 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
628629
629 const code = atom_code[rel_offset..][0..4];630 const code = atom_code[rel_offset..][0..4];
630 if (isArithmeticOp(code)) {631 if (Relocation.isArithmeticOp(code)) {
631 const off = try calcPageOffset(adjusted_target_addr, .arithmetic);632 const off = try Relocation.calcPageOffset(adjusted_target_addr, .arithmetic);
632 var inst = aarch64.Instruction{633 var inst = aarch64.Instruction{
633 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(634 .add_subtract_immediate = mem.bytesToValue(meta.TagPayload(
634 aarch64.Instruction,635 aarch64.Instruction,
...@@ -644,11 +645,11 @@ fn resolveRelocsArm64(...@@ -644,11 +645,11 @@ fn resolveRelocsArm64(
644 aarch64.Instruction.load_store_register,645 aarch64.Instruction.load_store_register,
645 ), code),646 ), code),
646 };647 };
647 const off = try calcPageOffset(adjusted_target_addr, switch (inst.load_store_register.size) {648 const off = try Relocation.calcPageOffset(adjusted_target_addr, switch (inst.load_store_register.size) {
648 0 => if (inst.load_store_register.v == 1)649 0 => if (inst.load_store_register.v == 1)
649 PageOffsetInstKind.load_store_128650 Relocation.PageOffsetInstKind.load_store_128
650 else651 else
651 PageOffsetInstKind.load_store_8,652 Relocation.PageOffsetInstKind.load_store_8,
652 1 => .load_store_16,653 1 => .load_store_16,
653 2 => .load_store_32,654 2 => .load_store_32,
654 3 => .load_store_64,655 3 => .load_store_64,
...@@ -665,7 +666,7 @@ fn resolveRelocsArm64(...@@ -665,7 +666,7 @@ fn resolveRelocsArm64(
665666
666 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});667 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
667668
668 const off = try calcPageOffset(adjusted_target_addr, .load_store_64);669 const off = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64);
669 var inst: aarch64.Instruction = .{670 var inst: aarch64.Instruction = .{
670 .load_store_register = mem.bytesToValue(meta.TagPayload(671 .load_store_register = mem.bytesToValue(meta.TagPayload(
671 aarch64.Instruction,672 aarch64.Instruction,
...@@ -689,7 +690,7 @@ fn resolveRelocsArm64(...@@ -689,7 +690,7 @@ fn resolveRelocsArm64(
689 size: u2,690 size: u2,
690 };691 };
691 const reg_info: RegInfo = blk: {692 const reg_info: RegInfo = blk: {
692 if (isArithmeticOp(code)) {693 if (Relocation.isArithmeticOp(code)) {
693 const inst = mem.bytesToValue(meta.TagPayload(694 const inst = mem.bytesToValue(meta.TagPayload(
694 aarch64.Instruction,695 aarch64.Instruction,
695 aarch64.Instruction.add_subtract_immediate,696 aarch64.Instruction.add_subtract_immediate,
...@@ -716,7 +717,7 @@ fn resolveRelocsArm64(...@@ -716,7 +717,7 @@ fn resolveRelocsArm64(
716 .load_store_register = .{717 .load_store_register = .{
717 .rt = reg_info.rd,718 .rt = reg_info.rd,
718 .rn = reg_info.rn,719 .rn = reg_info.rn,
719 .offset = try calcPageOffset(adjusted_target_addr, .load_store_64),720 .offset = try Relocation.calcPageOffset(adjusted_target_addr, .load_store_64),
720 .opc = 0b01,721 .opc = 0b01,
721 .op1 = 0b01,722 .op1 = 0b01,
722 .v = 0,723 .v = 0,
...@@ -726,7 +727,7 @@ fn resolveRelocsArm64(...@@ -726,7 +727,7 @@ fn resolveRelocsArm64(
726 .add_subtract_immediate = .{727 .add_subtract_immediate = .{
727 .rd = reg_info.rd,728 .rd = reg_info.rd,
728 .rn = reg_info.rn,729 .rn = reg_info.rn,
729 .imm12 = try calcPageOffset(adjusted_target_addr, .arithmetic),730 .imm12 = try Relocation.calcPageOffset(adjusted_target_addr, .arithmetic),
730 .sh = 0,731 .sh = 0,
731 .s = 0,732 .s = 0,
732 .op = 0,733 .op = 0,
...@@ -858,7 +859,7 @@ fn resolveRelocsX86(...@@ -858,7 +859,7 @@ fn resolveRelocsX86(
858 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);859 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
859 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);860 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);
860 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});861 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
861 const disp = try calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);862 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
862 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);863 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
863 },864 },
864865
...@@ -868,7 +869,7 @@ fn resolveRelocsX86(...@@ -868,7 +869,7 @@ fn resolveRelocsX86(
868 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);869 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
869 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);870 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);
870 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});871 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
871 const disp = try calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);872 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
872 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);873 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
873 },874 },
874875
...@@ -876,7 +877,7 @@ fn resolveRelocsX86(...@@ -876,7 +877,7 @@ fn resolveRelocsX86(
876 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);877 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
877 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);878 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);
878 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});879 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
879 const disp = try calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);880 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
880881
881 if (zld.tlv_ptr_table.get(target) == null) {882 if (zld.tlv_ptr_table.get(target) == null) {
882 // We need to rewrite the opcode from movq to leaq.883 // We need to rewrite the opcode from movq to leaq.
...@@ -913,7 +914,7 @@ fn resolveRelocsX86(...@@ -913,7 +914,7 @@ fn resolveRelocsX86(
913914
914 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});915 log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr});
915916
916 const disp = try calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction);917 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, correction);
917 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);918 mem.writeIntLittle(i32, atom_code[rel_offset..][0..4], disp);
918 },919 },
919920
...@@ -955,11 +956,6 @@ fn resolveRelocsX86(...@@ -955,11 +956,6 @@ fn resolveRelocsX86(
955 }956 }
956}957}
957958
958inline fn isArithmeticOp(inst: *const [4]u8) bool {
959 const group_decode = @truncate(u5, inst[3]);
960 return ((group_decode >> 2) == 4);
961}
962
963pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 {959pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 {
964 const atom = zld.getAtom(atom_index);960 const atom = zld.getAtom(atom_index);
965 assert(atom.getFile() != null); // Synthetic atom shouldn't need to inquire for code.961 assert(atom.getFile() != null); // Synthetic atom shouldn't need to inquire for code.
...@@ -1006,43 +1002,6 @@ pub fn getAtomRelocs(zld: *Zld, atom_index: AtomIndex) []const macho.relocation_...@@ -1006,43 +1002,6 @@ pub fn getAtomRelocs(zld: *Zld, atom_index: AtomIndex) []const macho.relocation_
1006 return relocs[cache.start..][0..cache.len];1002 return relocs[cache.start..][0..cache.len];
1007}1003}
10081004
1009pub fn calcPcRelativeDisplacementX86(source_addr: u64, target_addr: u64, correction: u3) error{Overflow}!i32 {
1010 const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr + 4 + correction);
1011 return math.cast(i32, disp) orelse error.Overflow;
1012}
1013
1014pub fn calcPcRelativeDisplacementArm64(source_addr: u64, target_addr: u64) error{Overflow}!i28 {
1015 const disp = @intCast(i64, target_addr) - @intCast(i64, source_addr);
1016 return math.cast(i28, disp) orelse error.Overflow;
1017}
1018
1019pub fn calcNumberOfPages(source_addr: u64, target_addr: u64) i21 {
1020 const source_page = @intCast(i32, source_addr >> 12);
1021 const target_page = @intCast(i32, target_addr >> 12);
1022 const pages = @intCast(i21, target_page - source_page);
1023 return pages;
1024}
1025
1026const PageOffsetInstKind = enum {
1027 arithmetic,
1028 load_store_8,
1029 load_store_16,
1030 load_store_32,
1031 load_store_64,
1032 load_store_128,
1033};
1034
1035pub fn calcPageOffset(target_addr: u64, kind: PageOffsetInstKind) !u12 {
1036 const narrowed = @truncate(u12, target_addr);
1037 return switch (kind) {
1038 .arithmetic, .load_store_8 => narrowed,
1039 .load_store_16 => try math.divExact(u12, narrowed, 2),
1040 .load_store_32 => try math.divExact(u12, narrowed, 4),
1041 .load_store_64 => try math.divExact(u12, narrowed, 8),
1042 .load_store_128 => try math.divExact(u12, narrowed, 16),
1043 };
1044}
1045
1046pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool {1005pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool {
1047 switch (zld.options.target.cpu.arch) {1006 switch (zld.options.target.cpu.arch) {
1048 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {1007 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
src/link/MachO/eh_frame.zig+2-1
...@@ -9,6 +9,7 @@ const log = std.log.scoped(.eh_frame);...@@ -9,6 +9,7 @@ const log = std.log.scoped(.eh_frame);
9const Allocator = mem.Allocator;9const Allocator = mem.Allocator;
10const AtomIndex = @import("zld.zig").AtomIndex;10const AtomIndex = @import("zld.zig").AtomIndex;
11const Atom = @import("ZldAtom.zig");11const Atom = @import("ZldAtom.zig");
12const Relocation = @import("Relocation.zig");
12const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;13const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;
13const UnwindInfo = @import("UnwindInfo.zig");14const UnwindInfo = @import("UnwindInfo.zig");
14const Zld = @import("zld.zig").Zld;15const Zld = @import("zld.zig").Zld;
...@@ -368,7 +369,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -368,7 +369,7 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
368 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false);369 const target_addr = try Atom.getRelocTargetAddress(zld, target, true, false);
369 const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]);370 const addend = mem.readIntLittle(i32, rec.data[rel_offset..][0..4]);
370 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);371 const adjusted_target_addr = @intCast(u64, @intCast(i64, target_addr) + addend);
371 const disp = try Atom.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);372 const disp = try Relocation.calcPcRelativeDisplacementX86(source_addr, adjusted_target_addr, 0);
372 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], disp);373 mem.writeIntLittle(i32, rec.data[rel_offset..][0..4], disp);
373 },374 },
374 else => unreachable,375 else => unreachable,
src/link/MachO/stubs.zig created+161
...@@ -0,0 +1,161 @@
1const std = @import("std");
2const aarch64 = @import("../../arch/aarch64/bits.zig");
3
4const Relocation = @import("Relocation.zig");
5
6pub inline fn calcStubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u5 {
7 return switch (cpu_arch) {
8 .x86_64 => 15,
9 .aarch64 => 6 * @sizeOf(u32),
10 else => unreachable, // unhandled architecture type
11 };
12}
13
14pub inline fn calcStubHelperEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {
15 return switch (cpu_arch) {
16 .x86_64 => 10,
17 .aarch64 => 3 * @sizeOf(u32),
18 else => unreachable, // unhandled architecture type
19 };
20}
21
22pub inline fn calcStubEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {
23 return switch (cpu_arch) {
24 .x86_64 => 6,
25 .aarch64 => 3 * @sizeOf(u32),
26 else => unreachable, // unhandled architecture type
27 };
28}
29
30pub inline fn calcStubOffsetInStubHelper(cpu_arch: std.Target.Cpu.Arch) u4 {
31 return switch (cpu_arch) {
32 .x86_64 => 1,
33 .aarch64 => 2 * @sizeOf(u32),
34 else => unreachable,
35 };
36}
37
38pub fn writeStubHelperPreambleCode(args: struct {
39 cpu_arch: std.Target.Cpu.Arch,
40 source_addr: u64,
41 dyld_private_addr: u64,
42 dyld_stub_binder_got_addr: u64,
43}, writer: anytype) !void {
44 switch (args.cpu_arch) {
45 .x86_64 => {
46 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });
47 {
48 const disp = try Relocation.calcPcRelativeDisplacementX86(
49 args.source_addr + 3,
50 args.dyld_private_addr,
51 0,
52 );
53 try writer.writeIntLittle(i32, disp);
54 }
55 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
56 {
57 const disp = try Relocation.calcPcRelativeDisplacementX86(
58 args.source_addr + 11,
59 args.dyld_stub_binder_got_addr,
60 0,
61 );
62 try writer.writeIntLittle(i32, disp);
63 }
64 },
65 .aarch64 => {
66 {
67 const pages = Relocation.calcNumberOfPages(args.source_addr, args.dyld_private_addr);
68 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x17, pages).toU32());
69 }
70 {
71 const off = try Relocation.calcPageOffset(args.dyld_private_addr, .arithmetic);
72 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32());
73 }
74 try writer.writeIntLittle(u32, aarch64.Instruction.stp(
75 .x16,
76 .x17,
77 aarch64.Register.sp,
78 aarch64.Instruction.LoadStorePairOffset.pre_index(-16),
79 ).toU32());
80 {
81 const pages = Relocation.calcNumberOfPages(args.source_addr + 12, args.dyld_stub_binder_got_addr);
82 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
83 }
84 {
85 const off = try Relocation.calcPageOffset(args.dyld_stub_binder_got_addr, .load_store_64);
86 try writer.writeIntLittle(u32, aarch64.Instruction.ldr(
87 .x16,
88 .x16,
89 aarch64.Instruction.LoadStoreOffset.imm(off),
90 ).toU32());
91 }
92 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
93 },
94 else => unreachable,
95 }
96}
97
98pub fn writeStubHelperCode(args: struct {
99 cpu_arch: std.Target.Cpu.Arch,
100 source_addr: u64,
101 target_addr: u64,
102}, writer: anytype) !void {
103 switch (args.cpu_arch) {
104 .x86_64 => {
105 try writer.writeAll(&.{ 0x68, 0x0, 0x0, 0x0, 0x0, 0xe9 });
106 {
107 const disp = try Relocation.calcPcRelativeDisplacementX86(args.source_addr + 6, args.target_addr, 0);
108 try writer.writeIntLittle(i32, disp);
109 }
110 },
111 .aarch64 => {
112 const stub_size: u4 = 3 * @sizeOf(u32);
113 const literal = blk: {
114 const div_res = try std.math.divExact(u64, stub_size - @sizeOf(u32), 4);
115 break :blk std.math.cast(u18, div_res) orelse return error.Overflow;
116 };
117 try writer.writeIntLittle(u32, aarch64.Instruction.ldrLiteral(
118 .w16,
119 literal,
120 ).toU32());
121 {
122 const disp = try Relocation.calcPcRelativeDisplacementArm64(args.source_addr + 4, args.target_addr);
123 try writer.writeIntLittle(u32, aarch64.Instruction.b(disp).toU32());
124 }
125 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
126 },
127 else => unreachable,
128 }
129}
130
131pub fn writeStubCode(args: struct {
132 cpu_arch: std.Target.Cpu.Arch,
133 source_addr: u64,
134 target_addr: u64,
135}, writer: anytype) !void {
136 switch (args.cpu_arch) {
137 .x86_64 => {
138 try writer.writeAll(&.{ 0xff, 0x25 });
139 {
140 const disp = try Relocation.calcPcRelativeDisplacementX86(args.source_addr + 2, args.target_addr, 0);
141 try writer.writeIntLittle(i32, disp);
142 }
143 },
144 .aarch64 => {
145 {
146 const pages = Relocation.calcNumberOfPages(args.source_addr, args.target_addr);
147 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
148 }
149 {
150 const off = try Relocation.calcPageOffset(args.target_addr, .load_store_64);
151 try writer.writeIntLittle(u32, aarch64.Instruction.ldr(
152 .x16,
153 .x16,
154 aarch64.Instruction.LoadStoreOffset.imm(off),
155 ).toU32());
156 }
157 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
158 },
159 else => unreachable,
160 }
161}
src/link/MachO/thunks.zig+4-3
...@@ -17,6 +17,7 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");...@@ -17,6 +17,7 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");
17const Allocator = mem.Allocator;17const Allocator = mem.Allocator;
18const Atom = @import("ZldAtom.zig");18const Atom = @import("ZldAtom.zig");
19const AtomIndex = @import("zld.zig").AtomIndex;19const AtomIndex = @import("zld.zig").AtomIndex;
20const Relocation = @import("Relocation.zig");
20const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;21const SymbolWithLoc = @import("zld.zig").SymbolWithLoc;
21const Zld = @import("zld.zig").Zld;22const Zld = @import("zld.zig").Zld;
2223
...@@ -317,7 +318,7 @@ fn isReachable(...@@ -317,7 +318,7 @@ fn isReachable(
317 const source_addr = source_sym.n_value + @intCast(u32, rel.r_address - base_offset);318 const source_addr = source_sym.n_value + @intCast(u32, rel.r_address - base_offset);
318 const is_via_got = Atom.relocRequiresGot(zld, rel);319 const is_via_got = Atom.relocRequiresGot(zld, rel);
319 const target_addr = Atom.getRelocTargetAddress(zld, target, is_via_got, false) catch unreachable;320 const target_addr = Atom.getRelocTargetAddress(zld, target, is_via_got, false) catch unreachable;
320 _ = Atom.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch321 _ = Relocation.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch
321 return false;322 return false;
322323
323 return true;324 return true;
...@@ -364,9 +365,9 @@ pub fn writeThunkCode(zld: *Zld, atom_index: AtomIndex, writer: anytype) !void {...@@ -364,9 +365,9 @@ pub fn writeThunkCode(zld: *Zld, atom_index: AtomIndex, writer: anytype) !void {
364 if (atom_index == target_atom_index) break zld.getSymbol(target).n_value;365 if (atom_index == target_atom_index) break zld.getSymbol(target).n_value;
365 } else unreachable;366 } else unreachable;
366367
367 const pages = Atom.calcNumberOfPages(source_addr, target_addr);368 const pages = Relocation.calcNumberOfPages(source_addr, target_addr);
368 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());369 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
369 const off = try Atom.calcPageOffset(target_addr, .arithmetic);370 const off = try Relocation.calcPageOffset(target_addr, .arithmetic);
370 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32());371 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32());
371 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());372 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
372}373}
src/link/MachO/zld.zig+20-110
...@@ -16,6 +16,7 @@ const link = @import("../../link.zig");...@@ -16,6 +16,7 @@ const link = @import("../../link.zig");
16const load_commands = @import("load_commands.zig");16const load_commands = @import("load_commands.zig");
17const thunks = @import("thunks.zig");17const thunks = @import("thunks.zig");
18const trace = @import("../../tracy.zig").trace;18const trace = @import("../../tracy.zig").trace;
19const stub_helpers = @import("stubs.zig");
1920
20const Allocator = mem.Allocator;21const Allocator = mem.Allocator;
21const Archive = @import("Archive.zig");22const Archive = @import("Archive.zig");
...@@ -666,59 +667,17 @@ pub const Zld = struct {...@@ -666,59 +667,17 @@ pub const Zld = struct {
666 const entry = self.got_entries.items[index];667 const entry = self.got_entries.items[index];
667 break :blk entry.getAtomSymbol(self).n_value;668 break :blk entry.getAtomSymbol(self).n_value;
668 };669 };
669 switch (cpu_arch) {670 try stub_helpers.writeStubHelperPreambleCode(.{
670 .x86_64 => {671 .cpu_arch = cpu_arch,
671 try writer.writeAll(&.{ 0x4c, 0x8d, 0x1d });672 .source_addr = source_addr,
672 {673 .dyld_private_addr = dyld_private_addr,
673 const disp = try Atom.calcPcRelativeDisplacementX86(source_addr + 3, dyld_private_addr, 0);674 .dyld_stub_binder_got_addr = dyld_stub_binder_got_addr,
674 try writer.writeIntLittle(i32, disp);675 }, writer);
675 }
676 try writer.writeAll(&.{ 0x41, 0x53, 0xff, 0x25 });
677 {
678 const disp = try Atom.calcPcRelativeDisplacementX86(source_addr + 11, dyld_stub_binder_got_addr, 0);
679 try writer.writeIntLittle(i32, disp);
680 }
681 },
682 .aarch64 => {
683 {
684 const pages = Atom.calcNumberOfPages(source_addr, dyld_private_addr);
685 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x17, pages).toU32());
686 }
687 {
688 const off = try Atom.calcPageOffset(dyld_private_addr, .arithmetic);
689 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x17, .x17, off, false).toU32());
690 }
691 try writer.writeIntLittle(u32, aarch64.Instruction.stp(
692 .x16,
693 .x17,
694 aarch64.Register.sp,
695 aarch64.Instruction.LoadStorePairOffset.pre_index(-16),
696 ).toU32());
697 {
698 const pages = Atom.calcNumberOfPages(source_addr + 12, dyld_stub_binder_got_addr);
699 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
700 }
701 {
702 const off = try Atom.calcPageOffset(dyld_stub_binder_got_addr, .load_store_64);
703 try writer.writeIntLittle(u32, aarch64.Instruction.ldr(
704 .x16,
705 .x16,
706 aarch64.Instruction.LoadStoreOffset.imm(off),
707 ).toU32());
708 }
709 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
710 },
711 else => unreachable,
712 }
713 }676 }
714677
715 pub fn createStubHelperAtom(self: *Zld) !AtomIndex {678 pub fn createStubHelperAtom(self: *Zld) !AtomIndex {
716 const cpu_arch = self.options.target.cpu.arch;679 const cpu_arch = self.options.target.cpu.arch;
717 const stub_size: u4 = switch (cpu_arch) {680 const stub_size = stub_helpers.calcStubHelperEntrySize(cpu_arch);
718 .x86_64 => 10,
719 .aarch64 => 3 * @sizeOf(u32),
720 else => unreachable,
721 };
722 const alignment: u2 = switch (cpu_arch) {681 const alignment: u2 = switch (cpu_arch) {
723 .x86_64 => 0,682 .x86_64 => 0,
724 .aarch64 => 2,683 .aarch64 => 2,
...@@ -749,32 +708,11 @@ pub const Zld = struct {...@@ -749,32 +708,11 @@ pub const Zld = struct {
749 const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? });708 const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? });
750 break :blk sym.n_value;709 break :blk sym.n_value;
751 };710 };
752 switch (cpu_arch) {711 try stub_helpers.writeStubHelperCode(.{
753 .x86_64 => {712 .cpu_arch = cpu_arch,
754 try writer.writeAll(&.{ 0x68, 0x0, 0x0, 0x0, 0x0, 0xe9 });713 .source_addr = source_addr,
755 {714 .target_addr = target_addr,
756 const disp = try Atom.calcPcRelativeDisplacementX86(source_addr + 6, target_addr, 0);715 }, writer);
757 try writer.writeIntLittle(i32, disp);
758 }
759 },
760 .aarch64 => {
761 const stub_size: u4 = 3 * @sizeOf(u32);
762 const literal = blk: {
763 const div_res = try math.divExact(u64, stub_size - @sizeOf(u32), 4);
764 break :blk math.cast(u18, div_res) orelse return error.Overflow;
765 };
766 try writer.writeIntLittle(u32, aarch64.Instruction.ldrLiteral(
767 .w16,
768 literal,
769 ).toU32());
770 {
771 const disp = try Atom.calcPcRelativeDisplacementArm64(source_addr + 4, target_addr);
772 try writer.writeIntLittle(u32, aarch64.Instruction.b(disp).toU32());
773 }
774 try writer.writeAll(&.{ 0x0, 0x0, 0x0, 0x0 });
775 },
776 else => unreachable,
777 }
778 }716 }
779717
780 pub fn createLazyPointerAtom(self: *Zld) !AtomIndex {718 pub fn createLazyPointerAtom(self: *Zld) !AtomIndex {
...@@ -819,11 +757,7 @@ pub const Zld = struct {...@@ -819,11 +757,7 @@ pub const Zld = struct {
819 .aarch64 => 2,757 .aarch64 => 2,
820 else => unreachable, // unhandled architecture type758 else => unreachable, // unhandled architecture type
821 };759 };
822 const stub_size: u4 = switch (cpu_arch) {760 const stub_size = stub_helpers.calcStubEntrySize(cpu_arch);
823 .x86_64 => 6,
824 .aarch64 => 3 * @sizeOf(u32),
825 else => unreachable, // unhandled architecture type
826 };
827 const sym_index = try self.allocateSymbol();761 const sym_index = try self.allocateSymbol();
828 const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment);762 const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment);
829 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });763 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
...@@ -863,31 +797,11 @@ pub const Zld = struct {...@@ -863,31 +797,11 @@ pub const Zld = struct {
863 const sym = self.getSymbol(atom.getSymbolWithLoc());797 const sym = self.getSymbol(atom.getSymbolWithLoc());
864 break :blk sym.n_value;798 break :blk sym.n_value;
865 };799 };
866 switch (cpu_arch) {800 try stub_helpers.writeStubCode(.{
867 .x86_64 => {801 .cpu_arch = cpu_arch,
868 try writer.writeAll(&.{ 0xff, 0x25 });802 .source_addr = source_addr,
869 {803 .target_addr = target_addr,
870 const disp = try Atom.calcPcRelativeDisplacementX86(source_addr + 2, target_addr, 0);804 }, writer);
871 try writer.writeIntLittle(i32, disp);
872 }
873 },
874 .aarch64 => {
875 {
876 const pages = Atom.calcNumberOfPages(source_addr, target_addr);
877 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
878 }
879 {
880 const off = try Atom.calcPageOffset(target_addr, .load_store_64);
881 try writer.writeIntLittle(u32, aarch64.Instruction.ldr(
882 .x16,
883 .x16,
884 aarch64.Instruction.LoadStoreOffset.imm(off),
885 ).toU32());
886 }
887 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
888 },
889 else => unreachable,
890 }
891 }805 }
892806
893 fn createTentativeDefAtoms(self: *Zld) !void {807 fn createTentativeDefAtoms(self: *Zld) !void {
...@@ -2267,11 +2181,7 @@ pub const Zld = struct {...@@ -2267,11 +2181,7 @@ pub const Zld = struct {
2267 assert(self.stub_helper_preamble_sym_index != null);2181 assert(self.stub_helper_preamble_sym_index != null);
22682182
2269 const section = self.sections.get(stub_helper_section_index);2183 const section = self.sections.get(stub_helper_section_index);
2270 const stub_offset: u4 = switch (self.options.target.cpu.arch) {2184 const stub_offset = stub_helpers.calcStubOffsetInStubHelper(self.options.target.cpu.arch);
2271 .x86_64 => 1,
2272 .aarch64 => 2 * @sizeOf(u32),
2273 else => unreachable,
2274 };
2275 const header = section.header;2185 const header = section.header;
2276 var atom_index = section.first_atom_index;2186 var atom_index = section.first_atom_index;
2277 atom_index = self.getAtom(atom_index).next_index.?; // skip preamble2187 atom_index = self.getAtom(atom_index).next_index.?; // skip preamble