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,...@@ -63,6 +63,11 @@ page_size: u16,
63/// https://github.com/ziglang/zig/issues/956763/// https://github.com/ziglang/zig/issues/9567
64requires_adhoc_codesig: bool,64requires_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
66/// We commit 0x1000 = 4096 bytes of space to the header and71/// We commit 0x1000 = 4096 bytes of space to the header and
67/// the table of load commands. This should be plenty for any72/// the table of load commands. This should be plenty for any
68/// potential future extensions.73/// potential future extensions.
...@@ -375,6 +380,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {...@@ -375,6 +380,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
375 // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator380 // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator
376 // ABI such as aarch64-ios-simulator, etc.381 // ABI such as aarch64-ios-simulator, etc.
377 const requires_adhoc_codesig = cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator);382 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
379 self.* = .{385 self.* = .{
380 .base = .{386 .base = .{
...@@ -385,6 +391,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {...@@ -385,6 +391,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
385 },391 },
386 .page_size = page_size,392 .page_size = page_size,
387 .requires_adhoc_codesig = requires_adhoc_codesig,393 .requires_adhoc_codesig = requires_adhoc_codesig,
394 .needs_prealloc = needs_prealloc,
388 };395 };
389396
390 return self;397 return self;
...@@ -911,42 +918,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -911,42 +918,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
911918
912 try self.createTentativeDefAtoms();919 try self.createTentativeDefAtoms();
913 try self.parseObjectsIntoAtoms();920 try self.parseObjectsIntoAtoms();
914 try self.allocateGlobalSymbols();
915921
916 log.debug("locals:", .{});922 if (use_stage1) {
917 for (self.locals.items) |sym, id| {923 try self.sortSections();
918 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });924 try self.allocateTextSegment();
919 }925 try self.allocateDataConstSegment();
920 log.debug("globals:", .{});926 try self.allocateDataSegment();
921 for (self.globals.items) |sym, id| {927 self.allocateLinkeditSegment();
922 log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym });928 try self.allocateLocals();
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 }
934 }929 }
935930
936 log.debug("GOT entries:", .{});931 try self.allocateGlobals();
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 }
943932
944 log.debug("stubs:", .{});933 if (build_options.enable_logging) {
945 for (self.stubs_map.keys()) |key| {934 self.logSymtab();
946 log.debug(" {} => {s}", .{ key, self.getString(key) });935 self.logSectionOrdinals();
947 }936 }
948937
949 try self.writeAtoms();938 if (use_stage1) {
939 try self.writeAllAtoms();
940 } else {
941 try self.writeAtoms();
942 }
950943
951 if (self.bss_section_index) |idx| {944 if (self.bss_section_index) |idx| {
952 const seg = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;945 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...@@ -1337,7 +1330,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1337 switch (commands.sectionType(sect)) {1330 switch (commands.sectionType(sect)) {
1338 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {1331 macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => {
1339 if (self.text_const_section_index == null) {1332 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(
1341 self.text_segment_cmd_index.?,1334 self.text_segment_cmd_index.?,
1342 "__const",1335 "__const",
1343 sect.size,1336 sect.size,
...@@ -1356,7 +1349,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1356,7 +1349,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1356 // TODO it seems the common values within the sections in objects are deduplicated/merged1349 // TODO it seems the common values within the sections in objects are deduplicated/merged
1357 // on merging the sections' contents.1350 // on merging the sections' contents.
1358 if (self.objc_methname_section_index == null) {1351 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(
1360 self.text_segment_cmd_index.?,1353 self.text_segment_cmd_index.?,
1361 "__objc_methname",1354 "__objc_methname",
1362 sect.size,1355 sect.size,
...@@ -1371,7 +1364,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1371,7 +1364,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1371 };1364 };
1372 } else if (mem.eql(u8, sectname, "__objc_methtype")) {1365 } else if (mem.eql(u8, sectname, "__objc_methtype")) {
1373 if (self.objc_methtype_section_index == null) {1366 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(
1375 self.text_segment_cmd_index.?,1368 self.text_segment_cmd_index.?,
1376 "__objc_methtype",1369 "__objc_methtype",
1377 sect.size,1370 sect.size,
...@@ -1386,7 +1379,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1386,7 +1379,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1386 };1379 };
1387 } else if (mem.eql(u8, sectname, "__objc_classname")) {1380 } else if (mem.eql(u8, sectname, "__objc_classname")) {
1388 if (self.objc_classname_section_index == null) {1381 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(
1390 self.text_segment_cmd_index.?,1383 self.text_segment_cmd_index.?,
1391 "__objc_classname",1384 "__objc_classname",
1392 sect.size,1385 sect.size,
...@@ -1402,7 +1395,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1402,7 +1395,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1402 }1395 }
14031396
1404 if (self.cstring_section_index == null) {1397 if (self.cstring_section_index == null) {
1405 self.cstring_section_index = try self.allocateSection(1398 self.cstring_section_index = try self.initSection(
1406 self.text_segment_cmd_index.?,1399 self.text_segment_cmd_index.?,
1407 "__cstring",1400 "__cstring",
1408 sect.size,1401 sect.size,
...@@ -1421,7 +1414,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1421,7 +1414,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1421 macho.S_LITERAL_POINTERS => {1414 macho.S_LITERAL_POINTERS => {
1422 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {1415 if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) {
1423 if (self.objc_selrefs_section_index == null) {1416 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(
1425 self.data_segment_cmd_index.?,1418 self.data_segment_cmd_index.?,
1426 "__objc_selrefs",1419 "__objc_selrefs",
1427 sect.size,1420 sect.size,
...@@ -1443,7 +1436,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1443,7 +1436,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1443 },1436 },
1444 macho.S_MOD_INIT_FUNC_POINTERS => {1437 macho.S_MOD_INIT_FUNC_POINTERS => {
1445 if (self.mod_init_func_section_index == null) {1438 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(
1447 self.data_const_segment_cmd_index.?,1440 self.data_const_segment_cmd_index.?,
1448 "__mod_init_func",1441 "__mod_init_func",
1449 sect.size,1442 sect.size,
...@@ -1461,7 +1454,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1461,7 +1454,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1461 },1454 },
1462 macho.S_MOD_TERM_FUNC_POINTERS => {1455 macho.S_MOD_TERM_FUNC_POINTERS => {
1463 if (self.mod_term_func_section_index == null) {1456 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(
1465 self.data_const_segment_cmd_index.?,1458 self.data_const_segment_cmd_index.?,
1466 "__mod_term_func",1459 "__mod_term_func",
1467 sect.size,1460 sect.size,
...@@ -1479,7 +1472,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1479,7 +1472,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1479 },1472 },
1480 macho.S_ZEROFILL => {1473 macho.S_ZEROFILL => {
1481 if (self.bss_section_index == null) {1474 if (self.bss_section_index == null) {
1482 self.bss_section_index = try self.allocateSection(1475 self.bss_section_index = try self.initSection(
1483 self.data_segment_cmd_index.?,1476 self.data_segment_cmd_index.?,
1484 "__bss",1477 "__bss",
1485 sect.size,1478 sect.size,
...@@ -1497,7 +1490,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1497,7 +1490,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1497 },1490 },
1498 macho.S_THREAD_LOCAL_VARIABLES => {1491 macho.S_THREAD_LOCAL_VARIABLES => {
1499 if (self.tlv_section_index == null) {1492 if (self.tlv_section_index == null) {
1500 self.tlv_section_index = try self.allocateSection(1493 self.tlv_section_index = try self.initSection(
1501 self.data_segment_cmd_index.?,1494 self.data_segment_cmd_index.?,
1502 "__thread_vars",1495 "__thread_vars",
1503 sect.size,1496 sect.size,
...@@ -1515,7 +1508,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1515,7 +1508,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1515 },1508 },
1516 macho.S_THREAD_LOCAL_REGULAR => {1509 macho.S_THREAD_LOCAL_REGULAR => {
1517 if (self.tlv_data_section_index == null) {1510 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(
1519 self.data_segment_cmd_index.?,1512 self.data_segment_cmd_index.?,
1520 "__thread_data",1513 "__thread_data",
1521 sect.size,1514 sect.size,
...@@ -1533,7 +1526,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1533,7 +1526,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1533 },1526 },
1534 macho.S_THREAD_LOCAL_ZEROFILL => {1527 macho.S_THREAD_LOCAL_ZEROFILL => {
1535 if (self.tlv_bss_section_index == null) {1528 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(
1537 self.data_segment_cmd_index.?,1530 self.data_segment_cmd_index.?,
1538 "__thread_bss",1531 "__thread_bss",
1539 sect.size,1532 sect.size,
...@@ -1554,7 +1547,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1554,7 +1547,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1554 // TODO I believe __eh_frame is currently part of __unwind_info section1547 // TODO I believe __eh_frame is currently part of __unwind_info section
1555 // in the latest ld64 output.1548 // in the latest ld64 output.
1556 if (self.eh_frame_section_index == null) {1549 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(
1558 self.text_segment_cmd_index.?,1551 self.text_segment_cmd_index.?,
1559 "__eh_frame",1552 "__eh_frame",
1560 sect.size,1553 sect.size,
...@@ -1571,7 +1564,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1571,7 +1564,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
15711564
1572 // TODO audit this: is this the right mapping?1565 // TODO audit this: is this the right mapping?
1573 if (self.data_const_section_index == null) {1566 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(
1575 self.data_const_segment_cmd_index.?,1568 self.data_const_segment_cmd_index.?,
1576 "__const",1569 "__const",
1577 sect.size,1570 sect.size,
...@@ -1588,7 +1581,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1588,7 +1581,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1588 macho.S_REGULAR => {1581 macho.S_REGULAR => {
1589 if (commands.sectionIsCode(sect)) {1582 if (commands.sectionIsCode(sect)) {
1590 if (self.text_section_index == null) {1583 if (self.text_section_index == null) {
1591 self.text_section_index = try self.allocateSection(1584 self.text_section_index = try self.initSection(
1592 self.text_segment_cmd_index.?,1585 self.text_segment_cmd_index.?,
1593 "__text",1586 "__text",
1594 sect.size,1587 sect.size,
...@@ -1619,7 +1612,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1619,7 +1612,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1619 if (mem.eql(u8, segname, "__TEXT")) {1612 if (mem.eql(u8, segname, "__TEXT")) {
1620 if (mem.eql(u8, sectname, "__ustring")) {1613 if (mem.eql(u8, sectname, "__ustring")) {
1621 if (self.ustring_section_index == null) {1614 if (self.ustring_section_index == null) {
1622 self.ustring_section_index = try self.allocateSection(1615 self.ustring_section_index = try self.initSection(
1623 self.text_segment_cmd_index.?,1616 self.text_segment_cmd_index.?,
1624 "__ustring",1617 "__ustring",
1625 sect.size,1618 sect.size,
...@@ -1634,7 +1627,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1634,7 +1627,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1634 };1627 };
1635 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {1628 } else if (mem.eql(u8, sectname, "__gcc_except_tab")) {
1636 if (self.gcc_except_tab_section_index == null) {1629 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(
1638 self.text_segment_cmd_index.?,1631 self.text_segment_cmd_index.?,
1639 "__gcc_except_tab",1632 "__gcc_except_tab",
1640 sect.size,1633 sect.size,
...@@ -1649,7 +1642,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1649,7 +1642,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1649 };1642 };
1650 } else if (mem.eql(u8, sectname, "__objc_methlist")) {1643 } else if (mem.eql(u8, sectname, "__objc_methlist")) {
1651 if (self.objc_methlist_section_index == null) {1644 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(
1653 self.text_segment_cmd_index.?,1646 self.text_segment_cmd_index.?,
1654 "__objc_methlist",1647 "__objc_methlist",
1655 sect.size,1648 sect.size,
...@@ -1669,7 +1662,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1669,7 +1662,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1669 mem.eql(u8, sectname, "__gopclntab"))1662 mem.eql(u8, sectname, "__gopclntab"))
1670 {1663 {
1671 if (self.data_const_section_index == null) {1664 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(
1673 self.data_const_segment_cmd_index.?,1666 self.data_const_segment_cmd_index.?,
1674 "__const",1667 "__const",
1675 sect.size,1668 sect.size,
...@@ -1684,7 +1677,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1684,7 +1677,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1684 };1677 };
1685 } else {1678 } else {
1686 if (self.text_const_section_index == null) {1679 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(
1688 self.text_segment_cmd_index.?,1681 self.text_segment_cmd_index.?,
1689 "__const",1682 "__const",
1690 sect.size,1683 sect.size,
...@@ -1702,7 +1695,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1702,7 +1695,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
17021695
1703 if (mem.eql(u8, segname, "__DATA_CONST")) {1696 if (mem.eql(u8, segname, "__DATA_CONST")) {
1704 if (self.data_const_section_index == null) {1697 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(
1706 self.data_const_segment_cmd_index.?,1699 self.data_const_segment_cmd_index.?,
1707 "__const",1700 "__const",
1708 sect.size,1701 sect.size,
...@@ -1720,7 +1713,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1720,7 +1713,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1720 if (mem.eql(u8, segname, "__DATA")) {1713 if (mem.eql(u8, segname, "__DATA")) {
1721 if (mem.eql(u8, sectname, "__const")) {1714 if (mem.eql(u8, sectname, "__const")) {
1722 if (self.data_const_section_index == null) {1715 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(
1724 self.data_const_segment_cmd_index.?,1717 self.data_const_segment_cmd_index.?,
1725 "__const",1718 "__const",
1726 sect.size,1719 sect.size,
...@@ -1735,7 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1735,7 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1735 };1728 };
1736 } else if (mem.eql(u8, sectname, "__cfstring")) {1729 } else if (mem.eql(u8, sectname, "__cfstring")) {
1737 if (self.objc_cfstring_section_index == null) {1730 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(
1739 self.data_const_segment_cmd_index.?,1732 self.data_const_segment_cmd_index.?,
1740 "__cfstring",1733 "__cfstring",
1741 sect.size,1734 sect.size,
...@@ -1750,7 +1743,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1750,7 +1743,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1750 };1743 };
1751 } else if (mem.eql(u8, sectname, "__objc_classlist")) {1744 } else if (mem.eql(u8, sectname, "__objc_classlist")) {
1752 if (self.objc_classlist_section_index == null) {1745 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(
1754 self.data_const_segment_cmd_index.?,1747 self.data_const_segment_cmd_index.?,
1755 "__objc_classlist",1748 "__objc_classlist",
1756 sect.size,1749 sect.size,
...@@ -1765,7 +1758,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1765,7 +1758,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1765 };1758 };
1766 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {1759 } else if (mem.eql(u8, sectname, "__objc_imageinfo")) {
1767 if (self.objc_imageinfo_section_index == null) {1760 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(
1769 self.data_const_segment_cmd_index.?,1762 self.data_const_segment_cmd_index.?,
1770 "__objc_imageinfo",1763 "__objc_imageinfo",
1771 sect.size,1764 sect.size,
...@@ -1780,7 +1773,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1780,7 +1773,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1780 };1773 };
1781 } else if (mem.eql(u8, sectname, "__objc_const")) {1774 } else if (mem.eql(u8, sectname, "__objc_const")) {
1782 if (self.objc_const_section_index == null) {1775 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(
1784 self.data_segment_cmd_index.?,1777 self.data_segment_cmd_index.?,
1785 "__objc_const",1778 "__objc_const",
1786 sect.size,1779 sect.size,
...@@ -1795,7 +1788,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1795,7 +1788,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1795 };1788 };
1796 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {1789 } else if (mem.eql(u8, sectname, "__objc_classrefs")) {
1797 if (self.objc_classrefs_section_index == null) {1790 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(
1799 self.data_segment_cmd_index.?,1792 self.data_segment_cmd_index.?,
1800 "__objc_classrefs",1793 "__objc_classrefs",
1801 sect.size,1794 sect.size,
...@@ -1810,7 +1803,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1810,7 +1803,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1810 };1803 };
1811 } else if (mem.eql(u8, sectname, "__objc_data")) {1804 } else if (mem.eql(u8, sectname, "__objc_data")) {
1812 if (self.objc_data_section_index == null) {1805 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(
1814 self.data_segment_cmd_index.?,1807 self.data_segment_cmd_index.?,
1815 "__objc_data",1808 "__objc_data",
1816 sect.size,1809 sect.size,
...@@ -1825,7 +1818,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio...@@ -1825,7 +1818,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio
1825 };1818 };
1826 } else {1819 } else {
1827 if (self.data_section_index == null) {1820 if (self.data_section_index == null) {
1828 self.data_section_index = try self.allocateSection(1821 self.data_section_index = try self.initSection(
1829 self.data_segment_cmd_index.?,1822 self.data_segment_cmd_index.?,
1830 "__data",1823 "__data",
1831 sect.size,1824 sect.size,
...@@ -1881,7 +1874,64 @@ pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {...@@ -1881,7 +1874,64 @@ pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void {
1881 try self.base.file.?.pwriteAll(atom.code.items, file_offset);1874 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
1882}1875}
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 {
1885 var atom = self.atoms.get(match) orelse return;1935 var atom = self.atoms.get(match) orelse return;
18861936
1887 while (true) {1937 while (true) {
...@@ -1904,7 +1954,9 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void...@@ -1904,7 +1954,9 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void
1904 }1954 }
1905}1955}
19061956
1907fn allocateGlobalSymbols(self: *MachO) !void {1957fn allocateGlobals(self: *MachO) !void {
1958 log.debug("allocating global symbols", .{});
1959
1908 var sym_it = self.symbol_resolver.valueIterator();1960 var sym_it = self.symbol_resolver.valueIterator();
1909 while (sym_it.next()) |resolv| {1961 while (sym_it.next()) |resolv| {
1910 if (resolv.where != .global) continue;1962 if (resolv.where != .global) continue;
...@@ -1914,7 +1966,60 @@ fn allocateGlobalSymbols(self: *MachO) !void {...@@ -1914,7 +1966,60 @@ fn allocateGlobalSymbols(self: *MachO) !void {
1914 const sym = &self.globals.items[resolv.where_index];1966 const sym = &self.globals.items[resolv.where_index];
1915 sym.n_value = local_sym.n_value;1967 sym.n_value = local_sym.n_value;
1916 sym.n_sect = local_sym.n_sect;1968 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 }
1918 }2023 }
1919}2024}
19202025
...@@ -1962,6 +2067,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -1962,6 +2067,7 @@ fn writeAtoms(self: *MachO) !void {
1962 atom.dirty = false;2067 atom.dirty = false;
1963 } else {2068 } else {
1964 if (file_offset) |off| {2069 if (file_offset) |off| {
2070 log.debug(" (writing at file offset 0x{x})", .{off});
1965 try self.base.file.?.pwriteAll(buffer.items, off);2071 try self.base.file.?.pwriteAll(buffer.items, off);
1966 }2072 }
1967 file_offset = null;2073 file_offset = null;
...@@ -1972,6 +2078,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -1972,6 +2078,7 @@ fn writeAtoms(self: *MachO) !void {
1972 atom = next;2078 atom = next;
1973 } else {2079 } else {
1974 if (file_offset) |off| {2080 if (file_offset) |off| {
2081 log.debug(" (writing at file offset 0x{x})", .{off});
1975 try self.base.file.?.pwriteAll(buffer.items, off);2082 try self.base.file.?.pwriteAll(buffer.items, off);
1976 }2083 }
1977 file_offset = null;2084 file_offset = null;
...@@ -2036,10 +2143,13 @@ fn createDyldPrivateAtom(self: *MachO) !void {...@@ -2036,10 +2143,13 @@ fn createDyldPrivateAtom(self: *MachO) !void {
2036 .seg = self.data_segment_cmd_index.?,2143 .seg = self.data_segment_cmd_index.?,
2037 .sect = self.data_section_index.?,2144 .sect = self.data_section_index.?,
2038 };2145 };
2039 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);2146 if (self.needs_prealloc) {
2040 sym.n_value = vaddr;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
2041 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);2152 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 });
2043}2153}
20442154
2045fn createStubHelperPreambleAtom(self: *MachO) !void {2155fn createStubHelperPreambleAtom(self: *MachO) !void {
...@@ -2165,11 +2275,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {...@@ -2165,11 +2275,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void {
2165 .seg = self.text_segment_cmd_index.?,2275 .seg = self.text_segment_cmd_index.?,
2166 .sect = self.stub_helper_section_index.?,2276 .sect = self.stub_helper_section_index.?,
2167 };2277 };
2168 const alignment_pow_2 = try math.powi(u32, 2, atom.alignment);2278
2169 const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match);2279 if (self.needs_prealloc) {
2170 sym.n_value = vaddr;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
2171 sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);2286 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 });
2173}2287}
21742288
2175pub fn createStubHelperAtom(self: *MachO) !*Atom {2289pub fn createStubHelperAtom(self: *MachO) !*Atom {
...@@ -2377,10 +2491,13 @@ fn createTentativeDefAtoms(self: *MachO) !void {...@@ -2377,10 +2491,13 @@ fn createTentativeDefAtoms(self: *MachO) !void {
2377 resolv.local_sym_index = local_sym_index;2491 resolv.local_sym_index = local_sym_index;
23782492
2379 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);2493 const atom = try self.createEmptyAtom(local_sym_index, size, alignment);
2380 const alignment_pow_2 = try math.powi(u32, 2, alignment);2494
2381 const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match);2495 if (self.needs_prealloc) {
2382 local_sym.n_value = vaddr;2496 const alignment_pow_2 = try math.powi(u32, 2, alignment);
2383 global_sym.n_value = vaddr;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);
2384 }2501 }
2385}2502}
23862503
...@@ -2429,10 +2546,11 @@ fn createDsoHandleAtom(self: *MachO) !void {...@@ -2429,10 +2546,11 @@ fn createDsoHandleAtom(self: *MachO) !void {
2429 // TODO perhaps we should special-case special symbols? Create a separate2546 // TODO perhaps we should special-case special symbols? Create a separate
2430 // linked list of atoms?2547 // linked list of atoms?
2431 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);2548 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2432 const sym = &self.locals.items[local_sym_index];2549 if (self.needs_prealloc) {
2433 const vaddr = try self.allocateAtom(atom, 0, 1, match);2550 const sym = &self.locals.items[local_sym_index];
2434 sym.n_value = vaddr;2551 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2435 atom.dirty = false; // We don't really want to write it to file.2552 sym.n_value = vaddr;
2553 } else try self.addAtomAndBumpSectionSize(atom, match);
2436 }2554 }
2437}2555}
24382556
...@@ -2466,12 +2584,11 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2466,12 +2584,11 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2466 return error.UnhandledSymbolType;2584 return error.UnhandledSymbolType;
2467 }2585 }
24682586
2469 const n_strx = try self.makeString(sym_name);
2470 if (sym.sect()) {2587 if (sym.sect()) {
2471 // Defined symbol regardless of scope lands in the locals symbol table.2588 // Defined symbol regardless of scope lands in the locals symbol table.
2472 const local_sym_index = @intCast(u32, self.locals.items.len);2589 const local_sym_index = @intCast(u32, self.locals.items.len);
2473 try self.locals.append(self.base.allocator, .{2590 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),
2475 .n_type = macho.N_SECT,2592 .n_type = macho.N_SECT,
2476 .n_sect = 0,2593 .n_sect = 0,
2477 .n_desc = 0,2594 .n_desc = 0,
...@@ -2484,6 +2601,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2484,6 +2601,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2484 // if we should save the symbol as a global, or potentially flag the error.2601 // if we should save the symbol as a global, or potentially flag the error.
2485 if (!sym.ext()) continue;2602 if (!sym.ext()) continue;
24862603
2604 const n_strx = try self.makeString(sym_name);
2487 const local = self.locals.items[local_sym_index];2605 const local = self.locals.items[local_sym_index];
2488 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {2606 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
2489 const global_sym_index = @intCast(u32, self.globals.items.len);2607 const global_sym_index = @intCast(u32, self.globals.items.len);
...@@ -2554,6 +2672,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2554,6 +2672,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2554 };2672 };
2555 } else if (sym.tentative()) {2673 } else if (sym.tentative()) {
2556 // Symbol is a tentative definition.2674 // Symbol is a tentative definition.
2675 const n_strx = try self.makeString(sym_name);
2557 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {2676 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
2558 const global_sym_index = @intCast(u32, self.globals.items.len);2677 const global_sym_index = @intCast(u32, self.globals.items.len);
2559 try self.globals.append(self.base.allocator, .{2678 try self.globals.append(self.base.allocator, .{
...@@ -2611,6 +2730,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2611,6 +2730,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2611 }2730 }
2612 } else {2731 } else {
2613 // Symbol is undefined.2732 // Symbol is undefined.
2733 const n_strx = try self.makeString(sym_name);
2614 if (self.symbol_resolver.contains(n_strx)) continue;2734 if (self.symbol_resolver.contains(n_strx)) continue;
26152735
2616 const undef_sym_index = @intCast(u32, self.undefs.items.len);2736 const undef_sym_index = @intCast(u32, self.undefs.items.len);
...@@ -2771,10 +2891,13 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void {...@@ -2771,10 +2891,13 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void {
2771 });2891 });
27722892
2773 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);2893 const atom = try self.createEmptyAtom(local_sym_index, 0, 0);
2774 const sym = &self.locals.items[local_sym_index];2894
2775 const vaddr = try self.allocateAtom(atom, 0, 1, match);2895 if (self.needs_prealloc) {
2776 sym.n_value = vaddr;2896 const sym = &self.locals.items[local_sym_index];
2777 atom.dirty = false;2897 const vaddr = try self.allocateAtom(atom, 0, 1, match);
2898 sym.n_value = vaddr;
2899 } else try self.addAtomAndBumpSectionSize(atom, match);
2900
2778 self.mh_execute_header_index = local_sym_index;2901 self.mh_execute_header_index = local_sym_index;
2779}2902}
27802903
...@@ -2828,13 +2951,19 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2828,13 +2951,19 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2828 .sect = self.got_section_index.?,2951 .sect = self.got_section_index.?,
2829 };2952 };
2830 const atom_sym = &self.locals.items[atom.local_sym_index];2953 const atom_sym = &self.locals.items[atom.local_sym_index];
2831 const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match);2954
2832 atom_sym.n_value = vaddr;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
2833 atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);2961 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 });
2835}2962}
28362963
2837fn parseObjectsIntoAtoms(self: *MachO) !void {2964fn 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.
2838 const tracy = trace(@src());2967 const tracy = trace(@src());
2839 defer tracy.end();2968 defer tracy.end();
28402969
...@@ -2858,20 +2987,31 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -2858,20 +2987,31 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
2858 var it = object.end_atoms.iterator();2987 var it = object.end_atoms.iterator();
2859 while (it.next()) |entry| {2988 while (it.next()) |entry| {
2860 const match = entry.key_ptr.*;2989 const match = entry.key_ptr.*;
2861 const last_atom = entry.value_ptr.*;2990 var atom = entry.value_ptr.*;
2862 var atom = last_atom;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];
2864 const metadata = try section_metadata.getOrPut(match);3000 const metadata = try section_metadata.getOrPut(match);
2865 if (!metadata.found_existing) {3001 if (!metadata.found_existing) {
2866 metadata.value_ptr.* = .{3002 metadata.value_ptr.* = .{
2867 .size = 0,3003 .size = sect.size,
2868 .alignment = 0,3004 .alignment = sect.@"align",
2869 };3005 };
2870 }3006 }
28713007
3008 log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) });
3009
2872 while (true) {3010 while (true) {
2873 const alignment = try math.powi(u32, 2, atom.alignment);3011 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;
2875 metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);3015 metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment);
28763016
2877 const sym = self.locals.items[atom.local_sym_index];3017 const sym = self.locals.items[atom.local_sym_index];
...@@ -2882,20 +3022,20 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -2882,20 +3022,20 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
2882 atom.alignment,3022 atom.alignment,
2883 });3023 });
28843024
2885 if (atom.prev) |prev| {3025 if (atom.next) |next| {
2886 atom = prev;3026 atom = next;
2887 } else break;3027 } else break;
2888 }3028 }
28893029
2890 if (parsed_atoms.getPtr(match)) |last| {3030 if (parsed_atoms.getPtr(match)) |last| {
2891 last.*.next = atom;3031 last.*.next = first_atom;
2892 atom.prev = last.*;3032 first_atom.prev = last.*;
2893 last.* = atom;3033 last.* = first_atom;
2894 }3034 }
2895 _ = try parsed_atoms.put(match, last_atom);3035 _ = try parsed_atoms.put(match, atom);
28963036
2897 if (!first_atoms.contains(match)) {3037 if (!first_atoms.contains(match)) {
2898 try first_atoms.putNoClobber(match, atom);3038 try first_atoms.putNoClobber(match, first_atom);
2899 }3039 }
2900 }3040 }
29013041
...@@ -2915,67 +3055,85 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {...@@ -2915,67 +3055,85 @@ fn parseObjectsIntoAtoms(self: *MachO) !void {
2915 metadata.alignment,3055 metadata.alignment,
2916 });3056 });
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
2923 sect.@"align" = math.max(sect.@"align", metadata.alignment);3058 sect.@"align" = math.max(sect.@"align", metadata.alignment);
2924 const needed_size = @intCast(u32, metadata.size + sect_size);3059 const needed_size = @intCast(u32, metadata.size);
2925 try self.growSection(match, needed_size);3060
3061 if (self.needs_prealloc) {
3062 try self.growSection(match, needed_size);
3063 }
2926 sect.size = needed_size;3064 sect.size = needed_size;
3065 }
29273066
2928 var base_vaddr = if (self.atoms.get(match)) |last| blk: {3067 for (&[_]?u16{
2929 const last_atom_sym = self.locals.items[last.local_sym_index];3068 self.text_segment_cmd_index,
2930 break :blk last_atom_sym.n_value + last.size;3069 self.data_const_segment_cmd_index,
2931 } else sect.addr;3070 self.data_segment_cmd_index,
2932 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);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).?;3075 for (seg.sections.items) |sect, sect_id| {
2935 while (true) {3076 const match = MatchingSection{
2936 const alignment = try math.powi(u32, 2, atom.alignment);3077 .seg = seg_id,
2937 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);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];3095 if (!self.needs_prealloc) continue;
2940 sym.n_value = base_vaddr;
2941 sym.n_sect = n_sect;
29423096
2943 log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{3097 const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1);
2944 self.getString(sym.n_strx),
2945 base_vaddr,
2946 base_vaddr + atom.size,
2947 atom.size,
2948 atom.alignment,
2949 });
29503098
2951 // Update each alias (if any)3099 var atom = first_atoms.get(match).?;
2952 for (atom.aliases.items) |index| {3100 while (true) {
2953 const alias_sym = &self.locals.items[index];3101 const alignment = try math.powi(u32, 2, atom.alignment);
2954 alias_sym.n_value = base_vaddr;3102 base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment);
2955 alias_sym.n_sect = n_sect;
2956 }
29573103
2958 // Update each symbol contained within the atom3104 const sym = &self.locals.items[atom.local_sym_index];
2959 for (atom.contained.items) |sym_at_off| {3105 sym.n_value = base_vaddr;
2960 const contained_sym = &self.locals.items[sym_at_off.local_sym_index];3106 sym.n_sect = n_sect;
2961 contained_sym.n_value = base_vaddr + sym_at_off.offset;
2962 contained_sym.n_sect = n_sect;
2963 }
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| {3116 // Update each alias (if any)
2968 atom = next;3117 for (atom.aliases.items) |index| {
2969 } else break;3118 const alias_sym = &self.locals.items[index];
2970 }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| {3132 if (atom.next) |next| {
2973 const first_atom = first_atoms.get(match).?;3133 atom = next;
2974 last.*.next = first_atom;3134 } else break;
2975 first_atom.prev = last.*;3135 }
2976 last.* = first_atom;
2977 }3136 }
2978 _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?);
2979 }3137 }
2980}3138}
29813139
...@@ -3714,7 +3872,9 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {...@@ -3714,7 +3872,9 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 {
3714 return self.locals.items[decl.link.macho.local_sym_index].n_value;3872 return self.locals.items[decl.link.macho.local_sym_index].n_value;
3715}3873}
37163874
3717pub fn populateMissingMetadata(self: *MachO) !void {3875fn populateMissingMetadata(self: *MachO) !void {
3876 const cpu_arch = self.base.options.target.cpu.arch;
3877
3718 if (self.pagezero_segment_cmd_index == null) {3878 if (self.pagezero_segment_cmd_index == null) {
3719 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3879 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3720 try self.load_commands.append(self.base.allocator, .{3880 try self.load_commands.append(self.base.allocator, .{
...@@ -3730,13 +3890,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3730,13 +3890,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37303890
3731 if (self.text_segment_cmd_index == null) {3891 if (self.text_segment_cmd_index == null) {
3732 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3892 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;3893 const needed_size = if (self.needs_prealloc) blk: {
3734 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;3894 const program_code_size_hint = self.base.options.program_code_size_hint;
3735 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;3895 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
3736 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);3896 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
37373897 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
3738 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });3898 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
37393899 break :blk needed_size;
3900 } else 0;
3740 try self.load_commands.append(self.base.allocator, .{3901 try self.load_commands.append(self.base.allocator, .{
3741 .Segment = .{3902 .Segment = .{
3742 .inner = .{3903 .inner = .{
...@@ -3753,13 +3914,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3753,13 +3914,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3753 }3914 }
37543915
3755 if (self.text_section_index == null) {3916 if (self.text_section_index == null) {
3756 const alignment: u2 = switch (self.base.options.target.cpu.arch) {3917 const alignment: u2 = switch (cpu_arch) {
3757 .x86_64 => 0,3918 .x86_64 => 0,
3758 .aarch64 => 2,3919 .aarch64 => 2,
3759 else => unreachable, // unhandled architecture type3920 else => unreachable, // unhandled architecture type
3760 };3921 };
3761 const needed_size = self.base.options.program_code_size_hint;3922 const needed_size = if (self.needs_prealloc) self.base.options.program_code_size_hint else 0;
3762 self.text_section_index = try self.allocateSection(3923 self.text_section_index = try self.initSection(
3763 self.text_segment_cmd_index.?,3924 self.text_segment_cmd_index.?,
3764 "__text",3925 "__text",
3765 needed_size,3926 needed_size,
...@@ -3771,18 +3932,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3771,18 +3932,18 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3771 }3932 }
37723933
3773 if (self.stubs_section_index == null) {3934 if (self.stubs_section_index == null) {
3774 const alignment: u2 = switch (self.base.options.target.cpu.arch) {3935 const alignment: u2 = switch (cpu_arch) {
3775 .x86_64 => 0,3936 .x86_64 => 0,
3776 .aarch64 => 2,3937 .aarch64 => 2,
3777 else => unreachable, // unhandled architecture type3938 else => unreachable, // unhandled architecture type
3778 };3939 };
3779 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {3940 const stub_size: u4 = switch (cpu_arch) {
3780 .x86_64 => 6,3941 .x86_64 => 6,
3781 .aarch64 => 3 * @sizeOf(u32),3942 .aarch64 => 3 * @sizeOf(u32),
3782 else => unreachable, // unhandled architecture type3943 else => unreachable, // unhandled architecture type
3783 };3944 };
3784 const needed_size = stub_size * self.base.options.symbol_count_hint;3945 const needed_size = if (self.needs_prealloc) stub_size * self.base.options.symbol_count_hint else 0;
3785 self.stubs_section_index = try self.allocateSection(3946 self.stubs_section_index = try self.initSection(
3786 self.text_segment_cmd_index.?,3947 self.text_segment_cmd_index.?,
3787 "__stubs",3948 "__stubs",
3788 needed_size,3949 needed_size,
...@@ -3795,23 +3956,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3795,23 +3956,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3795 }3956 }
37963957
3797 if (self.stub_helper_section_index == null) {3958 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) {
3799 .x86_64 => 0,3960 .x86_64 => 0,
3800 .aarch64 => 2,3961 .aarch64 => 2,
3801 else => unreachable, // unhandled architecture type3962 else => unreachable, // unhandled architecture type
3802 };3963 };
3803 const preamble_size: u6 = switch (self.base.options.target.cpu.arch) {3964 const preamble_size: u6 = switch (cpu_arch) {
3804 .x86_64 => 15,3965 .x86_64 => 15,
3805 .aarch64 => 6 * @sizeOf(u32),3966 .aarch64 => 6 * @sizeOf(u32),
3806 else => unreachable,3967 else => unreachable,
3807 };3968 };
3808 const stub_size: u4 = switch (self.base.options.target.cpu.arch) {3969 const stub_size: u4 = switch (cpu_arch) {
3809 .x86_64 => 10,3970 .x86_64 => 10,
3810 .aarch64 => 3 * @sizeOf(u32),3971 .aarch64 => 3 * @sizeOf(u32),
3811 else => unreachable,3972 else => unreachable,
3812 };3973 };
3813 const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;3974 const needed_size = if (self.needs_prealloc)
3814 self.stub_helper_section_index = try self.allocateSection(3975 stub_size * self.base.options.symbol_count_hint + preamble_size
3976 else
3977 0;
3978 self.stub_helper_section_index = try self.initSection(
3815 self.text_segment_cmd_index.?,3979 self.text_segment_cmd_index.?,
3816 "__stub_helper",3980 "__stub_helper",
3817 needed_size,3981 needed_size,
...@@ -3824,22 +3988,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3824,22 +3988,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38243988
3825 if (self.data_const_segment_cmd_index == null) {3989 if (self.data_const_segment_cmd_index == null) {
3826 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3990 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3827 const address_and_offset = self.nextSegmentAddressAndOffset();3991 var vmaddr: u64 = 0;
3828 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;3992 var fileoff: u64 = 0;
3829 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);3993 var needed_size: u64 = 0;
38303994 if (self.needs_prealloc) {
3831 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{3995 const address_and_offset = self.nextSegmentAddressAndOffset();
3832 address_and_offset.offset,3996 vmaddr = address_and_offset.address;
3833 address_and_offset.offset + needed_size,3997 fileoff = address_and_offset.offset;
3834 });3998 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
38353999 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 }
3836 try self.load_commands.append(self.base.allocator, .{4005 try self.load_commands.append(self.base.allocator, .{
3837 .Segment = .{4006 .Segment = .{
3838 .inner = .{4007 .inner = .{
3839 .segname = makeStaticString("__DATA_CONST"),4008 .segname = makeStaticString("__DATA_CONST"),
3840 .vmaddr = address_and_offset.address,4009 .vmaddr = vmaddr,
3841 .vmsize = needed_size,4010 .vmsize = needed_size,
3842 .fileoff = address_and_offset.offset,4011 .fileoff = fileoff,
3843 .filesize = needed_size,4012 .filesize = needed_size,
3844 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4013 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
3845 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4014 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
...@@ -3850,9 +4019,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3850,9 +4019,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3850 }4019 }
38514020
3852 if (self.got_section_index == null) {4021 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;
3854 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4026 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3855 self.got_section_index = try self.allocateSection(4027 self.got_section_index = try self.initSection(
3856 self.data_const_segment_cmd_index.?,4028 self.data_const_segment_cmd_index.?,
3857 "__got",4029 "__got",
3858 needed_size,4030 needed_size,
...@@ -3865,19 +4037,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3865,19 +4037,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
38654037
3866 if (self.data_segment_cmd_index == null) {4038 if (self.data_segment_cmd_index == null) {
3867 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4039 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3868 const address_and_offset = self.nextSegmentAddressAndOffset();4040 var vmaddr: u64 = 0;
3869 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;4041 var fileoff: u64 = 0;
3870 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);4042 var needed_size: u64 = 0;
38714043 if (self.needs_prealloc) {
3872 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });4044 const address_and_offset = self.nextSegmentAddressAndOffset();
38734045 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 }
3874 try self.load_commands.append(self.base.allocator, .{4054 try self.load_commands.append(self.base.allocator, .{
3875 .Segment = .{4055 .Segment = .{
3876 .inner = .{4056 .inner = .{
3877 .segname = makeStaticString("__DATA"),4057 .segname = makeStaticString("__DATA"),
3878 .vmaddr = address_and_offset.address,4058 .vmaddr = vmaddr,
3879 .vmsize = needed_size,4059 .vmsize = needed_size,
3880 .fileoff = address_and_offset.offset,4060 .fileoff = fileoff,
3881 .filesize = needed_size,4061 .filesize = needed_size,
3882 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4062 .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
3883 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,4063 .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE,
...@@ -3888,9 +4068,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3888,9 +4068,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3888 }4068 }
38894069
3890 if (self.la_symbol_ptr_section_index == null) {4070 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;
3892 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4075 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(
3894 self.data_segment_cmd_index.?,4077 self.data_segment_cmd_index.?,
3895 "__la_symbol_ptr",4078 "__la_symbol_ptr",
3896 needed_size,4079 needed_size,
...@@ -3902,9 +4085,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3902,9 +4085,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3902 }4085 }
39034086
3904 if (self.data_section_index == null) {4087 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;
3906 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4089 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3907 self.data_section_index = try self.allocateSection(4090 self.data_section_index = try self.initSection(
3908 self.data_segment_cmd_index.?,4091 self.data_segment_cmd_index.?,
3909 "__data",4092 "__data",
3910 needed_size,4093 needed_size,
...@@ -3914,9 +4097,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3914,9 +4097,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3914 }4097 }
39154098
3916 if (self.tlv_section_index == null) {4099 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;
3918 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4101 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3919 self.tlv_section_index = try self.allocateSection(4102 self.tlv_section_index = try self.initSection(
3920 self.data_segment_cmd_index.?,4103 self.data_segment_cmd_index.?,
3921 "__thread_vars",4104 "__thread_vars",
3922 needed_size,4105 needed_size,
...@@ -3928,9 +4111,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3928,9 +4111,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3928 }4111 }
39294112
3930 if (self.tlv_data_section_index == null) {4113 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;
3932 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4115 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(
3934 self.data_segment_cmd_index.?,4117 self.data_segment_cmd_index.?,
3935 "__thread_data",4118 "__thread_data",
3936 needed_size,4119 needed_size,
...@@ -3942,9 +4125,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3942,9 +4125,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3942 }4125 }
39434126
3944 if (self.tlv_bss_section_index == null) {4127 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;
3946 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4129 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(
3948 self.data_segment_cmd_index.?,4131 self.data_segment_cmd_index.?,
3949 "__thread_bss",4132 "__thread_bss",
3950 needed_size,4133 needed_size,
...@@ -3959,9 +4142,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3959,9 +4142,9 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3959 }4142 }
39604143
3961 if (self.bss_section_index == null) {4144 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;
3963 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)4146 const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
3964 self.bss_section_index = try self.allocateSection(4147 self.bss_section_index = try self.initSection(
3965 self.data_segment_cmd_index.?,4148 self.data_segment_cmd_index.?,
3966 "__bss",4149 "__bss",
3967 needed_size,4150 needed_size,
...@@ -3977,16 +4160,20 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3977,16 +4160,20 @@ pub fn populateMissingMetadata(self: *MachO) !void {
39774160
3978 if (self.linkedit_segment_cmd_index == null) {4161 if (self.linkedit_segment_cmd_index == null) {
3979 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);4162 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3980 const address_and_offset = self.nextSegmentAddressAndOffset();4163 var vmaddr: u64 = 0;
39814164 var fileoff: u64 = 0;
3982 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});4165 if (self.needs_prealloc) {
39834166 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 }
3984 try self.load_commands.append(self.base.allocator, .{4171 try self.load_commands.append(self.base.allocator, .{
3985 .Segment = .{4172 .Segment = .{
3986 .inner = .{4173 .inner = .{
3987 .segname = makeStaticString("__LINKEDIT"),4174 .segname = makeStaticString("__LINKEDIT"),
3988 .vmaddr = address_and_offset.address,4175 .vmaddr = vmaddr,
3989 .fileoff = address_and_offset.offset,4176 .fileoff = fileoff,
3990 .maxprot = macho.VM_PROT_READ,4177 .maxprot = macho.VM_PROT_READ,
3991 .initprot = macho.VM_PROT_READ,4178 .initprot = macho.VM_PROT_READ,
3992 },4179 },
...@@ -4198,44 +4385,123 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4198,44 +4385,123 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4198 self.cold_start = true;4385 self.cold_start = true;
4199}4386}
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 {
4202 flags: u32 = macho.S_REGULAR,4468 flags: u32 = macho.S_REGULAR,
4203 reserved1: u32 = 0,4469 reserved1: u32 = 0,
4204 reserved2: u32 = 0,4470 reserved2: u32 = 0,
4205};4471};
42064472
4207fn allocateSection(4473fn initSection(
4208 self: *MachO,4474 self: *MachO,
4209 segment_id: u16,4475 segment_id: u16,
4210 sectname: []const u8,4476 sectname: []const u8,
4211 size: u64,4477 size: u64,
4212 alignment: u32,4478 alignment: u32,
4213 opts: AllocateSectionOpts,4479 opts: InitSectionOpts,
4214) !u16 {4480) !u16 {
4215 const seg = &self.load_commands.items[segment_id].Segment;4481 const seg = &self.load_commands.items[segment_id].Segment;
4216 var sect = macho.section_64{4482 var sect = macho.section_64{
4217 .sectname = makeStaticString(sectname),4483 .sectname = makeStaticString(sectname),
4218 .segname = seg.inner.segname,4484 .segname = seg.inner.segname,
4219 .size = @intCast(u32, size),4485 .size = if (self.needs_prealloc) @intCast(u32, size) else 0,
4220 .@"align" = alignment,4486 .@"align" = alignment,
4221 .flags = opts.flags,4487 .flags = opts.flags,
4222 .reserved1 = opts.reserved1,4488 .reserved1 = opts.reserved1,
4223 .reserved2 = opts.reserved2,4489 .reserved2 = opts.reserved2,
4224 };4490 };
42254491
4226 const alignment_pow_2 = try math.powi(u32, 2, alignment);4492 if (self.needs_prealloc) {
4227 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;4493 const alignment_pow_2 = try math.powi(u32, 2, alignment);
4228 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);4494 const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null;
42294495 const off = self.findFreeSpace(segment_id, alignment_pow_2, padding);
4230 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{4496 log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{
4231 commands.segmentName(sect),4497 commands.segmentName(sect),
4232 commands.sectionName(sect),4498 commands.sectionName(sect),
4233 off,4499 off,
4234 off + size,4500 off + size,
4235 });4501 });
42364502 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;
4237 sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff;4503 sect.offset = @intCast(u32, off);
4238 sect.offset = @intCast(u32, off);4504 }
42394505
4240 const index = @intCast(u16, seg.sections.items.len);4506 const index = @intCast(u16, seg.sections.items.len);
4241 try seg.sections.append(self.base.allocator, sect);4507 try seg.sections.append(self.base.allocator, sect);
...@@ -4270,7 +4536,11 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {...@@ -4270,7 +4536,11 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
4270 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);4536 const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size);
4271 assert(new_seg_size > seg.inner.filesize);4537 assert(new_seg_size > seg.inner.filesize);
4272 const offset_amt = new_seg_size - seg.inner.filesize;4538 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 });
4274 seg.inner.filesize = new_seg_size;4544 seg.inner.filesize = new_seg_size;
4275 seg.inner.vmsize = new_seg_size;4545 seg.inner.vmsize = new_seg_size;
42764546
...@@ -4321,7 +4591,7 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {...@@ -4321,7 +4591,7 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void {
4321 moved_sect.addr + moved_sect.size,4591 moved_sect.addr + moved_sect.size,
4322 });4592 });
43234593
4324 try self.allocateLocalSymbols(.{4594 try self.shiftLocalsByOffset(.{
4325 .seg = @intCast(u16, next),4595 .seg = @intCast(u16, next),
4326 .sect = @intCast(u16, moved_sect_id),4596 .sect = @intCast(u16, moved_sect_id),
4327 }, @intCast(i64, offset_amt));4597 }, @intCast(i64, offset_amt));
...@@ -4395,7 +4665,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {...@@ -4395,7 +4665,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void {
4395 moved_sect.addr + moved_sect.size,4665 moved_sect.addr + moved_sect.size,
4396 });4666 });
43974667
4398 try self.allocateLocalSymbols(.{4668 try self.shiftLocalsByOffset(.{
4399 .seg = match.seg,4669 .seg = match.seg,
4400 .sect = next,4670 .sect = next,
4401 }, @intCast(i64, offset_amt));4671 }, @intCast(i64, offset_amt));
...@@ -4534,6 +4804,21 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m...@@ -4534,6 +4804,21 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
4534 return vaddr;4804 return vaddr;
4535}4805}
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
4537pub fn addExternFn(self: *MachO, name: []const u8) !u32 {4822pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
4538 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});4823 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
4539 defer self.base.allocator.free(sym_name);4824 defer self.base.allocator.free(sym_name);
...@@ -4580,6 +4865,160 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {...@@ -4580,6 +4865,160 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
4580 };4865 };
4581}4866}
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
4583fn updateSectionOrdinals(self: *MachO) !void {5022fn updateSectionOrdinals(self: *MachO) !void {
4584 if (!self.sections_order_dirty) return;5023 if (!self.sections_order_dirty) return;
45855024
...@@ -4957,7 +5396,7 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -4957,7 +5396,7 @@ fn writeSymbolTable(self: *MachO) !void {
49575396
4958 for (self.locals.items) |sym| {5397 for (self.locals.items) |sym| {
4959 if (sym.n_strx == 0) continue;5398 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;
4961 try locals.append(sym);5400 try locals.append(sym);
4962 }5401 }
49635402
...@@ -5309,7 +5748,7 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {...@@ -5309,7 +5748,7 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {
5309 return new_off;5748 return new_off;
5310}5749}
53115750
5312pub fn getString(self: *MachO, off: u32) []const u8 {5751pub fn getString(self: MachO, off: u32) []const u8 {
5313 assert(off < self.strtab.items.len);5752 assert(off < self.strtab.items.len);
5314 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.items.ptr + off), 0);5753 return mem.sliceTo(@ptrCast([*:0]const u8, self.strtab.items.ptr + off), 0);
5315}5754}
...@@ -5602,3 +6041,55 @@ fn snapshotState(self: *MachO) !void {...@@ -5602,3 +6041,55 @@ fn snapshotState(self: *MachO) !void {
5602 try std.json.stringify(snapshot, .{}, writer);6041 try std.json.stringify(snapshot, .{}, writer);
5603 try writer.writeByte(']');6042 try writer.writeByte(']');
5604}6043}
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...@@ -344,7 +344,8 @@ pub fn parseRelocs(self: *Atom, relocs: []macho.relocation_info, context: RelocC
344 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {344 const local_sym_index = context.object.sections_as_symbols.get(sect_id) orelse blk: {
345 const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;345 const seg = context.object.load_commands.items[context.object.segment_cmd_index.?].Segment;
346 const sect = seg.sections.items[sect_id];346 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;
348 const local_sym_index = @intCast(u32, context.macho_file.locals.items.len);349 const local_sym_index = @intCast(u32, context.macho_file.locals.items.len);
349 try context.macho_file.locals.append(context.allocator, .{350 try context.macho_file.locals.append(context.allocator, .{
350 .n_strx = 0,351 .n_strx = 0,
src/link/MachO/Object.zig+3-1
...@@ -474,7 +474,9 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !...@@ -474,7 +474,9 @@ pub fn parseIntoAtoms(self: *Object, allocator: Allocator, macho_file: *MachO) !
474 try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index);474 try self.sections_as_symbols.putNoClobber(allocator, sect_id, atom_local_sym_index);
475 break :blk atom_local_sym_index;475 break :blk atom_local_sym_index;
476 };476 };
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
479 const is_zerofill = blk: {481 const is_zerofill = blk: {
480 const section_type = commands.sectionType(sect);482 const section_type = commands.sectionType(sect);