| ... | @@ -1273,6 +1273,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1273,6 +1273,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1273 | } | 1273 | } |
| 1274 | header.reserved = 0; | 1274 | header.reserved = 0; |
| 1275 | self.header = header; | 1275 | self.header = header; |
| | 1276 | self.cmd_table_dirty = true; |
| 1276 | } | 1277 | } |
| 1277 | if (self.pagezero_segment_cmd_index == null) { | 1278 | if (self.pagezero_segment_cmd_index == null) { |
| 1278 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); | 1279 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | @@ -1410,6 +1411,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1410,6 +1411,14 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1410 | } | 1411 | } |
| 1411 | if (self.dyld_info_cmd_index == null) { | 1412 | if (self.dyld_info_cmd_index == null) { |
| 1412 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); | 1413 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1414 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1415 | |
| | 1416 | // TODO Preallocate rebase, binding, and lazy binding info. |
| | 1417 | const export_size = 2; |
| | 1418 | const export_off = self.findFreeSpace(&linkedit_segment, export_size, 1); |
| | 1419 | |
| | 1420 | log.debug("found export info free space 0x{x} to 0x{x}\n", .{ export_off, export_off + export_size }); |
| | 1421 | |
| 1413 | try self.load_commands.append(self.base.allocator, .{ | 1422 | try self.load_commands.append(self.base.allocator, .{ |
| 1414 | .DyldInfoOnly = .{ | 1423 | .DyldInfoOnly = .{ |
| 1415 | .cmd = macho.LC_DYLD_INFO_ONLY, | 1424 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| ... | @@ -1430,6 +1439,18 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1430,6 +1439,18 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1430 | } | 1439 | } |
| 1431 | if (self.symtab_cmd_index == null) { | 1440 | if (self.symtab_cmd_index == null) { |
| 1432 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 1441 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1442 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1443 | |
| | 1444 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); |
| | 1445 | const symtab_off = self.findFreeSpace(&linkedit_segment, symtab_size, @sizeOf(macho.nlist_64)); |
| | 1446 | |
| | 1447 | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size }); |
| | 1448 | |
| | 1449 | const strtab_size = 1; |
| | 1450 | const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1); |
| | 1451 | |
| | 1452 | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size }); |
| | 1453 | |
| 1433 | try self.load_commands.append(self.base.allocator, .{ | 1454 | try self.load_commands.append(self.base.allocator, .{ |
| 1434 | .Symtab = .{ | 1455 | .Symtab = .{ |
| 1435 | .cmd = macho.LC_SYMTAB, | 1456 | .cmd = macho.LC_SYMTAB, |
| ... | @@ -1444,6 +1465,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1444,6 +1465,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1444 | } | 1465 | } |
| 1445 | if (self.dysymtab_cmd_index == null) { | 1466 | if (self.dysymtab_cmd_index == null) { |
| 1446 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); | 1467 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1468 | |
| | 1469 | // TODO Preallocate space for indirect symbol table. |
| | 1470 | |
| 1447 | try self.load_commands.append(self.base.allocator, .{ | 1471 | try self.load_commands.append(self.base.allocator, .{ |
| 1448 | .Dysymtab = .{ | 1472 | .Dysymtab = .{ |
| 1449 | .cmd = macho.LC_DYSYMTAB, | 1473 | .cmd = macho.LC_DYSYMTAB, |
| ... | @@ -1552,6 +1576,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1552,6 +1576,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1552 | } | 1576 | } |
| 1553 | if (self.code_signature_cmd_index == null) { | 1577 | if (self.code_signature_cmd_index == null) { |
| 1554 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); | 1578 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| | 1579 | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| | 1580 | |
| | 1581 | const codesig_size = 1; |
| | 1582 | const codesig_off = self.findFreeSpace(&linkedit_segment, codesig_size, @sizeOf(u64)); |
| | 1583 | |
| | 1584 | log.debug("found code signature free space 0x{x} to 0x{x}\n", .{ codesig_off, codesig_off + codesig_size }); |
| | 1585 | |
| 1555 | try self.load_commands.append(self.base.allocator, .{ | 1586 | try self.load_commands.append(self.base.allocator, .{ |
| 1556 | .LinkeditData = .{ | 1587 | .LinkeditData = .{ |
| 1557 | .cmd = macho.LC_CODE_SIGNATURE, | 1588 | .cmd = macho.LC_CODE_SIGNATURE, |
| ... | @@ -1726,15 +1757,101 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { | ... | @@ -1726,15 +1757,101 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 1726 | }; | 1757 | }; |
| 1727 | } | 1758 | } |
| 1728 | | 1759 | |
| | 1760 | inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 { |
| | 1761 | const increased_size = satMul(size, alloc_num) / alloc_den; |
| | 1762 | const test_end = off + increased_size; |
| | 1763 | if (end > off and start < test_end) { |
| | 1764 | return test_end; |
| | 1765 | } |
| | 1766 | return null; |
| | 1767 | } |
| | 1768 | |
| 1729 | fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 { | 1769 | fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 { |
| 1730 | const end = start + satMul(size, alloc_num) / alloc_den; | 1770 | const end = start + satMul(size, alloc_num) / alloc_den; |
| 1731 | for (segment.sections.items) |section| { | 1771 | |
| 1732 | const increased_size = satMul(section.size, alloc_num) / alloc_den; | 1772 | if (parseAndCmpName(&segment.inner.segname, "__LINKEDIT")) { |
| 1733 | const test_end = section.offset + increased_size; | 1773 | // __LINKEDIT is a weird segment where sections get their own load commands so we |
| 1734 | if (end > section.offset and start < test_end) { | 1774 | // special-case it. |
| 1735 | return test_end; | 1775 | if (self.dyld_info_cmd_index) |idx| outer: { |
| | 1776 | if (self.load_commands.items.len == idx) break :outer; |
| | 1777 | const dyld_info = self.load_commands.items[idx].DyldInfoOnly; |
| | 1778 | if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| { |
| | 1779 | return pos; |
| | 1780 | } |
| | 1781 | // Binding info |
| | 1782 | if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| { |
| | 1783 | return pos; |
| | 1784 | } |
| | 1785 | // Weak binding info |
| | 1786 | if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| { |
| | 1787 | return pos; |
| | 1788 | } |
| | 1789 | // Lazy binding info |
| | 1790 | if (checkForCollision(start, end, dyld_info.lazy_bind_off, dyld_info.lazy_bind_size)) |pos| { |
| | 1791 | return pos; |
| | 1792 | } |
| | 1793 | // Export info |
| | 1794 | if (checkForCollision(start, end, dyld_info.export_off, dyld_info.export_size)) |pos| { |
| | 1795 | return pos; |
| | 1796 | } |
| | 1797 | } |
| | 1798 | |
| | 1799 | if (self.function_starts_cmd_index) |idx| outer: { |
| | 1800 | if (self.load_commands.items.len == idx) break :outer; |
| | 1801 | const fstart = self.load_commands.items[idx].LinkeditData; |
| | 1802 | if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| { |
| | 1803 | return pos; |
| | 1804 | } |
| | 1805 | } |
| | 1806 | |
| | 1807 | if (self.data_in_code_cmd_index) |idx| outer: { |
| | 1808 | if (self.load_commands.items.len == idx) break :outer; |
| | 1809 | const dic = self.load_commands.items[idx].LinkeditData; |
| | 1810 | if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| { |
| | 1811 | return pos; |
| | 1812 | } |
| | 1813 | } |
| | 1814 | |
| | 1815 | if (self.dysymtab_cmd_index) |idx| outer: { |
| | 1816 | if (self.load_commands.items.len == idx) break :outer; |
| | 1817 | const dysymtab = self.load_commands.items[idx].Dysymtab; |
| | 1818 | // Indirect symbol table |
| | 1819 | const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32); |
| | 1820 | if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| { |
| | 1821 | return pos; |
| | 1822 | } |
| | 1823 | // TODO Handle more dynamic symbol table sections. |
| | 1824 | } |
| | 1825 | |
| | 1826 | if (self.symtab_cmd_index) |idx| outer: { |
| | 1827 | if (self.load_commands.items.len == idx) break :outer; |
| | 1828 | const symtab = self.load_commands.items[idx].Symtab; |
| | 1829 | // Symbol table |
| | 1830 | const symsize = symtab.nsyms * @sizeOf(macho.nlist_64); |
| | 1831 | if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| { |
| | 1832 | return pos; |
| | 1833 | } |
| | 1834 | // String table |
| | 1835 | if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| { |
| | 1836 | return pos; |
| | 1837 | } |
| | 1838 | } |
| | 1839 | |
| | 1840 | if (self.code_signature_cmd_index) |idx| outer: { |
| | 1841 | if (self.load_commands.items.len == idx) break :outer; |
| | 1842 | const codesig = self.load_commands.items[idx].LinkeditData; |
| | 1843 | if (checkForCollision(start, end, codesig.dataoff, codesig.datasize)) |pos| { |
| | 1844 | return pos; |
| | 1845 | } |
| | 1846 | } |
| | 1847 | } else { |
| | 1848 | for (segment.sections.items) |section| { |
| | 1849 | if (checkForCollision(start, end, section.offset, section.size)) |pos| { |
| | 1850 | return pos; |
| | 1851 | } |
| 1736 | } | 1852 | } |
| 1737 | } | 1853 | } |
| | 1854 | |
| 1738 | return null; | 1855 | return null; |
| 1739 | } | 1856 | } |
| 1740 | | 1857 | |