authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-09 18:17:23+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:08+02:00
log2e87883be85956b2a5be682423256e9ba700c13f
tree2fa7e4db9d849d80d4001bf34107803a4eba7855
parent355992cbdff96db66dd79e8bbbee04cb081f683f

macho: migrate the MachO driver


1 files changed, 396 insertions(+), 546 deletions(-)

src/link/MachO.zig+396-546
......@@ -540,13 +540,13 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
540540 try self.sortSections();
541541 try self.addAtomsToSections();
542542 try self.calcSectionSizes();
543
543544 try self.generateUnwindInfo();
544 try self.initSegments();
545545
546 try self.initSegments();
546547 try self.allocateSections();
547548 self.allocateSegments();
548549 self.allocateSyntheticSymbols();
549 try self.allocateLinkeditSegment();
550550
551551 if (build_options.enable_logging) {
552552 state_log.debug("{}", .{self.dumpState()});
......@@ -554,6 +554,8 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
554554
555555 // Beyond this point, everything has been allocated a virtual address and we can resolve
556556 // the relocations, and commit objects to file.
557 try self.resizeSections();
558
557559 if (self.getZigObject()) |zo| {
558560 var has_resolve_error = false;
559561
......@@ -597,33 +599,11 @@ pub fn flushModule(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_n
597599
598600 if (has_resolve_error) return error.FlushFailure;
599601 }
602 try self.writeSectionsAndUpdateLinkeditSizes();
600603
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();
627607
628608 var codesig: ?CodeSignature = if (self.requiresCodeSig()) blk: {
629609 // Preallocate space for the code signature.
......@@ -1498,48 +1478,23 @@ fn checkDuplicates(self: *MachO) !void {
14981478}
14991479
15001480fn markImportsAndExports(self: *MachO) void {
1481 const tracy = trace(@src());
1482 defer tracy.end();
1483
15011484 if (self.getZigObject()) |zo| {
15021485 zo.asFile().markImportsExports(self);
15031486 }
15041487 for (self.objects.items) |index| {
15051488 self.getFile(index).?.markImportsExports(self);
15061489 }
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);
15271492 }
15281493}
15291494
15301495fn 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();
15431498
15441499 for (self.dylibs.items) |index| {
15451500 self.getFile(index).?.dylib.markReferenced(self);
......@@ -1560,50 +1515,26 @@ fn scanRelocs(self: *MachO) !void {
15601515 const tracy = trace(@src());
15611516 defer tracy.end();
15621517
1563 if (self.getZigObject()) |zo| try zo.scanRelocs(self);
1564
1518 if (self.getZigObject()) |zo| {
1519 try zo.scanRelocs(self);
1520 }
15651521 for (self.objects.items) |index| {
15661522 try self.getFile(index).?.object.scanRelocs(self);
15671523 }
1524 if (self.getInternalObject()) |obj| {
1525 try obj.scanRelocs(self);
1526 }
15681527
15691528 try self.reportUndefs();
15701529
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);
15811532 }
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);
15871535 }
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);
16071538 }
16081539}
16091540
......@@ -1611,17 +1542,15 @@ fn reportUndefs(self: *MachO) !void {
16111542 const tracy = trace(@src());
16121543 defer tracy.end();
16131544
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;
16181547
16191548 const max_notes = 4;
16201549
16211550 var has_undefs = false;
16221551 var it = self.undefs.iterator();
16231552 while (it.next()) |entry| {
1624 const undef_sym = self.getSymbol(entry.key_ptr.*);
1553 const undef_sym = entry.key_ptr.getSymbol(self).?;
16251554 const notes = entry.value_ptr.*;
16261555 const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
16271556
......@@ -1631,8 +1560,9 @@ fn reportUndefs(self: *MachO) !void {
16311560
16321561 var inote: usize = 0;
16331562 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).?;
16361566 try err.addNote(self, "referenced by {}:{s}", .{ file.fmtPath(), atom.getName(self) });
16371567 }
16381568
......@@ -1641,64 +1571,18 @@ fn reportUndefs(self: *MachO) !void {
16411571 try err.addNote(self, "referenced {d} more times", .{remaining});
16421572 }
16431573 }
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
16841574 if (has_undefs) return error.HasUndefinedSymbols;
16851575}
16861576
16871577fn initOutputSections(self: *MachO) !void {
1578 const tracy = trace(@src());
1579 defer tracy.end();
1580
16881581 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);
16951583 }
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);
17021586 }
17031587 self.text_sect_index = self.getSectionByName("__TEXT", "__text") orelse
17041588 try self.addSection("__TEXT", "__text", .{
......@@ -1771,46 +1655,50 @@ fn initSyntheticSections(self: *MachO) !void {
17711655 self.eh_frame_sect_index = try self.addSection("__TEXT", "__eh_frame", .{});
17721656 }
17731657
1774 for (self.boundary_symbols.items) |sym_index| {
1658 if (self.getInternalObject()) |obj| {
17751659 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 }
18141702 }
18151703}
18161704
......@@ -1917,38 +1805,25 @@ pub fn sortSections(self: *MachO) !void {
19171805 }
19181806
19191807 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;
19221810 if (!atom.flags.alive) continue;
19231811 atom.out_n_sect = backlinks[atom.out_n_sect];
19241812 }
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 }
19391813 }
19401814
19411815 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;
19441819 if (!atom.flags.alive) continue;
19451820 atom.out_n_sect = backlinks[atom.out_n_sect];
19461821 }
19471822 }
19481823
19491824 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;
19521827 if (!atom.flags.alive) continue;
19531828 atom.out_n_sect = backlinks[atom.out_n_sect];
19541829 }
......@@ -1985,35 +1860,23 @@ pub fn addAtomsToSections(self: *MachO) !void {
19851860 const tracy = trace(@src());
19861861 defer tracy.end();
19871862
1863 const gpa = self.base.comp.gpa;
1864
19881865 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;
19921869 if (!atom.flags.alive) continue;
19931870 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 });
20021872 }
20031873 }
20041874 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;
20071877 if (!atom.flags.alive) continue;
20081878 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 });
20171880 }
20181881 }
20191882}
......@@ -2035,8 +1898,8 @@ fn calcSectionSizes(self: *MachO) !void {
20351898 if (atoms.items.len == 0) continue;
20361899 if (self.requiresThunks() and header.isCode()) continue;
20371900
2038 for (atoms.items) |atom_index| {
2039 const atom = self.getAtom(atom_index).?;
1901 for (atoms.items) |ref| {
1902 const atom = ref.getAtom(self).?;
20401903 const atom_alignment = atom.alignment.toByteUnits() orelse 1;
20411904 const offset = mem.alignForward(u64, header.size, atom_alignment);
20421905 const padding = offset - header.size;
......@@ -2056,6 +1919,22 @@ fn calcSectionSizes(self: *MachO) !void {
20561919 }
20571920 }
20581921
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
20591938 if (self.got_sect_index) |idx| {
20601939 const header = &self.sections.items(.header)[idx];
20611940 header.size = self.got.size();
......@@ -2336,77 +2215,61 @@ fn allocateSegments(self: *MachO) void {
23362215}
23372216
23382217fn 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);
23452220
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();
23602222
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);
23642227
2365 sym.flags.@"export" = false;
2366 sym.value = text_seg.vmaddr;
2228 sym.value = text_seg.vmaddr;
23672229
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 }
24022264
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;
24052267
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 }
24102273 }
24112274 }
24122275}
......@@ -2424,177 +2287,224 @@ fn allocateLinkeditSegment(self: *MachO) !void {
24242287 const seg = self.getLinkeditSegment();
24252288 seg.vmaddr = mem.alignForward(u64, vmaddr, page_size);
24262289 seg.fileoff = mem.alignForward(u64, fileoff, page_size);
2427}
24282290
2429fn 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 }
24322315
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 }
24362323
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 }
24392331
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
2350fn resizeSections(self: *MachO) !void {
2351 const slice = self.sections.slice();
2352 for (slice.items(.header), slice.items(.atoms), slice.items(.out)) |header, atoms, *out| {
24422353 if (atoms.items.len == 0) continue;
24432354 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);
24482357 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}
24502361
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 }
2362fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void {
2363 const gpa = self.base.comp.gpa;
24622364
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;
24652369
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 }
24662376 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]);
24722381 try thunk.write(self, stream.writer());
2473 try self.base.file.?.pwriteAll(buffer, offset);
24742382 }
24752383
2476 if (has_resolve_error) return error.ResolveFailed;
2477}
2478
2479fn 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 }
24922398 }
24932399
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();
25012402 }
2502}
25032403
2504fn finalizeDyldInfoSections(self: *MachO) !void {
2505 const tracy = trace(@src());
2506 defer tracy.end();
25072404 try self.rebase.updateSize(self);
25082405 try self.bind.updateSize(self);
25092406 try self.weak_bind.updateSize(self);
2510 if (self.la_symbol_ptr_sect_index) |_| {
2511 try self.lazy_bind.updateSize(self);
2512 }
25132407 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 }
25142422}
25152423
2516fn writeSyntheticSections(self: *MachO) !void {
2424fn writeSyntheticSection(self: *MachO, sect_id: u8, out: []u8) !void {
25172425 const tracy = trace(@src());
25182426 defer tracy.end();
25192427
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 };
25312437
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()),
25402464 }
2465}
25412466
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 }
2467fn 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}
25512476
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 }
2477fn writeSectionsToFile(self: *MachO) !void {
2478 const tracy = trace(@src());
2479 defer tracy.end();
25612480
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);
25702484 }
2485}
25712486
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 }
2487fn 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();
25812494}
25822495
2583fn writeDyldInfoSections(self: *MachO, off: u32) !u32 {
2496fn writeDyldInfo(self: *MachO) !void {
25842497 const tracy = trace(@src());
25852498 defer tracy.end();
25862499
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;
25892503 var needed_size: u32 = 0;
25902504 needed_size += cmd.rebase_size;
2591 cmd.bind_off = needed_size;
25922505 needed_size += cmd.bind_size;
2593 cmd.weak_bind_off = needed_size;
25942506 needed_size += cmd.weak_bind_size;
2595 cmd.lazy_bind_off = needed_size;
25962507 needed_size += cmd.lazy_bind_size;
2597 cmd.export_off = needed_size;
25982508 needed_size += cmd.export_size;
25992509
26002510 const buffer = try gpa.alloc(u8, needed_size);
......@@ -2605,88 +2515,74 @@ fn writeDyldInfoSections(self: *MachO, off: u32) !u32 {
26052515 const writer = stream.writer();
26062516
26072517 try self.rebase.write(writer);
2608 try stream.seekTo(cmd.bind_off);
2518 try stream.seekTo(cmd.bind_off - base_off);
26092519 try self.bind.write(writer);
2610 try stream.seekTo(cmd.weak_bind_off);
2520 try stream.seekTo(cmd.weak_bind_off - base_off);
26112521 try self.weak_bind.write(writer);
2612 try stream.seekTo(cmd.lazy_bind_off);
2522 try stream.seekTo(cmd.lazy_bind_off - base_off);
26132523 try self.lazy_bind.write(writer);
2614 try stream.seekTo(cmd.export_off);
2524 try stream.seekTo(cmd.export_off - base_off);
26152525 try self.export_trie.write(writer);
2526 try self.base.file.pwriteAll(buffer, cmd.rebase_off);
2527}
26162528
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);
2529pub 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}
26232535
2624 return off + needed_size;
2536fn 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);
26252546}
26262547
2627fn 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;
2548pub 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);
26322554}
26332555
2634pub fn writeDataInCode(self: *MachO, base_address: u64, off: u32) !u32 {
2635 const cmd = &self.data_in_code_cmd;
2636 cmd.dataoff = off;
2556fn writeUnwindInfo(self: *MachO) !void {
2557 const tracy = trace(@src());
2558 defer tracy.end();
26372559
26382560 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);
26472561
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);
26702569 }
26712570
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 }
26782579}
26792580
2680pub fn calcSymtabSize(self: *MachO) !void {
2581fn calcSymtabSize(self: *MachO) !void {
26812582 const tracy = trace(@src());
26822583 defer tracy.end();
2683 const gpa = self.base.comp.gpa;
26842584
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;
26902586
26912587 var files = std.ArrayList(File.Index).init(gpa);
26922588 defer files.deinit();
......@@ -2696,6 +2592,12 @@ pub fn calcSymtabSize(self: *MachO) !void {
26962592 for (self.dylibs.items) |index| files.appendAssumeCapacity(index);
26972593 if (self.internal_object) |index| files.appendAssumeCapacity(index);
26982594
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
26992601 for (files.items) |index| {
27002602 const file = self.getFile(index).?;
27012603 const ctx = switch (file) {
......@@ -2705,7 +2607,7 @@ pub fn calcSymtabSize(self: *MachO) !void {
27052607 ctx.istab = nstabs;
27062608 ctx.iexport = nexports;
27072609 ctx.iimport = nimports;
2708 try file.calcSymtabSize(self);
2610 ctx.stroff = strsize;
27092611 nlocals += ctx.nlocals;
27102612 nstabs += ctx.nstabs;
27112613 nexports += ctx.nexports;
......@@ -2723,6 +2625,8 @@ pub fn calcSymtabSize(self: *MachO) !void {
27232625 ctx.iimport += nlocals + nstabs + nexports;
27242626 }
27252627
2628 try self.indsymtab.updateSize(self);
2629
27262630 {
27272631 const cmd = &self.symtab_cmd;
27282632 cmd.nsyms = nlocals + nstabs + nexports + nimports;
......@@ -2740,60 +2644,6 @@ pub fn calcSymtabSize(self: *MachO) !void {
27402644 }
27412645}
27422646
2743pub 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
2773fn 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
2790pub 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
27972647fn writeLoadCommands(self: *MachO) !struct { usize, usize, u64 } {
27982648 const comp = self.base.comp;
27992649 const gpa = comp.gpa;