authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-19 23:37:21+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-19 23:37:21+01:00
log6712575e044ff56e17d0cf8329d8edcd462453f9
treea978c91beaef51c1b8219b0b6e6e3d37269c35c6
parentca1d03fe77b8f173870804580b868568c1d61fbd

macho: preallocate space for linkedit hidden sections;


1 files changed, 122 insertions(+), 5 deletions(-)

src/link/MachO.zig+122-5
...@@ -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}
17281759
1760inline 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
1729fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 {1769fn 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}
17401857