| ... | ... | @@ -540,13 +540,13 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 540 | 540 | try self.sortSections(); |
| 541 | 541 | try self.addAtomsToSections(); |
| 542 | 542 | try self.calcSectionSizes(); |
| 543 | |
| 543 | 544 | try self.generateUnwindInfo(); |
| 544 | | try self.initSegments(); |
| 545 | 545 | |
| 546 | try self.initSegments(); |
| 546 | 547 | try self.allocateSections(); |
| 547 | 548 | self.allocateSegments(); |
| 548 | 549 | self.allocateSyntheticSymbols(); |
| 549 | | try self.allocateLinkeditSegment(); |
| 550 | 550 | |
| 551 | 551 | if (build_options.enable_logging) { |
| 552 | 552 | state_log.debug("{}", .{self.dumpState()}); |
| ... | ... | @@ -554,6 +554,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 554 | 554 | |
| 555 | 555 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 556 | 556 | // the relocations, and commit objects to file. |
| 557 | try self.resizeSections(); |
| 558 | |
| 557 | 559 | if (self.getZigObject()) |zo| { |
| 558 | 560 | var has_resolve_error = false; |
| 559 | 561 | |
| ... | ... | @@ -597,33 +599,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n |
| 597 | 599 | |
| 598 | 600 | if (has_resolve_error) return error.FlushFailure; |
| 599 | 601 | } |
| 602 | try self.writeSectionsAndUpdateLinkeditSizes(); |
| 600 | 603 | |
| 601 | | self.writeAtoms() catch |err| switch (err) { |
| 602 | | error.ResolveFailed => return error.FlushFailure, |
| 603 | | else => |e| { |
| 604 | | try self.reportUnexpectedError("unexpected error while resolving relocations", .{}); |
| 605 | | return e; |
| 606 | | }, |
| 607 | | }; |
| 608 | | try self.writeUnwindInfo(); |
| 609 | | try self.finalizeDyldInfoSections(); |
| 610 | | try self.writeSyntheticSections(); |
| 611 | | |
| 612 | | var off = math.cast(u32, self.getLinkeditSegment().fileoff) orelse return error.Overflow; |
| 613 | | off = try self.writeDyldInfoSections(off); |
| 614 | | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 615 | | off = try self.writeFunctionStarts(off); |
| 616 | | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 617 | | off = try self.writeDataInCode(self.getTextSegment().vmaddr, off); |
| 618 | | try self.calcSymtabSize(); |
| 619 | | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 620 | | off = try self.writeSymtab(off); |
| 621 | | off = mem.alignForward(u32, off, @alignOf(u32)); |
| 622 | | off = try self.writeIndsymtab(off); |
| 623 | | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 624 | | off = try self.writeStrtab(off); |
| 625 | | |
| 626 | | self.getLinkeditSegment().filesize = off - self.getLinkeditSegment().fileoff; |
| 604 | try self.writeSectionsToFile(); |
| 605 | try self.allocateLinkeditSegment(); |
| 606 | try self.writeLinkeditSectionsToFile(); |
| 627 | 607 | |
| 628 | 608 | var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: { |
| 629 | 609 | // Preallocate space for the code signature. |
| ... | ... | @@ -1498,48 +1478,23 @@ fn checkDuplicates(self: *MachO) !void { |
| 1498 | 1478 | } |
| 1499 | 1479 | |
| 1500 | 1480 | fn markImportsAndExports(self: *MachO) void { |
| 1481 | const tracy = trace(@src()); |
| 1482 | defer tracy.end(); |
| 1483 | |
| 1501 | 1484 | if (self.getZigObject()) |zo| { |
| 1502 | 1485 | zo.asFile().markImportsExports(self); |
| 1503 | 1486 | } |
| 1504 | 1487 | for (self.objects.items) |index| { |
| 1505 | 1488 | self.getFile(index).?.markImportsExports(self); |
| 1506 | 1489 | } |
| 1507 | | |
| 1508 | | for (self.undefined_symbols.items) |index| { |
| 1509 | | const sym = self.getSymbol(index); |
| 1510 | | if (sym.getFile(self)) |file| { |
| 1511 | | if (sym.visibility != .global) continue; |
| 1512 | | if (file == .dylib and !sym.flags.abs) sym.flags.import = true; |
| 1513 | | } |
| 1514 | | } |
| 1515 | | |
| 1516 | | for (&[_]?Symbol.Index{ |
| 1517 | | self.entry_index, |
| 1518 | | self.dyld_stub_binder_index, |
| 1519 | | self.objc_msg_send_index, |
| 1520 | | }) |index| { |
| 1521 | | if (index) |idx| { |
| 1522 | | const sym = self.getSymbol(idx); |
| 1523 | | if (sym.getFile(self)) |file| { |
| 1524 | | if (file == .dylib) sym.flags.import = true; |
| 1525 | | } |
| 1526 | | } |
| 1490 | if (self.getInternalObject()) |obj| { |
| 1491 | obj.asFile().markImportsExports(self); |
| 1527 | 1492 | } |
| 1528 | 1493 | } |
| 1529 | 1494 | |
| 1530 | 1495 | fn deadStripDylibs(self: *MachO) void { |
| 1531 | | for (&[_]?Symbol.Index{ |
| 1532 | | self.entry_index, |
| 1533 | | self.dyld_stub_binder_index, |
| 1534 | | self.objc_msg_send_index, |
| 1535 | | }) |index| { |
| 1536 | | if (index) |idx| { |
| 1537 | | const sym = self.getSymbol(idx); |
| 1538 | | if (sym.getFile(self)) |file| { |
| 1539 | | if (file == .dylib) file.dylib.referenced = true; |
| 1540 | | } |
| 1541 | | } |
| 1542 | | } |
| 1496 | const tracy = trace(@src()); |
| 1497 | defer tracy.end(); |
| 1543 | 1498 | |
| 1544 | 1499 | for (self.dylibs.items) |index| { |
| 1545 | 1500 | self.getFile(index).?.dylib.markReferenced(self); |
| ... | ... | @@ -1560,50 +1515,26 @@ fn scanRelocs(self: *MachO) !void { |
| 1560 | 1515 | const tracy = trace(@src()); |
| 1561 | 1516 | defer tracy.end(); |
| 1562 | 1517 | |
| 1563 | | if (self.getZigObject()) |zo| try zo.scanRelocs(self); |
| 1564 | | |
| 1518 | if (self.getZigObject()) |zo| { |
| 1519 | try zo.scanRelocs(self); |
| 1520 | } |
| 1565 | 1521 | for (self.objects.items) |index| { |
| 1566 | 1522 | try self.getFile(index).?.object.scanRelocs(self); |
| 1567 | 1523 | } |
| 1524 | if (self.getInternalObject()) |obj| { |
| 1525 | try obj.scanRelocs(self); |
| 1526 | } |
| 1568 | 1527 | |
| 1569 | 1528 | try self.reportUndefs(); |
| 1570 | 1529 | |
| 1571 | | if (self.entry_index) |index| { |
| 1572 | | const sym = self.getSymbol(index); |
| 1573 | | if (sym.getFile(self) != null) { |
| 1574 | | if (sym.flags.import) sym.flags.stubs = true; |
| 1575 | | } |
| 1576 | | } |
| 1577 | | |
| 1578 | | if (self.dyld_stub_binder_index) |index| { |
| 1579 | | const sym = self.getSymbol(index); |
| 1580 | | if (sym.getFile(self) != null) sym.flags.needs_got = true; |
| 1530 | if (self.getZigObject()) |zo| { |
| 1531 | try zo.asFile().createSymbolIndirection(self); |
| 1581 | 1532 | } |
| 1582 | | |
| 1583 | | if (self.objc_msg_send_index) |index| { |
| 1584 | | const sym = self.getSymbol(index); |
| 1585 | | if (sym.getFile(self) != null) |
| 1586 | | sym.flags.needs_got = true; // TODO is it always needed, or only if we are synthesising fast stubs? |
| 1533 | for (self.objects.items) |index| { |
| 1534 | try self.getFile(index).?.createSymbolIndirection(self); |
| 1587 | 1535 | } |
| 1588 | | |
| 1589 | | for (self.symbols.items, 0..) |*symbol, i| { |
| 1590 | | const index = @as(Symbol.Index, @intCast(i)); |
| 1591 | | if (symbol.flags.needs_got) { |
| 1592 | | log.debug("'{s}' needs GOT", .{symbol.getName(self)}); |
| 1593 | | try self.got.addSymbol(index, self); |
| 1594 | | } |
| 1595 | | if (symbol.flags.stubs) { |
| 1596 | | log.debug("'{s}' needs STUBS", .{symbol.getName(self)}); |
| 1597 | | try self.stubs.addSymbol(index, self); |
| 1598 | | } |
| 1599 | | if (symbol.flags.tlv_ptr) { |
| 1600 | | log.debug("'{s}' needs TLV pointer", .{symbol.getName(self)}); |
| 1601 | | try self.tlv_ptr.addSymbol(index, self); |
| 1602 | | } |
| 1603 | | if (symbol.flags.objc_stubs) { |
| 1604 | | log.debug("'{s}' needs OBJC STUBS", .{symbol.getName(self)}); |
| 1605 | | try self.objc_stubs.addSymbol(index, self); |
| 1606 | | } |
| 1536 | if (self.getInternalObject()) |obj| { |
| 1537 | try obj.asFile().createSymbolIndirection(self); |
| 1607 | 1538 | } |
| 1608 | 1539 | } |
| 1609 | 1540 | |
| ... | ... | @@ -1611,17 +1542,15 @@ fn reportUndefs(self: *MachO) !void { |
| 1611 | 1542 | const tracy = trace(@src()); |
| 1612 | 1543 | defer tracy.end(); |
| 1613 | 1544 | |
| 1614 | | switch (self.undefined_treatment) { |
| 1615 | | .dynamic_lookup, .suppress => return, |
| 1616 | | .@"error", .warn => {}, |
| 1617 | | } |
| 1545 | if (self.undefined_treatment == .suppress or |
| 1546 | self.undefined_treatment == .dynamic_lookup) return; |
| 1618 | 1547 | |
| 1619 | 1548 | const max_notes = 4; |
| 1620 | 1549 | |
| 1621 | 1550 | var has_undefs = false; |
| 1622 | 1551 | var it = self.undefs.iterator(); |
| 1623 | 1552 | while (it.next()) |entry| { |
| 1624 | | const undef_sym = self.getSymbol(entry.key_ptr.*); |
| 1553 | const undef_sym = entry.key_ptr.getSymbol(self).?; |
| 1625 | 1554 | const notes = entry.value_ptr.*; |
| 1626 | 1555 | const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes); |
| 1627 | 1556 | |
| ... | ... | @@ -1631,8 +1560,9 @@ fn reportUndefs(self: *MachO) !void { |
| 1631 | 1560 | |
| 1632 | 1561 | var inote: usize = 0; |
| 1633 | 1562 | while (inote < @min(notes.items.len, max_notes)) : (inote += 1) { |
| 1634 | | const atom = self.getAtom(notes.items[inote]).?; |
| 1635 | | const file = atom.getFile(self); |
| 1563 | const note = notes.items[inote]; |
| 1564 | const file = self.getFile(note.file).?; |
| 1565 | const atom = note.getAtom(self).?; |
| 1636 | 1566 | try err.addNote(self, "referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) }); |
| 1637 | 1567 | } |
| 1638 | 1568 | |
| ... | ... | @@ -1641,64 +1571,18 @@ fn reportUndefs(self: *MachO) !void { |
| 1641 | 1571 | try err.addNote(self, "referenced {d} more times", .{remaining}); |
| 1642 | 1572 | } |
| 1643 | 1573 | } |
| 1644 | | |
| 1645 | | for (self.undefined_symbols.items) |index| { |
| 1646 | | const sym = self.getSymbol(index); |
| 1647 | | if (sym.getFile(self) != null) continue; // If undefined in an object file, will be reported above |
| 1648 | | has_undefs = true; |
| 1649 | | var err = try self.addErrorWithNotes(1); |
| 1650 | | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); |
| 1651 | | try err.addNote(self, "-u command line option", .{}); |
| 1652 | | } |
| 1653 | | |
| 1654 | | if (self.entry_index) |index| { |
| 1655 | | const sym = self.getSymbol(index); |
| 1656 | | if (sym.getFile(self) == null) { |
| 1657 | | has_undefs = true; |
| 1658 | | var err = try self.addErrorWithNotes(1); |
| 1659 | | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); |
| 1660 | | try err.addNote(self, "implicit entry/start for main executable", .{}); |
| 1661 | | } |
| 1662 | | } |
| 1663 | | |
| 1664 | | if (self.dyld_stub_binder_index) |index| { |
| 1665 | | const sym = self.getSymbol(index); |
| 1666 | | if (sym.getFile(self) == null and self.stubs_sect_index != null) { |
| 1667 | | has_undefs = true; |
| 1668 | | var err = try self.addErrorWithNotes(1); |
| 1669 | | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); |
| 1670 | | try err.addNote(self, "implicit -u command line option", .{}); |
| 1671 | | } |
| 1672 | | } |
| 1673 | | |
| 1674 | | if (self.objc_msg_send_index) |index| { |
| 1675 | | const sym = self.getSymbol(index); |
| 1676 | | if (sym.getFile(self) == null and self.objc_stubs_sect_index != null) { |
| 1677 | | has_undefs = true; |
| 1678 | | var err = try self.addErrorWithNotes(1); |
| 1679 | | try err.addMsg(self, "undefined symbol: {s}", .{sym.getName(self)}); |
| 1680 | | try err.addNote(self, "implicit -u command line option", .{}); |
| 1681 | | } |
| 1682 | | } |
| 1683 | | |
| 1684 | 1574 | if (has_undefs) return error.HasUndefinedSymbols; |
| 1685 | 1575 | } |
| 1686 | 1576 | |
| 1687 | 1577 | fn initOutputSections(self: *MachO) !void { |
| 1578 | const tracy = trace(@src()); |
| 1579 | defer tracy.end(); |
| 1580 | |
| 1688 | 1581 | for (self.objects.items) |index| { |
| 1689 | | const object = self.getFile(index).?.object; |
| 1690 | | for (object.atoms.items) |atom_index| { |
| 1691 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1692 | | if (!atom.flags.alive) continue; |
| 1693 | | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(self), self); |
| 1694 | | } |
| 1582 | try self.getFile(index).?.initOutputSections(self); |
| 1695 | 1583 | } |
| 1696 | | if (self.getInternalObject()) |object| { |
| 1697 | | for (object.atoms.items) |atom_index| { |
| 1698 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1699 | | if (!atom.flags.alive) continue; |
| 1700 | | atom.out_n_sect = try Atom.initOutputSection(atom.getInputSection(self), self); |
| 1701 | | } |
| 1584 | if (self.getInternalObject()) |obj| { |
| 1585 | try obj.asFile().initOutputSections(self); |
| 1702 | 1586 | } |
| 1703 | 1587 | self.text_sect_index = self.getSectionByName("__TEXT", "__text") orelse |
| 1704 | 1588 | try self.addSection("__TEXT", "__text", .{ |
| ... | ... | @@ -1771,46 +1655,50 @@ fn initSyntheticSections(self: *MachO) !void { |
| 1771 | 1655 | self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{}); |
| 1772 | 1656 | } |
| 1773 | 1657 | |
| 1774 | | for (self.boundary_symbols.items) |sym_index| { |
| 1658 | if (self.getInternalObject()) |obj| { |
| 1775 | 1659 | const gpa = self.base.comp.gpa; |
| 1776 | | const sym = self.getSymbol(sym_index); |
| 1777 | | const name = sym.getName(self); |
| 1778 | | |
| 1779 | | if (eatPrefix(name, "segment$start$")) |segname| { |
| 1780 | | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1781 | | const prot = getSegmentProt(segname); |
| 1782 | | _ = try self.segments.append(gpa, .{ |
| 1783 | | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1784 | | .segname = makeStaticString(segname), |
| 1785 | | .initprot = prot, |
| 1786 | | .maxprot = prot, |
| 1787 | | }); |
| 1788 | | } |
| 1789 | | } else if (eatPrefix(name, "segment$stop$")) |segname| { |
| 1790 | | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1791 | | const prot = getSegmentProt(segname); |
| 1792 | | _ = try self.segments.append(gpa, .{ |
| 1793 | | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1794 | | .segname = makeStaticString(segname), |
| 1795 | | .initprot = prot, |
| 1796 | | .maxprot = prot, |
| 1797 | | }); |
| 1798 | | } |
| 1799 | | } else if (eatPrefix(name, "section$start$")) |actual_name| { |
| 1800 | | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1801 | | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1802 | | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1803 | | if (self.getSectionByName(segname, sectname) == null) { |
| 1804 | | _ = try self.addSection(segname, sectname, .{}); |
| 1805 | | } |
| 1806 | | } else if (eatPrefix(name, "section$stop$")) |actual_name| { |
| 1807 | | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1808 | | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1809 | | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1810 | | if (self.getSectionByName(segname, sectname) == null) { |
| 1811 | | _ = try self.addSection(segname, sectname, .{}); |
| 1812 | | } |
| 1813 | | } else unreachable; |
| 1660 | |
| 1661 | for (obj.boundary_symbols.items) |sym_index| { |
| 1662 | const ref = obj.getSymbolRef(sym_index, self); |
| 1663 | const sym = ref.getSymbol(self).?; |
| 1664 | const name = sym.getName(self); |
| 1665 | |
| 1666 | if (eatPrefix(name, "segment$start$")) |segname| { |
| 1667 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1668 | const prot = getSegmentProt(segname); |
| 1669 | _ = try self.segments.append(gpa, .{ |
| 1670 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1671 | .segname = makeStaticString(segname), |
| 1672 | .initprot = prot, |
| 1673 | .maxprot = prot, |
| 1674 | }); |
| 1675 | } |
| 1676 | } else if (eatPrefix(name, "segment$stop$")) |segname| { |
| 1677 | if (self.getSegmentByName(segname) == null) { // TODO check segname is valid |
| 1678 | const prot = getSegmentProt(segname); |
| 1679 | _ = try self.segments.append(gpa, .{ |
| 1680 | .cmdsize = @sizeOf(macho.segment_command_64), |
| 1681 | .segname = makeStaticString(segname), |
| 1682 | .initprot = prot, |
| 1683 | .maxprot = prot, |
| 1684 | }); |
| 1685 | } |
| 1686 | } else if (eatPrefix(name, "section$start$")) |actual_name| { |
| 1687 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1688 | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1689 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1690 | if (self.getSectionByName(segname, sectname) == null) { |
| 1691 | _ = try self.addSection(segname, sectname, .{}); |
| 1692 | } |
| 1693 | } else if (eatPrefix(name, "section$stop$")) |actual_name| { |
| 1694 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 1695 | const segname = actual_name[0..sep]; // TODO check segname is valid |
| 1696 | const sectname = actual_name[sep + 1 ..]; // TODO check sectname is valid |
| 1697 | if (self.getSectionByName(segname, sectname) == null) { |
| 1698 | _ = try self.addSection(segname, sectname, .{}); |
| 1699 | } |
| 1700 | } else unreachable; |
| 1701 | } |
| 1814 | 1702 | } |
| 1815 | 1703 | } |
| 1816 | 1704 | |
| ... | ... | @@ -1917,38 +1805,25 @@ pub fn sortSections(self: *MachO) !void { |
| 1917 | 1805 | } |
| 1918 | 1806 | |
| 1919 | 1807 | if (self.getZigObject()) |zo| { |
| 1920 | | for (zo.atoms.items) |atom_index| { |
| 1921 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1808 | for (zo.getAtoms()) |atom_index| { |
| 1809 | const atom = zo.getAtom(atom_index) orelse continue; |
| 1922 | 1810 | if (!atom.flags.alive) continue; |
| 1923 | 1811 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 1924 | 1812 | } |
| 1925 | | |
| 1926 | | for (zo.symtab.items(.nlist)) |*sym| { |
| 1927 | | if (sym.sect()) { |
| 1928 | | sym.n_sect = backlinks[sym.n_sect - 1] + 1; |
| 1929 | | } |
| 1930 | | } |
| 1931 | | |
| 1932 | | for (zo.symbols.items) |sym_index| { |
| 1933 | | const sym = self.getSymbol(sym_index); |
| 1934 | | const atom = sym.getAtom(self) orelse continue; |
| 1935 | | if (!atom.flags.alive) continue; |
| 1936 | | if (sym.getFile(self).?.getIndex() != zo.index) continue; |
| 1937 | | sym.out_n_sect = backlinks[sym.out_n_sect]; |
| 1938 | | } |
| 1939 | 1813 | } |
| 1940 | 1814 | |
| 1941 | 1815 | for (self.objects.items) |index| { |
| 1942 | | for (self.getFile(index).?.object.atoms.items) |atom_index| { |
| 1943 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1816 | const file = self.getFile(index).?; |
| 1817 | for (file.getAtoms()) |atom_index| { |
| 1818 | const atom = file.getAtom(atom_index) orelse continue; |
| 1944 | 1819 | if (!atom.flags.alive) continue; |
| 1945 | 1820 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 1946 | 1821 | } |
| 1947 | 1822 | } |
| 1948 | 1823 | |
| 1949 | 1824 | if (self.getInternalObject()) |object| { |
| 1950 | | for (object.atoms.items) |atom_index| { |
| 1951 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1825 | for (object.getAtoms()) |atom_index| { |
| 1826 | const atom = object.getAtom(atom_index) orelse continue; |
| 1952 | 1827 | if (!atom.flags.alive) continue; |
| 1953 | 1828 | atom.out_n_sect = backlinks[atom.out_n_sect]; |
| 1954 | 1829 | } |
| ... | ... | @@ -1985,35 +1860,23 @@ pub fn addAtomsToSections(self: *MachO) !void { |
| 1985 | 1860 | const tracy = trace(@src()); |
| 1986 | 1861 | defer tracy.end(); |
| 1987 | 1862 | |
| 1863 | const gpa = self.base.comp.gpa; |
| 1864 | |
| 1988 | 1865 | for (self.objects.items) |index| { |
| 1989 | | const object = self.getFile(index).?.object; |
| 1990 | | for (object.atoms.items) |atom_index| { |
| 1991 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1866 | const file = self.getFile(index).?; |
| 1867 | for (file.getAtoms()) |atom_index| { |
| 1868 | const atom = file.getAtom(atom_index) orelse continue; |
| 1992 | 1869 | if (!atom.flags.alive) continue; |
| 1993 | 1870 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 1994 | | try atoms.append(self.base.comp.gpa, atom_index); |
| 1995 | | } |
| 1996 | | for (object.symbols.items) |sym_index| { |
| 1997 | | const sym = self.getSymbol(sym_index); |
| 1998 | | const atom = sym.getAtom(self) orelse continue; |
| 1999 | | if (!atom.flags.alive) continue; |
| 2000 | | if (sym.getFile(self).?.getIndex() != index) continue; |
| 2001 | | sym.out_n_sect = atom.out_n_sect; |
| 1871 | try atoms.append(gpa, .{ .index = atom_index, .file = index }); |
| 2002 | 1872 | } |
| 2003 | 1873 | } |
| 2004 | 1874 | if (self.getInternalObject()) |object| { |
| 2005 | | for (object.atoms.items) |atom_index| { |
| 2006 | | const atom = self.getAtom(atom_index) orelse continue; |
| 1875 | for (object.getAtoms()) |atom_index| { |
| 1876 | const atom = object.getAtom(atom_index) orelse continue; |
| 2007 | 1877 | if (!atom.flags.alive) continue; |
| 2008 | 1878 | const atoms = &self.sections.items(.atoms)[atom.out_n_sect]; |
| 2009 | | try atoms.append(self.base.comp.gpa, atom_index); |
| 2010 | | } |
| 2011 | | for (object.symbols.items) |sym_index| { |
| 2012 | | const sym = self.getSymbol(sym_index); |
| 2013 | | const atom = sym.getAtom(self) orelse continue; |
| 2014 | | if (!atom.flags.alive) continue; |
| 2015 | | if (sym.getFile(self).?.getIndex() != object.index) continue; |
| 2016 | | sym.out_n_sect = atom.out_n_sect; |
| 1879 | try atoms.append(gpa, .{ .index = atom_index, .file = object.index }); |
| 2017 | 1880 | } |
| 2018 | 1881 | } |
| 2019 | 1882 | } |
| ... | ... | @@ -2035,8 +1898,8 @@ fn calcSectionSizes(self: *MachO) !void { |
| 2035 | 1898 | if (atoms.items.len == 0) continue; |
| 2036 | 1899 | if (self.requiresThunks() and header.isCode()) continue; |
| 2037 | 1900 | |
| 2038 | | for (atoms.items) |atom_index| { |
| 2039 | | const atom = self.getAtom(atom_index).?; |
| 1901 | for (atoms.items) |ref| { |
| 1902 | const atom = ref.getAtom(self).?; |
| 2040 | 1903 | const atom_alignment = atom.alignment.toByteUnits() orelse 1; |
| 2041 | 1904 | const offset = mem.alignForward(u64, header.size, atom_alignment); |
| 2042 | 1905 | const padding = offset - header.size; |
| ... | ... | @@ -2056,6 +1919,22 @@ fn calcSectionSizes(self: *MachO) !void { |
| 2056 | 1919 | } |
| 2057 | 1920 | } |
| 2058 | 1921 | |
| 1922 | // At this point, we can also calculate symtab and data-in-code linkedit section sizes |
| 1923 | if (self.getZigObject()) |zo| { |
| 1924 | zo.asFile().calcSymtabSize(self); |
| 1925 | } |
| 1926 | for (self.objects.items) |index| { |
| 1927 | self.getFile(index).?.calcSymtabSize(self); |
| 1928 | } |
| 1929 | for (self.dylibs.items) |index| { |
| 1930 | self.getFile(index).?.calcSymtabSize(self); |
| 1931 | } |
| 1932 | if (self.getInternalObject()) |obj| { |
| 1933 | obj.asFile().calcSymtabSize(self); |
| 1934 | } |
| 1935 | |
| 1936 | try self.calcSymtabSize(); |
| 1937 | |
| 2059 | 1938 | if (self.got_sect_index) |idx| { |
| 2060 | 1939 | const header = &self.sections.items(.header)[idx]; |
| 2061 | 1940 | header.size = self.got.size(); |
| ... | ... | @@ -2336,77 +2215,61 @@ fn allocateSegments(self: *MachO) void { |
| 2336 | 2215 | } |
| 2337 | 2216 | |
| 2338 | 2217 | fn allocateSyntheticSymbols(self: *MachO) void { |
| 2339 | | const text_seg = self.getTextSegment(); |
| 2340 | | |
| 2341 | | if (self.mh_execute_header_index) |index| { |
| 2342 | | const global = self.getSymbol(index); |
| 2343 | | global.value = text_seg.vmaddr; |
| 2344 | | } |
| 2218 | if (self.getInternalObject()) |obj| { |
| 2219 | obj.allocateSyntheticSymbols(self); |
| 2345 | 2220 | |
| 2346 | | if (self.data_sect_index) |idx| { |
| 2347 | | const sect = self.sections.items(.header)[idx]; |
| 2348 | | for (&[_]?Symbol.Index{ |
| 2349 | | self.dso_handle_index, |
| 2350 | | self.mh_dylib_header_index, |
| 2351 | | self.dyld_private_index, |
| 2352 | | }) |maybe_index| { |
| 2353 | | if (maybe_index) |index| { |
| 2354 | | const global = self.getSymbol(index); |
| 2355 | | global.value = sect.addr; |
| 2356 | | global.out_n_sect = idx; |
| 2357 | | } |
| 2358 | | } |
| 2359 | | } |
| 2221 | const text_seg = self.getTextSegment(); |
| 2360 | 2222 | |
| 2361 | | for (self.boundary_symbols.items) |sym_index| { |
| 2362 | | const sym = self.getSymbol(sym_index); |
| 2363 | | const name = sym.getName(self); |
| 2223 | for (obj.boundary_symbols.items) |sym_index| { |
| 2224 | const ref = obj.getSymbolRef(sym_index, self); |
| 2225 | const sym = ref.getSymbol(self).?; |
| 2226 | const name = sym.getName(self); |
| 2364 | 2227 | |
| 2365 | | sym.flags.@"export" = false; |
| 2366 | | sym.value = text_seg.vmaddr; |
| 2228 | sym.value = text_seg.vmaddr; |
| 2367 | 2229 | |
| 2368 | | if (mem.startsWith(u8, name, "segment$start$")) { |
| 2369 | | const segname = name["segment$start$".len..]; |
| 2370 | | if (self.getSegmentByName(segname)) |seg_id| { |
| 2371 | | const seg = self.segments.items[seg_id]; |
| 2372 | | sym.value = seg.vmaddr; |
| 2373 | | } |
| 2374 | | } else if (mem.startsWith(u8, name, "segment$stop$")) { |
| 2375 | | const segname = name["segment$stop$".len..]; |
| 2376 | | if (self.getSegmentByName(segname)) |seg_id| { |
| 2377 | | const seg = self.segments.items[seg_id]; |
| 2378 | | sym.value = seg.vmaddr + seg.vmsize; |
| 2379 | | } |
| 2380 | | } else if (mem.startsWith(u8, name, "section$start$")) { |
| 2381 | | const actual_name = name["section$start$".len..]; |
| 2382 | | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2383 | | const segname = actual_name[0..sep]; |
| 2384 | | const sectname = actual_name[sep + 1 ..]; |
| 2385 | | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2386 | | const sect = self.sections.items(.header)[sect_id]; |
| 2387 | | sym.value = sect.addr; |
| 2388 | | sym.out_n_sect = sect_id; |
| 2389 | | } |
| 2390 | | } else if (mem.startsWith(u8, name, "section$stop$")) { |
| 2391 | | const actual_name = name["section$stop$".len..]; |
| 2392 | | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2393 | | const segname = actual_name[0..sep]; |
| 2394 | | const sectname = actual_name[sep + 1 ..]; |
| 2395 | | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2396 | | const sect = self.sections.items(.header)[sect_id]; |
| 2397 | | sym.value = sect.addr + sect.size; |
| 2398 | | sym.out_n_sect = sect_id; |
| 2399 | | } |
| 2400 | | } else unreachable; |
| 2401 | | } |
| 2230 | if (mem.startsWith(u8, name, "segment$start$")) { |
| 2231 | const segname = name["segment$start$".len..]; |
| 2232 | if (self.getSegmentByName(segname)) |seg_id| { |
| 2233 | const seg = self.segments.items[seg_id]; |
| 2234 | sym.value = seg.vmaddr; |
| 2235 | } |
| 2236 | } else if (mem.startsWith(u8, name, "segment$stop$")) { |
| 2237 | const segname = name["segment$stop$".len..]; |
| 2238 | if (self.getSegmentByName(segname)) |seg_id| { |
| 2239 | const seg = self.segments.items[seg_id]; |
| 2240 | sym.value = seg.vmaddr + seg.vmsize; |
| 2241 | } |
| 2242 | } else if (mem.startsWith(u8, name, "section$start$")) { |
| 2243 | const actual_name = name["section$start$".len..]; |
| 2244 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2245 | const segname = actual_name[0..sep]; |
| 2246 | const sectname = actual_name[sep + 1 ..]; |
| 2247 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2248 | const sect = self.sections.items(.header)[sect_id]; |
| 2249 | sym.value = sect.addr; |
| 2250 | sym.out_n_sect = sect_id; |
| 2251 | } |
| 2252 | } else if (mem.startsWith(u8, name, "section$stop$")) { |
| 2253 | const actual_name = name["section$stop$".len..]; |
| 2254 | const sep = mem.indexOfScalar(u8, actual_name, '$').?; // TODO error rather than a panic |
| 2255 | const segname = actual_name[0..sep]; |
| 2256 | const sectname = actual_name[sep + 1 ..]; |
| 2257 | if (self.getSectionByName(segname, sectname)) |sect_id| { |
| 2258 | const sect = self.sections.items(.header)[sect_id]; |
| 2259 | sym.value = sect.addr + sect.size; |
| 2260 | sym.out_n_sect = sect_id; |
| 2261 | } |
| 2262 | } else unreachable; |
| 2263 | } |
| 2402 | 2264 | |
| 2403 | | if (self.objc_stubs.symbols.items.len > 0) { |
| 2404 | | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; |
| 2265 | if (self.objc_stubs.symbols.items.len > 0) { |
| 2266 | const addr = self.sections.items(.header)[self.objc_stubs_sect_index.?].addr; |
| 2405 | 2267 | |
| 2406 | | for (self.objc_stubs.symbols.items, 0..) |sym_index, idx| { |
| 2407 | | const sym = self.getSymbol(sym_index); |
| 2408 | | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); |
| 2409 | | sym.out_n_sect = self.objc_stubs_sect_index.?; |
| 2268 | for (self.objc_stubs.symbols.items, 0..) |ref, idx| { |
| 2269 | const sym = ref.getSymbol(self).?; |
| 2270 | sym.value = addr + idx * ObjcStubsSection.entrySize(self.getTarget().cpu.arch); |
| 2271 | sym.out_n_sect = self.objc_stubs_sect_index.?; |
| 2272 | } |
| 2410 | 2273 | } |
| 2411 | 2274 | } |
| 2412 | 2275 | } |
| ... | ... | @@ -2424,177 +2287,224 @@ fn allocateLinkeditSegment(self: *MachO) !void { |
| 2424 | 2287 | const seg = self.getLinkeditSegment(); |
| 2425 | 2288 | seg.vmaddr = mem.alignForward(u64, vmaddr, page_size); |
| 2426 | 2289 | seg.fileoff = mem.alignForward(u64, fileoff, page_size); |
| 2427 | | } |
| 2428 | 2290 | |
| 2429 | | fn writeAtoms(self: *MachO) !void { |
| 2430 | | const tracy = trace(@src()); |
| 2431 | | defer tracy.end(); |
| 2291 | var off = math.cast(u32, seg.fileoff) orelse return error.Overflow; |
| 2292 | // DYLD_INFO_ONLY |
| 2293 | { |
| 2294 | const cmd = &self.dyld_info_cmd; |
| 2295 | cmd.rebase_off = off; |
| 2296 | off += cmd.rebase_size; |
| 2297 | cmd.bind_off = off; |
| 2298 | off += cmd.bind_size; |
| 2299 | cmd.weak_bind_off = off; |
| 2300 | off += cmd.weak_bind_size; |
| 2301 | cmd.lazy_bind_off = off; |
| 2302 | off += cmd.lazy_bind_size; |
| 2303 | cmd.export_off = off; |
| 2304 | off += cmd.export_size; |
| 2305 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2306 | } |
| 2307 | |
| 2308 | // FUNCTION_STARTS |
| 2309 | { |
| 2310 | const cmd = &self.function_starts_cmd; |
| 2311 | cmd.dataoff = off; |
| 2312 | off += cmd.datasize; |
| 2313 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2314 | } |
| 2432 | 2315 | |
| 2433 | | const gpa = self.base.comp.gpa; |
| 2434 | | var arena = std.heap.ArenaAllocator.init(gpa); |
| 2435 | | defer arena.deinit(); |
| 2316 | // DATA_IN_CODE |
| 2317 | { |
| 2318 | const cmd = &self.data_in_code_cmd; |
| 2319 | cmd.dataoff = off; |
| 2320 | off += cmd.datasize; |
| 2321 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2322 | } |
| 2436 | 2323 | |
| 2437 | | const cpu_arch = self.getTarget().cpu.arch; |
| 2438 | | const slice = self.sections.slice(); |
| 2324 | // SYMTAB (symtab) |
| 2325 | { |
| 2326 | const cmd = &self.symtab_cmd; |
| 2327 | cmd.symoff = off; |
| 2328 | off += cmd.nsyms * @sizeOf(macho.nlist_64); |
| 2329 | off = mem.alignForward(u32, off, @alignOf(u32)); |
| 2330 | } |
| 2439 | 2331 | |
| 2440 | | var has_resolve_error = false; |
| 2441 | | for (slice.items(.header), slice.items(.atoms)) |header, atoms| { |
| 2332 | // DYSYMTAB |
| 2333 | { |
| 2334 | const cmd = &self.dysymtab_cmd; |
| 2335 | cmd.indirectsymoff = off; |
| 2336 | off += cmd.nindirectsyms * @sizeOf(u32); |
| 2337 | off = mem.alignForward(u32, off, @alignOf(u64)); |
| 2338 | } |
| 2339 | |
| 2340 | // SYMTAB (strtab) |
| 2341 | { |
| 2342 | const cmd = &self.symtab_cmd; |
| 2343 | cmd.stroff = off; |
| 2344 | off += cmd.strsize; |
| 2345 | } |
| 2346 | |
| 2347 | seg.filesize = off - seg.fileoff; |
| 2348 | } |
| 2349 | |
| 2350 | fn resizeSections(self: *MachO) !void { |
| 2351 | const slice = self.sections.slice(); |
| 2352 | for (slice.items(.header), slice.items(.atoms), slice.items(.out)) |header, atoms, *out| { |
| 2442 | 2353 | if (atoms.items.len == 0) continue; |
| 2443 | 2354 | if (header.isZerofill()) continue; |
| 2444 | | |
| 2445 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2446 | | const buffer = try gpa.alloc(u8, size); |
| 2447 | | defer gpa.free(buffer); |
| 2355 | const cpu_arch = self.getTarget().cpu.arch; |
| 2356 | try out.resize(self.base.comp.gpa, header.size); |
| 2448 | 2357 | const padding_byte: u8 = if (header.isCode() and cpu_arch == .x86_64) 0xcc else 0; |
| 2449 | | @memset(buffer, padding_byte); |
| 2358 | @memset(out.items, padding_byte); |
| 2359 | } |
| 2360 | } |
| 2450 | 2361 | |
| 2451 | | for (atoms.items) |atom_index| { |
| 2452 | | const atom = self.getAtom(atom_index).?; |
| 2453 | | assert(atom.flags.alive); |
| 2454 | | const off = math.cast(usize, atom.value) orelse return error.Overflow; |
| 2455 | | const atom_size = math.cast(usize, atom.size) orelse return error.Overflow; |
| 2456 | | try atom.getData(self, buffer[off..][0..atom_size]); |
| 2457 | | atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) { |
| 2458 | | error.ResolveFailed => has_resolve_error = true, |
| 2459 | | else => |e| return e, |
| 2460 | | }; |
| 2461 | | } |
| 2362 | fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void { |
| 2363 | const gpa = self.base.comp.gpa; |
| 2462 | 2364 | |
| 2463 | | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 2464 | | } |
| 2365 | const cmd = self.symtab_cmd; |
| 2366 | try self.symtab.resize(gpa, cmd.nsyms); |
| 2367 | try self.strtab.resize(gpa, cmd.strsize); |
| 2368 | self.strtab.items[0] = 0; |
| 2465 | 2369 | |
| 2370 | for (self.objects.items) |index| { |
| 2371 | try self.getFile(index).?.writeAtoms(self); |
| 2372 | } |
| 2373 | if (self.getInternalObject()) |obj| { |
| 2374 | try obj.asFile().writeAtoms(self); |
| 2375 | } |
| 2466 | 2376 | for (self.thunks.items) |thunk| { |
| 2467 | | const header = slice.items(.header)[thunk.out_n_sect]; |
| 2468 | | const offset = thunk.value + header.offset; |
| 2469 | | const buffer = try gpa.alloc(u8, thunk.size()); |
| 2470 | | defer gpa.free(buffer); |
| 2471 | | var stream = std.io.fixedBufferStream(buffer); |
| 2377 | const out = self.sections.items(.out)[thunk.out_n_sect].items; |
| 2378 | const off = thunk.value; |
| 2379 | const size = thunk.size(); |
| 2380 | var stream = std.io.fixedBufferStream(out[off..][0..size]); |
| 2472 | 2381 | try thunk.write(self, stream.writer()); |
| 2473 | | try self.base.file.?.pwriteAll(buffer, offset); |
| 2474 | 2382 | } |
| 2475 | 2383 | |
| 2476 | | if (has_resolve_error) return error.ResolveFailed; |
| 2477 | | } |
| 2478 | | |
| 2479 | | fn writeUnwindInfo(self: *MachO) !void { |
| 2480 | | const tracy = trace(@src()); |
| 2481 | | defer tracy.end(); |
| 2482 | | |
| 2483 | | const gpa = self.base.comp.gpa; |
| 2484 | | |
| 2485 | | if (self.eh_frame_sect_index) |index| { |
| 2486 | | const header = self.sections.items(.header)[index]; |
| 2487 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2488 | | const buffer = try gpa.alloc(u8, size); |
| 2489 | | defer gpa.free(buffer); |
| 2490 | | eh_frame.write(self, buffer); |
| 2491 | | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 2384 | const slice = self.sections.slice(); |
| 2385 | for (&[_]?u8{ |
| 2386 | self.eh_frame_sect_index, |
| 2387 | self.unwind_info_sect_index, |
| 2388 | self.got_sect_index, |
| 2389 | self.stubs_sect_index, |
| 2390 | self.la_symbol_ptr_sect_index, |
| 2391 | self.tlv_ptr_sect_index, |
| 2392 | self.objc_stubs_sect_index, |
| 2393 | }) |maybe_sect_id| { |
| 2394 | if (maybe_sect_id) |sect_id| { |
| 2395 | const out = &slice.items(.out)[sect_id]; |
| 2396 | try self.writeSyntheticSection(sect_id, out); |
| 2397 | } |
| 2492 | 2398 | } |
| 2493 | 2399 | |
| 2494 | | if (self.unwind_info_sect_index) |index| { |
| 2495 | | const header = self.sections.items(.header)[index]; |
| 2496 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2497 | | const buffer = try gpa.alloc(u8, size); |
| 2498 | | defer gpa.free(buffer); |
| 2499 | | try self.unwind_info.write(self, buffer); |
| 2500 | | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 2400 | if (self.la_symbol_ptr_sect_index) |_| { |
| 2401 | try self.updatelazyBindSize(); |
| 2501 | 2402 | } |
| 2502 | | } |
| 2503 | 2403 | |
| 2504 | | fn finalizeDyldInfoSections(self: *MachO) !void { |
| 2505 | | const tracy = trace(@src()); |
| 2506 | | defer tracy.end(); |
| 2507 | 2404 | try self.rebase.updateSize(self); |
| 2508 | 2405 | try self.bind.updateSize(self); |
| 2509 | 2406 | try self.weak_bind.updateSize(self); |
| 2510 | | if (self.la_symbol_ptr_sect_index) |_| { |
| 2511 | | try self.lazy_bind.updateSize(self); |
| 2512 | | } |
| 2513 | 2407 | try self.export_trie.updateSize(self); |
| 2408 | try self.data_in_code.updateSize(self); |
| 2409 | |
| 2410 | if (self.getZigObject()) |zo| { |
| 2411 | zo.asFile().writeSymtab(self); |
| 2412 | } |
| 2413 | for (self.objects.items) |index| { |
| 2414 | self.getFile(index).?.writeSymtab(self); |
| 2415 | } |
| 2416 | for (self.dylibs.items) |index| { |
| 2417 | self.getFile(index).?.writeSymtab(self); |
| 2418 | } |
| 2419 | if (self.getInternalObject()) |obj| { |
| 2420 | obj.asFile().writeSymtab(self); |
| 2421 | } |
| 2514 | 2422 | } |
| 2515 | 2423 | |
| 2516 | | fn writeSyntheticSections(self: *MachO) !void { |
| 2424 | fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void { |
| 2517 | 2425 | const tracy = trace(@src()); |
| 2518 | 2426 | defer tracy.end(); |
| 2519 | 2427 | |
| 2520 | | const gpa = self.base.comp.gpa; |
| 2521 | | |
| 2522 | | if (self.got_sect_index) |sect_id| { |
| 2523 | | const header = self.sections.items(.header)[sect_id]; |
| 2524 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2525 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2526 | | defer buffer.deinit(); |
| 2527 | | try self.got.write(self, buffer.writer()); |
| 2528 | | assert(buffer.items.len == header.size); |
| 2529 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2530 | | } |
| 2428 | const Tag = enum { |
| 2429 | eh_frame, |
| 2430 | unwind_info, |
| 2431 | got, |
| 2432 | stubs, |
| 2433 | la_symbol_ptr, |
| 2434 | tlv_ptr, |
| 2435 | objc_stubs, |
| 2436 | }; |
| 2531 | 2437 | |
| 2532 | | if (self.stubs_sect_index) |sect_id| { |
| 2533 | | const header = self.sections.items(.header)[sect_id]; |
| 2534 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2535 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2536 | | defer buffer.deinit(); |
| 2537 | | try self.stubs.write(self, buffer.writer()); |
| 2538 | | assert(buffer.items.len == header.size); |
| 2539 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2438 | const tag: Tag = tag: { |
| 2439 | if (self.eh_frame_sect_index != null and |
| 2440 | self.eh_frame_sect_index.? == sect_id) break :tag .eh_frame; |
| 2441 | if (self.unwind_info_sect_index != null and |
| 2442 | self.unwind_info_sect_index.? == sect_id) break :tag .unwind_info; |
| 2443 | if (self.got_sect_index != null and |
| 2444 | self.got_sect_index.? == sect_id) break :tag .got; |
| 2445 | if (self.stubs_sect_index != null and |
| 2446 | self.stubs_sect_index.? == sect_id) break :tag .stubs; |
| 2447 | if (self.la_symbol_ptr_sect_index != null and |
| 2448 | self.la_symbol_ptr_sect_index.? == sect_id) break :tag .la_symbol_ptr; |
| 2449 | if (self.tlv_ptr_sect_index != null and |
| 2450 | self.tlv_ptr_sect_index.? == sect_id) break :tag .tlv_ptr; |
| 2451 | if (self.objc_stubs_sect_index != null and |
| 2452 | self.objc_stubs_sect_index.? == sect_id) break :tag .objc_stubs; |
| 2453 | unreachable; |
| 2454 | }; |
| 2455 | var stream = std.io.fixedBufferStream(out); |
| 2456 | switch (tag) { |
| 2457 | .eh_frame => eh_frame.write(self, out), |
| 2458 | .unwind_info => try self.unwind_info.write(self, out), |
| 2459 | .got => try self.got.write(self, stream.writer()), |
| 2460 | .stubs => try self.stubs.write(self, stream.writer()), |
| 2461 | .la_symbol_ptr => try self.la_symbol_ptr.write(self, stream.writer()), |
| 2462 | .tlv_ptr => try self.tlv_ptr.write(self, stream.writer()), |
| 2463 | .objc_stubs => try self.objc_stubs.write(self, stream.writer()), |
| 2540 | 2464 | } |
| 2465 | } |
| 2541 | 2466 | |
| 2542 | | if (self.stubs_helper_sect_index) |sect_id| { |
| 2543 | | const header = self.sections.items(.header)[sect_id]; |
| 2544 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2545 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2546 | | defer buffer.deinit(); |
| 2547 | | try self.stubs_helper.write(self, buffer.writer()); |
| 2548 | | assert(buffer.items.len == header.size); |
| 2549 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2550 | | } |
| 2467 | fn updateLazyBindSize(self: *MachO) !void { |
| 2468 | const tracy = trace(@src()); |
| 2469 | defer tracy.end(); |
| 2470 | try self.lazy_bind.updateSize(self); |
| 2471 | const sect_id = self.stubs_helper_sect_index.?; |
| 2472 | const out = &self.sections.items(.out)[sect_id]; |
| 2473 | var stream = std.io.fixedBufferStream(out.items); |
| 2474 | try self.stubs_helper.write(self, stream.writer()); |
| 2475 | } |
| 2551 | 2476 | |
| 2552 | | if (self.la_symbol_ptr_sect_index) |sect_id| { |
| 2553 | | const header = self.sections.items(.header)[sect_id]; |
| 2554 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2555 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2556 | | defer buffer.deinit(); |
| 2557 | | try self.la_symbol_ptr.write(self, buffer.writer()); |
| 2558 | | assert(buffer.items.len == header.size); |
| 2559 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2560 | | } |
| 2477 | fn writeSectionsToFile(self: *MachO) !void { |
| 2478 | const tracy = trace(@src()); |
| 2479 | defer tracy.end(); |
| 2561 | 2480 | |
| 2562 | | if (self.tlv_ptr_sect_index) |sect_id| { |
| 2563 | | const header = self.sections.items(.header)[sect_id]; |
| 2564 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2565 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2566 | | defer buffer.deinit(); |
| 2567 | | try self.tlv_ptr.write(self, buffer.writer()); |
| 2568 | | assert(buffer.items.len == header.size); |
| 2569 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2481 | const slice = self.sections.slice(); |
| 2482 | for (slice.items(.header), slice.items(.out)) |header, out| { |
| 2483 | try self.base.file.pwriteAll(out.items, header.offset); |
| 2570 | 2484 | } |
| 2485 | } |
| 2571 | 2486 | |
| 2572 | | if (self.objc_stubs_sect_index) |sect_id| { |
| 2573 | | const header = self.sections.items(.header)[sect_id]; |
| 2574 | | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2575 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, size); |
| 2576 | | defer buffer.deinit(); |
| 2577 | | try self.objc_stubs.write(self, buffer.writer()); |
| 2578 | | assert(buffer.items.len == header.size); |
| 2579 | | try self.base.file.?.pwriteAll(buffer.items, header.offset); |
| 2580 | | } |
| 2487 | fn writeLinkeditSectionsToFile(self: *MachO) !void { |
| 2488 | const tracy = trace(@src()); |
| 2489 | defer tracy.end(); |
| 2490 | try self.writeDyldInfo(); |
| 2491 | try self.writeDataInCode(); |
| 2492 | try self.writeSymtabToFile(); |
| 2493 | try self.writeIndsymtab(); |
| 2581 | 2494 | } |
| 2582 | 2495 | |
| 2583 | | fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { |
| 2496 | fn writeDyldInfo(self: *MachO) !void { |
| 2584 | 2497 | const tracy = trace(@src()); |
| 2585 | 2498 | defer tracy.end(); |
| 2586 | 2499 | |
| 2587 | | const gpa = self.base.comp.gpa; |
| 2588 | | const cmd = &self.dyld_info_cmd; |
| 2500 | const gpa = self.base.allocator; |
| 2501 | const base_off = self.getLinkeditSegment().fileoff; |
| 2502 | const cmd = self.dyld_info_cmd; |
| 2589 | 2503 | var needed_size: u32 = 0; |
| 2590 | 2504 | needed_size += cmd.rebase_size; |
| 2591 | | cmd.bind_off = needed_size; |
| 2592 | 2505 | needed_size += cmd.bind_size; |
| 2593 | | cmd.weak_bind_off = needed_size; |
| 2594 | 2506 | needed_size += cmd.weak_bind_size; |
| 2595 | | cmd.lazy_bind_off = needed_size; |
| 2596 | 2507 | needed_size += cmd.lazy_bind_size; |
| 2597 | | cmd.export_off = needed_size; |
| 2598 | 2508 | needed_size += cmd.export_size; |
| 2599 | 2509 | |
| 2600 | 2510 | const buffer = try gpa.alloc(u8, needed_size); |
| ... | ... | @@ -2605,88 +2515,74 @@ fn writeDyldInfoSections(self: *MachO, off: u32) !u32 { |
| 2605 | 2515 | const writer = stream.writer(); |
| 2606 | 2516 | |
| 2607 | 2517 | try self.rebase.write(writer); |
| 2608 | | try stream.seekTo(cmd.bind_off); |
| 2518 | try stream.seekTo(cmd.bind_off - base_off); |
| 2609 | 2519 | try self.bind.write(writer); |
| 2610 | | try stream.seekTo(cmd.weak_bind_off); |
| 2520 | try stream.seekTo(cmd.weak_bind_off - base_off); |
| 2611 | 2521 | try self.weak_bind.write(writer); |
| 2612 | | try stream.seekTo(cmd.lazy_bind_off); |
| 2522 | try stream.seekTo(cmd.lazy_bind_off - base_off); |
| 2613 | 2523 | try self.lazy_bind.write(writer); |
| 2614 | | try stream.seekTo(cmd.export_off); |
| 2524 | try stream.seekTo(cmd.export_off - base_off); |
| 2615 | 2525 | try self.export_trie.write(writer); |
| 2526 | try self.base.file.pwriteAll(buffer, cmd.rebase_off); |
| 2527 | } |
| 2616 | 2528 | |
| 2617 | | cmd.rebase_off += off; |
| 2618 | | cmd.bind_off += off; |
| 2619 | | cmd.weak_bind_off += off; |
| 2620 | | cmd.lazy_bind_off += off; |
| 2621 | | cmd.export_off += off; |
| 2622 | | try self.base.file.?.pwriteAll(buffer, off); |
| 2529 | pub fn writeDataInCode(self: *MachO) !void { |
| 2530 | const tracy = trace(@src()); |
| 2531 | defer tracy.end(); |
| 2532 | const cmd = self.data_in_code_cmd; |
| 2533 | try self.base.file.pwriteAll(mem.sliceAsBytes(self.data_in_code.entries.items), cmd.dataoff); |
| 2534 | } |
| 2623 | 2535 | |
| 2624 | | return off + needed_size; |
| 2536 | fn writeIndsymtab(self: *MachO) !void { |
| 2537 | const tracy = trace(@src()); |
| 2538 | defer tracy.end(); |
| 2539 | const gpa = self.base.comp.gpa; |
| 2540 | const cmd = self.dysymtab_cmd; |
| 2541 | const needed_size = cmd.nindirectsyms * @sizeOf(u32); |
| 2542 | var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); |
| 2543 | defer buffer.deinit(); |
| 2544 | try self.indsymtab.write(self, buffer.writer()); |
| 2545 | try self.base.file.pwriteAll(buffer.items, cmd.indirectsymoff); |
| 2625 | 2546 | } |
| 2626 | 2547 | |
| 2627 | | fn writeFunctionStarts(self: *MachO, off: u32) !u32 { |
| 2628 | | // TODO actually write it out |
| 2629 | | const cmd = &self.function_starts_cmd; |
| 2630 | | cmd.dataoff = off; |
| 2631 | | return off; |
| 2548 | pub fn writeSymtabToFile(self: *MachO) !void { |
| 2549 | const tracy = trace(@src()); |
| 2550 | defer tracy.end(); |
| 2551 | const cmd = self.symtab_cmd; |
| 2552 | try self.base.file.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); |
| 2553 | try self.base.file.pwriteAll(self.strtab.items, cmd.stroff); |
| 2632 | 2554 | } |
| 2633 | 2555 | |
| 2634 | | pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 { |
| 2635 | | const cmd = &self.data_in_code_cmd; |
| 2636 | | cmd.dataoff = off; |
| 2556 | fn writeUnwindInfo(self: *MachO) !void { |
| 2557 | const tracy = trace(@src()); |
| 2558 | defer tracy.end(); |
| 2637 | 2559 | |
| 2638 | 2560 | const gpa = self.base.comp.gpa; |
| 2639 | | var dices = std.ArrayList(macho.data_in_code_entry).init(gpa); |
| 2640 | | defer dices.deinit(); |
| 2641 | | |
| 2642 | | for (self.objects.items) |index| { |
| 2643 | | const object = self.getFile(index).?.object; |
| 2644 | | const in_dices = object.getDataInCode(); |
| 2645 | | |
| 2646 | | try dices.ensureUnusedCapacity(in_dices.len); |
| 2647 | 2561 | |
| 2648 | | var next_dice: usize = 0; |
| 2649 | | for (object.atoms.items) |atom_index| { |
| 2650 | | if (next_dice >= in_dices.len) break; |
| 2651 | | const atom = self.getAtom(atom_index) orelse continue; |
| 2652 | | const start_off = atom.getInputAddress(self); |
| 2653 | | const end_off = start_off + atom.size; |
| 2654 | | const start_dice = next_dice; |
| 2655 | | |
| 2656 | | if (end_off < in_dices[next_dice].offset) continue; |
| 2657 | | |
| 2658 | | while (next_dice < in_dices.len and |
| 2659 | | in_dices[next_dice].offset < end_off) : (next_dice += 1) |
| 2660 | | {} |
| 2661 | | |
| 2662 | | if (atom.flags.alive) for (in_dices[start_dice..next_dice]) |dice| { |
| 2663 | | dices.appendAssumeCapacity(.{ |
| 2664 | | .offset = @intCast(atom.getAddress(self) + dice.offset - start_off - base_address), |
| 2665 | | .length = dice.length, |
| 2666 | | .kind = dice.kind, |
| 2667 | | }); |
| 2668 | | }; |
| 2669 | | } |
| 2562 | if (self.eh_frame_sect_index) |index| { |
| 2563 | const header = self.sections.items(.header)[index]; |
| 2564 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2565 | const buffer = try gpa.alloc(u8, size); |
| 2566 | defer gpa.free(buffer); |
| 2567 | eh_frame.write(self, buffer); |
| 2568 | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 2670 | 2569 | } |
| 2671 | 2570 | |
| 2672 | | const needed_size = math.cast(u32, dices.items.len * @sizeOf(macho.data_in_code_entry)) orelse return error.Overflow; |
| 2673 | | cmd.datasize = needed_size; |
| 2674 | | |
| 2675 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(dices.items), cmd.dataoff); |
| 2676 | | |
| 2677 | | return off + needed_size; |
| 2571 | if (self.unwind_info_sect_index) |index| { |
| 2572 | const header = self.sections.items(.header)[index]; |
| 2573 | const size = math.cast(usize, header.size) orelse return error.Overflow; |
| 2574 | const buffer = try gpa.alloc(u8, size); |
| 2575 | defer gpa.free(buffer); |
| 2576 | try self.unwind_info.write(self, buffer); |
| 2577 | try self.base.file.?.pwriteAll(buffer, header.offset); |
| 2578 | } |
| 2678 | 2579 | } |
| 2679 | 2580 | |
| 2680 | | pub fn calcSymtabSize(self: *MachO) !void { |
| 2581 | fn calcSymtabSize(self: *MachO) !void { |
| 2681 | 2582 | const tracy = trace(@src()); |
| 2682 | 2583 | defer tracy.end(); |
| 2683 | | const gpa = self.base.comp.gpa; |
| 2684 | 2584 | |
| 2685 | | var nlocals: u32 = 0; |
| 2686 | | var nstabs: u32 = 0; |
| 2687 | | var nexports: u32 = 0; |
| 2688 | | var nimports: u32 = 0; |
| 2689 | | var strsize: u32 = 0; |
| 2585 | const gpa = self.base.comp.gpa; |
| 2690 | 2586 | |
| 2691 | 2587 | var files = std.ArrayList(File.Index).init(gpa); |
| 2692 | 2588 | defer files.deinit(); |
| ... | ... | @@ -2696,6 +2592,12 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2696 | 2592 | for (self.dylibs.items) |index| files.appendAssumeCapacity(index); |
| 2697 | 2593 | if (self.internal_object) |index| files.appendAssumeCapacity(index); |
| 2698 | 2594 | |
| 2595 | var nlocals: u32 = 0; |
| 2596 | var nstabs: u32 = 0; |
| 2597 | var nexports: u32 = 0; |
| 2598 | var nimports: u32 = 0; |
| 2599 | var strsize: u32 = 0; |
| 2600 | |
| 2699 | 2601 | for (files.items) |index| { |
| 2700 | 2602 | const file = self.getFile(index).?; |
| 2701 | 2603 | const ctx = switch (file) { |
| ... | ... | @@ -2705,7 +2607,7 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2705 | 2607 | ctx.istab = nstabs; |
| 2706 | 2608 | ctx.iexport = nexports; |
| 2707 | 2609 | ctx.iimport = nimports; |
| 2708 | | try file.calcSymtabSize(self); |
| 2610 | ctx.stroff = strsize; |
| 2709 | 2611 | nlocals += ctx.nlocals; |
| 2710 | 2612 | nstabs += ctx.nstabs; |
| 2711 | 2613 | nexports += ctx.nexports; |
| ... | ... | @@ -2723,6 +2625,8 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2723 | 2625 | ctx.iimport += nlocals + nstabs + nexports; |
| 2724 | 2626 | } |
| 2725 | 2627 | |
| 2628 | try self.indsymtab.updateSize(self); |
| 2629 | |
| 2726 | 2630 | { |
| 2727 | 2631 | const cmd = &self.symtab_cmd; |
| 2728 | 2632 | cmd.nsyms = nlocals + nstabs + nexports + nimports; |
| ... | ... | @@ -2740,60 +2644,6 @@ pub fn calcSymtabSize(self: *MachO) !void { |
| 2740 | 2644 | } |
| 2741 | 2645 | } |
| 2742 | 2646 | |
| 2743 | | pub fn writeSymtab(self: *MachO, off: u32) !u32 { |
| 2744 | | const tracy = trace(@src()); |
| 2745 | | defer tracy.end(); |
| 2746 | | const gpa = self.base.comp.gpa; |
| 2747 | | const cmd = &self.symtab_cmd; |
| 2748 | | cmd.symoff = off; |
| 2749 | | |
| 2750 | | try self.symtab.resize(gpa, cmd.nsyms); |
| 2751 | | try self.strtab.ensureUnusedCapacity(gpa, cmd.strsize - 1); |
| 2752 | | |
| 2753 | | if (self.getZigObject()) |zo| { |
| 2754 | | zo.writeSymtab(self, self); |
| 2755 | | } |
| 2756 | | for (self.objects.items) |index| { |
| 2757 | | try self.getFile(index).?.writeSymtab(self, self); |
| 2758 | | } |
| 2759 | | for (self.dylibs.items) |index| { |
| 2760 | | try self.getFile(index).?.writeSymtab(self, self); |
| 2761 | | } |
| 2762 | | if (self.getInternalObject()) |internal| { |
| 2763 | | internal.writeSymtab(self, self); |
| 2764 | | } |
| 2765 | | |
| 2766 | | assert(self.strtab.items.len == cmd.strsize); |
| 2767 | | |
| 2768 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), cmd.symoff); |
| 2769 | | |
| 2770 | | return off + cmd.nsyms * @sizeOf(macho.nlist_64); |
| 2771 | | } |
| 2772 | | |
| 2773 | | fn writeIndsymtab(self: *MachO, off: u32) !u32 { |
| 2774 | | const gpa = self.base.comp.gpa; |
| 2775 | | const cmd = &self.dysymtab_cmd; |
| 2776 | | cmd.indirectsymoff = off; |
| 2777 | | cmd.nindirectsyms = self.indsymtab.nsyms(self); |
| 2778 | | |
| 2779 | | const needed_size = cmd.nindirectsyms * @sizeOf(u32); |
| 2780 | | var buffer = try std.ArrayList(u8).initCapacity(gpa, needed_size); |
| 2781 | | defer buffer.deinit(); |
| 2782 | | try self.indsymtab.write(self, buffer.writer()); |
| 2783 | | |
| 2784 | | try self.base.file.?.pwriteAll(buffer.items, cmd.indirectsymoff); |
| 2785 | | assert(buffer.items.len == needed_size); |
| 2786 | | |
| 2787 | | return off + needed_size; |
| 2788 | | } |
| 2789 | | |
| 2790 | | pub fn writeStrtab(self: *MachO, off: u32) !u32 { |
| 2791 | | const cmd = &self.symtab_cmd; |
| 2792 | | cmd.stroff = off; |
| 2793 | | try self.base.file.?.pwriteAll(self.strtab.items, cmd.stroff); |
| 2794 | | return off + cmd.strsize; |
| 2795 | | } |
| 2796 | | |
| 2797 | 2647 | fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } { |
| 2798 | 2648 | const comp = self.base.comp; |
| 2799 | 2649 | const gpa = comp.gpa; |