authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-06 09:52:09+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-12-06 09:52:09+01:00
log933999dad13ed4f4acc095a3b0d6a327f0899555
tree3f9453e9fd503a9a456169d1480ac5267076947d
parent2af94e76a3d3fb8ddfa4bba698c13e51c7ef2b1b
parent71d19318e78b6126561f630333bb47edca5fb7bd
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10280 from ziglang/zld-rel-code-path

macho: add preliminary non-prealloc path to the linker

3 files changed, 724 insertions(+), 230 deletions(-)

src/link/MachO.zig+719-228
......@@ -63,6 +63,11 @@ page_size: u16,
6363/// https://github.com/ziglang/zig/issues/9567
6464requires_adhoc_codesig: bool,
6565
66/// If true, the linker will preallocate several sections and segments before starting the linking
67/// process. This is for example true for stage2 debug builds, however, this is false for stage1
68/// and potentially stage2 release builds in the future.
69needs_prealloc: bool = true,
70
6671/// We commit 0x1000 = 4096 bytes of space to the header and
6772/// the table of load commands. This should be plenty for any
6873/// potential future extensions.
......@@ -375,6 +380,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
375380 // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator
376381 // ABI such as aarch64-ios-simulator, etc.
377382 const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator);
383 const needs_prealloc = !(build_options.is_stage1 and options.use_stage1);
378384
379385 self.* = .{
380386 .base = .{
......@@ -385,6 +391,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
385391 },
386392 .page_size = page_size,
387393 .requires_adhoc_codesig = requires_adhoc_codesig,
394 .needs_prealloc = needs_prealloc,
388395 };
389396
390397 return self;
......@@ -911,42 +918,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
911918
912919 try self.createTentativeDefAtoms();
913920 try self.parseObjectsIntoAtoms();
914 try self.allocateGlobalSymbols();
915921
916 log.debug("locals:", .{});
917 for (self.locals.items) |sym, id| {
918 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
919 }
920 log.debug("globals:", .{});
921 for (self.globals.items) |sym, id| {
922 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
923 }
924 log.debug("undefs:", .{});
925 for (self.undefs.items) |sym, id| {
926 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
927 }
928 {
929 log.debug("resolver:", .{});
930 var it = self.symbol_resolver.iterator();
931 while (it.next()) |entry| {
932 log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
933 }
922 if (use_stage1) {
923 try self.sortSections();
924 try self.allocateTextSegment();
925 try self.allocateDataConstSegment();
926 try self.allocateDataSegment();
927 self.allocateLinkeditSegment();
928 try self.allocateLocals();
934929 }
935930
936 log.debug("GOT entries:", .{});
937 for (self.got_entries_map.keys()) |key| {
938 switch (key) {
939 .local => |sym_index| log.debug(" {} => {d}", .{ key, sym_index }),
940 .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }),
941 }
942 }
931 try self.allocateGlobals();
943932
944 log.debug("stubs:", .{});
945 for (self.stubs_map.keys()) |key| {
946 log.debug(" {} => {s}", .{ key, self.getString(key) });
933 if (build_options.enable_logging) {
934 self.logSymtab();
935 self.logSectionOrdinals();
947936 }
948937
949 try self.writeAtoms();
938 if (use_stage1) {
939 try self.writeAllAtoms();
940 } else {
941 try self.writeAtoms();
942 }
950943
951944 if (self.bss_section_index) |idx| {
952945 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
......@@ -1337,7 +1330,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13371330 switch (commands.sectionType(sect)) {
13381331 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
13391332 if (self.text_const_section_index == null) {
1340 self.text_const_section_index = try self.allocateSection(
1333 self.text_const_section_index = try self.initSection(
13411334 self.text_segment_cmd_index.?,
13421335 "__const",
13431336 sect.size,
......@@ -1356,7 +1349,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13561349 // TODO it seems the common values within the sections in objects are deduplicated/merged
13571350 // on merging the sections' contents.
13581351 if (self.objc_methname_section_index == null) {
1359 self.objc_methname_section_index = try self.allocateSection(
1352 self.objc_methname_section_index = try self.initSection(
13601353 self.text_segment_cmd_index.?,
13611354 "__objc_methname",
13621355 sect.size,
......@@ -1371,7 +1364,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13711364 };
13721365 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
13731366 if (self.objc_methtype_section_index == null) {
1374 self.objc_methtype_section_index = try self.allocateSection(
1367 self.objc_methtype_section_index = try self.initSection(
13751368 self.text_segment_cmd_index.?,
13761369 "__objc_methtype",
13771370 sect.size,
......@@ -1386,7 +1379,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13861379 };
13871380 } else if (mem.eql(u8, sectname, "__objc_classname")) {
13881381 if (self.objc_classname_section_index == null) {
1389 self.objc_classname_section_index = try self.allocateSection(
1382 self.objc_classname_section_index = try self.initSection(
13901383 self.text_segment_cmd_index.?,
13911384 "__objc_classname",
13921385 sect.size,
......@@ -1402,7 +1395,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14021395 }
14031396
14041397 if (self.cstring_section_index == null) {
1405 self.cstring_section_index = try self.allocateSection(
1398 self.cstring_section_index = try self.initSection(
14061399 self.text_segment_cmd_index.?,
14071400 "__cstring",
14081401 sect.size,
......@@ -1421,7 +1414,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14211414 macho.S_LITERAL_POINTERS => {
14221415 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
14231416 if (self.objc_selrefs_section_index == null) {
1424 self.objc_selrefs_section_index = try self.allocateSection(
1417 self.objc_selrefs_section_index = try self.initSection(
14251418 self.data_segment_cmd_index.?,
14261419 "__objc_selrefs",
14271420 sect.size,
......@@ -1443,7 +1436,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14431436 },
14441437 macho.S_MOD_INIT_FUNC_POINTERS => {
14451438 if (self.mod_init_func_section_index == null) {
1446 self.mod_init_func_section_index = try self.allocateSection(
1439 self.mod_init_func_section_index = try self.initSection(
14471440 self.data_const_segment_cmd_index.?,
14481441 "__mod_init_func",
14491442 sect.size,
......@@ -1461,7 +1454,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14611454 },
14621455 macho.S_MOD_TERM_FUNC_POINTERS => {
14631456 if (self.mod_term_func_section_index == null) {
1464 self.mod_term_func_section_index = try self.allocateSection(
1457 self.mod_term_func_section_index = try self.initSection(
14651458 self.data_const_segment_cmd_index.?,
14661459 "__mod_term_func",
14671460 sect.size,
......@@ -1479,7 +1472,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14791472 },
14801473 macho.S_ZEROFILL => {
14811474 if (self.bss_section_index == null) {
1482 self.bss_section_index = try self.allocateSection(
1475 self.bss_section_index = try self.initSection(
14831476 self.data_segment_cmd_index.?,
14841477 "__bss",
14851478 sect.size,
......@@ -1497,7 +1490,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14971490 },
14981491 macho.S_THREAD_LOCAL_VARIABLES => {
14991492 if (self.tlv_section_index == null) {
1500 self.tlv_section_index = try self.allocateSection(
1493 self.tlv_section_index = try self.initSection(
15011494 self.data_segment_cmd_index.?,
15021495 "__thread_vars",
15031496 sect.size,
......@@ -1515,7 +1508,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15151508 },
15161509 macho.S_THREAD_LOCAL_REGULAR => {
15171510 if (self.tlv_data_section_index == null) {
1518 self.tlv_data_section_index = try self.allocateSection(
1511 self.tlv_data_section_index = try self.initSection(
15191512 self.data_segment_cmd_index.?,
15201513 "__thread_data",
15211514 sect.size,
......@@ -1533,7 +1526,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15331526 },
15341527 macho.S_THREAD_LOCAL_ZEROFILL => {
15351528 if (self.tlv_bss_section_index == null) {
1536 self.tlv_bss_section_index = try self.allocateSection(
1529 self.tlv_bss_section_index = try self.initSection(
15371530 self.data_segment_cmd_index.?,
15381531 "__thread_bss",
15391532 sect.size,
......@@ -1554,7 +1547,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15541547 // TODO I believe __eh_frame is currently part of __unwind_info section
15551548 // in the latest ld64 output.
15561549 if (self.eh_frame_section_index == null) {
1557 self.eh_frame_section_index = try self.allocateSection(
1550 self.eh_frame_section_index = try self.initSection(
15581551 self.text_segment_cmd_index.?,
15591552 "__eh_frame",
15601553 sect.size,
......@@ -1571,7 +1564,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15711564
15721565 // TODO audit this: is this the right mapping?
15731566 if (self.data_const_section_index == null) {
1574 self.data_const_section_index = try self.allocateSection(
1567 self.data_const_section_index = try self.initSection(
15751568 self.data_const_segment_cmd_index.?,
15761569 "__const",
15771570 sect.size,
......@@ -1588,7 +1581,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15881581 macho.S_REGULAR => {
15891582 if (commands.sectionIsCode(sect)) {
15901583 if (self.text_section_index == null) {
1591 self.text_section_index = try self.allocateSection(
1584 self.text_section_index = try self.initSection(
15921585 self.text_segment_cmd_index.?,
15931586 "__text",
15941587 sect.size,
......@@ -1619,7 +1612,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16191612 if (mem.eql(u8, segname, "__TEXT")) {
16201613 if (mem.eql(u8, sectname, "__ustring")) {
16211614 if (self.ustring_section_index == null) {
1622 self.ustring_section_index = try self.allocateSection(
1615 self.ustring_section_index = try self.initSection(
16231616 self.text_segment_cmd_index.?,
16241617 "__ustring",
16251618 sect.size,
......@@ -1634,7 +1627,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16341627 };
16351628 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
16361629 if (self.gcc_except_tab_section_index == null) {
1637 self.gcc_except_tab_section_index = try self.allocateSection(
1630 self.gcc_except_tab_section_index = try self.initSection(
16381631 self.text_segment_cmd_index.?,
16391632 "__gcc_except_tab",
16401633 sect.size,
......@@ -1649,7 +1642,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16491642 };
16501643 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
16511644 if (self.objc_methlist_section_index == null) {
1652 self.objc_methlist_section_index = try self.allocateSection(
1645 self.objc_methlist_section_index = try self.initSection(
16531646 self.text_segment_cmd_index.?,
16541647 "__objc_methlist",
16551648 sect.size,
......@@ -1669,7 +1662,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16691662 mem.eql(u8, sectname, "__gopclntab"))
16701663 {
16711664 if (self.data_const_section_index == null) {
1672 self.data_const_section_index = try self.allocateSection(
1665 self.data_const_section_index = try self.initSection(
16731666 self.data_const_segment_cmd_index.?,
16741667 "__const",
16751668 sect.size,
......@@ -1684,7 +1677,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16841677 };
16851678 } else {
16861679 if (self.text_const_section_index == null) {
1687 self.text_const_section_index = try self.allocateSection(
1680 self.text_const_section_index = try self.initSection(
16881681 self.text_segment_cmd_index.?,
16891682 "__const",
16901683 sect.size,
......@@ -1702,7 +1695,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17021695
17031696 if (mem.eql(u8, segname, "__DATA_CONST")) {
17041697 if (self.data_const_section_index == null) {
1705 self.data_const_section_index = try self.allocateSection(
1698 self.data_const_section_index = try self.initSection(
17061699 self.data_const_segment_cmd_index.?,
17071700 "__const",
17081701 sect.size,
......@@ -1720,7 +1713,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17201713 if (mem.eql(u8, segname, "__DATA")) {
17211714 if (mem.eql(u8, sectname, "__const")) {
17221715 if (self.data_const_section_index == null) {
1723 self.data_const_section_index = try self.allocateSection(
1716 self.data_const_section_index = try self.initSection(
17241717 self.data_const_segment_cmd_index.?,
17251718 "__const",
17261719 sect.size,
......@@ -1735,7 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17351728 };
17361729 } else if (mem.eql(u8, sectname, "__cfstring")) {
17371730 if (self.objc_cfstring_section_index == null) {
1738 self.objc_cfstring_section_index = try self.allocateSection(
1731 self.objc_cfstring_section_index = try self.initSection(
17391732 self.data_const_segment_cmd_index.?,
17401733 "__cfstring",
17411734 sect.size,
......@@ -1750,7 +1743,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17501743 };
17511744 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
17521745 if (self.objc_classlist_section_index == null) {
1753 self.objc_classlist_section_index = try self.allocateSection(
1746 self.objc_classlist_section_index = try self.initSection(
17541747 self.data_const_segment_cmd_index.?,
17551748 "__objc_classlist",
17561749 sect.size,
......@@ -1765,7 +1758,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17651758 };
17661759 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
17671760 if (self.objc_imageinfo_section_index == null) {
1768 self.objc_imageinfo_section_index = try self.allocateSection(
1761 self.objc_imageinfo_section_index = try self.initSection(
17691762 self.data_const_segment_cmd_index.?,
17701763 "__objc_imageinfo",
17711764 sect.size,
......@@ -1780,7 +1773,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17801773 };
17811774 } else if (mem.eql(u8, sectname, "__objc_const")) {
17821775 if (self.objc_const_section_index == null) {
1783 self.objc_const_section_index = try self.allocateSection(
1776 self.objc_const_section_index = try self.initSection(
17841777 self.data_segment_cmd_index.?,
17851778 "__objc_const",
17861779 sect.size,
......@@ -1795,7 +1788,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17951788 };
17961789 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
17971790 if (self.objc_classrefs_section_index == null) {
1798 self.objc_classrefs_section_index = try self.allocateSection(
1791 self.objc_classrefs_section_index = try self.initSection(
17991792 self.data_segment_cmd_index.?,
18001793 "__objc_classrefs",
18011794 sect.size,
......@@ -1810,7 +1803,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
18101803 };
18111804 } else if (mem.eql(u8, sectname, "__objc_data")) {
18121805 if (self.objc_data_section_index == null) {
1813 self.objc_data_section_index = try self.allocateSection(
1806 self.objc_data_section_index = try self.initSection(
18141807 self.data_segment_cmd_index.?,
18151808 "__objc_data",
18161809 sect.size,
......@@ -1825,7 +1818,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
18251818 };
18261819 } else {
18271820 if (self.data_section_index == null) {
1828 self.data_section_index = try self.allocateSection(
1821 self.data_section_index = try self.initSection(
18291822 self.data_segment_cmd_index.?,
18301823 "__data",
18311824 sect.size,
......@@ -1881,7 +1874,64 @@ pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
18811874 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
18821875}
18831876
1884fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {
1877fn allocateLocals(self: *MachO) !void {
1878 var it = self.atoms.iterator();
1879 while (it.next()) |entry| {
1880 const match = entry.key_ptr.*;
1881 var atom = entry.value_ptr.*;
1882
1883 while (atom.prev) |prev| {
1884 atom = prev;
1885 }
1886
1887 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1888 const seg = self.load_commands.items[match.seg].Segment;
1889 const sect = seg.sections.items[match.sect];
1890 var base_vaddr = sect.addr;
1891
1892 log.debug("allocating local symbols in {s},{s}", .{
1893 commands.segmentName(sect),
1894 commands.sectionName(sect),
1895 });
1896
1897 while (true) {
1898 const alignment = try math.powi(u32, 2, atom.alignment);
1899 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
1900
1901 const sym = &self.locals.items[atom.local_sym_index];
1902 sym.n_value = base_vaddr;
1903 sym.n_sect = n_sect;
1904
1905 log.debug(" {d}: {s} allocated at 0x{x}", .{
1906 atom.local_sym_index,
1907 self.getString(sym.n_strx),
1908 base_vaddr,
1909 });
1910
1911 // Update each alias (if any)
1912 for (atom.aliases.items) |index| {
1913 const alias_sym = &self.locals.items[index];
1914 alias_sym.n_value = base_vaddr;
1915 alias_sym.n_sect = n_sect;
1916 }
1917
1918 // Update each symbol contained within the atom
1919 for (atom.contained.items) |sym_at_off| {
1920 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
1921 contained_sym.n_value = base_vaddr + sym_at_off.offset;
1922 contained_sym.n_sect = n_sect;
1923 }
1924
1925 base_vaddr += atom.size;
1926
1927 if (atom.next) |next| {
1928 atom = next;
1929 } else break;
1930 }
1931 }
1932}
1933
1934fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void {
18851935 var atom = self.atoms.get(match) orelse return;
18861936
18871937 while (true) {
......@@ -1904,7 +1954,9 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void
19041954 }
19051955}
19061956
1907fn allocateGlobalSymbols(self: *MachO) !void {
1957fn allocateGlobals(self: *MachO) !void {
1958 log.debug("allocating global symbols", .{});
1959
19081960 var sym_it = self.symbol_resolver.valueIterator();
19091961 while (sym_it.next()) |resolv| {
19101962 if (resolv.where != .global) continue;
......@@ -1914,7 +1966,60 @@ fn allocateGlobalSymbols(self: *MachO) !void {
19141966 const sym = &self.globals.items[resolv.where_index];
19151967 sym.n_value = local_sym.n_value;
19161968 sym.n_sect = local_sym.n_sect;
1917 log.debug("allocating global symbol {s} at 0x{x}", .{ self.getString(sym.n_strx), local_sym.n_value });
1969
1970 log.debug(" {d}: {s} allocated at 0x{x}", .{
1971 resolv.where_index,
1972 self.getString(sym.n_strx),
1973 local_sym.n_value,
1974 });
1975 }
1976}
1977
1978fn writeAllAtoms(self: *MachO) !void {
1979 var it = self.atoms.iterator();
1980 while (it.next()) |entry| {
1981 const match = entry.key_ptr.*;
1982 const seg = self.load_commands.items[match.seg].Segment;
1983 const sect = seg.sections.items[match.sect];
1984 var atom: *Atom = entry.value_ptr.*;
1985
1986 var buffer = std.ArrayList(u8).init(self.base.allocator);
1987 defer buffer.deinit();
1988 try buffer.ensureTotalCapacity(sect.size);
1989
1990 log.debug("writing atoms in {s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
1991
1992 while (atom.prev) |prev| {
1993 atom = prev;
1994 }
1995
1996 while (true) {
1997 const atom_sym = self.locals.items[atom.local_sym_index];
1998 const padding_size: usize = if (atom.next) |next| blk: {
1999 const next_sym = self.locals.items[next.local_sym_index];
2000 const size = next_sym.n_value - (atom_sym.n_value + atom.size);
2001 break :blk try math.cast(usize, size);
2002 } else 0;
2003
2004 log.debug(" (adding atom {s} to buffer: {})", .{ self.getString(atom_sym.n_strx), atom_sym });
2005
2006 try atom.resolveRelocs(self);
2007 buffer.appendSliceAssumeCapacity(atom.code.items);
2008
2009 var i: usize = 0;
2010 while (i < padding_size) : (i += 1) {
2011 buffer.appendAssumeCapacity(0);
2012 }
2013
2014 if (atom.next) |next| {
2015 atom = next;
2016 } else {
2017 assert(buffer.items.len == sect.size);
2018 log.debug(" (writing at file offset 0x{x})", .{sect.offset});
2019 try self.base.file.?.pwriteAll(buffer.items, sect.offset);
2020 break;
2021 }
2022 }
19182023 }
19192024}
19202025
......@@ -1962,6 +2067,7 @@ fn writeAtoms(self: *MachO) !void {
19622067 atom.dirty = false;
19632068 } else {
19642069 if (file_offset) |off| {
2070 log.debug(" (writing at file offset 0x{x})", .{off});
19652071 try self.base.file.?.pwriteAll(buffer.items, off);
19662072 }
19672073 file_offset = null;
......@@ -1972,6 +2078,7 @@ fn writeAtoms(self: *MachO) !void {
19722078 atom = next;
19732079 } else {
19742080 if (file_offset) |off| {
2081 log.debug(" (writing at file offset 0x{x})", .{off});
19752082 try self.base.file.?.pwriteAll(buffer.items, off);
19762083 }
19772084 file_offset = null;
......@@ -2036,10 +2143,13 @@ fn createDyldPrivateAtom(self: *MachO) !void {
20362143 .seg = self.data_segment_cmd_index.?,
20372144 .sect = self.data_section_index.?,
20382145 };
2039 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2040 sym.n_value = vaddr;
2146 if (self.needs_prealloc) {
2147 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2148 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2149 sym.n_value = vaddr;
2150 } else try self.addAtomAndBumpSectionSize(atom, match);
2151
20412152 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2042 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
20432153}
20442154
20452155fn createStubHelperPreambleAtom(self: *MachO) !void {
......@@ -2165,11 +2275,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
21652275 .seg = self.text_segment_cmd_index.?,
21662276 .sect = self.stub_helper_section_index.?,
21672277 };
2168 const alignment_pow_2 = try math.powi(u32, 2, atom.alignment);
2169 const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match);
2170 sym.n_value = vaddr;
2278
2279 if (self.needs_prealloc) {
2280 const alignment_pow_2 = try math.powi(u32, 2, atom.alignment);
2281 const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match);
2282 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2283 sym.n_value = vaddr;
2284 } else try self.addAtomAndBumpSectionSize(atom, match);
2285
21712286 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2172 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
21732287}
21742288
21752289pub fn createStubHelperAtom(self: *MachO) !*Atom {
......@@ -2377,10 +2491,13 @@ fn createTentativeDefAtoms(self: *MachO) !void {
23772491 resolv.local_sym_index = local_sym_index;
23782492
23792493 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
2380 const alignment_pow_2 = try math.powi(u32, 2, alignment);
2381 const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);
2382 local_sym.n_value = vaddr;
2383 global_sym.n_value = vaddr;
2494
2495 if (self.needs_prealloc) {
2496 const alignment_pow_2 = try math.powi(u32, 2, alignment);
2497 const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);
2498 local_sym.n_value = vaddr;
2499 global_sym.n_value = vaddr;
2500 } else try self.addAtomAndBumpSectionSize(atom, match);
23842501 }
23852502}
23862503
......@@ -2429,10 +2546,11 @@ fn createDsoHandleAtom(self: *MachO) !void {
24292546 // TODO perhaps we should special-case special symbols? Create a separate
24302547 // linked list of atoms?
24312548 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2432 const sym = &self.locals.items[local_sym_index];
2433 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2434 sym.n_value = vaddr;
2435 atom.dirty = false; // We don't really want to write it to file.
2549 if (self.needs_prealloc) {
2550 const sym = &self.locals.items[local_sym_index];
2551 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2552 sym.n_value = vaddr;
2553 } else try self.addAtomAndBumpSectionSize(atom, match);
24362554 }
24372555}
24382556
......@@ -2466,12 +2584,11 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
24662584 return error.UnhandledSymbolType;
24672585 }
24682586
2469 const n_strx = try self.makeString(sym_name);
24702587 if (sym.sect()) {
24712588 // Defined symbol regardless of scope lands in the locals symbol table.
24722589 const local_sym_index = @intCast(u32, self.locals.items.len);
24732590 try self.locals.append(self.base.allocator, .{
2474 .n_strx = n_strx,
2591 .n_strx = if (symbolIsTemp(sym, sym_name)) 0 else try self.makeString(sym_name),
24752592 .n_type = macho.N_SECT,
24762593 .n_sect = 0,
24772594 .n_desc = 0,
......@@ -2484,6 +2601,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
24842601 // if we should save the symbol as a global, or potentially flag the error.
24852602 if (!sym.ext()) continue;
24862603
2604 const n_strx = try self.makeString(sym_name);
24872605 const local = self.locals.items[local_sym_index];
24882606 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
24892607 const global_sym_index = @intCast(u32, self.globals.items.len);
......@@ -2554,6 +2672,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
25542672 };
25552673 } else if (sym.tentative()) {
25562674 // Symbol is a tentative definition.
2675 const n_strx = try self.makeString(sym_name);
25572676 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
25582677 const global_sym_index = @intCast(u32, self.globals.items.len);
25592678 try self.globals.append(self.base.allocator, .{
......@@ -2611,6 +2730,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
26112730 }
26122731 } else {
26132732 // Symbol is undefined.
2733 const n_strx = try self.makeString(sym_name);
26142734 if (self.symbol_resolver.contains(n_strx)) continue;
26152735
26162736 const undef_sym_index = @intCast(u32, self.undefs.items.len);
......@@ -2771,10 +2891,13 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void {
27712891 });
27722892
27732893 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2774 const sym = &self.locals.items[local_sym_index];
2775 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2776 sym.n_value = vaddr;
2777 atom.dirty = false;
2894
2895 if (self.needs_prealloc) {
2896 const sym = &self.locals.items[local_sym_index];
2897 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2898 sym.n_value = vaddr;
2899 } else try self.addAtomAndBumpSectionSize(atom, match);
2900
27782901 self.mh_execute_header_index = local_sym_index;
27792902}
27802903
......@@ -2828,13 +2951,19 @@ fn resolveDyldStubBinder(self: *MachO) !void {
28282951 .sect = self.got_section_index.?,
28292952 };
28302953 const atom_sym = &self.locals.items[atom.local_sym_index];
2831 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2832 atom_sym.n_value = vaddr;
2954
2955 if (self.needs_prealloc) {
2956 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2957 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2958 atom_sym.n_value = vaddr;
2959 } else try self.addAtomAndBumpSectionSize(atom, match);
2960
28332961 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2834 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
28352962}
28362963
28372964fn parseObjectsIntoAtoms(self: *MachO) !void {
2965 // TODO I need to see if I can simplify this logic, or perhaps split it into two functions:
2966 // one for non-prealloc traditional path, and one for incremental prealloc path.
28382967 const tracy = trace(@src());
28392968 defer tracy.end();
28402969
......@@ -2858,20 +2987,31 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
28582987 var it = object.end_atoms.iterator();
28592988 while (it.next()) |entry| {
28602989 const match = entry.key_ptr.*;
2861 const last_atom = entry.value_ptr.*;
2862 var atom = last_atom;
2990 var atom = entry.value_ptr.*;
2991
2992 while (atom.prev) |prev| {
2993 atom = prev;
2994 }
2995
2996 const first_atom = atom;
28632997
2998 const seg = self.load_commands.items[match.seg].Segment;
2999 const sect = seg.sections.items[match.sect];
28643000 const metadata = try section_metadata.getOrPut(match);
28653001 if (!metadata.found_existing) {
28663002 metadata.value_ptr.* = .{
2867 .size = 0,
2868 .alignment = 0,
3003 .size = sect.size,
3004 .alignment = sect.@"align",
28693005 };
28703006 }
28713007
3008 log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
3009
28723010 while (true) {
28733011 const alignment = try math.powi(u32, 2, atom.alignment);
2874 metadata.value_ptr.size += mem.alignForwardGeneric(u64, atom.size, alignment);
3012 const curr_size = metadata.value_ptr.size;
3013 const curr_size_aligned = mem.alignForwardGeneric(u64, curr_size, alignment);
3014 metadata.value_ptr.size = curr_size_aligned + atom.size;
28753015 metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);
28763016
28773017 const sym = self.locals.items[atom.local_sym_index];
......@@ -2882,20 +3022,20 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
28823022 atom.alignment,
28833023 });
28843024
2885 if (atom.prev) |prev| {
2886 atom = prev;
3025 if (atom.next) |next| {
3026 atom = next;
28873027 } else break;
28883028 }
28893029
28903030 if (parsed_atoms.getPtr(match)) |last| {
2891 last.*.next = atom;
2892 atom.prev = last.*;
2893 last.* = atom;
3031 last.*.next = first_atom;
3032 first_atom.prev = last.*;
3033 last.* = first_atom;
28943034 }
2895 _ = try parsed_atoms.put(match, last_atom);
3035 _ = try parsed_atoms.put(match, atom);
28963036
28973037 if (!first_atoms.contains(match)) {
2898 try first_atoms.putNoClobber(match, atom);
3038 try first_atoms.putNoClobber(match, first_atom);
28993039 }
29003040 }
29013041
......@@ -2915,67 +3055,85 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
29153055 metadata.alignment,
29163056 });
29173057
2918 const sect_size = if (self.atoms.get(match)) |last| blk: {
2919 const last_atom_sym = self.locals.items[last.local_sym_index];
2920 break :blk last_atom_sym.n_value + last.size - sect.addr;
2921 } else 0;
2922
29233058 sect.@"align" = math.max(sect.@"align", metadata.alignment);
2924 const needed_size = @intCast(u32, metadata.size + sect_size);
2925 try self.growSection(match, needed_size);
3059 const needed_size = @intCast(u32, metadata.size);
3060
3061 if (self.needs_prealloc) {
3062 try self.growSection(match, needed_size);
3063 }
29263064 sect.size = needed_size;
3065 }
29273066
2928 var base_vaddr = if (self.atoms.get(match)) |last| blk: {
2929 const last_atom_sym = self.locals.items[last.local_sym_index];
2930 break :blk last_atom_sym.n_value + last.size;
2931 } else sect.addr;
2932 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
3067 for (&[_]?u16{
3068 self.text_segment_cmd_index,
3069 self.data_const_segment_cmd_index,
3070 self.data_segment_cmd_index,
3071 }) |maybe_seg_id| {
3072 const seg_id = maybe_seg_id orelse continue;
3073 const seg = self.load_commands.items[seg_id].Segment;
29333074
2934 var atom = first_atoms.get(match).?;
2935 while (true) {
2936 const alignment = try math.powi(u32, 2, atom.alignment);
2937 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
3075 for (seg.sections.items) |sect, sect_id| {
3076 const match = MatchingSection{
3077 .seg = seg_id,
3078 .sect = @intCast(u16, sect_id),
3079 };
3080 if (!section_metadata.contains(match)) continue;
3081
3082 var base_vaddr = if (self.atoms.get(match)) |last| blk: {
3083 const last_atom_sym = self.locals.items[last.local_sym_index];
3084 break :blk last_atom_sym.n_value + last.size;
3085 } else sect.addr;
3086
3087 if (self.atoms.getPtr(match)) |last| {
3088 const first_atom = first_atoms.get(match).?;
3089 last.*.next = first_atom;
3090 first_atom.prev = last.*;
3091 last.* = first_atom;
3092 }
3093 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
29383094
2939 const sym = &self.locals.items[atom.local_sym_index];
2940 sym.n_value = base_vaddr;
2941 sym.n_sect = n_sect;
3095 if (!self.needs_prealloc) continue;
29423096
2943 log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{
2944 self.getString(sym.n_strx),
2945 base_vaddr,
2946 base_vaddr + atom.size,
2947 atom.size,
2948 atom.alignment,
2949 });
3097 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
29503098
2951 // Update each alias (if any)
2952 for (atom.aliases.items) |index| {
2953 const alias_sym = &self.locals.items[index];
2954 alias_sym.n_value = base_vaddr;
2955 alias_sym.n_sect = n_sect;
2956 }
3099 var atom = first_atoms.get(match).?;
3100 while (true) {
3101 const alignment = try math.powi(u32, 2, atom.alignment);
3102 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
29573103
2958 // Update each symbol contained within the atom
2959 for (atom.contained.items) |sym_at_off| {
2960 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
2961 contained_sym.n_value = base_vaddr + sym_at_off.offset;
2962 contained_sym.n_sect = n_sect;
2963 }
3104 const sym = &self.locals.items[atom.local_sym_index];
3105 sym.n_value = base_vaddr;
3106 sym.n_sect = n_sect;
29643107
2965 base_vaddr += atom.size;
3108 log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{
3109 self.getString(sym.n_strx),
3110 base_vaddr,
3111 base_vaddr + atom.size,
3112 atom.size,
3113 atom.alignment,
3114 });
29663115
2967 if (atom.next) |next| {
2968 atom = next;
2969 } else break;
2970 }
3116 // Update each alias (if any)
3117 for (atom.aliases.items) |index| {
3118 const alias_sym = &self.locals.items[index];
3119 alias_sym.n_value = base_vaddr;
3120 alias_sym.n_sect = n_sect;
3121 }
3122
3123 // Update each symbol contained within the atom
3124 for (atom.contained.items) |sym_at_off| {
3125 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
3126 contained_sym.n_value = base_vaddr + sym_at_off.offset;
3127 contained_sym.n_sect = n_sect;
3128 }
3129
3130 base_vaddr += atom.size;
29713131
2972 if (self.atoms.getPtr(match)) |last| {
2973 const first_atom = first_atoms.get(match).?;
2974 last.*.next = first_atom;
2975 first_atom.prev = last.*;
2976 last.* = first_atom;
3132 if (atom.next) |next| {
3133 atom = next;
3134 } else break;
3135 }
29773136 }
2978 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
29793137 }
29803138}
29813139
......@@ -3714,7 +3872,9 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
37143872 return self.locals.items[decl.link.macho.local_sym_index].n_value;
37153873}
37163874
3717pub fn populateMissingMetadata(self: *MachO) !void {
3875fn populateMissingMetadata(self: *MachO) !void {
3876 const cpu_arch = self.base.options.target.cpu.arch;
3877
37183878 if (self.pagezero_segment_cmd_index == null) {
37193879 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
37203880 try self.load_commands.append(self.base.allocator, .{
......@@ -3730,13 +3890,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37303890
37313891 if (self.text_segment_cmd_index == null) {
37323892 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3733 const program_code_size_hint = self.base.options.program_code_size_hint;
3734 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
3735 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
3736 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3737
3738 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
3739
3893 const needed_size = if (self.needs_prealloc) blk: {
3894 const program_code_size_hint = self.base.options.program_code_size_hint;
3895 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
3896 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
3897 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3898 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
3899 break :blk needed_size;
3900 } else 0;
37403901 try self.load_commands.append(self.base.allocator, .{
37413902 .Segment = .{
37423903 .inner = .{
......@@ -3753,13 +3914,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37533914 }
37543915
37553916 if (self.text_section_index == null) {
3756 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3917 const alignment: u2 = switch (cpu_arch) {
37573918 .x86_64 => 0,
37583919 .aarch64 => 2,
37593920 else => unreachable, // unhandled architecture type
37603921 };
3761 const needed_size = self.base.options.program_code_size_hint;
3762 self.text_section_index = try self.allocateSection(
3922 const needed_size = if (self.needs_prealloc) self.base.options.program_code_size_hint else 0;
3923 self.text_section_index = try self.initSection(
37633924 self.text_segment_cmd_index.?,
37643925 "__text",
37653926 needed_size,
......@@ -3771,18 +3932,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37713932 }
37723933
37733934 if (self.stubs_section_index == null) {
3774 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3935 const alignment: u2 = switch (cpu_arch) {
37753936 .x86_64 => 0,
37763937 .aarch64 => 2,
37773938 else => unreachable, // unhandled architecture type
37783939 };
3779 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
3940 const stub_size: u4 = switch (cpu_arch) {
37803941 .x86_64 => 6,
37813942 .aarch64 => 3 * @sizeOf(u32),
37823943 else => unreachable, // unhandled architecture type
37833944 };
3784 const needed_size = stub_size * self.base.options.symbol_count_hint;
3785 self.stubs_section_index = try self.allocateSection(
3945 const needed_size = if (self.needs_prealloc) stub_size * self.base.options.symbol_count_hint else 0;
3946 self.stubs_section_index = try self.initSection(
37863947 self.text_segment_cmd_index.?,
37873948 "__stubs",
37883949 needed_size,
......@@ -3795,23 +3956,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37953956 }
37963957
37973958 if (self.stub_helper_section_index == null) {
3798 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3959 const alignment: u2 = switch (cpu_arch) {
37993960 .x86_64 => 0,
38003961 .aarch64 => 2,
38013962 else => unreachable, // unhandled architecture type
38023963 };
3803 const preamble_size: u6 = switch (self.base.options.target.cpu.arch) {
3964 const preamble_size: u6 = switch (cpu_arch) {
38043965 .x86_64 => 15,
38053966 .aarch64 => 6 * @sizeOf(u32),
38063967 else => unreachable,
38073968 };
3808 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
3969 const stub_size: u4 = switch (cpu_arch) {
38093970 .x86_64 => 10,
38103971 .aarch64 => 3 * @sizeOf(u32),
38113972 else => unreachable,
38123973 };
3813 const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;
3814 self.stub_helper_section_index = try self.allocateSection(
3974 const needed_size = if (self.needs_prealloc)
3975 stub_size * self.base.options.symbol_count_hint + preamble_size
3976 else
3977 0;
3978 self.stub_helper_section_index = try self.initSection(
38153979 self.text_segment_cmd_index.?,
38163980 "__stub_helper",
38173981 needed_size,
......@@ -3824,22 +3988,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38243988
38253989 if (self.data_const_segment_cmd_index == null) {
38263990 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3827 const address_and_offset = self.nextSegmentAddressAndOffset();
3828 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
3829 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3830
3831 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
3832 address_and_offset.offset,
3833 address_and_offset.offset + needed_size,
3834 });
3835
3991 var vmaddr: u64 = 0;
3992 var fileoff: u64 = 0;
3993 var needed_size: u64 = 0;
3994 if (self.needs_prealloc) {
3995 const address_and_offset = self.nextSegmentAddressAndOffset();
3996 vmaddr = address_and_offset.address;
3997 fileoff = address_and_offset.offset;
3998 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
3999 needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
4000 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
4001 fileoff,
4002 fileoff + needed_size,
4003 });
4004 }
38364005 try self.load_commands.append(self.base.allocator, .{
38374006 .Segment = .{
38384007 .inner = .{
38394008 .segname = makeStaticString("__DATA_CONST"),
3840 .vmaddr = address_and_offset.address,
4009 .vmaddr = vmaddr,
38414010 .vmsize = needed_size,
3842 .fileoff = address_and_offset.offset,
4011 .fileoff = fileoff,
38434012 .filesize = needed_size,
38444013 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
38454014 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
......@@ -3850,9 +4019,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38504019 }
38514020
38524021 if (self.got_section_index == null) {
3853 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4022 const needed_size = if (self.needs_prealloc)
4023 @sizeOf(u64) * self.base.options.symbol_count_hint
4024 else
4025 0;
38544026 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3855 self.got_section_index = try self.allocateSection(
4027 self.got_section_index = try self.initSection(
38564028 self.data_const_segment_cmd_index.?,
38574029 "__got",
38584030 needed_size,
......@@ -3865,19 +4037,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38654037
38664038 if (self.data_segment_cmd_index == null) {
38674039 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3868 const address_and_offset = self.nextSegmentAddressAndOffset();
3869 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
3870 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3871
3872 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
3873
4040 var vmaddr: u64 = 0;
4041 var fileoff: u64 = 0;
4042 var needed_size: u64 = 0;
4043 if (self.needs_prealloc) {
4044 const address_and_offset = self.nextSegmentAddressAndOffset();
4045 vmaddr = address_and_offset.address;
4046 fileoff = address_and_offset.offset;
4047 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
4048 needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
4049 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{
4050 fileoff,
4051 fileoff + needed_size,
4052 });
4053 }
38744054 try self.load_commands.append(self.base.allocator, .{
38754055 .Segment = .{
38764056 .inner = .{
38774057 .segname = makeStaticString("__DATA"),
3878 .vmaddr = address_and_offset.address,
4058 .vmaddr = vmaddr,
38794059 .vmsize = needed_size,
3880 .fileoff = address_and_offset.offset,
4060 .fileoff = fileoff,
38814061 .filesize = needed_size,
38824062 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
38834063 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
......@@ -3888,9 +4068,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38884068 }
38894069
38904070 if (self.la_symbol_ptr_section_index == null) {
3891 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4071 const needed_size = if (self.needs_prealloc)
4072 @sizeOf(u64) * self.base.options.symbol_count_hint
4073 else
4074 0;
38924075 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3893 self.la_symbol_ptr_section_index = try self.allocateSection(
4076 self.la_symbol_ptr_section_index = try self.initSection(
38944077 self.data_segment_cmd_index.?,
38954078 "__la_symbol_ptr",
38964079 needed_size,
......@@ -3902,9 +4085,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39024085 }
39034086
39044087 if (self.data_section_index == null) {
3905 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4088 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39064089 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3907 self.data_section_index = try self.allocateSection(
4090 self.data_section_index = try self.initSection(
39084091 self.data_segment_cmd_index.?,
39094092 "__data",
39104093 needed_size,
......@@ -3914,9 +4097,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39144097 }
39154098
39164099 if (self.tlv_section_index == null) {
3917 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4100 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39184101 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3919 self.tlv_section_index = try self.allocateSection(
4102 self.tlv_section_index = try self.initSection(
39204103 self.data_segment_cmd_index.?,
39214104 "__thread_vars",
39224105 needed_size,
......@@ -3928,9 +4111,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39284111 }
39294112
39304113 if (self.tlv_data_section_index == null) {
3931 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4114 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39324115 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3933 self.tlv_data_section_index = try self.allocateSection(
4116 self.tlv_data_section_index = try self.initSection(
39344117 self.data_segment_cmd_index.?,
39354118 "__thread_data",
39364119 needed_size,
......@@ -3942,9 +4125,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39424125 }
39434126
39444127 if (self.tlv_bss_section_index == null) {
3945 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4128 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39464129 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3947 self.tlv_bss_section_index = try self.allocateSection(
4130 self.tlv_bss_section_index = try self.initSection(
39484131 self.data_segment_cmd_index.?,
39494132 "__thread_bss",
39504133 needed_size,
......@@ -3959,9 +4142,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39594142 }
39604143
39614144 if (self.bss_section_index == null) {
3962 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4145 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39634146 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3964 self.bss_section_index = try self.allocateSection(
4147 self.bss_section_index = try self.initSection(
39654148 self.data_segment_cmd_index.?,
39664149 "__bss",
39674150 needed_size,
......@@ -3977,16 +4160,20 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39774160
39784161 if (self.linkedit_segment_cmd_index == null) {
39794162 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3980 const address_and_offset = self.nextSegmentAddressAndOffset();
3981
3982 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
3983
4163 var vmaddr: u64 = 0;
4164 var fileoff: u64 = 0;
4165 if (self.needs_prealloc) {
4166 const address_and_offset = self.nextSegmentAddressAndOffset();
4167 vmaddr = address_and_offset.address;
4168 fileoff = address_and_offset.offset;
4169 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
4170 }
39844171 try self.load_commands.append(self.base.allocator, .{
39854172 .Segment = .{
39864173 .inner = .{
39874174 .segname = makeStaticString("__LINKEDIT"),
3988 .vmaddr = address_and_offset.address,
3989 .fileoff = address_and_offset.offset,
4175 .vmaddr = vmaddr,
4176 .fileoff = fileoff,
39904177 .maxprot = macho.VM_PROT_READ,
39914178 .initprot = macho.VM_PROT_READ,
39924179 },
......@@ -4198,44 +4385,123 @@ pub fn populateMissingMetadata(self: *MachO) !void {
41984385 self.cold_start = true;
41994386}
42004387
4201const AllocateSectionOpts = struct {
4388fn allocateTextSegment(self: *MachO) !void {
4389 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4390 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
4391 seg.inner.fileoff = 0;
4392 seg.inner.vmaddr = base_vmaddr;
4393
4394 var sizeofcmds: u64 = 0;
4395 for (self.load_commands.items) |lc| {
4396 sizeofcmds += lc.cmdsize();
4397 }
4398
4399 try self.allocateSegment(self.text_segment_cmd_index.?, @sizeOf(macho.mach_header_64) + sizeofcmds);
4400
4401 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
4402 var min_alignment: u32 = 0;
4403 for (seg.sections.items) |sect| {
4404 const alignment = try math.powi(u32, 2, sect.@"align");
4405 min_alignment = math.max(min_alignment, alignment);
4406 }
4407
4408 assert(min_alignment > 0);
4409 const last_sect_idx = seg.sections.items.len - 1;
4410 const last_sect = seg.sections.items[last_sect_idx];
4411 const shift: u32 = blk: {
4412 const diff = seg.inner.filesize - last_sect.offset - last_sect.size;
4413 const factor = @divTrunc(diff, min_alignment);
4414 break :blk @intCast(u32, factor * min_alignment);
4415 };
4416
4417 if (shift > 0) {
4418 for (seg.sections.items) |*sect| {
4419 sect.offset += shift;
4420 sect.addr += shift;
4421 }
4422 }
4423}
4424
4425fn allocateDataConstSegment(self: *MachO) !void {
4426 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4427 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4428 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
4429 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
4430 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
4431}
4432
4433fn allocateDataSegment(self: *MachO) !void {
4434 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4435 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4436 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
4437 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
4438 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
4439}
4440
4441fn allocateLinkeditSegment(self: *MachO) void {
4442 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4443 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4444 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
4445 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
4446}
4447
4448fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {
4449 const seg = &self.load_commands.items[index].Segment;
4450
4451 // Allocate the sections according to their alignment at the beginning of the segment.
4452 var start: u64 = offset;
4453 for (seg.sections.items) |*sect| {
4454 const alignment = try math.powi(u32, 2, sect.@"align");
4455 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
4456 const end = start_aligned + sect.size;
4457 sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned);
4458 sect.addr = seg.inner.vmaddr + start_aligned;
4459 start = end;
4460 }
4461
4462 const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size);
4463 seg.inner.filesize = seg_size_aligned;
4464 seg.inner.vmsize = seg_size_aligned;
4465}
4466
4467const InitSectionOpts = struct {
42024468 flags: u32 = macho.S_REGULAR,
42034469 reserved1: u32 = 0,
42044470 reserved2: u32 = 0,
42054471};
42064472
4207fn allocateSection(
4473fn initSection(
42084474 self: *MachO,
42094475 segment_id: u16,
42104476 sectname: []const u8,
42114477 size: u64,
42124478 alignment: u32,
4213 opts: AllocateSectionOpts,
4479 opts: InitSectionOpts,
42144480) !u16 {
42154481 const seg = &self.load_commands.items[segment_id].Segment;
42164482 var sect = macho.section_64{
42174483 .sectname = makeStaticString(sectname),
42184484 .segname = seg.inner.segname,
4219 .size = @intCast(u32, size),
4485 .size = if (self.needs_prealloc) @intCast(u32, size) else 0,
42204486 .@"align" = alignment,
42214487 .flags = opts.flags,
42224488 .reserved1 = opts.reserved1,
42234489 .reserved2 = opts.reserved2,
42244490 };
42254491
4226 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4227 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
4228 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4229
4230 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4231 commands.segmentName(sect),
4232 commands.sectionName(sect),
4233 off,
4234 off + size,
4235 });
4236
4237 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
4238 sect.offset = @intCast(u32, off);
4492 if (self.needs_prealloc) {
4493 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4494 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
4495 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4496 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4497 commands.segmentName(sect),
4498 commands.sectionName(sect),
4499 off,
4500 off + size,
4501 });
4502 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
4503 sect.offset = @intCast(u32, off);
4504 }
42394505
42404506 const index = @intCast(u16, seg.sections.items.len);
42414507 try seg.sections.append(self.base.allocator, sect);
......@@ -4270,7 +4536,11 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
42704536 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
42714537 assert(new_seg_size > seg.inner.filesize);
42724538 const offset_amt = new_seg_size - seg.inner.filesize;
4273 log.debug("growing segment {s} from 0x{x} to 0x{x}", .{ seg.inner.segname, seg.inner.filesize, new_seg_size });
4539 log.debug("growing segment {s} from 0x{x} to 0x{x}", .{
4540 seg.inner.segname,
4541 seg.inner.filesize,
4542 new_seg_size,
4543 });
42744544 seg.inner.filesize = new_seg_size;
42754545 seg.inner.vmsize = new_seg_size;
42764546
......@@ -4321,7 +4591,7 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
43214591 moved_sect.addr + moved_sect.size,
43224592 });
43234593
4324 try self.allocateLocalSymbols(.{
4594 try self.shiftLocalsByOffset(.{
43254595 .seg = @intCast(u16, next),
43264596 .sect = @intCast(u16, moved_sect_id),
43274597 }, @intCast(i64, offset_amt));
......@@ -4395,7 +4665,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
43954665 moved_sect.addr + moved_sect.size,
43964666 });
43974667
4398 try self.allocateLocalSymbols(.{
4668 try self.shiftLocalsByOffset(.{
43994669 .seg = match.seg,
44004670 .sect = next,
44014671 }, @intCast(i64, offset_amt));
......@@ -4534,6 +4804,21 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
45344804 return vaddr;
45354805}
45364806
4807fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void {
4808 const seg = &self.load_commands.items[match.seg].Segment;
4809 const sect = &seg.sections.items[match.sect];
4810 const alignment = try math.powi(u32, 2, atom.alignment);
4811 sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;
4812
4813 if (self.atoms.getPtr(match)) |last| {
4814 last.*.next = atom;
4815 atom.prev = last.*;
4816 last.* = atom;
4817 } else {
4818 try self.atoms.putNoClobber(self.base.allocator, match, atom);
4819 }
4820}
4821
45374822pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
45384823 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
45394824 defer self.base.allocator.free(sym_name);
......@@ -4580,6 +4865,160 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
45804865 };
45814866}
45824867
4868fn sortSections(self: *MachO) !void {
4869 var text_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
4870 defer text_index_mapping.deinit();
4871 var data_const_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
4872 defer data_const_index_mapping.deinit();
4873 var data_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator);
4874 defer data_index_mapping.deinit();
4875
4876 {
4877 // __TEXT segment
4878 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4879 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4880 defer self.base.allocator.free(sections);
4881 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
4882
4883 const indices = &[_]*?u16{
4884 &self.text_section_index,
4885 &self.stubs_section_index,
4886 &self.stub_helper_section_index,
4887 &self.gcc_except_tab_section_index,
4888 &self.cstring_section_index,
4889 &self.ustring_section_index,
4890 &self.text_const_section_index,
4891 &self.objc_methlist_section_index,
4892 &self.objc_methname_section_index,
4893 &self.objc_methtype_section_index,
4894 &self.objc_classname_section_index,
4895 &self.eh_frame_section_index,
4896 };
4897 for (indices) |maybe_index| {
4898 const new_index: u16 = if (maybe_index.*) |index| blk: {
4899 const idx = @intCast(u16, seg.sections.items.len);
4900 seg.sections.appendAssumeCapacity(sections[index]);
4901 try text_index_mapping.putNoClobber(index, idx);
4902 break :blk idx;
4903 } else continue;
4904 maybe_index.* = new_index;
4905 }
4906 }
4907
4908 {
4909 // __DATA_CONST segment
4910 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4911 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4912 defer self.base.allocator.free(sections);
4913 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
4914
4915 const indices = &[_]*?u16{
4916 &self.got_section_index,
4917 &self.mod_init_func_section_index,
4918 &self.mod_term_func_section_index,
4919 &self.data_const_section_index,
4920 &self.objc_cfstring_section_index,
4921 &self.objc_classlist_section_index,
4922 &self.objc_imageinfo_section_index,
4923 };
4924 for (indices) |maybe_index| {
4925 const new_index: u16 = if (maybe_index.*) |index| blk: {
4926 const idx = @intCast(u16, seg.sections.items.len);
4927 seg.sections.appendAssumeCapacity(sections[index]);
4928 try data_const_index_mapping.putNoClobber(index, idx);
4929 break :blk idx;
4930 } else continue;
4931 maybe_index.* = new_index;
4932 }
4933 }
4934
4935 {
4936 // __DATA segment
4937 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4938 var sections = seg.sections.toOwnedSlice(self.base.allocator);
4939 defer self.base.allocator.free(sections);
4940 try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len);
4941
4942 // __DATA segment
4943 const indices = &[_]*?u16{
4944 &self.la_symbol_ptr_section_index,
4945 &self.objc_const_section_index,
4946 &self.objc_selrefs_section_index,
4947 &self.objc_classrefs_section_index,
4948 &self.objc_data_section_index,
4949 &self.data_section_index,
4950 &self.tlv_section_index,
4951 &self.tlv_data_section_index,
4952 &self.tlv_bss_section_index,
4953 &self.bss_section_index,
4954 };
4955 for (indices) |maybe_index| {
4956 const new_index: u16 = if (maybe_index.*) |index| blk: {
4957 const idx = @intCast(u16, seg.sections.items.len);
4958 seg.sections.appendAssumeCapacity(sections[index]);
4959 try data_index_mapping.putNoClobber(index, idx);
4960 break :blk idx;
4961 } else continue;
4962 maybe_index.* = new_index;
4963 }
4964 }
4965
4966 {
4967 var transient: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{};
4968 try transient.ensureTotalCapacity(self.base.allocator, self.atoms.count());
4969
4970 var it = self.atoms.iterator();
4971 while (it.next()) |entry| {
4972 const old = entry.key_ptr.*;
4973 const sect = if (old.seg == self.text_segment_cmd_index.?)
4974 text_index_mapping.get(old.sect).?
4975 else if (old.seg == self.data_const_segment_cmd_index.?)
4976 data_const_index_mapping.get(old.sect).?
4977 else
4978 data_index_mapping.get(old.sect).?;
4979 transient.putAssumeCapacityNoClobber(.{
4980 .seg = old.seg,
4981 .sect = sect,
4982 }, entry.value_ptr.*);
4983 }
4984
4985 self.atoms.clearAndFree(self.base.allocator);
4986 self.atoms.deinit(self.base.allocator);
4987 self.atoms = transient;
4988 }
4989
4990 {
4991 // Create new section ordinals.
4992 self.section_ordinals.clearRetainingCapacity();
4993 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4994 for (text_seg.sections.items) |_, sect_id| {
4995 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
4996 .seg = self.text_segment_cmd_index.?,
4997 .sect = @intCast(u16, sect_id),
4998 });
4999 assert(!res.found_existing);
5000 }
5001 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
5002 for (data_const_seg.sections.items) |_, sect_id| {
5003 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5004 .seg = self.data_const_segment_cmd_index.?,
5005 .sect = @intCast(u16, sect_id),
5006 });
5007 assert(!res.found_existing);
5008 }
5009 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
5010 for (data_seg.sections.items) |_, sect_id| {
5011 const res = self.section_ordinals.getOrPutAssumeCapacity(.{
5012 .seg = self.data_segment_cmd_index.?,
5013 .sect = @intCast(u16, sect_id),
5014 });
5015 assert(!res.found_existing);
5016 }
5017 }
5018
5019 self.sections_order_dirty = false;
5020}
5021
45835022fn updateSectionOrdinals(self: *MachO) !void {
45845023 if (!self.sections_order_dirty) return;
45855024
......@@ -4957,7 +5396,7 @@ fn writeSymbolTable(self: *MachO) !void {
49575396
49585397 for (self.locals.items) |sym| {
49595398 if (sym.n_strx == 0) continue;
4960 if (symbolIsTemp(sym, self.getString(sym.n_strx))) continue;
5399 if (self.symbol_resolver.get(sym.n_strx)) |_| continue;
49615400 try locals.append(sym);
49625401 }
49635402
......@@ -5309,7 +5748,7 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {
53095748 return new_off;
53105749}
53115750
5312pub fn getString(self: *MachO, off: u32) []const u8 {
5751pub fn getString(self: MachO, off: u32) []const u8 {
53135752 assert(off < self.strtab.items.len);
53145753 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.items.ptr + off), 0);
53155754}
......@@ -5602,3 +6041,55 @@ fn snapshotState(self: *MachO) !void {
56026041 try std.json.stringify(snapshot, .{}, writer);
56036042 try writer.writeByte(']');
56046043}
6044
6045fn logSymtab(self: MachO) void {
6046 log.debug("locals:", .{});
6047 for (self.locals.items) |sym, id| {
6048 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
6049 }
6050
6051 log.debug("globals:", .{});
6052 for (self.globals.items) |sym, id| {
6053 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
6054 }
6055
6056 log.debug("undefs:", .{});
6057 for (self.undefs.items) |sym, id| {
6058 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });
6059 }
6060
6061 {
6062 log.debug("resolver:", .{});
6063 var it = self.symbol_resolver.iterator();
6064 while (it.next()) |entry| {
6065 log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* });
6066 }
6067 }
6068
6069 log.debug("GOT entries:", .{});
6070 for (self.got_entries_map.keys()) |key| {
6071 switch (key) {
6072 .local => |sym_index| log.debug(" {} => {d}", .{ key, sym_index }),
6073 .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }),
6074 }
6075 }
6076
6077 log.debug("stubs:", .{});
6078 for (self.stubs_map.keys()) |key| {
6079 log.debug(" {} => {s}", .{ key, self.getString(key) });
6080 }
6081}
6082
6083fn logSectionOrdinals(self: MachO) void {
6084 for (self.section_ordinals.keys()) |match, i| {
6085 const seg = self.load_commands.items[match.seg].Segment;
6086 const sect = seg.sections.items[match.sect];
6087 log.debug("ord {d}: {d},{d} => {s},{s}", .{
6088 i + 1,
6089 match.seg,
6090 match.sect,
6091 commands.segmentName(sect),
6092 commands.sectionName(sect),
6093 });
6094 }
6095}
src/link/MachO/Atom.zig+2-1
......@@ -344,7 +344,8 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
344344 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {
345345 const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
346346 const sect = seg.sections.items[sect_id];
347 const match = (try context.macho_file.getMatchingSection(sect)) orelse unreachable;
347 const match = (try context.macho_file.getMatchingSection(sect)) orelse
348 unreachable;
348349 const local_sym_index = @intCast(u32, context.macho_file.locals.items.len);
349350 try context.macho_file.locals.append(context.allocator, .{
350351 .n_strx = 0,
src/link/MachO/Object.zig+3-1
......@@ -474,7 +474,9 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
474474 try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index);
475475 break :blk atom_local_sym_index;
476476 };
477 const atom = try macho_file.createEmptyAtom(atom_local_sym_index, sect.size, sect.@"align");
477 const alignment = try math.powi(u32, 2, sect.@"align");
478 const aligned_size = mem.alignForwardGeneric(u64, sect.size, alignment);
479 const atom = try macho_file.createEmptyAtom(atom_local_sym_index, aligned_size, sect.@"align");
478480
479481 const is_zerofill = blk: {
480482 const section_type = commands.sectionType(sect);