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 {
155155};
156156
157157/// `alloc_num / alloc_den` is the factor of padding when allocating.
158const alloc_num = 4;
159const alloc_den = 3;
158pub const alloc_num = 4;
159pub const alloc_den = 3;
160160
161161/// Default path to dyld
162162/// 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 {
13581358 };
13591359 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
13601360 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
13631363 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 {
13861386
13871387 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
13881388 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);
13901390 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
13911391
13921392 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 {
14371437 }
14381438 if (self.dyld_info_cmd_index == null) {
14391439 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
14421441 // TODO Preallocate rebase, binding, and lazy binding info.
14431442 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
14461445 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 {
14661465 }
14671466 if (self.symtab_cmd_index == null) {
14681467 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
14711469 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
14741472 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
14751473
14761474 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
14771475 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
14801478 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 {
16131611 }
16141612 if (self.code_signature_cmd_index == null) {
16151613 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;
16171614 try self.load_commands.append(self.base.allocator, .{
16181615 .LinkeditData = .{
16191616 .cmd = macho.LC_CODE_SIGNATURE,
......@@ -1790,48 +1787,41 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
17901787 };
17911788}
17921789
1793fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 {
1790fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 {
17941791 assert(start > 0);
17951792 var min_pos: u64 = std.math.maxInt(u64);
17961793
1797 if (parseAndCmpName(&segment.inner.segname, "__LINKEDIT")) {
1798 assert(segment.sections.items.len == 0);
1799 // __LINKEDIT is a weird segment where sections get their own load commands so we
1800 // special-case it.
1801 if (self.dyld_info_cmd_index) |idx| {
1802 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1803 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
1804 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.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;
1806 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;
1807 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1808 }
1794 // __LINKEDIT is a weird segment where sections get their own load commands so we
1795 // special-case it.
1796 if (self.dyld_info_cmd_index) |idx| {
1797 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1798 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
1799 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;
1800 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_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;
1802 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1803 }
18091804
1810 if (self.function_starts_cmd_index) |idx| {
1811 const fstart = self.load_commands.items[idx].LinkeditData;
1812 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;
1813 }
1805 if (self.function_starts_cmd_index) |idx| {
1806 const fstart = self.load_commands.items[idx].LinkeditData;
1807 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;
1808 }
18141809
1815 if (self.data_in_code_cmd_index) |idx| {
1816 const dic = self.load_commands.items[idx].LinkeditData;
1817 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;
1818 }
1810 if (self.data_in_code_cmd_index) |idx| {
1811 const dic = self.load_commands.items[idx].LinkeditData;
1812 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;
1813 }
18191814
1820 if (self.dysymtab_cmd_index) |idx| {
1821 const dysymtab = self.load_commands.items[idx].Dysymtab;
1822 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;
1823 // TODO Handle more dynamic symbol table sections.
1824 }
1815 if (self.dysymtab_cmd_index) |idx| {
1816 const dysymtab = self.load_commands.items[idx].Dysymtab;
1817 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;
1818 // TODO Handle more dynamic symbol table sections.
1819 }
18251820
1826 if (self.symtab_cmd_index) |idx| {
1827 const symtab = self.load_commands.items[idx].Symtab;
1828 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;
1830 }
1831 } else {
1832 for (segment.sections.items) |section| {
1833 if (section.offset > start and section.offset < min_pos) min_pos = section.offset;
1834 }
1821 if (self.symtab_cmd_index) |idx| {
1822 const symtab = self.load_commands.items[idx].Symtab;
1823 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
1824 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;
18351825 }
18361826
18371827 return min_pos - start;
......@@ -1846,101 +1836,90 @@ inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 {
18461836 return null;
18471837}
18481838
1849fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64, size: u64) ?u64 {
1839fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 {
18501840 const end = start + satMul(size, alloc_num) / alloc_den;
18511841
1852 if (parseAndCmpName(&segment.inner.segname, "__LINKEDIT")) {
1853 assert(segment.sections.items.len == 0);
1854 // __LINKEDIT is a weird segment where sections get their own load commands so we
1855 // special-case it.
1856 if (self.dyld_info_cmd_index) |idx| outer: {
1857 if (self.load_commands.items.len == idx) break :outer;
1858 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1859 if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| {
1860 return pos;
1861 }
1862 // Binding info
1863 if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| {
1864 return pos;
1865 }
1866 // Weak binding info
1867 if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| {
1868 return pos;
1869 }
1870 // Lazy binding info
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 }
1842 // __LINKEDIT is a weird segment where sections get their own load commands so we
1843 // special-case it.
1844 if (self.dyld_info_cmd_index) |idx| outer: {
1845 if (self.load_commands.items.len == idx) break :outer;
1846 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1847 if (checkForCollision(start, end, dyld_info.rebase_off, dyld_info.rebase_size)) |pos| {
1848 return pos;
1849 }
1850 // Binding info
1851 if (checkForCollision(start, end, dyld_info.bind_off, dyld_info.bind_size)) |pos| {
1852 return pos;
1853 }
1854 // Weak binding info
1855 if (checkForCollision(start, end, dyld_info.weak_bind_off, dyld_info.weak_bind_size)) |pos| {
1856 return pos;
1857 }
1858 // Lazy binding info
1859 if (checkForCollision(start, end, dyld_info.lazy_bind_off, dyld_info.lazy_bind_size)) |pos| {
1860 return pos;
18781861 }
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: {
1881 if (self.load_commands.items.len == idx) break :outer;
1882 const fstart = self.load_commands.items[idx].LinkeditData;
1883 if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| {
1884 return pos;
1885 }
1868 if (self.function_starts_cmd_index) |idx| outer: {
1869 if (self.load_commands.items.len == idx) break :outer;
1870 const fstart = self.load_commands.items[idx].LinkeditData;
1871 if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| {
1872 return pos;
18861873 }
1874 }
18871875
1888 if (self.data_in_code_cmd_index) |idx| outer: {
1889 if (self.load_commands.items.len == idx) break :outer;
1890 const dic = self.load_commands.items[idx].LinkeditData;
1891 if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| {
1892 return pos;
1893 }
1876 if (self.data_in_code_cmd_index) |idx| outer: {
1877 if (self.load_commands.items.len == idx) break :outer;
1878 const dic = self.load_commands.items[idx].LinkeditData;
1879 if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| {
1880 return pos;
18941881 }
1882 }
18951883
1896 if (self.dysymtab_cmd_index) |idx| outer: {
1897 if (self.load_commands.items.len == idx) break :outer;
1898 const dysymtab = self.load_commands.items[idx].Dysymtab;
1899 // Indirect symbol table
1900 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
1901 if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| {
1902 return pos;
1903 }
1904 // TODO Handle more dynamic symbol table sections.
1884 if (self.dysymtab_cmd_index) |idx| outer: {
1885 if (self.load_commands.items.len == idx) break :outer;
1886 const dysymtab = self.load_commands.items[idx].Dysymtab;
1887 // Indirect symbol table
1888 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
1889 if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| {
1890 return pos;
19051891 }
1892 // TODO Handle more dynamic symbol table sections.
1893 }
19061894
1907 if (self.symtab_cmd_index) |idx| outer: {
1908 if (self.load_commands.items.len == idx) break :outer;
1909 const symtab = self.load_commands.items[idx].Symtab;
1910 // Symbol table
1911 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
1912 if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| {
1913 return pos;
1914 }
1915 // String table
1916 if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| {
1917 return pos;
1918 }
1895 if (self.symtab_cmd_index) |idx| outer: {
1896 if (self.load_commands.items.len == idx) break :outer;
1897 const symtab = self.load_commands.items[idx].Symtab;
1898 // Symbol table
1899 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
1900 if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| {
1901 return pos;
19191902 }
1920 } else {
1921 for (segment.sections.items) |section| {
1922 if (checkForCollision(start, end, section.offset, section.size)) |pos| {
1923 return pos;
1924 }
1903 // String table
1904 if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| {
1905 return pos;
19251906 }
19261907 }
19271908
19281909 return null;
19291910}
19301911
1931fn findFreeSpace(self: *MachO, segment: *const SegmentCommand, object_size: u64, min_alignment: u16) u64 {
1932 var start: u64 = if (parseAndCmpName(&segment.inner.segname, "__TEXT"))
1933 self.header_pad
1934 else
1935 segment.inner.fileoff;
1936 while (self.detectAllocCollision(segment, start, object_size)) |item_end| {
1912fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16) u64 {
1913 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1914 var start: u64 = linkedit.inner.fileoff;
1915 while (self.detectAllocCollisionLinkedit(start, object_size)) |item_end| {
19371916 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
19381917 }
19391918 return start;
19401919}
19411920
19421921/// Saturating multiplication
1943fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
1922pub fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
19441923 const T = @TypeOf(a, b);
19451924 return std.math.mul(T, a, b) catch std.math.maxInt(T);
19461925}
......@@ -1993,9 +1972,9 @@ fn relocateSymbolTable(self: *MachO) !void {
19931972 if (symtab.nsyms < nsyms) {
19941973 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
19951974 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)) {
19971976 // 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));
19991978 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
20001979
20011980 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
......@@ -2140,12 +2119,12 @@ fn writeExportTrie(self: *MachO) !void {
21402119
21412120 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
21422121 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);
21442123 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
21452124
21462125 if (needed_size > allocated_size) {
21472126 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));
21492128 }
21502129 dyld_info.export_size = @intCast(u32, needed_size);
21512130 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 {
21702149
21712150 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
21722151 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);
21742153 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
21752154
21762155 if (needed_size > allocated_size) {
21772156 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));
21792158 }
21802159
21812160 dyld_info.bind_size = @intCast(u32, needed_size);
......@@ -2198,12 +2177,12 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
21982177
21992178 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
22002179 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);
22022181 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
22032182
22042183 if (needed_size > allocated_size) {
22052184 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));
22072186 }
22082187
22092188 dyld_info.lazy_bind_size = @intCast(u32, needed_size);
......@@ -2222,12 +2201,12 @@ fn writeStringTable(self: *MachO) !void {
22222201
22232202 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
22242203 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);
22262205 const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64));
22272206
22282207 if (needed_size > allocated_size) {
22292208 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));
22312210 }
22322211 symtab.strsize = @intCast(u32, needed_size);
22332212 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 {
22802259 const filesize = final_offset - linkedit_segment.inner.fileoff;
22812260 linkedit_segment.inner.filesize = filesize;
22822261 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);
22842263 self.load_commands_dirty = true;
22852264}
22862265
......@@ -2301,7 +2280,7 @@ fn writeLoadCommands(self: *MachO) !void {
23012280 }
23022281
23032282 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 });
23052284 try self.base.file.?.pwriteAll(buffer, off);
23062285 self.load_commands_dirty = false;
23072286}
src/link/MachO/commands.zig+34-1
......@@ -7,7 +7,11 @@ const macho = std.macho;
77const testing = std.testing;
88
99const 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
1216pub const LoadCommand = union(enum) {
1317 Segment: SegmentCommand,
......@@ -188,6 +192,35 @@ pub const SegmentCommand = struct {
188192 self.sections.deinit(alloc);
189193 }
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
191224 fn eql(self: SegmentCommand, other: SegmentCommand) bool {
192225 if (!meta.eql(self.inner, other.inner)) return false;
193226 const lhs = self.sections.items;