| ... | ... | @@ -63,6 +63,11 @@ page_size: u16, |
| 63 | 63 | /// https://github.com/ziglang/zig/issues/9567 |
| 64 | 64 | requires_adhoc_codesig: bool, |
| 65 | 65 | |
| 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. |
| 69 | needs_prealloc: bool = true, |
| 70 | |
| 66 | 71 | /// We commit 0x1000 = 4096 bytes of space to the header and |
| 67 | 72 | /// the table of load commands. This should be plenty for any |
| 68 | 73 | /// potential future extensions. |
| ... | ... | @@ -375,6 +380,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 375 | 380 | // Adhoc code signature is required when targeting aarch64-macos either directly or indirectly via the simulator |
| 376 | 381 | // ABI such as aarch64-ios-simulator, etc. |
| 377 | 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); |
| 378 | 384 | |
| 379 | 385 | self.* = .{ |
| 380 | 386 | .base = .{ |
| ... | ... | @@ -385,6 +391,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO { |
| 385 | 391 | }, |
| 386 | 392 | .page_size = page_size, |
| 387 | 393 | .requires_adhoc_codesig = requires_adhoc_codesig, |
| 394 | .needs_prealloc = needs_prealloc, |
| 388 | 395 | }; |
| 389 | 396 | |
| 390 | 397 | return self; |
| ... | ... | @@ -911,42 +918,28 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 911 | 918 | |
| 912 | 919 | try self.createTentativeDefAtoms(); |
| 913 | 920 | try self.parseObjectsIntoAtoms(); |
| 914 | | try self.allocateGlobalSymbols(); |
| 915 | 921 | |
| 916 | | log.debug("locals:", .{}); |
| 917 | | for (self.locals.items) |sym, id| { |
| 918 | | log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); |
| 919 | | } |
| 920 | | log.debug("globals:", .{}); |
| 921 | | for (self.globals.items) |sym, id| { |
| 922 | | log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); |
| 923 | | } |
| 924 | | log.debug("undefs:", .{}); |
| 925 | | for (self.undefs.items) |sym, id| { |
| 926 | | log.debug(" {d}: {s}: {}", .{ id, self.getString(sym.n_strx), sym }); |
| 927 | | } |
| 928 | | { |
| 929 | | log.debug("resolver:", .{}); |
| 930 | | var it = self.symbol_resolver.iterator(); |
| 931 | | while (it.next()) |entry| { |
| 932 | | log.debug(" {s} => {}", .{ self.getString(entry.key_ptr.*), entry.value_ptr.* }); |
| 933 | | } |
| 922 | if (use_stage1) { |
| 923 | try self.sortSections(); |
| 924 | try self.allocateTextSegment(); |
| 925 | try self.allocateDataConstSegment(); |
| 926 | try self.allocateDataSegment(); |
| 927 | self.allocateLinkeditSegment(); |
| 928 | try self.allocateLocals(); |
| 934 | 929 | } |
| 935 | 930 | |
| 936 | | log.debug("GOT entries:", .{}); |
| 937 | | for (self.got_entries_map.keys()) |key| { |
| 938 | | switch (key) { |
| 939 | | .local => |sym_index| log.debug(" {} => {d}", .{ key, sym_index }), |
| 940 | | .global => |n_strx| log.debug(" {} => {s}", .{ key, self.getString(n_strx) }), |
| 941 | | } |
| 942 | | } |
| 931 | try self.allocateGlobals(); |
| 943 | 932 | |
| 944 | | log.debug("stubs:", .{}); |
| 945 | | for (self.stubs_map.keys()) |key| { |
| 946 | | log.debug(" {} => {s}", .{ key, self.getString(key) }); |
| 933 | if (build_options.enable_logging) { |
| 934 | self.logSymtab(); |
| 935 | self.logSectionOrdinals(); |
| 947 | 936 | } |
| 948 | 937 | |
| 949 | | try self.writeAtoms(); |
| 938 | if (use_stage1) { |
| 939 | try self.writeAllAtoms(); |
| 940 | } else { |
| 941 | try self.writeAtoms(); |
| 942 | } |
| 950 | 943 | |
| 951 | 944 | if (self.bss_section_index) |idx| { |
| 952 | 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 | 1330 | switch (commands.sectionType(sect)) { |
| 1338 | 1331 | macho.S_4BYTE_LITERALS, macho.S_8BYTE_LITERALS, macho.S_16BYTE_LITERALS => { |
| 1339 | 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 | 1334 | self.text_segment_cmd_index.?, |
| 1342 | 1335 | "__const", |
| 1343 | 1336 | sect.size, |
| ... | ... | @@ -1356,7 +1349,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1356 | 1349 | // TODO it seems the common values within the sections in objects are deduplicated/merged |
| 1357 | 1350 | // on merging the sections' contents. |
| 1358 | 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 | 1353 | self.text_segment_cmd_index.?, |
| 1361 | 1354 | "__objc_methname", |
| 1362 | 1355 | sect.size, |
| ... | ... | @@ -1371,7 +1364,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1371 | 1364 | }; |
| 1372 | 1365 | } else if (mem.eql(u8, sectname, "__objc_methtype")) { |
| 1373 | 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 | 1368 | self.text_segment_cmd_index.?, |
| 1376 | 1369 | "__objc_methtype", |
| 1377 | 1370 | sect.size, |
| ... | ... | @@ -1386,7 +1379,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1386 | 1379 | }; |
| 1387 | 1380 | } else if (mem.eql(u8, sectname, "__objc_classname")) { |
| 1388 | 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 | 1383 | self.text_segment_cmd_index.?, |
| 1391 | 1384 | "__objc_classname", |
| 1392 | 1385 | sect.size, |
| ... | ... | @@ -1402,7 +1395,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1402 | 1395 | } |
| 1403 | 1396 | |
| 1404 | 1397 | if (self.cstring_section_index == null) { |
| 1405 | | self.cstring_section_index = try self.allocateSection( |
| 1398 | self.cstring_section_index = try self.initSection( |
| 1406 | 1399 | self.text_segment_cmd_index.?, |
| 1407 | 1400 | "__cstring", |
| 1408 | 1401 | sect.size, |
| ... | ... | @@ -1421,7 +1414,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1421 | 1414 | macho.S_LITERAL_POINTERS => { |
| 1422 | 1415 | if (mem.eql(u8, segname, "__DATA") and mem.eql(u8, sectname, "__objc_selrefs")) { |
| 1423 | 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 | 1418 | self.data_segment_cmd_index.?, |
| 1426 | 1419 | "__objc_selrefs", |
| 1427 | 1420 | sect.size, |
| ... | ... | @@ -1443,7 +1436,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1443 | 1436 | }, |
| 1444 | 1437 | macho.S_MOD_INIT_FUNC_POINTERS => { |
| 1445 | 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 | 1440 | self.data_const_segment_cmd_index.?, |
| 1448 | 1441 | "__mod_init_func", |
| 1449 | 1442 | sect.size, |
| ... | ... | @@ -1461,7 +1454,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1461 | 1454 | }, |
| 1462 | 1455 | macho.S_MOD_TERM_FUNC_POINTERS => { |
| 1463 | 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 | 1458 | self.data_const_segment_cmd_index.?, |
| 1466 | 1459 | "__mod_term_func", |
| 1467 | 1460 | sect.size, |
| ... | ... | @@ -1479,7 +1472,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1479 | 1472 | }, |
| 1480 | 1473 | macho.S_ZEROFILL => { |
| 1481 | 1474 | if (self.bss_section_index == null) { |
| 1482 | | self.bss_section_index = try self.allocateSection( |
| 1475 | self.bss_section_index = try self.initSection( |
| 1483 | 1476 | self.data_segment_cmd_index.?, |
| 1484 | 1477 | "__bss", |
| 1485 | 1478 | sect.size, |
| ... | ... | @@ -1497,7 +1490,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1497 | 1490 | }, |
| 1498 | 1491 | macho.S_THREAD_LOCAL_VARIABLES => { |
| 1499 | 1492 | if (self.tlv_section_index == null) { |
| 1500 | | self.tlv_section_index = try self.allocateSection( |
| 1493 | self.tlv_section_index = try self.initSection( |
| 1501 | 1494 | self.data_segment_cmd_index.?, |
| 1502 | 1495 | "__thread_vars", |
| 1503 | 1496 | sect.size, |
| ... | ... | @@ -1515,7 +1508,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1515 | 1508 | }, |
| 1516 | 1509 | macho.S_THREAD_LOCAL_REGULAR => { |
| 1517 | 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 | 1512 | self.data_segment_cmd_index.?, |
| 1520 | 1513 | "__thread_data", |
| 1521 | 1514 | sect.size, |
| ... | ... | @@ -1533,7 +1526,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1533 | 1526 | }, |
| 1534 | 1527 | macho.S_THREAD_LOCAL_ZEROFILL => { |
| 1535 | 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 | 1530 | self.data_segment_cmd_index.?, |
| 1538 | 1531 | "__thread_bss", |
| 1539 | 1532 | sect.size, |
| ... | ... | @@ -1554,7 +1547,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1554 | 1547 | // TODO I believe __eh_frame is currently part of __unwind_info section |
| 1555 | 1548 | // in the latest ld64 output. |
| 1556 | 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 | 1551 | self.text_segment_cmd_index.?, |
| 1559 | 1552 | "__eh_frame", |
| 1560 | 1553 | sect.size, |
| ... | ... | @@ -1571,7 +1564,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1571 | 1564 | |
| 1572 | 1565 | // TODO audit this: is this the right mapping? |
| 1573 | 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 | 1568 | self.data_const_segment_cmd_index.?, |
| 1576 | 1569 | "__const", |
| 1577 | 1570 | sect.size, |
| ... | ... | @@ -1588,7 +1581,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1588 | 1581 | macho.S_REGULAR => { |
| 1589 | 1582 | if (commands.sectionIsCode(sect)) { |
| 1590 | 1583 | if (self.text_section_index == null) { |
| 1591 | | self.text_section_index = try self.allocateSection( |
| 1584 | self.text_section_index = try self.initSection( |
| 1592 | 1585 | self.text_segment_cmd_index.?, |
| 1593 | 1586 | "__text", |
| 1594 | 1587 | sect.size, |
| ... | ... | @@ -1619,7 +1612,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1619 | 1612 | if (mem.eql(u8, segname, "__TEXT")) { |
| 1620 | 1613 | if (mem.eql(u8, sectname, "__ustring")) { |
| 1621 | 1614 | if (self.ustring_section_index == null) { |
| 1622 | | self.ustring_section_index = try self.allocateSection( |
| 1615 | self.ustring_section_index = try self.initSection( |
| 1623 | 1616 | self.text_segment_cmd_index.?, |
| 1624 | 1617 | "__ustring", |
| 1625 | 1618 | sect.size, |
| ... | ... | @@ -1634,7 +1627,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1634 | 1627 | }; |
| 1635 | 1628 | } else if (mem.eql(u8, sectname, "__gcc_except_tab")) { |
| 1636 | 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 | 1631 | self.text_segment_cmd_index.?, |
| 1639 | 1632 | "__gcc_except_tab", |
| 1640 | 1633 | sect.size, |
| ... | ... | @@ -1649,7 +1642,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1649 | 1642 | }; |
| 1650 | 1643 | } else if (mem.eql(u8, sectname, "__objc_methlist")) { |
| 1651 | 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 | 1646 | self.text_segment_cmd_index.?, |
| 1654 | 1647 | "__objc_methlist", |
| 1655 | 1648 | sect.size, |
| ... | ... | @@ -1669,7 +1662,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1669 | 1662 | mem.eql(u8, sectname, "__gopclntab")) |
| 1670 | 1663 | { |
| 1671 | 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 | 1666 | self.data_const_segment_cmd_index.?, |
| 1674 | 1667 | "__const", |
| 1675 | 1668 | sect.size, |
| ... | ... | @@ -1684,7 +1677,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1684 | 1677 | }; |
| 1685 | 1678 | } else { |
| 1686 | 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 | 1681 | self.text_segment_cmd_index.?, |
| 1689 | 1682 | "__const", |
| 1690 | 1683 | sect.size, |
| ... | ... | @@ -1702,7 +1695,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1702 | 1695 | |
| 1703 | 1696 | if (mem.eql(u8, segname, "__DATA_CONST")) { |
| 1704 | 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 | 1699 | self.data_const_segment_cmd_index.?, |
| 1707 | 1700 | "__const", |
| 1708 | 1701 | sect.size, |
| ... | ... | @@ -1720,7 +1713,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1720 | 1713 | if (mem.eql(u8, segname, "__DATA")) { |
| 1721 | 1714 | if (mem.eql(u8, sectname, "__const")) { |
| 1722 | 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 | 1717 | self.data_const_segment_cmd_index.?, |
| 1725 | 1718 | "__const", |
| 1726 | 1719 | sect.size, |
| ... | ... | @@ -1735,7 +1728,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1735 | 1728 | }; |
| 1736 | 1729 | } else if (mem.eql(u8, sectname, "__cfstring")) { |
| 1737 | 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 | 1732 | self.data_const_segment_cmd_index.?, |
| 1740 | 1733 | "__cfstring", |
| 1741 | 1734 | sect.size, |
| ... | ... | @@ -1750,7 +1743,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1750 | 1743 | }; |
| 1751 | 1744 | } else if (mem.eql(u8, sectname, "__objc_classlist")) { |
| 1752 | 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 | 1747 | self.data_const_segment_cmd_index.?, |
| 1755 | 1748 | "__objc_classlist", |
| 1756 | 1749 | sect.size, |
| ... | ... | @@ -1765,7 +1758,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1765 | 1758 | }; |
| 1766 | 1759 | } else if (mem.eql(u8, sectname, "__objc_imageinfo")) { |
| 1767 | 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 | 1762 | self.data_const_segment_cmd_index.?, |
| 1770 | 1763 | "__objc_imageinfo", |
| 1771 | 1764 | sect.size, |
| ... | ... | @@ -1780,7 +1773,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1780 | 1773 | }; |
| 1781 | 1774 | } else if (mem.eql(u8, sectname, "__objc_const")) { |
| 1782 | 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 | 1777 | self.data_segment_cmd_index.?, |
| 1785 | 1778 | "__objc_const", |
| 1786 | 1779 | sect.size, |
| ... | ... | @@ -1795,7 +1788,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1795 | 1788 | }; |
| 1796 | 1789 | } else if (mem.eql(u8, sectname, "__objc_classrefs")) { |
| 1797 | 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 | 1792 | self.data_segment_cmd_index.?, |
| 1800 | 1793 | "__objc_classrefs", |
| 1801 | 1794 | sect.size, |
| ... | ... | @@ -1810,7 +1803,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1810 | 1803 | }; |
| 1811 | 1804 | } else if (mem.eql(u8, sectname, "__objc_data")) { |
| 1812 | 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 | 1807 | self.data_segment_cmd_index.?, |
| 1815 | 1808 | "__objc_data", |
| 1816 | 1809 | sect.size, |
| ... | ... | @@ -1825,7 +1818,7 @@ pub fn getMatchingSection(self: *MachO, sect: macho.section_64) !?MatchingSectio |
| 1825 | 1818 | }; |
| 1826 | 1819 | } else { |
| 1827 | 1820 | if (self.data_section_index == null) { |
| 1828 | | self.data_section_index = try self.allocateSection( |
| 1821 | self.data_section_index = try self.initSection( |
| 1829 | 1822 | self.data_segment_cmd_index.?, |
| 1830 | 1823 | "__data", |
| 1831 | 1824 | sect.size, |
| ... | ... | @@ -1881,7 +1874,64 @@ pub fn writeAtom(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 1881 | 1874 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 1882 | 1875 | } |
| 1883 | 1876 | |
| 1884 | | fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void { |
| 1877 | fn 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 | |
| 1934 | fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void { |
| 1885 | 1935 | var atom = self.atoms.get(match) orelse return; |
| 1886 | 1936 | |
| 1887 | 1937 | while (true) { |
| ... | ... | @@ -1904,7 +1954,9 @@ fn allocateLocalSymbols(self: *MachO, match: MatchingSection, offset: i64) !void |
| 1904 | 1954 | } |
| 1905 | 1955 | } |
| 1906 | 1956 | |
| 1907 | | fn allocateGlobalSymbols(self: *MachO) !void { |
| 1957 | fn allocateGlobals(self: *MachO) !void { |
| 1958 | log.debug("allocating global symbols", .{}); |
| 1959 | |
| 1908 | 1960 | var sym_it = self.symbol_resolver.valueIterator(); |
| 1909 | 1961 | while (sym_it.next()) |resolv| { |
| 1910 | 1962 | if (resolv.where != .global) continue; |
| ... | ... | @@ -1914,7 +1966,60 @@ fn allocateGlobalSymbols(self: *MachO) !void { |
| 1914 | 1966 | const sym = &self.globals.items[resolv.where_index]; |
| 1915 | 1967 | sym.n_value = local_sym.n_value; |
| 1916 | 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 | |
| 1978 | fn 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 | } |
| 1920 | 2025 | |
| ... | ... | @@ -1962,6 +2067,7 @@ fn writeAtoms(self: *MachO) !void { |
| 1962 | 2067 | atom.dirty = false; |
| 1963 | 2068 | } else { |
| 1964 | 2069 | if (file_offset) |off| { |
| 2070 | log.debug(" (writing at file offset 0x{x})", .{off}); |
| 1965 | 2071 | try self.base.file.?.pwriteAll(buffer.items, off); |
| 1966 | 2072 | } |
| 1967 | 2073 | file_offset = null; |
| ... | ... | @@ -1972,6 +2078,7 @@ fn writeAtoms(self: *MachO) !void { |
| 1972 | 2078 | atom = next; |
| 1973 | 2079 | } else { |
| 1974 | 2080 | if (file_offset) |off| { |
| 2081 | log.debug(" (writing at file offset 0x{x})", .{off}); |
| 1975 | 2082 | try self.base.file.?.pwriteAll(buffer.items, off); |
| 1976 | 2083 | } |
| 1977 | 2084 | file_offset = null; |
| ... | ... | @@ -2036,10 +2143,13 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 2036 | 2143 | .seg = self.data_segment_cmd_index.?, |
| 2037 | 2144 | .sect = self.data_section_index.?, |
| 2038 | 2145 | }; |
| 2039 | | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 2040 | | sym.n_value = vaddr; |
| 2146 | if (self.needs_prealloc) { |
| 2147 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 2148 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 2149 | sym.n_value = vaddr; |
| 2150 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2151 | |
| 2041 | 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 | } |
| 2044 | 2154 | |
| 2045 | 2155 | fn createStubHelperPreambleAtom(self: *MachO) !void { |
| ... | ... | @@ -2165,11 +2275,15 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2165 | 2275 | .seg = self.text_segment_cmd_index.?, |
| 2166 | 2276 | .sect = self.stub_helper_section_index.?, |
| 2167 | 2277 | }; |
| 2168 | | const alignment_pow_2 = try math.powi(u32, 2, atom.alignment); |
| 2169 | | const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match); |
| 2170 | | sym.n_value = vaddr; |
| 2278 | |
| 2279 | if (self.needs_prealloc) { |
| 2280 | const alignment_pow_2 = try math.powi(u32, 2, atom.alignment); |
| 2281 | const vaddr = try self.allocateAtom(atom, atom.size, alignment_pow_2, match); |
| 2282 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 2283 | sym.n_value = vaddr; |
| 2284 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2285 | |
| 2171 | 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 | } |
| 2174 | 2288 | |
| 2175 | 2289 | pub fn createStubHelperAtom(self: *MachO) !*Atom { |
| ... | ... | @@ -2377,10 +2491,13 @@ fn createTentativeDefAtoms(self: *MachO) !void { |
| 2377 | 2491 | resolv.local_sym_index = local_sym_index; |
| 2378 | 2492 | |
| 2379 | 2493 | const atom = try self.createEmptyAtom(local_sym_index, size, alignment); |
| 2380 | | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 2381 | | const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match); |
| 2382 | | local_sym.n_value = vaddr; |
| 2383 | | global_sym.n_value = vaddr; |
| 2494 | |
| 2495 | if (self.needs_prealloc) { |
| 2496 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 2497 | const vaddr = try self.allocateAtom(atom, size, alignment_pow_2, match); |
| 2498 | local_sym.n_value = vaddr; |
| 2499 | global_sym.n_value = vaddr; |
| 2500 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2384 | 2501 | } |
| 2385 | 2502 | } |
| 2386 | 2503 | |
| ... | ... | @@ -2429,10 +2546,11 @@ fn createDsoHandleAtom(self: *MachO) !void { |
| 2429 | 2546 | // TODO perhaps we should special-case special symbols? Create a separate |
| 2430 | 2547 | // linked list of atoms? |
| 2431 | 2548 | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); |
| 2432 | | const sym = &self.locals.items[local_sym_index]; |
| 2433 | | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| 2434 | | sym.n_value = vaddr; |
| 2435 | | atom.dirty = false; // We don't really want to write it to file. |
| 2549 | if (self.needs_prealloc) { |
| 2550 | const sym = &self.locals.items[local_sym_index]; |
| 2551 | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| 2552 | sym.n_value = vaddr; |
| 2553 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2436 | 2554 | } |
| 2437 | 2555 | } |
| 2438 | 2556 | |
| ... | ... | @@ -2466,12 +2584,11 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2466 | 2584 | return error.UnhandledSymbolType; |
| 2467 | 2585 | } |
| 2468 | 2586 | |
| 2469 | | const n_strx = try self.makeString(sym_name); |
| 2470 | 2587 | if (sym.sect()) { |
| 2471 | 2588 | // Defined symbol regardless of scope lands in the locals symbol table. |
| 2472 | 2589 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2473 | 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 | 2592 | .n_type = macho.N_SECT, |
| 2476 | 2593 | .n_sect = 0, |
| 2477 | 2594 | .n_desc = 0, |
| ... | ... | @@ -2484,6 +2601,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2484 | 2601 | // if we should save the symbol as a global, or potentially flag the error. |
| 2485 | 2602 | if (!sym.ext()) continue; |
| 2486 | 2603 | |
| 2604 | const n_strx = try self.makeString(sym_name); |
| 2487 | 2605 | const local = self.locals.items[local_sym_index]; |
| 2488 | 2606 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse { |
| 2489 | 2607 | const global_sym_index = @intCast(u32, self.globals.items.len); |
| ... | ... | @@ -2554,6 +2672,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2554 | 2672 | }; |
| 2555 | 2673 | } else if (sym.tentative()) { |
| 2556 | 2674 | // Symbol is a tentative definition. |
| 2675 | const n_strx = try self.makeString(sym_name); |
| 2557 | 2676 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse { |
| 2558 | 2677 | const global_sym_index = @intCast(u32, self.globals.items.len); |
| 2559 | 2678 | try self.globals.append(self.base.allocator, .{ |
| ... | ... | @@ -2611,6 +2730,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| 2611 | 2730 | } |
| 2612 | 2731 | } else { |
| 2613 | 2732 | // Symbol is undefined. |
| 2733 | const n_strx = try self.makeString(sym_name); |
| 2614 | 2734 | if (self.symbol_resolver.contains(n_strx)) continue; |
| 2615 | 2735 | |
| 2616 | 2736 | const undef_sym_index = @intCast(u32, self.undefs.items.len); |
| ... | ... | @@ -2771,10 +2891,13 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void { |
| 2771 | 2891 | }); |
| 2772 | 2892 | |
| 2773 | 2893 | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); |
| 2774 | | const sym = &self.locals.items[local_sym_index]; |
| 2775 | | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| 2776 | | sym.n_value = vaddr; |
| 2777 | | atom.dirty = false; |
| 2894 | |
| 2895 | if (self.needs_prealloc) { |
| 2896 | const sym = &self.locals.items[local_sym_index]; |
| 2897 | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| 2898 | sym.n_value = vaddr; |
| 2899 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2900 | |
| 2778 | 2901 | self.mh_execute_header_index = local_sym_index; |
| 2779 | 2902 | } |
| 2780 | 2903 | |
| ... | ... | @@ -2828,13 +2951,19 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2828 | 2951 | .sect = self.got_section_index.?, |
| 2829 | 2952 | }; |
| 2830 | 2953 | const atom_sym = &self.locals.items[atom.local_sym_index]; |
| 2831 | | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 2832 | | atom_sym.n_value = vaddr; |
| 2954 | |
| 2955 | if (self.needs_prealloc) { |
| 2956 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 2957 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 2958 | atom_sym.n_value = vaddr; |
| 2959 | } else try self.addAtomAndBumpSectionSize(atom, match); |
| 2960 | |
| 2833 | 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 | } |
| 2836 | 2963 | |
| 2837 | 2964 | fn 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 | 2967 | const tracy = trace(@src()); |
| 2839 | 2968 | defer tracy.end(); |
| 2840 | 2969 | |
| ... | ... | @@ -2858,20 +2987,31 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2858 | 2987 | var it = object.end_atoms.iterator(); |
| 2859 | 2988 | while (it.next()) |entry| { |
| 2860 | 2989 | const match = entry.key_ptr.*; |
| 2861 | | const last_atom = entry.value_ptr.*; |
| 2862 | | var atom = last_atom; |
| 2990 | var atom = entry.value_ptr.*; |
| 2991 | |
| 2992 | while (atom.prev) |prev| { |
| 2993 | atom = prev; |
| 2994 | } |
| 2995 | |
| 2996 | const first_atom = atom; |
| 2863 | 2997 | |
| 2998 | const seg = self.load_commands.items[match.seg].Segment; |
| 2999 | const sect = seg.sections.items[match.sect]; |
| 2864 | 3000 | const metadata = try section_metadata.getOrPut(match); |
| 2865 | 3001 | if (!metadata.found_existing) { |
| 2866 | 3002 | metadata.value_ptr.* = .{ |
| 2867 | | .size = 0, |
| 2868 | | .alignment = 0, |
| 3003 | .size = sect.size, |
| 3004 | .alignment = sect.@"align", |
| 2869 | 3005 | }; |
| 2870 | 3006 | } |
| 2871 | 3007 | |
| 3008 | log.debug("{s},{s}", .{ commands.segmentName(sect), commands.sectionName(sect) }); |
| 3009 | |
| 2872 | 3010 | while (true) { |
| 2873 | 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 | 3015 | metadata.value_ptr.alignment = math.max(metadata.value_ptr.alignment, atom.alignment); |
| 2876 | 3016 | |
| 2877 | 3017 | const sym = self.locals.items[atom.local_sym_index]; |
| ... | ... | @@ -2882,20 +3022,20 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2882 | 3022 | atom.alignment, |
| 2883 | 3023 | }); |
| 2884 | 3024 | |
| 2885 | | if (atom.prev) |prev| { |
| 2886 | | atom = prev; |
| 3025 | if (atom.next) |next| { |
| 3026 | atom = next; |
| 2887 | 3027 | } else break; |
| 2888 | 3028 | } |
| 2889 | 3029 | |
| 2890 | 3030 | if (parsed_atoms.getPtr(match)) |last| { |
| 2891 | | last.*.next = atom; |
| 2892 | | atom.prev = last.*; |
| 2893 | | last.* = atom; |
| 3031 | last.*.next = first_atom; |
| 3032 | first_atom.prev = last.*; |
| 3033 | last.* = first_atom; |
| 2894 | 3034 | } |
| 2895 | | _ = try parsed_atoms.put(match, last_atom); |
| 3035 | _ = try parsed_atoms.put(match, atom); |
| 2896 | 3036 | |
| 2897 | 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 | } |
| 2901 | 3041 | |
| ... | ... | @@ -2915,67 +3055,85 @@ fn parseObjectsIntoAtoms(self: *MachO) !void { |
| 2915 | 3055 | metadata.alignment, |
| 2916 | 3056 | }); |
| 2917 | 3057 | |
| 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 | 3058 | sect.@"align" = math.max(sect.@"align", metadata.alignment); |
| 2924 | | const needed_size = @intCast(u32, metadata.size + sect_size); |
| 2925 | | try self.growSection(match, needed_size); |
| 3059 | const needed_size = @intCast(u32, metadata.size); |
| 3060 | |
| 3061 | if (self.needs_prealloc) { |
| 3062 | try self.growSection(match, needed_size); |
| 3063 | } |
| 2926 | 3064 | sect.size = needed_size; |
| 3065 | } |
| 2927 | 3066 | |
| 2928 | | var base_vaddr = if (self.atoms.get(match)) |last| blk: { |
| 2929 | | const last_atom_sym = self.locals.items[last.local_sym_index]; |
| 2930 | | break :blk last_atom_sym.n_value + last.size; |
| 2931 | | } else sect.addr; |
| 2932 | | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 3067 | for (&[_]?u16{ |
| 3068 | self.text_segment_cmd_index, |
| 3069 | self.data_const_segment_cmd_index, |
| 3070 | self.data_segment_cmd_index, |
| 3071 | }) |maybe_seg_id| { |
| 3072 | const seg_id = maybe_seg_id orelse continue; |
| 3073 | const seg = self.load_commands.items[seg_id].Segment; |
| 2933 | 3074 | |
| 2934 | | var atom = first_atoms.get(match).?; |
| 2935 | | while (true) { |
| 2936 | | const alignment = try math.powi(u32, 2, atom.alignment); |
| 2937 | | base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment); |
| 3075 | for (seg.sections.items) |sect, sect_id| { |
| 3076 | const match = MatchingSection{ |
| 3077 | .seg = seg_id, |
| 3078 | .sect = @intCast(u16, sect_id), |
| 3079 | }; |
| 3080 | if (!section_metadata.contains(match)) continue; |
| 3081 | |
| 3082 | var base_vaddr = if (self.atoms.get(match)) |last| blk: { |
| 3083 | const last_atom_sym = self.locals.items[last.local_sym_index]; |
| 3084 | break :blk last_atom_sym.n_value + last.size; |
| 3085 | } else sect.addr; |
| 3086 | |
| 3087 | if (self.atoms.getPtr(match)) |last| { |
| 3088 | const first_atom = first_atoms.get(match).?; |
| 3089 | last.*.next = first_atom; |
| 3090 | first_atom.prev = last.*; |
| 3091 | last.* = first_atom; |
| 3092 | } |
| 3093 | _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?); |
| 2938 | 3094 | |
| 2939 | | const sym = &self.locals.items[atom.local_sym_index]; |
| 2940 | | sym.n_value = base_vaddr; |
| 2941 | | sym.n_sect = n_sect; |
| 3095 | if (!self.needs_prealloc) continue; |
| 2942 | 3096 | |
| 2943 | | log.debug(" {s}: start=0x{x}, end=0x{x}, size=0x{x}, alignment=0x{x}", .{ |
| 2944 | | self.getString(sym.n_strx), |
| 2945 | | base_vaddr, |
| 2946 | | base_vaddr + atom.size, |
| 2947 | | atom.size, |
| 2948 | | atom.alignment, |
| 2949 | | }); |
| 3097 | const n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 2950 | 3098 | |
| 2951 | | // Update each alias (if any) |
| 2952 | | for (atom.aliases.items) |index| { |
| 2953 | | const alias_sym = &self.locals.items[index]; |
| 2954 | | alias_sym.n_value = base_vaddr; |
| 2955 | | alias_sym.n_sect = n_sect; |
| 2956 | | } |
| 3099 | var atom = first_atoms.get(match).?; |
| 3100 | while (true) { |
| 3101 | const alignment = try math.powi(u32, 2, atom.alignment); |
| 3102 | base_vaddr = mem.alignForwardGeneric(u64, base_vaddr, alignment); |
| 2957 | 3103 | |
| 2958 | | // Update each symbol contained within the atom |
| 2959 | | for (atom.contained.items) |sym_at_off| { |
| 2960 | | const contained_sym = &self.locals.items[sym_at_off.local_sym_index]; |
| 2961 | | contained_sym.n_value = base_vaddr + sym_at_off.offset; |
| 2962 | | contained_sym.n_sect = n_sect; |
| 2963 | | } |
| 3104 | const sym = &self.locals.items[atom.local_sym_index]; |
| 3105 | sym.n_value = base_vaddr; |
| 3106 | sym.n_sect = n_sect; |
| 2964 | 3107 | |
| 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 | }); |
| 2966 | 3115 | |
| 2967 | | if (atom.next) |next| { |
| 2968 | | atom = next; |
| 2969 | | } else break; |
| 2970 | | } |
| 3116 | // Update each alias (if any) |
| 3117 | for (atom.aliases.items) |index| { |
| 3118 | const alias_sym = &self.locals.items[index]; |
| 3119 | alias_sym.n_value = base_vaddr; |
| 3120 | alias_sym.n_sect = n_sect; |
| 3121 | } |
| 3122 | |
| 3123 | // Update each symbol contained within the atom |
| 3124 | for (atom.contained.items) |sym_at_off| { |
| 3125 | const contained_sym = &self.locals.items[sym_at_off.local_sym_index]; |
| 3126 | contained_sym.n_value = base_vaddr + sym_at_off.offset; |
| 3127 | contained_sym.n_sect = n_sect; |
| 3128 | } |
| 3129 | |
| 3130 | base_vaddr += atom.size; |
| 2971 | 3131 | |
| 2972 | | if (self.atoms.getPtr(match)) |last| { |
| 2973 | | const first_atom = first_atoms.get(match).?; |
| 2974 | | last.*.next = first_atom; |
| 2975 | | first_atom.prev = last.*; |
| 2976 | | last.* = first_atom; |
| 3132 | if (atom.next) |next| { |
| 3133 | atom = next; |
| 3134 | } else break; |
| 3135 | } |
| 2977 | 3136 | } |
| 2978 | | _ = try self.atoms.put(self.base.allocator, match, parsed_atoms.get(match).?); |
| 2979 | 3137 | } |
| 2980 | 3138 | } |
| 2981 | 3139 | |
| ... | ... | @@ -3714,7 +3872,9 @@ pub fn getDeclVAddr(self: *MachO, decl: *const Module.Decl) u64 { |
| 3714 | 3872 | return self.locals.items[decl.link.macho.local_sym_index].n_value; |
| 3715 | 3873 | } |
| 3716 | 3874 | |
| 3717 | | pub fn populateMissingMetadata(self: *MachO) !void { |
| 3875 | fn populateMissingMetadata(self: *MachO) !void { |
| 3876 | const cpu_arch = self.base.options.target.cpu.arch; |
| 3877 | |
| 3718 | 3878 | if (self.pagezero_segment_cmd_index == null) { |
| 3719 | 3879 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3720 | 3880 | try self.load_commands.append(self.base.allocator, .{ |
| ... | ... | @@ -3730,13 +3890,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3730 | 3890 | |
| 3731 | 3891 | if (self.text_segment_cmd_index == null) { |
| 3732 | 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; |
| 3734 | | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3735 | | const ideal_size = self.header_pad + program_code_size_hint + got_size_hint; |
| 3736 | | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3737 | | |
| 3738 | | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); |
| 3739 | | |
| 3893 | const needed_size = if (self.needs_prealloc) blk: { |
| 3894 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 3895 | const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3896 | const ideal_size = self.header_pad + program_code_size_hint + got_size_hint; |
| 3897 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3898 | log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size }); |
| 3899 | break :blk needed_size; |
| 3900 | } else 0; |
| 3740 | 3901 | try self.load_commands.append(self.base.allocator, .{ |
| 3741 | 3902 | .Segment = .{ |
| 3742 | 3903 | .inner = .{ |
| ... | ... | @@ -3753,13 +3914,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3753 | 3914 | } |
| 3754 | 3915 | |
| 3755 | 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 | 3918 | .x86_64 => 0, |
| 3758 | 3919 | .aarch64 => 2, |
| 3759 | 3920 | else => unreachable, // unhandled architecture type |
| 3760 | 3921 | }; |
| 3761 | | const needed_size = self.base.options.program_code_size_hint; |
| 3762 | | self.text_section_index = try self.allocateSection( |
| 3922 | const needed_size = if (self.needs_prealloc) self.base.options.program_code_size_hint else 0; |
| 3923 | self.text_section_index = try self.initSection( |
| 3763 | 3924 | self.text_segment_cmd_index.?, |
| 3764 | 3925 | "__text", |
| 3765 | 3926 | needed_size, |
| ... | ... | @@ -3771,18 +3932,18 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3771 | 3932 | } |
| 3772 | 3933 | |
| 3773 | 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 | 3936 | .x86_64 => 0, |
| 3776 | 3937 | .aarch64 => 2, |
| 3777 | 3938 | 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 | 3941 | .x86_64 => 6, |
| 3781 | 3942 | .aarch64 => 3 * @sizeOf(u32), |
| 3782 | 3943 | else => unreachable, // unhandled architecture type |
| 3783 | 3944 | }; |
| 3784 | | const needed_size = stub_size * self.base.options.symbol_count_hint; |
| 3785 | | self.stubs_section_index = try self.allocateSection( |
| 3945 | const needed_size = if (self.needs_prealloc) stub_size * self.base.options.symbol_count_hint else 0; |
| 3946 | self.stubs_section_index = try self.initSection( |
| 3786 | 3947 | self.text_segment_cmd_index.?, |
| 3787 | 3948 | "__stubs", |
| 3788 | 3949 | needed_size, |
| ... | ... | @@ -3795,23 +3956,26 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3795 | 3956 | } |
| 3796 | 3957 | |
| 3797 | 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 | 3960 | .x86_64 => 0, |
| 3800 | 3961 | .aarch64 => 2, |
| 3801 | 3962 | 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 | 3965 | .x86_64 => 15, |
| 3805 | 3966 | .aarch64 => 6 * @sizeOf(u32), |
| 3806 | 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 | 3970 | .x86_64 => 10, |
| 3810 | 3971 | .aarch64 => 3 * @sizeOf(u32), |
| 3811 | 3972 | else => unreachable, |
| 3812 | 3973 | }; |
| 3813 | | const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size; |
| 3814 | | self.stub_helper_section_index = try self.allocateSection( |
| 3974 | const needed_size = if (self.needs_prealloc) |
| 3975 | stub_size * self.base.options.symbol_count_hint + preamble_size |
| 3976 | else |
| 3977 | 0; |
| 3978 | self.stub_helper_section_index = try self.initSection( |
| 3815 | 3979 | self.text_segment_cmd_index.?, |
| 3816 | 3980 | "__stub_helper", |
| 3817 | 3981 | needed_size, |
| ... | ... | @@ -3824,22 +3988,27 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3824 | 3988 | |
| 3825 | 3989 | if (self.data_const_segment_cmd_index == null) { |
| 3826 | 3990 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3827 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3828 | | const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3829 | | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3830 | | |
| 3831 | | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ |
| 3832 | | address_and_offset.offset, |
| 3833 | | address_and_offset.offset + needed_size, |
| 3834 | | }); |
| 3835 | | |
| 3991 | var vmaddr: u64 = 0; |
| 3992 | var fileoff: u64 = 0; |
| 3993 | var needed_size: u64 = 0; |
| 3994 | if (self.needs_prealloc) { |
| 3995 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3996 | vmaddr = address_and_offset.address; |
| 3997 | fileoff = address_and_offset.offset; |
| 3998 | const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3999 | needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 4000 | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ |
| 4001 | fileoff, |
| 4002 | fileoff + needed_size, |
| 4003 | }); |
| 4004 | } |
| 3836 | 4005 | try self.load_commands.append(self.base.allocator, .{ |
| 3837 | 4006 | .Segment = .{ |
| 3838 | 4007 | .inner = .{ |
| 3839 | 4008 | .segname = makeStaticString("__DATA_CONST"), |
| 3840 | | .vmaddr = address_and_offset.address, |
| 4009 | .vmaddr = vmaddr, |
| 3841 | 4010 | .vmsize = needed_size, |
| 3842 | | .fileoff = address_and_offset.offset, |
| 4011 | .fileoff = fileoff, |
| 3843 | 4012 | .filesize = needed_size, |
| 3844 | 4013 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| 3845 | 4014 | .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| ... | ... | @@ -3850,9 +4019,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3850 | 4019 | } |
| 3851 | 4020 | |
| 3852 | 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 | 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 | 4028 | self.data_const_segment_cmd_index.?, |
| 3857 | 4029 | "__got", |
| 3858 | 4030 | needed_size, |
| ... | ... | @@ -3865,19 +4037,27 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3865 | 4037 | |
| 3866 | 4038 | if (self.data_segment_cmd_index == null) { |
| 3867 | 4039 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3868 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3869 | | const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 3870 | | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3871 | | |
| 3872 | | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size }); |
| 3873 | | |
| 4040 | var vmaddr: u64 = 0; |
| 4041 | var fileoff: u64 = 0; |
| 4042 | var needed_size: u64 = 0; |
| 4043 | if (self.needs_prealloc) { |
| 4044 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 4045 | vmaddr = address_and_offset.address; |
| 4046 | fileoff = address_and_offset.offset; |
| 4047 | const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 4048 | needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 4049 | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ |
| 4050 | fileoff, |
| 4051 | fileoff + needed_size, |
| 4052 | }); |
| 4053 | } |
| 3874 | 4054 | try self.load_commands.append(self.base.allocator, .{ |
| 3875 | 4055 | .Segment = .{ |
| 3876 | 4056 | .inner = .{ |
| 3877 | 4057 | .segname = makeStaticString("__DATA"), |
| 3878 | | .vmaddr = address_and_offset.address, |
| 4058 | .vmaddr = vmaddr, |
| 3879 | 4059 | .vmsize = needed_size, |
| 3880 | | .fileoff = address_and_offset.offset, |
| 4060 | .fileoff = fileoff, |
| 3881 | 4061 | .filesize = needed_size, |
| 3882 | 4062 | .maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| 3883 | 4063 | .initprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE, |
| ... | ... | @@ -3888,9 +4068,12 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3888 | 4068 | } |
| 3889 | 4069 | |
| 3890 | 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 | 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 | 4077 | self.data_segment_cmd_index.?, |
| 3895 | 4078 | "__la_symbol_ptr", |
| 3896 | 4079 | needed_size, |
| ... | ... | @@ -3902,9 +4085,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3902 | 4085 | } |
| 3903 | 4086 | |
| 3904 | 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 | 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 | 4091 | self.data_segment_cmd_index.?, |
| 3909 | 4092 | "__data", |
| 3910 | 4093 | needed_size, |
| ... | ... | @@ -3914,9 +4097,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3914 | 4097 | } |
| 3915 | 4098 | |
| 3916 | 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 | 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 | 4103 | self.data_segment_cmd_index.?, |
| 3921 | 4104 | "__thread_vars", |
| 3922 | 4105 | needed_size, |
| ... | ... | @@ -3928,9 +4111,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3928 | 4111 | } |
| 3929 | 4112 | |
| 3930 | 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 | 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 | 4117 | self.data_segment_cmd_index.?, |
| 3935 | 4118 | "__thread_data", |
| 3936 | 4119 | needed_size, |
| ... | ... | @@ -3942,9 +4125,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3942 | 4125 | } |
| 3943 | 4126 | |
| 3944 | 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 | 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 | 4131 | self.data_segment_cmd_index.?, |
| 3949 | 4132 | "__thread_bss", |
| 3950 | 4133 | needed_size, |
| ... | ... | @@ -3959,9 +4142,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3959 | 4142 | } |
| 3960 | 4143 | |
| 3961 | 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 | 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 | 4148 | self.data_segment_cmd_index.?, |
| 3966 | 4149 | "__bss", |
| 3967 | 4150 | needed_size, |
| ... | ... | @@ -3977,16 +4160,20 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3977 | 4160 | |
| 3978 | 4161 | if (self.linkedit_segment_cmd_index == null) { |
| 3979 | 4162 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3980 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 3981 | | |
| 3982 | | log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset}); |
| 3983 | | |
| 4163 | var vmaddr: u64 = 0; |
| 4164 | var fileoff: u64 = 0; |
| 4165 | if (self.needs_prealloc) { |
| 4166 | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 4167 | vmaddr = address_and_offset.address; |
| 4168 | fileoff = address_and_offset.offset; |
| 4169 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff}); |
| 4170 | } |
| 3984 | 4171 | try self.load_commands.append(self.base.allocator, .{ |
| 3985 | 4172 | .Segment = .{ |
| 3986 | 4173 | .inner = .{ |
| 3987 | 4174 | .segname = makeStaticString("__LINKEDIT"), |
| 3988 | | .vmaddr = address_and_offset.address, |
| 3989 | | .fileoff = address_and_offset.offset, |
| 4175 | .vmaddr = vmaddr, |
| 4176 | .fileoff = fileoff, |
| 3990 | 4177 | .maxprot = macho.VM_PROT_READ, |
| 3991 | 4178 | .initprot = macho.VM_PROT_READ, |
| 3992 | 4179 | }, |
| ... | ... | @@ -4198,44 +4385,123 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 4198 | 4385 | self.cold_start = true; |
| 4199 | 4386 | } |
| 4200 | 4387 | |
| 4201 | | const AllocateSectionOpts = struct { |
| 4388 | fn 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 | |
| 4425 | fn 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 | |
| 4433 | fn 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 | |
| 4441 | fn 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 | |
| 4448 | fn 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 | |
| 4467 | const InitSectionOpts = struct { |
| 4202 | 4468 | flags: u32 = macho.S_REGULAR, |
| 4203 | 4469 | reserved1: u32 = 0, |
| 4204 | 4470 | reserved2: u32 = 0, |
| 4205 | 4471 | }; |
| 4206 | 4472 | |
| 4207 | | fn allocateSection( |
| 4473 | fn initSection( |
| 4208 | 4474 | self: *MachO, |
| 4209 | 4475 | segment_id: u16, |
| 4210 | 4476 | sectname: []const u8, |
| 4211 | 4477 | size: u64, |
| 4212 | 4478 | alignment: u32, |
| 4213 | | opts: AllocateSectionOpts, |
| 4479 | opts: InitSectionOpts, |
| 4214 | 4480 | ) !u16 { |
| 4215 | 4481 | const seg = &self.load_commands.items[segment_id].Segment; |
| 4216 | 4482 | var sect = macho.section_64{ |
| 4217 | 4483 | .sectname = makeStaticString(sectname), |
| 4218 | 4484 | .segname = seg.inner.segname, |
| 4219 | | .size = @intCast(u32, size), |
| 4485 | .size = if (self.needs_prealloc) @intCast(u32, size) else 0, |
| 4220 | 4486 | .@"align" = alignment, |
| 4221 | 4487 | .flags = opts.flags, |
| 4222 | 4488 | .reserved1 = opts.reserved1, |
| 4223 | 4489 | .reserved2 = opts.reserved2, |
| 4224 | 4490 | }; |
| 4225 | 4491 | |
| 4226 | | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 4227 | | const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null; |
| 4228 | | const off = self.findFreeSpace(segment_id, alignment_pow_2, padding); |
| 4229 | | |
| 4230 | | log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{ |
| 4231 | | commands.segmentName(sect), |
| 4232 | | commands.sectionName(sect), |
| 4233 | | off, |
| 4234 | | off + size, |
| 4235 | | }); |
| 4236 | | |
| 4237 | | sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff; |
| 4238 | | sect.offset = @intCast(u32, off); |
| 4492 | if (self.needs_prealloc) { |
| 4493 | const alignment_pow_2 = try math.powi(u32, 2, alignment); |
| 4494 | const padding: ?u64 = if (segment_id == self.text_segment_cmd_index.?) self.header_pad else null; |
| 4495 | const off = self.findFreeSpace(segment_id, alignment_pow_2, padding); |
| 4496 | log.debug("allocating {s},{s} section from 0x{x} to 0x{x}", .{ |
| 4497 | commands.segmentName(sect), |
| 4498 | commands.sectionName(sect), |
| 4499 | off, |
| 4500 | off + size, |
| 4501 | }); |
| 4502 | sect.addr = seg.inner.vmaddr + off - seg.inner.fileoff; |
| 4503 | sect.offset = @intCast(u32, off); |
| 4504 | } |
| 4239 | 4505 | |
| 4240 | 4506 | const index = @intCast(u16, seg.sections.items.len); |
| 4241 | 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 | 4536 | const new_seg_size = mem.alignForwardGeneric(u64, new_size, self.page_size); |
| 4271 | 4537 | assert(new_seg_size > seg.inner.filesize); |
| 4272 | 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 | 4544 | seg.inner.filesize = new_seg_size; |
| 4275 | 4545 | seg.inner.vmsize = new_seg_size; |
| 4276 | 4546 | |
| ... | ... | @@ -4321,7 +4591,7 @@ fn growSegment(self: *MachO, seg_id: u16, new_size: u64) !void { |
| 4321 | 4591 | moved_sect.addr + moved_sect.size, |
| 4322 | 4592 | }); |
| 4323 | 4593 | |
| 4324 | | try self.allocateLocalSymbols(.{ |
| 4594 | try self.shiftLocalsByOffset(.{ |
| 4325 | 4595 | .seg = @intCast(u16, next), |
| 4326 | 4596 | .sect = @intCast(u16, moved_sect_id), |
| 4327 | 4597 | }, @intCast(i64, offset_amt)); |
| ... | ... | @@ -4395,7 +4665,7 @@ fn growSection(self: *MachO, match: MatchingSection, new_size: u32) !void { |
| 4395 | 4665 | moved_sect.addr + moved_sect.size, |
| 4396 | 4666 | }); |
| 4397 | 4667 | |
| 4398 | | try self.allocateLocalSymbols(.{ |
| 4668 | try self.shiftLocalsByOffset(.{ |
| 4399 | 4669 | .seg = match.seg, |
| 4400 | 4670 | .sect = next, |
| 4401 | 4671 | }, @intCast(i64, offset_amt)); |
| ... | ... | @@ -4534,6 +4804,21 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m |
| 4534 | 4804 | return vaddr; |
| 4535 | 4805 | } |
| 4536 | 4806 | |
| 4807 | fn 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 | |
| 4537 | 4822 | pub fn addExternFn(self: *MachO, name: []const u8) !u32 { |
| 4538 | 4823 | const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name}); |
| 4539 | 4824 | defer self.base.allocator.free(sym_name); |
| ... | ... | @@ -4580,6 +4865,160 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 4580 | 4865 | }; |
| 4581 | 4866 | } |
| 4582 | 4867 | |
| 4868 | fn 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 | |
| 4583 | 5022 | fn updateSectionOrdinals(self: *MachO) !void { |
| 4584 | 5023 | if (!self.sections_order_dirty) return; |
| 4585 | 5024 | |
| ... | ... | @@ -4957,7 +5396,7 @@ fn writeSymbolTable(self: *MachO) !void { |
| 4957 | 5396 | |
| 4958 | 5397 | for (self.locals.items) |sym| { |
| 4959 | 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 | 5400 | try locals.append(sym); |
| 4962 | 5401 | } |
| 4963 | 5402 | |
| ... | ... | @@ -5309,7 +5748,7 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 { |
| 5309 | 5748 | return new_off; |
| 5310 | 5749 | } |
| 5311 | 5750 | |
| 5312 | | pub fn getString(self: *MachO, off: u32) []const u8 { |
| 5751 | pub fn getString(self: MachO, off: u32) []const u8 { |
| 5313 | 5752 | assert(off < self.strtab.items.len); |
| 5314 | 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 | 6041 | try std.json.stringify(snapshot, .{}, writer); |
| 5603 | 6042 | try writer.writeByte(']'); |
| 5604 | 6043 | } |
| 6044 | |
| 6045 | fn 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 | |
| 6083 | fn 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 | } |