authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-26 20:55:11+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-31 10:19:04+01:00
loge1451f92f8e49f844c528386c4463c9b6fc9a0f3
treefc5a2922061adffe7544fe255d2c48b806a0cd50
parent595397dbeb17305d50f5995871fc2bf8f0377580

macho: move findFreeSpace into SegmentCommand

One exception will be treatment of the __LINKEDIT segment which will be handled separately inside MachO directly since it doesn't include any sections.

2 files changed, 142 insertions(+), 130 deletions(-)

src/link/MachO.zig+108-129
...@@ -155,8 +155,8 @@ pub const PieFixup = struct {...@@ -155,8 +155,8 @@ pub const PieFixup = struct {
155};155};
156156
157/// `alloc_num / alloc_den` is the factor of padding when allocating.157/// `alloc_num / alloc_den` is the factor of padding when allocating.
158const alloc_num = 4;158pub const alloc_num = 4;
159const alloc_den = 3;159pub const alloc_den = 3;
160160
161/// Default path to dyld161/// Default path to dyld
162/// TODO instead of hardcoding it, we should probably look through some env vars and search paths162/// TODO instead of hardcoding it, we should probably look through some env vars and search paths
...@@ -1358,7 +1358,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1358,7 +1358,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1358 };1358 };
1359 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;1359 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
1360 const needed_size = self.base.options.program_code_size_hint;1360 const needed_size = self.base.options.program_code_size_hint;
1361 const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment);1361 const off = text_segment.findFreeSpace(needed_size, @as(u16, 1) << alignment, self.header_pad);
13621362
1363 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1363 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
13641364
...@@ -1386,7 +1386,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1386,7 +1386,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13861386
1387 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;1387 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
1388 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;1388 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
1389 const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));1389 const off = text_segment.findFreeSpace(needed_size, @alignOf(u64), self.header_pad);
1390 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.1390 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
13911391
1392 log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size });1392 log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
...@@ -1437,11 +1437,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1437,11 +1437,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1437 }1437 }
1438 if (self.dyld_info_cmd_index == null) {1438 if (self.dyld_info_cmd_index == null) {
1439 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);1439 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
1440 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
14411440
1442 // TODO Preallocate rebase, binding, and lazy binding info.1441 // TODO Preallocate rebase, binding, and lazy binding info.
1443 const export_size = 2;1442 const export_size = 2;
1444 const export_off = self.findFreeSpace(&linkedit_segment, export_size, 1);1443 const export_off = self.findFreeSpaceLinkedit(export_size, 1);
14451444
1446 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + export_size });1445 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
14471446
...@@ -1466,16 +1465,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1466,16 +1465,15 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1466 }1465 }
1467 if (self.symtab_cmd_index == null) {1466 if (self.symtab_cmd_index == null) {
1468 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);1467 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
1469 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
14701468
1471 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);1469 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);
1472 const symtab_off = self.findFreeSpace(&linkedit_segment, symtab_size, @sizeOf(macho.nlist_64));1470 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64));
14731471
1474 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });1472 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
14751473
1476 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.1474 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
1477 const strtab_size = self.string_table.items.len;1475 const strtab_size = self.string_table.items.len;
1478 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);1476 const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1);
14791477
1480 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });1478 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
14811479
...@@ -1613,7 +1611,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1613,7 +1611,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1613 }1611 }
1614 if (self.code_signature_cmd_index == null) {1612 if (self.code_signature_cmd_index == null) {
1615 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);1613 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
1616 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1617 try self.load_commands.append(self.base.allocator, .{1614 try self.load_commands.append(self.base.allocator, .{
1618 .LinkeditData = .{1615 .LinkeditData = .{
1619 .cmd = macho.LC_CODE_SIGNATURE,1616 .cmd = macho.LC_CODE_SIGNATURE,
...@@ -1790,48 +1787,41 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {...@@ -1790,48 +1787,41 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
1790 };1787 };
1791}1788}
17921789
1793fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 {1790fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 {
1794 assert(start > 0);1791 assert(start > 0);
1795 var min_pos: u64 = std.math.maxInt(u64);1792 var min_pos: u64 = std.math.maxInt(u64);
17961793
1797 if (parseAndCmpName(&segment.inner.segname, "__LINKEDIT")) {1794 // __LINKEDIT is a weird segment where sections get their own load commands so we
1798 assert(segment.sections.items.len == 0);1795 // special-case it.
1799 // __LINKEDIT is a weird segment where sections get their own load commands so we1796 if (self.dyld_info_cmd_index) |idx| {
1800 // special-case it.1797 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1801 if (self.dyld_info_cmd_index) |idx| {1798 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
1802 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;1799 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;
1803 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;1800 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off;
1804 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;1801 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;
1805 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off;1802 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1806 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;1803 }
1807 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1808 }
18091804
1810 if (self.function_starts_cmd_index) |idx| {1805 if (self.function_starts_cmd_index) |idx| {
1811 const fstart = self.load_commands.items[idx].LinkeditData;1806 const fstart = self.load_commands.items[idx].LinkeditData;
1812 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;1807 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;
1813 }1808 }
18141809
1815 if (self.data_in_code_cmd_index) |idx| {1810 if (self.data_in_code_cmd_index) |idx| {
1816 const dic = self.load_commands.items[idx].LinkeditData;1811 const dic = self.load_commands.items[idx].LinkeditData;
1817 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;1812 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;
1818 }1813 }
18191814
1820 if (self.dysymtab_cmd_index) |idx| {1815 if (self.dysymtab_cmd_index) |idx| {
1821 const dysymtab = self.load_commands.items[idx].Dysymtab;1816 const dysymtab = self.load_commands.items[idx].Dysymtab;
1822 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;1817 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;
1823 // TODO Handle more dynamic symbol table sections.1818 // TODO Handle more dynamic symbol table sections.
1824 }1819 }
18251820
1826 if (self.symtab_cmd_index) |idx| {1821 if (self.symtab_cmd_index) |idx| {
1827 const symtab = self.load_commands.items[idx].Symtab;1822 const symtab = self.load_commands.items[idx].Symtab;
1828 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;1823 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
1829 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;1824 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;
1830 }
1831 } else {
1832 for (segment.sections.items) |section| {
1833 if (section.offset > start and section.offset < min_pos) min_pos = section.offset;
1834 }
1835 }1825 }
18361826
1837 return min_pos - start;1827 return min_pos - start;
...@@ -1846,101 +1836,90 @@ inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 {...@@ -1846,101 +1836,90 @@ inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 {
1846 return null;1836 return null;
1847}1837}
18481838
1849fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 {1839fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 {
1850 const end = start + satMul(size, alloc_num) / alloc_den;1840 const end = start + satMul(size, alloc_num) / alloc_den;
18511841
1852 if (parseAndCmpName(&segment.inner.segname, "__LINKEDIT")) {1842 // __LINKEDIT is a weird segment where sections get their own load commands so we
1853 assert(segment.sections.items.len == 0);1843 // special-case it.
1854 // __LINKEDIT is a weird segment where sections get their own load commands so we1844 if (self.dyld_info_cmd_index) |idx| outer: {
1855 // special-case it.1845 if (self.load_commands.items.len == idx) break :outer;
1856 if (self.dyld_info_cmd_index) |idx| outer: {1846 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1857 if (self.load_commands.items.len == idx) break :outer;1847 if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| {
1858 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;1848 return pos;
1859 if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| {1849 }
1860 return pos;1850 // Binding info
1861 }1851 if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| {
1862 // Binding info1852 return pos;
1863 if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| {1853 }
1864 return pos;1854 // Weak binding info
1865 }1855 if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| {
1866 // Weak binding info1856 return pos;
1867 if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| {1857 }
1868 return pos;1858 // Lazy binding info
1869 }1859 if (checkForCollision(start, end, dyld_info.lazy_bind_off, dyld_info.lazy_bind_size)) |pos| {
1870 // Lazy binding info1860 return pos;
1871 if (checkForCollision(start, end, dyld_info.lazy_bind_off, dyld_info.lazy_bind_size)) |pos| {
1872 return pos;
1873 }
1874 // Export info
1875 if (checkForCollision(start, end, dyld_info.export_off, dyld_info.export_size)) |pos| {
1876 return pos;
1877 }
1878 }1861 }
1862 // Export info
1863 if (checkForCollision(start, end, dyld_info.export_off, dyld_info.export_size)) |pos| {
1864 return pos;
1865 }
1866 }
18791867
1880 if (self.function_starts_cmd_index) |idx| outer: {1868 if (self.function_starts_cmd_index) |idx| outer: {
1881 if (self.load_commands.items.len == idx) break :outer;1869 if (self.load_commands.items.len == idx) break :outer;
1882 const fstart = self.load_commands.items[idx].LinkeditData;1870 const fstart = self.load_commands.items[idx].LinkeditData;
1883 if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| {1871 if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| {
1884 return pos;1872 return pos;
1885 }
1886 }1873 }
1874 }
18871875
1888 if (self.data_in_code_cmd_index) |idx| outer: {1876 if (self.data_in_code_cmd_index) |idx| outer: {
1889 if (self.load_commands.items.len == idx) break :outer;1877 if (self.load_commands.items.len == idx) break :outer;
1890 const dic = self.load_commands.items[idx].LinkeditData;1878 const dic = self.load_commands.items[idx].LinkeditData;
1891 if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| {1879 if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| {
1892 return pos;1880 return pos;
1893 }
1894 }1881 }
1882 }
18951883
1896 if (self.dysymtab_cmd_index) |idx| outer: {1884 if (self.dysymtab_cmd_index) |idx| outer: {
1897 if (self.load_commands.items.len == idx) break :outer;1885 if (self.load_commands.items.len == idx) break :outer;
1898 const dysymtab = self.load_commands.items[idx].Dysymtab;1886 const dysymtab = self.load_commands.items[idx].Dysymtab;
1899 // Indirect symbol table1887 // Indirect symbol table
1900 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);1888 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
1901 if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| {1889 if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| {
1902 return pos;1890 return pos;
1903 }
1904 // TODO Handle more dynamic symbol table sections.
1905 }1891 }
1892 // TODO Handle more dynamic symbol table sections.
1893 }
19061894
1907 if (self.symtab_cmd_index) |idx| outer: {1895 if (self.symtab_cmd_index) |idx| outer: {
1908 if (self.load_commands.items.len == idx) break :outer;1896 if (self.load_commands.items.len == idx) break :outer;
1909 const symtab = self.load_commands.items[idx].Symtab;1897 const symtab = self.load_commands.items[idx].Symtab;
1910 // Symbol table1898 // Symbol table
1911 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);1899 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
1912 if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| {1900 if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| {
1913 return pos;1901 return pos;
1914 }
1915 // String table
1916 if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| {
1917 return pos;
1918 }
1919 }1902 }
1920 } else {1903 // String table
1921 for (segment.sections.items) |section| {1904 if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| {
1922 if (checkForCollision(start, end, section.offset, section.size)) |pos| {1905 return pos;
1923 return pos;
1924 }
1925 }1906 }
1926 }1907 }
19271908
1928 return null;1909 return null;
1929}1910}
19301911
1931fn findFreeSpace(self: *MachO, segment: *const SegmentCommand, object_size: u64, min_alignment: u16) u64 {1912fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16) u64 {
1932 var start: u64 = if (parseAndCmpName(&segment.inner.segname, "__TEXT"))1913 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1933 self.header_pad1914 var start: u64 = linkedit.inner.fileoff;
1934 else1915 while (self.detectAllocCollisionLinkedit(start, object_size)) |item_end| {
1935 segment.inner.fileoff;
1936 while (self.detectAllocCollision(segment, start, object_size)) |item_end| {
1937 start = mem.alignForwardGeneric(u64, item_end, min_alignment);1916 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
1938 }1917 }
1939 return start;1918 return start;
1940}1919}
19411920
1942/// Saturating multiplication1921/// Saturating multiplication
1943fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {1922pub fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
1944 const T = @TypeOf(a, b);1923 const T = @TypeOf(a, b);
1945 return std.math.mul(T, a, b) catch std.math.maxInt(T);1924 return std.math.mul(T, a, b) catch std.math.maxInt(T);
1946}1925}
...@@ -1993,9 +1972,9 @@ fn relocateSymbolTable(self: *MachO) !void {...@@ -1993,9 +1972,9 @@ fn relocateSymbolTable(self: *MachO) !void {
1993 if (symtab.nsyms < nsyms) {1972 if (symtab.nsyms < nsyms) {
1994 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;1973 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1995 const needed_size = nsyms * @sizeOf(macho.nlist_64);1974 const needed_size = nsyms * @sizeOf(macho.nlist_64);
1996 if (needed_size > self.allocatedSize(&linkedit_segment, symtab.symoff)) {1975 if (needed_size > self.allocatedSizeLinkedit(symtab.symoff)) {
1997 // Move the entire symbol table to a new location1976 // Move the entire symbol table to a new location
1998 const new_symoff = self.findFreeSpace(&linkedit_segment, needed_size, @alignOf(macho.nlist_64));1977 const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64));
1999 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);1978 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
20001979
2001 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{1980 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
...@@ -2140,12 +2119,12 @@ fn writeExportTrie(self: *MachO) !void {...@@ -2140,12 +2119,12 @@ fn writeExportTrie(self: *MachO) !void {
21402119
2141 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2120 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2142 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2121 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2143 const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.export_off);2122 const allocated_size = self.allocatedSizeLinkedit(dyld_info.export_off);
2144 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));2123 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
21452124
2146 if (needed_size > allocated_size) {2125 if (needed_size > allocated_size) {
2147 dyld_info.export_off = 0;2126 dyld_info.export_off = 0;
2148 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2127 dyld_info.export_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1));
2149 }2128 }
2150 dyld_info.export_size = @intCast(u32, needed_size);2129 dyld_info.export_size = @intCast(u32, needed_size);
2151 log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });2130 log.debug("writing export info from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
...@@ -2170,12 +2149,12 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2170,12 +2149,12 @@ fn writeBindingInfoTable(self: *MachO) !void {
21702149
2171 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2150 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2172 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2151 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2173 const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.bind_off);2152 const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off);
2174 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));2153 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
21752154
2176 if (needed_size > allocated_size) {2155 if (needed_size > allocated_size) {
2177 dyld_info.bind_off = 0;2156 dyld_info.bind_off = 0;
2178 dyld_info.bind_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2157 dyld_info.bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1));
2179 }2158 }
21802159
2181 dyld_info.bind_size = @intCast(u32, needed_size);2160 dyld_info.bind_size = @intCast(u32, needed_size);
...@@ -2198,12 +2177,12 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2198,12 +2177,12 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
21982177
2199 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2178 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2200 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2179 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2201 const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.lazy_bind_off);2180 const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off);
2202 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));2181 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
22032182
2204 if (needed_size > allocated_size) {2183 if (needed_size > allocated_size) {
2205 dyld_info.lazy_bind_off = 0;2184 dyld_info.lazy_bind_off = 0;
2206 dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2185 dyld_info.lazy_bind_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1));
2207 }2186 }
22082187
2209 dyld_info.lazy_bind_size = @intCast(u32, needed_size);2188 dyld_info.lazy_bind_size = @intCast(u32, needed_size);
...@@ -2222,12 +2201,12 @@ fn writeStringTable(self: *MachO) !void {...@@ -2222,12 +2201,12 @@ fn writeStringTable(self: *MachO) !void {
22222201
2223 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2202 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2224 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2203 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2225 const allocated_size = self.allocatedSize(&linkedit_segment, symtab.stroff);2204 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
2226 const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64));2205 const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64));
22272206
2228 if (needed_size > allocated_size) {2207 if (needed_size > allocated_size) {
2229 symtab.strsize = 0;2208 symtab.strsize = 0;
2230 symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2209 symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1));
2231 }2210 }
2232 symtab.strsize = @intCast(u32, needed_size);2211 symtab.strsize = @intCast(u32, needed_size);
2233 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });2212 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
...@@ -2280,7 +2259,7 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {...@@ -2280,7 +2259,7 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {
2280 const filesize = final_offset - linkedit_segment.inner.fileoff;2259 const filesize = final_offset - linkedit_segment.inner.fileoff;
2281 linkedit_segment.inner.filesize = filesize;2260 linkedit_segment.inner.filesize = filesize;
2282 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);2261 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
2283 try self.base.file.?.pwriteAll(&[_]u8{ 0 }, final_offset);2262 try self.base.file.?.pwriteAll(&[_]u8{0}, final_offset);
2284 self.load_commands_dirty = true;2263 self.load_commands_dirty = true;
2285}2264}
22862265
...@@ -2301,7 +2280,7 @@ fn writeLoadCommands(self: *MachO) !void {...@@ -2301,7 +2280,7 @@ fn writeLoadCommands(self: *MachO) !void {
2301 }2280 }
23022281
2303 const off = @sizeOf(macho.mach_header_64);2282 const off = @sizeOf(macho.mach_header_64);
2304 log.debug("writing {} load commands from 0x{x} to 0x{x}", .{self.load_commands.items.len, off, off + sizeofcmds});2283 log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds });
2305 try self.base.file.?.pwriteAll(buffer, off);2284 try self.base.file.?.pwriteAll(buffer, off);
2306 self.load_commands_dirty = false;2285 self.load_commands_dirty = false;
2307}2286}
src/link/MachO/commands.zig+34-1
...@@ -7,7 +7,11 @@ const macho = std.macho;...@@ -7,7 +7,11 @@ const macho = std.macho;
7const testing = std.testing;7const testing = std.testing;
88
9const Allocator = std.mem.Allocator;9const Allocator = std.mem.Allocator;
10const makeStaticString = @import("../MachO.zig").makeStaticString;10const MachO = @import("../MachO.zig");
11const makeStaticString = MachO.makeStaticString;
12const satMul = MachO.satMul;
13const alloc_num = MachO.alloc_num;
14const alloc_den = MachO.alloc_den;
1115
12pub const LoadCommand = union(enum) {16pub const LoadCommand = union(enum) {
13 Segment: SegmentCommand,17 Segment: SegmentCommand,
...@@ -188,6 +192,35 @@ pub const SegmentCommand = struct {...@@ -188,6 +192,35 @@ pub const SegmentCommand = struct {
188 self.sections.deinit(alloc);192 self.sections.deinit(alloc);
189 }193 }
190194
195 pub fn allocatedSize(self: SegmentCommand, start: u64) u64 {
196 assert(start > 0);
197 var min_pos: u64 = std.math.maxInt(u64);
198 for (self.sections.items) |section| {
199 if (section.offset > start and section.offset < min_pos) min_pos = section.offset;
200 }
201 return min_pos - start;
202 }
203
204 fn detectAllocCollision(self: SegmentCommand, start: u64, size: u64) ?u64 {
205 const end = start + satMul(size, alloc_num) / alloc_den;
206 for (self.sections.items) |section| {
207 const increased_size = satMul(section.size, alloc_num) / alloc_den;
208 const test_end = section.offset + increased_size;
209 if (end > section.offset and start < test_end) {
210 return test_end;
211 }
212 }
213 return null;
214 }
215
216 pub fn findFreeSpace(self: SegmentCommand, object_size: u64, min_alignment: u16, start: ?u64) u64 {
217 var st: u64 = if (start) |v| v else self.inner.fileoff;
218 while (self.detectAllocCollision(st, object_size)) |item_end| {
219 st = mem.alignForwardGeneric(u64, item_end, min_alignment);
220 }
221 return st;
222 }
223
191 fn eql(self: SegmentCommand, other: SegmentCommand) bool {224 fn eql(self: SegmentCommand, other: SegmentCommand) bool {
192 if (!meta.eql(self.inner, other.inner)) return false;225 if (!meta.eql(self.inner, other.inner)) return false;
193 const lhs = self.sections.items;226 const lhs = self.sections.items;