| author | |
| committer | |
| log | fa40267b04e29fa8e36e73cb54eb68d58d26fa8d |
| tree | c6f77455c305e37e13d66eda48da736c93b4c9d6 |
| parent | c55e821df6d6adca449720e052f40463eef8174b |
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"); |
| 19 | const link = @import("../link.zig"); | 19 | const link = @import("../link.zig"); |
| 20 | const llvm_backend = @import("../codegen/llvm.zig"); | 20 | const llvm_backend = @import("../codegen/llvm.zig"); |
| 21 | const load_commands = @import("MachO/load_commands.zig"); | 21 | const load_commands = @import("MachO/load_commands.zig"); |
| 22 | const stubs = @import("MachO/stubs.zig"); | ||
| 22 | const target_util = @import("../target.zig"); | 23 | const target_util = @import("../target.zig"); |
| 23 | const trace = @import("../tracy.zig").trace; | 24 | const trace = @import("../tracy.zig").trace; |
| 24 | const zld = @import("MachO/zld.zig"); | 25 | const 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, |
| 156 | strtab: StringTable(.strtab) = .{}, | 157 | strtab: StringTable(.strtab) = .{}, |
| 157 | 158 | ||
| 158 | got_table: TableSection(SymbolWithLoc) = .{}, | 159 | got_table: TableSection(SymbolWithLoc) = .{}, |
| 159 | stubs_table: SectionTable = .{}, | 160 | stub_table: TableSection(SymbolWithLoc) = .{}, |
| 160 | tlv_table: SectionTable = .{}, | 161 | tlv_table: SectionTable = .{}, |
| 161 | 162 | ||
| 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 163 | error_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{}, |
| 164 | segment_table_dirty: bool = false, | 165 | segment_table_dirty: bool = false, |
| 165 | got_table_count_dirty: bool = false, | 166 | got_table_count_dirty: bool = false, |
| 166 | got_table_contents_dirty: bool = false, | 167 | got_table_contents_dirty: bool = false, |
| 168 | stub_table_count_dirty: bool = false, | ||
| 169 | stub_table_contents_dirty: bool = false, | ||
| 167 | 170 | ||
| 168 | /// A helper var to indicate if we are at the start of the incremental updates, or | 171 | /// 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. |
| 214 | bindings: BindingTable = .{}, | 217 | bindings: BindingTable = .{}, |
| 215 | 218 | ||
| 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. | ||
| 219 | lazy_bindings: BindingTable = .{}, | ||
| 220 | |||
| 221 | /// Table of tracked LazySymbols. | 219 | /// Table of tracked LazySymbols. |
| 222 | lazy_syms: LazySymbolTable = .{}, | 220 | lazy_syms: LazySymbolTable = .{}, |
| 223 | 221 | ||
| ... | @@ -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 | } |
| 770 | 769 | ||
| 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 | } |
| 1313 | 1323 | ||
| 1324 | fn 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 | |||
| 1314 | fn writePtrWidthAtom(self: *MachO, atom_index: Atom.Index) !void { | 1404 | fn 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 | } |
| 1340 | 1430 | ||
| 1341 | // Dirty synthetic table sections if necessary | 1431 | // 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 | } |
| 1350 | 1444 | ||
| ... | @@ -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 | } |
| 1527 | 1621 | ||
| 1528 | fn 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 | |||
| 1609 | fn 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 | |||
| 1639 | fn 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 | |||
| 1722 | fn createThreadLocalDescriptorAtom(self: *MachO, target: SymbolWithLoc) !Atom.Index { | 1622 | fn 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 | } |
| 1905 | 1805 | ||
| 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); |
| 1910 | 1810 | ||
| ... | @@ -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 | } |
| 1977 | 1872 | ||
| 1978 | fn freeAtom(self: *MachO, atom_index: Atom.Index) void { | 1873 | fn 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 | } |
| 2125 | 2020 | ||
| 2126 | fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void { | 2021 | fn 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 | } |
| 2138 | 2027 | ||
| 2139 | fn addTlvEntry(self: *MachO, target: SymbolWithLoc) !void { | 2028 | fn 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 | } |
| 2841 | 2730 | ||
| 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 | } |
| 3379 | 3264 | ||
| 3380 | fn collectLazyBindData(self: *MachO, bind: anytype, raw_bindings: anytype) !void { | 3265 | fn collectLazyBindData(self: *MachO, bind: anytype) !void { |
| 3381 | const gpa = self.base.allocator; | 3266 | const gpa = self.base.allocator; |
| 3382 | const slice = self.sections.slice(); | ||
| 3383 | 3267 | ||
| 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| { |
| 3387 | 3271 | 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); |
| 3391 | 3275 | const offset = i * @sizeOf(u64); | |
| 3392 | const base_offset = sym.n_value - seg.vmaddr; | 3276 | const dylib_ordinal = @divTrunc( |
| 3393 | 3277 | @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 | ); |
| 3396 | 3280 | 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 | } |
| 3420 | 3295 | ||
| 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 { |
| 3464 | 3339 | ||
| 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); |
| 3468 | 3343 | ||
| 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); |
| 3544 | 3419 | ||
| 3545 | const section = self.sections.get(stub_helper_section_index); | 3420 | const header = self.sections.items(.header)[stub_helper_section_index]; |
| 3546 | 3421 | ||
| 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.?; | ||
| 3554 | 3427 | ||
| 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]; | ||
| 3561 | 3430 | ||
| 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 | }); |
| 3567 | 3436 | ||
| 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 | } |
| 3573 | 3440 | ||
| ... | @@ -3683,7 +3550,7 @@ const SymtabCtx = struct { | ... | @@ -3683,7 +3550,7 @@ const SymtabCtx = struct { |
| 3683 | 3550 | ||
| 3684 | fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void { | 3551 | fn 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(); |
| 3705 | 3572 | ||
| 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 | } |
| 3716 | 3583 | ||
| ... | @@ -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 | } |
| 3741 | 3608 | ||
| ... | @@ -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}); |
| 4423 | 4290 | ||
| 4424 | log.debug("stubs entries:", .{}); | 4291 | log.debug("stubs entries:", .{}); |
| 4425 | log.debug("{}", .{self.stubs_table.fmtDebug(self)}); | 4292 | log.debug("{}", .{self.stub_table}); |
| 4426 | 4293 | ||
| 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 | } |
| 160 | 160 | ||
| 161 | pub 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 | |||
| 176 | pub fn resolveRelocations( | 161 | pub 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 | } |
| 198 | 200 | ||
| 199 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | 201 | pub 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 | } |
| 203 | 205 | ||
| 206 | pub 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 | |||
| 211 | pub 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 | |||
| 216 | pub 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 | |||
| 223 | pub 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 | |||
| 232 | pub 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 | |||
| 204 | const Relocation = @This(); | 243 | const Relocation = @This(); |
| 205 | 244 | ||
| 206 | const std = @import("std"); | 245 | const 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; |
| 21 | const Arch = std.Target.Cpu.Arch; | 21 | const Arch = std.Target.Cpu.Arch; |
| 22 | const AtomIndex = @import("zld.zig").AtomIndex; | 22 | const AtomIndex = @import("zld.zig").AtomIndex; |
| 23 | const Object = @import("Object.zig"); | 23 | const Object = @import("Object.zig"); |
| 24 | const Relocation = @import("Relocation.zig"); | ||
| 24 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; | 25 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; |
| 25 | const Zld = @import("zld.zig").Zld; | 26 | const Zld = @import("zld.zig").Zld; |
| 26 | 27 | ||
| ... | @@ -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 | }); |
| 573 | 574 | ||
| 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 | }; |
| 590 | 591 | ||
| 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( |
| 607 | 608 | ||
| 608 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | 609 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); |
| 609 | 610 | ||
| 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}); |
| 628 | 629 | ||
| 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_128 | 650 | Relocation.PageOffsetInstKind.load_store_128 |
| 650 | else | 651 | 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( |
| 665 | 666 | ||
| 666 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | 667 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); |
| 667 | 668 | ||
| 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 | }, |
| 864 | 865 | ||
| ... | @@ -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 | }, |
| 874 | 875 | ||
| ... | @@ -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); |
| 880 | 881 | ||
| 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( |
| 913 | 914 | ||
| 914 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); | 915 | log.debug(" | target_addr = 0x{x}", .{adjusted_target_addr}); |
| 915 | 916 | ||
| 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 | }, |
| 919 | 920 | ||
| ... | @@ -955,11 +956,6 @@ fn resolveRelocsX86( | ... | @@ -955,11 +956,6 @@ fn resolveRelocsX86( |
| 955 | } | 956 | } |
| 956 | } | 957 | } |
| 957 | 958 | ||
| 958 | inline fn isArithmeticOp(inst: *const [4]u8) bool { | ||
| 959 | const group_decode = @truncate(u5, inst[3]); | ||
| 960 | return ((group_decode >> 2) == 4); | ||
| 961 | } | ||
| 962 | |||
| 963 | pub fn getAtomCode(zld: *Zld, atom_index: AtomIndex) []const u8 { | 959 | pub 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 | } |
| 1008 | 1004 | ||
| 1009 | pub 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 | |||
| 1014 | pub 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 | |||
| 1019 | pub 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 | |||
| 1026 | const 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 | |||
| 1035 | pub 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 | |||
| 1046 | pub fn relocRequiresGot(zld: *Zld, rel: macho.relocation_info) bool { | 1005 | pub 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); |
| 9 | const Allocator = mem.Allocator; | 9 | const Allocator = mem.Allocator; |
| 10 | const AtomIndex = @import("zld.zig").AtomIndex; | 10 | const AtomIndex = @import("zld.zig").AtomIndex; |
| 11 | const Atom = @import("ZldAtom.zig"); | 11 | const Atom = @import("ZldAtom.zig"); |
| 12 | const Relocation = @import("Relocation.zig"); | ||
| 12 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; | 13 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; |
| 13 | const UnwindInfo = @import("UnwindInfo.zig"); | 14 | const UnwindInfo = @import("UnwindInfo.zig"); |
| 14 | const Zld = @import("zld.zig").Zld; | 15 | const 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 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const aarch64 = @import("../../arch/aarch64/bits.zig"); | ||
| 3 | |||
| 4 | const Relocation = @import("Relocation.zig"); | ||
| 5 | |||
| 6 | pub 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 | |||
| 14 | pub 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 | |||
| 22 | pub 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 | |||
| 30 | pub 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 | |||
| 38 | pub 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 | |||
| 98 | pub 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 | |||
| 131 | pub 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"); |
| 17 | const Allocator = mem.Allocator; | 17 | const Allocator = mem.Allocator; |
| 18 | const Atom = @import("ZldAtom.zig"); | 18 | const Atom = @import("ZldAtom.zig"); |
| 19 | const AtomIndex = @import("zld.zig").AtomIndex; | 19 | const AtomIndex = @import("zld.zig").AtomIndex; |
| 20 | const Relocation = @import("Relocation.zig"); | ||
| 20 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; | 21 | const SymbolWithLoc = @import("zld.zig").SymbolWithLoc; |
| 21 | const Zld = @import("zld.zig").Zld; | 22 | const Zld = @import("zld.zig").Zld; |
| 22 | 23 | ||
| ... | @@ -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) catch | 321 | _ = Relocation.calcPcRelativeDisplacementArm64(source_addr, target_addr) catch |
| 321 | return false; | 322 | return false; |
| 322 | 323 | ||
| 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; |
| 366 | 367 | ||
| 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"); |
| 16 | const load_commands = @import("load_commands.zig"); | 16 | const load_commands = @import("load_commands.zig"); |
| 17 | const thunks = @import("thunks.zig"); | 17 | const thunks = @import("thunks.zig"); |
| 18 | const trace = @import("../../tracy.zig").trace; | 18 | const trace = @import("../../tracy.zig").trace; |
| 19 | const stub_helpers = @import("stubs.zig"); | ||
| 19 | 20 | ||
| 20 | const Allocator = mem.Allocator; | 21 | const Allocator = mem.Allocator; |
| 21 | const Archive = @import("Archive.zig"); | 22 | const 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 | } |
| 714 | 677 | ||
| 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 | } |
| 779 | 717 | ||
| 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 type | 758 | 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 | } |
| 892 | 806 | ||
| 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); |
| 2268 | 2182 | ||
| 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 preamble | 2187 | atom_index = self.getAtom(atom_index).next_index.?; // skip preamble |