authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-04 13:53:57+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-05 22:46:46+01:00
logc86f2402d077077489154a14af73ff5616722036
tree03ad1942f65c292ee2469f143ffd6fc52a3dce60
parent9e03cf948948ea25feb3f413f234e98e71d55786

macho: don't prealloc sections when stage1


3 files changed, 461 insertions(+), 189 deletions(-)

src/link/MachO.zig+456-187
......@@ -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,6 +918,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
911918
912919 try self.createTentativeDefAtoms();
913920 try self.parseObjectsIntoAtoms();
921
922 if (use_stage1) {
923 try self.allocateTextSegment();
924 try self.allocateDataConstSegment();
925 try self.allocateDataSegment();
926 self.allocateLinkeditSegment();
927 try self.allocLocalSymbols();
928 }
929
914930 try self.allocateGlobalSymbols();
915931
916932 log.debug("locals:", .{});
......@@ -946,6 +962,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
946962 log.debug(" {} => {s}", .{ key, self.getString(key) });
947963 }
948964
965 for (self.section_ordinals.keys()) |match, i| {
966 const seg = self.load_commands.items[match.seg].Segment;
967 const sect = seg.sections.items[match.sect];
968 log.debug("{d}: {d},{d} == {s},{s}", .{
969 i + 1,
970 match.seg,
971 match.sect,
972 commands.segmentName(sect),
973 commands.sectionName(sect),
974 });
975 }
976
949977 try self.writeAtoms();
950978
951979 if (self.bss_section_index) |idx| {
......@@ -1337,7 +1365,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13371365 switch (commands.sectionType(sect)) {
13381366 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
13391367 if (self.text_const_section_index == null) {
1340 self.text_const_section_index = try self.allocateSection(
1368 self.text_const_section_index = try self.initSection(
13411369 self.text_segment_cmd_index.?,
13421370 "__const",
13431371 sect.size,
......@@ -1356,7 +1384,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13561384 // TODO it seems the common values within the sections in objects are deduplicated/merged
13571385 // on merging the sections' contents.
13581386 if (self.objc_methname_section_index == null) {
1359 self.objc_methname_section_index = try self.allocateSection(
1387 self.objc_methname_section_index = try self.initSection(
13601388 self.text_segment_cmd_index.?,
13611389 "__objc_methname",
13621390 sect.size,
......@@ -1371,7 +1399,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13711399 };
13721400 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
13731401 if (self.objc_methtype_section_index == null) {
1374 self.objc_methtype_section_index = try self.allocateSection(
1402 self.objc_methtype_section_index = try self.initSection(
13751403 self.text_segment_cmd_index.?,
13761404 "__objc_methtype",
13771405 sect.size,
......@@ -1386,7 +1414,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
13861414 };
13871415 } else if (mem.eql(u8, sectname, "__objc_classname")) {
13881416 if (self.objc_classname_section_index == null) {
1389 self.objc_classname_section_index = try self.allocateSection(
1417 self.objc_classname_section_index = try self.initSection(
13901418 self.text_segment_cmd_index.?,
13911419 "__objc_classname",
13921420 sect.size,
......@@ -1402,7 +1430,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14021430 }
14031431
14041432 if (self.cstring_section_index == null) {
1405 self.cstring_section_index = try self.allocateSection(
1433 self.cstring_section_index = try self.initSection(
14061434 self.text_segment_cmd_index.?,
14071435 "__cstring",
14081436 sect.size,
......@@ -1421,7 +1449,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14211449 macho.S_LITERAL_POINTERS => {
14221450 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
14231451 if (self.objc_selrefs_section_index == null) {
1424 self.objc_selrefs_section_index = try self.allocateSection(
1452 self.objc_selrefs_section_index = try self.initSection(
14251453 self.data_segment_cmd_index.?,
14261454 "__objc_selrefs",
14271455 sect.size,
......@@ -1443,7 +1471,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14431471 },
14441472 macho.S_MOD_INIT_FUNC_POINTERS => {
14451473 if (self.mod_init_func_section_index == null) {
1446 self.mod_init_func_section_index = try self.allocateSection(
1474 self.mod_init_func_section_index = try self.initSection(
14471475 self.data_const_segment_cmd_index.?,
14481476 "__mod_init_func",
14491477 sect.size,
......@@ -1461,7 +1489,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14611489 },
14621490 macho.S_MOD_TERM_FUNC_POINTERS => {
14631491 if (self.mod_term_func_section_index == null) {
1464 self.mod_term_func_section_index = try self.allocateSection(
1492 self.mod_term_func_section_index = try self.initSection(
14651493 self.data_const_segment_cmd_index.?,
14661494 "__mod_term_func",
14671495 sect.size,
......@@ -1479,7 +1507,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14791507 },
14801508 macho.S_ZEROFILL => {
14811509 if (self.bss_section_index == null) {
1482 self.bss_section_index = try self.allocateSection(
1510 self.bss_section_index = try self.initSection(
14831511 self.data_segment_cmd_index.?,
14841512 "__bss",
14851513 sect.size,
......@@ -1497,7 +1525,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
14971525 },
14981526 macho.S_THREAD_LOCAL_VARIABLES => {
14991527 if (self.tlv_section_index == null) {
1500 self.tlv_section_index = try self.allocateSection(
1528 self.tlv_section_index = try self.initSection(
15011529 self.data_segment_cmd_index.?,
15021530 "__thread_vars",
15031531 sect.size,
......@@ -1515,7 +1543,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15151543 },
15161544 macho.S_THREAD_LOCAL_REGULAR => {
15171545 if (self.tlv_data_section_index == null) {
1518 self.tlv_data_section_index = try self.allocateSection(
1546 self.tlv_data_section_index = try self.initSection(
15191547 self.data_segment_cmd_index.?,
15201548 "__thread_data",
15211549 sect.size,
......@@ -1533,7 +1561,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15331561 },
15341562 macho.S_THREAD_LOCAL_ZEROFILL => {
15351563 if (self.tlv_bss_section_index == null) {
1536 self.tlv_bss_section_index = try self.allocateSection(
1564 self.tlv_bss_section_index = try self.initSection(
15371565 self.data_segment_cmd_index.?,
15381566 "__thread_bss",
15391567 sect.size,
......@@ -1554,7 +1582,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15541582 // TODO I believe __eh_frame is currently part of __unwind_info section
15551583 // in the latest ld64 output.
15561584 if (self.eh_frame_section_index == null) {
1557 self.eh_frame_section_index = try self.allocateSection(
1585 self.eh_frame_section_index = try self.initSection(
15581586 self.text_segment_cmd_index.?,
15591587 "__eh_frame",
15601588 sect.size,
......@@ -1571,7 +1599,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15711599
15721600 // TODO audit this: is this the right mapping?
15731601 if (self.data_const_section_index == null) {
1574 self.data_const_section_index = try self.allocateSection(
1602 self.data_const_section_index = try self.initSection(
15751603 self.data_const_segment_cmd_index.?,
15761604 "__const",
15771605 sect.size,
......@@ -1588,7 +1616,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15881616 macho.S_REGULAR => {
15891617 if (commands.sectionIsCode(sect)) {
15901618 if (self.text_section_index == null) {
1591 self.text_section_index = try self.allocateSection(
1619 self.text_section_index = try self.initSection(
15921620 self.text_segment_cmd_index.?,
15931621 "__text",
15941622 sect.size,
......@@ -1619,7 +1647,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16191647 if (mem.eql(u8, segname, "__TEXT")) {
16201648 if (mem.eql(u8, sectname, "__ustring")) {
16211649 if (self.ustring_section_index == null) {
1622 self.ustring_section_index = try self.allocateSection(
1650 self.ustring_section_index = try self.initSection(
16231651 self.text_segment_cmd_index.?,
16241652 "__ustring",
16251653 sect.size,
......@@ -1634,7 +1662,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16341662 };
16351663 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
16361664 if (self.gcc_except_tab_section_index == null) {
1637 self.gcc_except_tab_section_index = try self.allocateSection(
1665 self.gcc_except_tab_section_index = try self.initSection(
16381666 self.text_segment_cmd_index.?,
16391667 "__gcc_except_tab",
16401668 sect.size,
......@@ -1649,7 +1677,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16491677 };
16501678 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
16511679 if (self.objc_methlist_section_index == null) {
1652 self.objc_methlist_section_index = try self.allocateSection(
1680 self.objc_methlist_section_index = try self.initSection(
16531681 self.text_segment_cmd_index.?,
16541682 "__objc_methlist",
16551683 sect.size,
......@@ -1669,7 +1697,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16691697 mem.eql(u8, sectname, "__gopclntab"))
16701698 {
16711699 if (self.data_const_section_index == null) {
1672 self.data_const_section_index = try self.allocateSection(
1700 self.data_const_section_index = try self.initSection(
16731701 self.data_const_segment_cmd_index.?,
16741702 "__const",
16751703 sect.size,
......@@ -1684,7 +1712,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
16841712 };
16851713 } else {
16861714 if (self.text_const_section_index == null) {
1687 self.text_const_section_index = try self.allocateSection(
1715 self.text_const_section_index = try self.initSection(
16881716 self.text_segment_cmd_index.?,
16891717 "__const",
16901718 sect.size,
......@@ -1702,7 +1730,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17021730
17031731 if (mem.eql(u8, segname, "__DATA_CONST")) {
17041732 if (self.data_const_section_index == null) {
1705 self.data_const_section_index = try self.allocateSection(
1733 self.data_const_section_index = try self.initSection(
17061734 self.data_const_segment_cmd_index.?,
17071735 "__const",
17081736 sect.size,
......@@ -1720,7 +1748,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17201748 if (mem.eql(u8, segname, "__DATA")) {
17211749 if (mem.eql(u8, sectname, "__const")) {
17221750 if (self.data_const_section_index == null) {
1723 self.data_const_section_index = try self.allocateSection(
1751 self.data_const_section_index = try self.initSection(
17241752 self.data_const_segment_cmd_index.?,
17251753 "__const",
17261754 sect.size,
......@@ -1735,7 +1763,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17351763 };
17361764 } else if (mem.eql(u8, sectname, "__cfstring")) {
17371765 if (self.objc_cfstring_section_index == null) {
1738 self.objc_cfstring_section_index = try self.allocateSection(
1766 self.objc_cfstring_section_index = try self.initSection(
17391767 self.data_const_segment_cmd_index.?,
17401768 "__cfstring",
17411769 sect.size,
......@@ -1750,7 +1778,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17501778 };
17511779 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
17521780 if (self.objc_classlist_section_index == null) {
1753 self.objc_classlist_section_index = try self.allocateSection(
1781 self.objc_classlist_section_index = try self.initSection(
17541782 self.data_const_segment_cmd_index.?,
17551783 "__objc_classlist",
17561784 sect.size,
......@@ -1765,7 +1793,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17651793 };
17661794 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
17671795 if (self.objc_imageinfo_section_index == null) {
1768 self.objc_imageinfo_section_index = try self.allocateSection(
1796 self.objc_imageinfo_section_index = try self.initSection(
17691797 self.data_const_segment_cmd_index.?,
17701798 "__objc_imageinfo",
17711799 sect.size,
......@@ -1780,7 +1808,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17801808 };
17811809 } else if (mem.eql(u8, sectname, "__objc_const")) {
17821810 if (self.objc_const_section_index == null) {
1783 self.objc_const_section_index = try self.allocateSection(
1811 self.objc_const_section_index = try self.initSection(
17841812 self.data_segment_cmd_index.?,
17851813 "__objc_const",
17861814 sect.size,
......@@ -1795,7 +1823,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17951823 };
17961824 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
17971825 if (self.objc_classrefs_section_index == null) {
1798 self.objc_classrefs_section_index = try self.allocateSection(
1826 self.objc_classrefs_section_index = try self.initSection(
17991827 self.data_segment_cmd_index.?,
18001828 "__objc_classrefs",
18011829 sect.size,
......@@ -1810,7 +1838,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
18101838 };
18111839 } else if (mem.eql(u8, sectname, "__objc_data")) {
18121840 if (self.objc_data_section_index == null) {
1813 self.objc_data_section_index = try self.allocateSection(
1841 self.objc_data_section_index = try self.initSection(
18141842 self.data_segment_cmd_index.?,
18151843 "__objc_data",
18161844 sect.size,
......@@ -1825,7 +1853,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
18251853 };
18261854 } else {
18271855 if (self.data_section_index == null) {
1828 self.data_section_index = try self.allocateSection(
1856 self.data_section_index = try self.initSection(
18291857 self.data_segment_cmd_index.?,
18301858 "__data",
18311859 sect.size,
......@@ -1881,6 +1909,63 @@ pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
18811909 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
18821910}
18831911
1912fn allocLocalSymbols(self: *MachO) !void {
1913 var it = self.atoms.iterator();
1914 while (it.next()) |entry| {
1915 const match = entry.key_ptr.*;
1916 var atom = entry.value_ptr.*;
1917
1918 while (atom.prev) |prev| {
1919 atom = prev;
1920 }
1921
1922 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
1923 const seg = self.load_commands.items[match.seg].Segment;
1924 const sect = seg.sections.items[match.sect];
1925 var base_vaddr = sect.addr;
1926
1927 log.debug("allocating local symbols in {s},{s}", .{
1928 commands.segmentName(sect),
1929 commands.sectionName(sect),
1930 });
1931
1932 while (true) {
1933 const alignment = try math.powi(u32, 2, atom.alignment);
1934 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
1935
1936 const sym = &self.locals.items[atom.local_sym_index];
1937 sym.n_value = base_vaddr;
1938 sym.n_sect = n_sect;
1939
1940 log.debug(" {d}: {s} @0x{x}", .{
1941 atom.local_sym_index,
1942 self.getString(sym.n_strx),
1943 base_vaddr,
1944 });
1945
1946 // Update each alias (if any)
1947 for (atom.aliases.items) |index| {
1948 const alias_sym = &self.locals.items[index];
1949 alias_sym.n_value = base_vaddr;
1950 alias_sym.n_sect = n_sect;
1951 }
1952
1953 // Update each symbol contained within the atom
1954 for (atom.contained.items) |sym_at_off| {
1955 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
1956 contained_sym.n_value = base_vaddr + sym_at_off.offset;
1957 contained_sym.n_sect = n_sect;
1958 }
1959
1960 base_vaddr += atom.size;
1961
1962 if (atom.next) |next| {
1963 atom = next;
1964 } else break;
1965 }
1966 }
1967}
1968
18841969fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void {
18851970 var atom = self.atoms.get(match) orelse return;
18861971
......@@ -1971,7 +2056,15 @@ fn writeAtoms(self: *MachO) !void {
19712056 if (atom.next) |next| {
19722057 atom = next;
19732058 } else {
2059 if (buffer.items.len != sect.size) {
2060 log.warn("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
2061 log.warn(" alignment: 0x{x}", .{sect.@"align"});
2062 log.warn(" expected: 0x{x}", .{sect.size});
2063 log.warn(" given: 0x{x}", .{buffer.items.len});
2064 }
2065 assert(buffer.items.len == sect.size);
19742066 if (file_offset) |off| {
2067 log.debug(" (writing at file offset 0x{x})", .{off});
19752068 try self.base.file.?.pwriteAll(buffer.items, off);
19762069 }
19772070 file_offset = null;
......@@ -2036,10 +2129,13 @@ fn createDyldPrivateAtom(self: *MachO) !void {
20362129 .seg = self.data_segment_cmd_index.?,
20372130 .sect = self.data_section_index.?,
20382131 };
2039 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2040 sym.n_value = vaddr;
2132 if (self.needs_prealloc) {
2133 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2134 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2135 sym.n_value = vaddr;
2136 } else try self.addAtomAndBumpSectionSize(atom, match);
2137
20412138 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 });
20432139}
20442140
20452141fn createStubHelperPreambleAtom(self: *MachO) !void {
......@@ -2165,11 +2261,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
21652261 .seg = self.text_segment_cmd_index.?,
21662262 .sect = self.stub_helper_section_index.?,
21672263 };
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;
2264
2265 if (self.needs_prealloc) {
2266 const alignment_pow_2 = try math.powi(u32, 2, atom.alignment);
2267 const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match);
2268 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2269 sym.n_value = vaddr;
2270 } else try self.addAtomAndBumpSectionSize(atom, match);
2271
21712272 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 });
21732273}
21742274
21752275pub fn createStubHelperAtom(self: *MachO) !*Atom {
......@@ -2377,10 +2477,13 @@ fn createTentativeDefAtoms(self: *MachO) !void {
23772477 resolv.local_sym_index = local_sym_index;
23782478
23792479 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;
2480
2481 if (self.needs_prealloc) {
2482 const alignment_pow_2 = try math.powi(u32, 2, alignment);
2483 const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);
2484 local_sym.n_value = vaddr;
2485 global_sym.n_value = vaddr;
2486 } else try self.addAtomAndBumpSectionSize(atom, match);
23842487 }
23852488}
23862489
......@@ -2429,9 +2532,12 @@ fn createDsoHandleAtom(self: *MachO) !void {
24292532 // TODO perhaps we should special-case special symbols? Create a separate
24302533 // linked list of atoms?
24312534 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;
2535 if (self.needs_prealloc) {
2536 const sym = &self.locals.items[local_sym_index];
2537 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2538 sym.n_value = vaddr;
2539 } else try self.addAtomAndBumpSectionSize(atom, match);
2540
24352541 atom.dirty = false; // We don't really want to write it to file.
24362542 }
24372543}
......@@ -2771,9 +2877,13 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void {
27712877 });
27722878
27732879 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;
2880
2881 if (self.needs_prealloc) {
2882 const sym = &self.locals.items[local_sym_index];
2883 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2884 sym.n_value = vaddr;
2885 } else try self.addAtomAndBumpSectionSize(atom, match);
2886
27772887 atom.dirty = false;
27782888 self.mh_execute_header_index = local_sym_index;
27792889}
......@@ -2828,10 +2938,14 @@ fn resolveDyldStubBinder(self: *MachO) !void {
28282938 .sect = self.got_section_index.?,
28292939 };
28302940 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;
2941
2942 if (self.needs_prealloc) {
2943 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);
2944 log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr });
2945 atom_sym.n_value = vaddr;
2946 } else try self.addAtomAndBumpSectionSize(atom, match);
2947
28332948 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 });
28352949}
28362950
28372951fn parseObjectsIntoAtoms(self: *MachO) !void {
......@@ -2858,20 +2972,31 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
28582972 var it = object.end_atoms.iterator();
28592973 while (it.next()) |entry| {
28602974 const match = entry.key_ptr.*;
2861 const last_atom = entry.value_ptr.*;
2862 var atom = last_atom;
2975 var atom = entry.value_ptr.*;
2976
2977 while (atom.prev) |prev| {
2978 atom = prev;
2979 }
28632980
2981 const first_atom = atom;
2982
2983 const seg = self.load_commands.items[match.seg].Segment;
2984 const sect = seg.sections.items[match.sect];
28642985 const metadata = try section_metadata.getOrPut(match);
28652986 if (!metadata.found_existing) {
28662987 metadata.value_ptr.* = .{
2867 .size = 0,
2868 .alignment = 0,
2988 .size = sect.size,
2989 .alignment = sect.@"align",
28692990 };
28702991 }
28712992
2993 log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
2994
28722995 while (true) {
28732996 const alignment = try math.powi(u32, 2, atom.alignment);
2874 metadata.value_ptr.size += mem.alignForwardGeneric(u64, atom.size, alignment);
2997 const curr_size = metadata.value_ptr.size;
2998 const curr_size_aligned = mem.alignForwardGeneric(u64, curr_size, alignment);
2999 metadata.value_ptr.size = curr_size_aligned + atom.size;
28753000 metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);
28763001
28773002 const sym = self.locals.items[atom.local_sym_index];
......@@ -2882,20 +3007,20 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
28823007 atom.alignment,
28833008 });
28843009
2885 if (atom.prev) |prev| {
2886 atom = prev;
3010 if (atom.next) |next| {
3011 atom = next;
28873012 } else break;
28883013 }
28893014
28903015 if (parsed_atoms.getPtr(match)) |last| {
2891 last.*.next = atom;
2892 atom.prev = last.*;
2893 last.* = atom;
3016 last.*.next = first_atom;
3017 first_atom.prev = last.*;
3018 last.* = first_atom;
28943019 }
2895 _ = try parsed_atoms.put(match, last_atom);
3020 _ = try parsed_atoms.put(match, atom);
28963021
28973022 if (!first_atoms.contains(match)) {
2898 try first_atoms.putNoClobber(match, atom);
3023 try first_atoms.putNoClobber(match, first_atom);
28993024 }
29003025 }
29013026
......@@ -2915,67 +3040,84 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
29153040 metadata.alignment,
29163041 });
29173042
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
29233043 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);
3044 const needed_size = @intCast(u32, metadata.size);
3045
3046 if (self.needs_prealloc) {
3047 try self.growSection(match, needed_size);
3048 }
29263049 sect.size = needed_size;
3050 }
29273051
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);
3052 for (&[_]?u16{
3053 self.text_segment_cmd_index,
3054 self.data_const_segment_cmd_index,
3055 self.data_segment_cmd_index,
3056 }) |maybe_seg_id| {
3057 const seg_id = maybe_seg_id orelse continue;
3058 const seg = self.load_commands.items[seg_id].Segment;
29333059
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);
3060 for (seg.sections.items) |sect, sect_id| {
3061 const match = MatchingSection{
3062 .seg = seg_id,
3063 .sect = @intCast(u16, sect_id),
3064 };
3065 if (!section_metadata.contains(match)) continue;
29383066
2939 const sym = &self.locals.items[atom.local_sym_index];
2940 sym.n_value = base_vaddr;
2941 sym.n_sect = n_sect;
3067 if (self.atoms.getPtr(match)) |last| {
3068 const first_atom = first_atoms.get(match).?;
3069 last.*.next = first_atom;
3070 first_atom.prev = last.*;
3071 last.* = first_atom;
3072 }
3073 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
29423074
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 });
3075 if (!self.needs_prealloc) continue;
29503076
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 }
3077 var base_vaddr = if (self.atoms.get(match)) |last| blk: {
3078 const last_atom_sym = self.locals.items[last.local_sym_index];
3079 break :blk last_atom_sym.n_value + last.size;
3080 } else sect.addr;
3081 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
29573082
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 }
3083 var atom = first_atoms.get(match).?;
3084 while (true) {
3085 const alignment = try math.powi(u32, 2, atom.alignment);
3086 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
29643087
2965 base_vaddr += atom.size;
3088 const sym = &self.locals.items[atom.local_sym_index];
3089 sym.n_value = base_vaddr;
3090 sym.n_sect = n_sect;
29663091
2967 if (atom.next) |next| {
2968 atom = next;
2969 } else break;
2970 }
3092 log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{
3093 self.getString(sym.n_strx),
3094 base_vaddr,
3095 base_vaddr + atom.size,
3096 atom.size,
3097 atom.alignment,
3098 });
3099
3100 // Update each alias (if any)
3101 for (atom.aliases.items) |index| {
3102 const alias_sym = &self.locals.items[index];
3103 alias_sym.n_value = base_vaddr;
3104 alias_sym.n_sect = n_sect;
3105 }
3106
3107 // Update each symbol contained within the atom
3108 for (atom.contained.items) |sym_at_off| {
3109 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];
3110 contained_sym.n_value = base_vaddr + sym_at_off.offset;
3111 contained_sym.n_sect = n_sect;
3112 }
29713113
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;
3114 base_vaddr += atom.size;
3115
3116 if (atom.next) |next| {
3117 atom = next;
3118 } else break;
3119 }
29773120 }
2978 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
29793121 }
29803122}
29813123
......@@ -3714,7 +3856,9 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
37143856 return self.locals.items[decl.link.macho.local_sym_index].n_value;
37153857}
37163858
3717pub fn populateMissingMetadata(self: *MachO) !void {
3859fn populateMissingMetadata(self: *MachO) !void {
3860 const cpu_arch = self.base.options.target.cpu.arch;
3861
37183862 if (self.pagezero_segment_cmd_index == null) {
37193863 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
37203864 try self.load_commands.append(self.base.allocator, .{
......@@ -3730,13 +3874,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37303874
37313875 if (self.text_segment_cmd_index == null) {
37323876 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
3877 const needed_size = if (self.needs_prealloc) blk: {
3878 const program_code_size_hint = self.base.options.program_code_size_hint;
3879 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
3880 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
3881 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3882 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
3883 break :blk needed_size;
3884 } else 0;
37403885 try self.load_commands.append(self.base.allocator, .{
37413886 .Segment = .{
37423887 .inner = .{
......@@ -3753,13 +3898,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37533898 }
37543899
37553900 if (self.text_section_index == null) {
3756 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3901 const alignment: u2 = switch (cpu_arch) {
37573902 .x86_64 => 0,
37583903 .aarch64 => 2,
37593904 else => unreachable, // unhandled architecture type
37603905 };
3761 const needed_size = self.base.options.program_code_size_hint;
3762 self.text_section_index = try self.allocateSection(
3906 const needed_size = if (self.needs_prealloc) self.base.options.program_code_size_hint else 0;
3907 self.text_section_index = try self.initSection(
37633908 self.text_segment_cmd_index.?,
37643909 "__text",
37653910 needed_size,
......@@ -3771,18 +3916,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37713916 }
37723917
37733918 if (self.stubs_section_index == null) {
3774 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3919 const alignment: u2 = switch (cpu_arch) {
37753920 .x86_64 => 0,
37763921 .aarch64 => 2,
37773922 else => unreachable, // unhandled architecture type
37783923 };
3779 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
3924 const stub_size: u4 = switch (cpu_arch) {
37803925 .x86_64 => 6,
37813926 .aarch64 => 3 * @sizeOf(u32),
37823927 else => unreachable, // unhandled architecture type
37833928 };
3784 const needed_size = stub_size * self.base.options.symbol_count_hint;
3785 self.stubs_section_index = try self.allocateSection(
3929 const needed_size = if (self.needs_prealloc) stub_size * self.base.options.symbol_count_hint else 0;
3930 self.stubs_section_index = try self.initSection(
37863931 self.text_segment_cmd_index.?,
37873932 "__stubs",
37883933 needed_size,
......@@ -3795,23 +3940,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37953940 }
37963941
37973942 if (self.stub_helper_section_index == null) {
3798 const alignment: u2 = switch (self.base.options.target.cpu.arch) {
3943 const alignment: u2 = switch (cpu_arch) {
37993944 .x86_64 => 0,
38003945 .aarch64 => 2,
38013946 else => unreachable, // unhandled architecture type
38023947 };
3803 const preamble_size: u6 = switch (self.base.options.target.cpu.arch) {
3948 const preamble_size: u6 = switch (cpu_arch) {
38043949 .x86_64 => 15,
38053950 .aarch64 => 6 * @sizeOf(u32),
38063951 else => unreachable,
38073952 };
3808 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {
3953 const stub_size: u4 = switch (cpu_arch) {
38093954 .x86_64 => 10,
38103955 .aarch64 => 3 * @sizeOf(u32),
38113956 else => unreachable,
38123957 };
3813 const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;
3814 self.stub_helper_section_index = try self.allocateSection(
3958 const needed_size = if (self.needs_prealloc)
3959 stub_size * self.base.options.symbol_count_hint + preamble_size
3960 else
3961 0;
3962 self.stub_helper_section_index = try self.initSection(
38153963 self.text_segment_cmd_index.?,
38163964 "__stub_helper",
38173965 needed_size,
......@@ -3824,22 +3972,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38243972
38253973 if (self.data_const_segment_cmd_index == null) {
38263974 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
3975 var vmaddr: u64 = 0;
3976 var fileoff: u64 = 0;
3977 var needed_size: u64 = 0;
3978 if (self.needs_prealloc) {
3979 const address_and_offset = self.nextSegmentAddressAndOffset();
3980 vmaddr = address_and_offset.address;
3981 fileoff = address_and_offset.offset;
3982 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
3983 needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3984 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
3985 fileoff,
3986 fileoff + needed_size,
3987 });
3988 }
38363989 try self.load_commands.append(self.base.allocator, .{
38373990 .Segment = .{
38383991 .inner = .{
38393992 .segname = makeStaticString("__DATA_CONST"),
3840 .vmaddr = address_and_offset.address,
3993 .vmaddr = vmaddr,
38413994 .vmsize = needed_size,
3842 .fileoff = address_and_offset.offset,
3995 .fileoff = fileoff,
38433996 .filesize = needed_size,
38443997 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
38453998 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
......@@ -3850,9 +4003,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38504003 }
38514004
38524005 if (self.got_section_index == null) {
3853 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4006 const needed_size = if (self.needs_prealloc)
4007 @sizeOf(u64) * self.base.options.symbol_count_hint
4008 else
4009 0;
38544010 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3855 self.got_section_index = try self.allocateSection(
4011 self.got_section_index = try self.initSection(
38564012 self.data_const_segment_cmd_index.?,
38574013 "__got",
38584014 needed_size,
......@@ -3865,19 +4021,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38654021
38664022 if (self.data_segment_cmd_index == null) {
38674023 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
4024 var vmaddr: u64 = 0;
4025 var fileoff: u64 = 0;
4026 var needed_size: u64 = 0;
4027 if (self.needs_prealloc) {
4028 const address_and_offset = self.nextSegmentAddressAndOffset();
4029 vmaddr = address_and_offset.address;
4030 fileoff = address_and_offset.offset;
4031 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
4032 needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
4033 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{
4034 fileoff,
4035 fileoff + needed_size,
4036 });
4037 }
38744038 try self.load_commands.append(self.base.allocator, .{
38754039 .Segment = .{
38764040 .inner = .{
38774041 .segname = makeStaticString("__DATA"),
3878 .vmaddr = address_and_offset.address,
4042 .vmaddr = vmaddr,
38794043 .vmsize = needed_size,
3880 .fileoff = address_and_offset.offset,
4044 .fileoff = fileoff,
38814045 .filesize = needed_size,
38824046 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
38834047 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
......@@ -3888,9 +4052,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38884052 }
38894053
38904054 if (self.la_symbol_ptr_section_index == null) {
3891 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4055 const needed_size = if (self.needs_prealloc)
4056 @sizeOf(u64) * self.base.options.symbol_count_hint
4057 else
4058 0;
38924059 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3893 self.la_symbol_ptr_section_index = try self.allocateSection(
4060 self.la_symbol_ptr_section_index = try self.initSection(
38944061 self.data_segment_cmd_index.?,
38954062 "__la_symbol_ptr",
38964063 needed_size,
......@@ -3902,9 +4069,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39024069 }
39034070
39044071 if (self.data_section_index == null) {
3905 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4072 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39064073 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3907 self.data_section_index = try self.allocateSection(
4074 self.data_section_index = try self.initSection(
39084075 self.data_segment_cmd_index.?,
39094076 "__data",
39104077 needed_size,
......@@ -3914,9 +4081,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39144081 }
39154082
39164083 if (self.tlv_section_index == null) {
3917 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4084 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39184085 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3919 self.tlv_section_index = try self.allocateSection(
4086 self.tlv_section_index = try self.initSection(
39204087 self.data_segment_cmd_index.?,
39214088 "__thread_vars",
39224089 needed_size,
......@@ -3928,9 +4095,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39284095 }
39294096
39304097 if (self.tlv_data_section_index == null) {
3931 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4098 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39324099 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3933 self.tlv_data_section_index = try self.allocateSection(
4100 self.tlv_data_section_index = try self.initSection(
39344101 self.data_segment_cmd_index.?,
39354102 "__thread_data",
39364103 needed_size,
......@@ -3942,9 +4109,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39424109 }
39434110
39444111 if (self.tlv_bss_section_index == null) {
3945 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4112 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39464113 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3947 self.tlv_bss_section_index = try self.allocateSection(
4114 self.tlv_bss_section_index = try self.initSection(
39484115 self.data_segment_cmd_index.?,
39494116 "__thread_bss",
39504117 needed_size,
......@@ -3959,9 +4126,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39594126 }
39604127
39614128 if (self.bss_section_index == null) {
3962 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
4129 const needed_size = if (self.needs_prealloc) @sizeOf(u64) * self.base.options.symbol_count_hint else 0;
39634130 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3964 self.bss_section_index = try self.allocateSection(
4131 self.bss_section_index = try self.initSection(
39654132 self.data_segment_cmd_index.?,
39664133 "__bss",
39674134 needed_size,
......@@ -3977,16 +4144,20 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39774144
39784145 if (self.linkedit_segment_cmd_index == null) {
39794146 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
4147 var vmaddr: u64 = 0;
4148 var fileoff: u64 = 0;
4149 if (self.needs_prealloc) {
4150 const address_and_offset = self.nextSegmentAddressAndOffset();
4151 vmaddr = address_and_offset.address;
4152 fileoff = address_and_offset.offset;
4153 log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
4154 }
39844155 try self.load_commands.append(self.base.allocator, .{
39854156 .Segment = .{
39864157 .inner = .{
39874158 .segname = makeStaticString("__LINKEDIT"),
3988 .vmaddr = address_and_offset.address,
3989 .fileoff = address_and_offset.offset,
4159 .vmaddr = vmaddr,
4160 .fileoff = fileoff,
39904161 .maxprot = macho.VM_PROT_READ,
39914162 .initprot = macho.VM_PROT_READ,
39924163 },
......@@ -4198,44 +4369,123 @@ pub fn populateMissingMetadata(self: *MachO) !void {
41984369 self.cold_start = true;
41994370}
42004371
4201const AllocateSectionOpts = struct {
4372fn allocateTextSegment(self: *MachO) !void {
4373 const seg = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4374 const base_vmaddr = self.load_commands.items[self.pagezero_segment_cmd_index.?].Segment.inner.vmsize;
4375 seg.inner.fileoff = 0;
4376 seg.inner.vmaddr = base_vmaddr;
4377
4378 var sizeofcmds: u64 = 0;
4379 for (self.load_commands.items) |lc| {
4380 sizeofcmds += lc.cmdsize();
4381 }
4382
4383 try self.allocateSegment(self.text_segment_cmd_index.?, @sizeOf(macho.mach_header_64) + sizeofcmds);
4384
4385 // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments.
4386 var min_alignment: u32 = 0;
4387 for (seg.sections.items) |sect| {
4388 const alignment = try math.powi(u32, 2, sect.@"align");
4389 min_alignment = math.max(min_alignment, alignment);
4390 }
4391
4392 assert(min_alignment > 0);
4393 const last_sect_idx = seg.sections.items.len - 1;
4394 const last_sect = seg.sections.items[last_sect_idx];
4395 const shift: u32 = blk: {
4396 const diff = seg.inner.filesize - last_sect.offset - last_sect.size;
4397 const factor = @divTrunc(diff, min_alignment);
4398 break :blk @intCast(u32, factor * min_alignment);
4399 };
4400
4401 if (shift > 0) {
4402 for (seg.sections.items) |*sect| {
4403 sect.offset += shift;
4404 sect.addr += shift;
4405 }
4406 }
4407}
4408
4409fn allocateDataConstSegment(self: *MachO) !void {
4410 const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4411 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4412 seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize;
4413 seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize;
4414 try self.allocateSegment(self.data_const_segment_cmd_index.?, 0);
4415}
4416
4417fn allocateDataSegment(self: *MachO) !void {
4418 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4419 const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4420 seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize;
4421 seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize;
4422 try self.allocateSegment(self.data_segment_cmd_index.?, 0);
4423}
4424
4425fn allocateLinkeditSegment(self: *MachO) void {
4426 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4427 const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4428 seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize;
4429 seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize;
4430}
4431
4432fn allocateSegment(self: *MachO, index: u16, offset: u64) !void {
4433 const seg = &self.load_commands.items[index].Segment;
4434
4435 // Allocate the sections according to their alignment at the beginning of the segment.
4436 var start: u64 = offset;
4437 for (seg.sections.items) |*sect| {
4438 const alignment = try math.powi(u32, 2, sect.@"align");
4439 const start_aligned = mem.alignForwardGeneric(u64, start, alignment);
4440 const end = start_aligned + sect.size;
4441 sect.offset = @intCast(u32, seg.inner.fileoff + start_aligned);
4442 sect.addr = seg.inner.vmaddr + start_aligned;
4443 start = end;
4444 }
4445
4446 const seg_size_aligned = mem.alignForwardGeneric(u64, start, self.page_size);
4447 seg.inner.filesize = seg_size_aligned;
4448 seg.inner.vmsize = seg_size_aligned;
4449}
4450
4451const InitSectionOpts = struct {
42024452 flags: u32 = macho.S_REGULAR,
42034453 reserved1: u32 = 0,
42044454 reserved2: u32 = 0,
42054455};
42064456
4207fn allocateSection(
4457fn initSection(
42084458 self: *MachO,
42094459 segment_id: u16,
42104460 sectname: []const u8,
42114461 size: u64,
42124462 alignment: u32,
4213 opts: AllocateSectionOpts,
4463 opts: InitSectionOpts,
42144464) !u16 {
42154465 const seg = &self.load_commands.items[segment_id].Segment;
42164466 var sect = macho.section_64{
42174467 .sectname = makeStaticString(sectname),
42184468 .segname = seg.inner.segname,
4219 .size = @intCast(u32, size),
4469 .size = if (self.needs_prealloc) @intCast(u32, size) else 0,
42204470 .@"align" = alignment,
42214471 .flags = opts.flags,
42224472 .reserved1 = opts.reserved1,
42234473 .reserved2 = opts.reserved2,
42244474 };
42254475
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);
4476 if (self.needs_prealloc) {
4477 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4478 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
4479 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4480 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4481 commands.segmentName(sect),
4482 commands.sectionName(sect),
4483 off,
4484 off + size,
4485 });
4486 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
4487 sect.offset = @intCast(u32, off);
4488 }
42394489
42404490 const index = @intCast(u16, seg.sections.items.len);
42414491 try seg.sections.append(self.base.allocator, sect);
......@@ -4270,7 +4520,11 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
42704520 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
42714521 assert(new_seg_size > seg.inner.filesize);
42724522 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 });
4523 log.debug("growing segment {s} from 0x{x} to 0x{x}", .{
4524 seg.inner.segname,
4525 seg.inner.filesize,
4526 new_seg_size,
4527 });
42744528 seg.inner.filesize = new_seg_size;
42754529 seg.inner.vmsize = new_seg_size;
42764530
......@@ -4534,6 +4788,21 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
45344788 return vaddr;
45354789}
45364790
4791fn addAtomAndBumpSectionSize(self: *MachO, atom: *Atom, match: MatchingSection) !void {
4792 const seg = &self.load_commands.items[match.seg].Segment;
4793 const sect = &seg.sections.items[match.sect];
4794 const alignment = try math.powi(u32, 2, atom.alignment);
4795 sect.size = mem.alignForwardGeneric(u64, sect.size, alignment) + atom.size;
4796
4797 if (self.atoms.getPtr(match)) |last| {
4798 last.*.next = atom;
4799 atom.prev = last.*;
4800 last.* = atom;
4801 } else {
4802 try self.atoms.putNoClobber(self.base.allocator, match, atom);
4803 }
4804}
4805
45374806pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
45384807 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
45394808 defer self.base.allocator.free(sym_name);
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);