authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-21 15:13:04+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-21 17:03:55+01:00
loga1b3606f0e53755778e408188a08a98b950e62ac
treed15d25584a2cc325afa2635faa395ecc6e744617
parent3f7dbde92af9dbcc657b0f3dffb68adf90d68989

macho: dynamically preallocate space for LINKEDIT sections as well


1 files changed, 181 insertions(+), 110 deletions(-)

src/link/MachO.zig+181-110
......@@ -84,9 +84,6 @@ got_section_index: ?u16 = null,
8484/// The absolute address of the entry point.
8585entry_addr: ?u64 = null,
8686
87/// TODO move this into each Segment aggregator
88linkedit_segment_next_offset: ?u32 = null,
89
9087/// Table of all local symbols
9188/// Internally references string table for names (which are optional).
9289local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},
......@@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
319316 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
320317 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
321318 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
319 self.cmd_table_dirty = true;
322320 }
323321 try self.writeExportTrie();
324 try self.writeSymbolTable();
322 try self.writeAllGlobalAndUndefSymbols();
325323 try self.writeStringTable();
324 try self.updateLinkeditSegmentSizes();
326325
327326 if (target.cpu.arch == .aarch64) {
328327 // Preallocate space for the code signature.
......@@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
870869 return error.NotEnoughPadding;
871870 }
872871
873 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
874 // TODO This is clunky.
875 self.linkedit_segment_next_offset = @intCast(u32, mem.alignForwardGeneric(u64, linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize, @sizeOf(u64)));
876872 // Add code signature load command
877873 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
878874 try self.load_commands.append(self.base.allocator, .{
......@@ -1073,6 +1069,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
10731069 symbol.n_type = macho.N_SECT;
10741070 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
10751071 symbol.n_desc = 0;
1072
1073 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
10761074 } else {
10771075 const decl_name = mem.spanZ(decl.name);
10781076 const name_str_index = try self.makeString(decl_name);
......@@ -1088,6 +1086,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
10881086 .n_value = addr,
10891087 };
10901088 self.offset_table.items[decl.link.macho.offset_table_index] = addr;
1089
1090 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
10911091 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
10921092 }
10931093
......@@ -1361,7 +1361,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13611361
13621362 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
13631363 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
1364 const off = self.findFreeSpace(text_segment, needed_size, @sizeOf(u64));
1364 const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));
13651365 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
13661366
13671367 log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });
......@@ -1406,7 +1406,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14061406 .flags = 0,
14071407 }),
14081408 });
1409 self.linkedit_segment_next_offset = @intCast(u32, address_and_offset.offset);
14101409 self.cmd_table_dirty = true;
14111410 }
14121411 if (self.dyld_info_cmd_index == null) {
......@@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14311430 .weak_bind_size = 0,
14321431 .lazy_bind_off = 0,
14331432 .lazy_bind_size = 0,
1434 .export_off = 0,
1435 .export_size = 0,
1433 .export_off = @intCast(u32, export_off),
1434 .export_size = export_size,
14361435 },
14371436 });
14381437 self.cmd_table_dirty = true;
......@@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14461445
14471446 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size });
14481447
1449 const strtab_size = 1;
1448 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
1449 const strtab_size = self.string_table.items.len;
14501450 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);
14511451
14521452 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size });
......@@ -1455,13 +1455,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14551455 .Symtab = .{
14561456 .cmd = macho.LC_SYMTAB,
14571457 .cmdsize = @sizeOf(macho.symtab_command),
1458 .symoff = 0,
1459 .nsyms = 0,
1460 .stroff = 0,
1461 .strsize = 0,
1458 .symoff = @intCast(u32, symtab_off),
1459 .nsyms = @intCast(u32, self.base.options.symbol_count_hint),
1460 .stroff = @intCast(u32, strtab_off),
1461 .strsize = @intCast(u32, strtab_size),
14621462 },
14631463 });
14641464 self.cmd_table_dirty = true;
1465 try self.writeLocalSymbol(0);
14651466 }
14661467 if (self.dysymtab_cmd_index == null) {
14671468 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15771578 if (self.code_signature_cmd_index == null) {
15781579 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
15791580 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
15861581 try self.load_commands.append(self.base.allocator, .{
15871582 .LinkeditData = .{
15881583 .cmd = macho.LC_CODE_SIGNATURE,
......@@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 {
17671762 // special-case it.
17681763 if (self.dyld_info_cmd_index) |idx| {
17691764 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
1770 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = off;
1771 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = off;
1772 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = off;
1773 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = off;
1774 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = off;
1765 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
1766 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;
1767 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off;
1768 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;
1769 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
17751770 }
17761771
17771772 if (self.function_starts_cmd_index) |idx| {
17781773 const fstart = self.load_commands.items[idx].LinkeditData;
1779 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = off;
1774 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;
17801775 }
17811776
17821777 if (self.data_in_code_cmd_index) |idx| {
17831778 const dic = self.load_commands.items[idx].LinkeditData;
1784 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = off;
1779 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;
17851780 }
17861781
17871782 if (self.dysymtab_cmd_index) |idx| {
17881783 const dysymtab = self.load_commands.items[idx].Dysymtab;
1789 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = off;
1784 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;
17901785 // TODO Handle more dynamic symbol table sections.
17911786 }
17921787
17931788 if (self.symtab_cmd_index) |idx| {
17941789 const symtab = self.load_commands.items[idx].Symtab;
1795 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = off;
1796 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = off;
1797 }
1798
1799 if (self.code_signature_cmd_index) |idx| {
1800 const codesig = self.load_commands.items[idx].LinkeditData;
1801 if (codesig.dataoff > start and codesig.dataoff < min_pos) min_pos = off;
1790 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
1791 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;
18021792 }
18031793 } else {
18041794 for (segment.sections.items) |section| {
1805 if (section.offset > start and sections.offset < min_pos) min_pos = off;
1795 if (section.offset > start and section.offset < min_pos) min_pos = section.offset;
18061796 }
18071797 }
18081798
......@@ -1889,14 +1879,6 @@ fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64
18891879 return pos;
18901880 }
18911881 }
1892
1893 if (self.code_signature_cmd_index) |idx| outer: {
1894 if (self.load_commands.items.len == idx) break :outer;
1895 const codesig = self.load_commands.items[idx].LinkeditData;
1896 if (checkForCollision(start, end, codesig.dataoff, codesig.datasize)) |pos| {
1897 return pos;
1898 }
1899 }
19001882 } else {
19011883 for (segment.sections.items) |section| {
19021884 if (checkForCollision(start, end, section.offset, section.size)) |pos| {
......@@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
19581940 try self.base.file.?.pwriteAll(&code, off);
19591941}
19601942
1961fn writeSymbolTable(self: *MachO) !void {
1962 // TODO workout how we can cache these so that we only overwrite symbols that were updated
1943fn writeLocalSymbol(self: *MachO, index: usize) !void {
1944 const tracy = trace(@src());
1945 defer tracy.end();
1946
19631947 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1948 const nlocals = self.local_symbols.items.len;
1949 const nglobals = self.global_symbols.items.len;
1950 const nundefs = self.undef_symbols.items.len;
1951 const nsyms = nlocals + nglobals + nundefs;
19641952
1965 const locals_off = self.linkedit_segment_next_offset.?;
1953 if (symtab.nsyms < nsyms) {
1954 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1955 const needed_size = nsyms * @sizeOf(macho.nlist_64);
1956 if (needed_size > self.allocatedSize(&linkedit_segment, symtab.symoff)) {
1957 // Move the entire symbol table to a new location
1958 const new_symoff = self.findFreeSpace(&linkedit_segment, needed_size, @alignOf(macho.nlist_64));
1959 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
1960
1961 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
1962 symtab.symoff,
1963 symtab.symoff + existing_size,
1964 new_symoff,
1965 new_symoff + existing_size,
1966 });
1967
1968 const amt = try self.base.file.?.copyRangeAll(symtab.symoff, self.base.file.?, new_symoff, existing_size);
1969 if (amt != existing_size) return error.InputOutput;
1970 symtab.symoff = @intCast(u32, new_symoff);
1971 }
1972 symtab.nsyms = @intCast(u32, nsyms);
1973 self.cmd_table_dirty = true;
1974 }
1975
1976 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
1977 log.debug("writing local symbol {} at 0x{x}", .{ index, off });
1978 try self.base.file.?.pwriteAll(mem.asBytes(&self.local_symbols.items[index]), off);
1979}
1980
1981fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
1982 const tracy = trace(@src());
1983 defer tracy.end();
1984
1985 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1986 const nlocals = self.local_symbols.items.len;
1987 const nglobals = self.global_symbols.items.len;
1988 const nundefs = self.undef_symbols.items.len;
1989 const nsyms = nlocals + nglobals + nundefs;
1990
1991 if (symtab.nsyms < nsyms) {
1992 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1993 const needed_size = nsyms * @sizeOf(macho.nlist_64);
1994 if (needed_size > self.allocatedSize(&linkedit_segment, symtab.symoff)) {
1995 // Move the entire symbol table to a new location
1996 const new_symoff = self.findFreeSpace(&linkedit_segment, needed_size, @alignOf(macho.nlist_64));
1997 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
1998
1999 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
2000 symtab.symoff,
2001 symtab.symoff + existing_size,
2002 new_symoff,
2003 new_symoff + existing_size,
2004 });
2005
2006 const amt = try self.base.file.?.copyRangeAll(symtab.symoff, self.base.file.?, new_symoff, existing_size);
2007 if (amt != existing_size) return error.InputOutput;
2008 symtab.symoff = @intCast(u32, new_symoff);
2009 }
2010 symtab.nsyms = @intCast(u32, nsyms);
2011 self.cmd_table_dirty = true;
2012 }
2013
2014 const locals_off = symtab.symoff;
19662015 const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64);
1967 log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off });
1968 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.local_symbols.items), locals_off);
19692016
19702017 const globals_off = locals_off + locals_size;
19712018 const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);
......@@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void {
19772024 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
19782025 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
19792026
1980 // Update symbol table.
1981 const nlocals = @intCast(u32, self.local_symbols.items.len);
1982 const nglobals = @intCast(u32, self.global_symbols.items.len);
1983 const nundefs = @intCast(u32, self.undef_symbols.items.len);
1984 symtab.symoff = self.linkedit_segment_next_offset.?;
1985 symtab.nsyms = nlocals + nglobals + nundefs;
1986 self.linkedit_segment_next_offset = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
1987
19882027 // Update dynamic symbol table.
19892028 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
1990 dysymtab.nlocalsym = nlocals;
1991 dysymtab.iextdefsym = nlocals;
1992 dysymtab.nextdefsym = nglobals;
1993 dysymtab.iundefsym = nlocals + nglobals;
1994 dysymtab.nundefsym = nundefs;
1995
1996 // Advance size of __LINKEDIT segment
1997 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1998 linkedit.inner.filesize += symtab.nsyms * @sizeOf(macho.nlist_64);
1999 if (linkedit.inner.vmsize < linkedit.inner.filesize) {
2000 linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size);
2001 }
2029 dysymtab.nlocalsym = @intCast(u32, nlocals);
2030 dysymtab.iextdefsym = @intCast(u32, nlocals);
2031 dysymtab.nextdefsym = @intCast(u32, nglobals);
2032 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
2033 dysymtab.nundefsym = @intCast(u32, nundefs);
20022034 self.cmd_table_dirty = true;
20032035}
20042036
20052037fn writeCodeSignaturePadding(self: *MachO) !void {
2038 const tracy = trace(@src());
2039 defer tracy.end();
2040
2041 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
20062042 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
2007 const fileoff = self.linkedit_segment_next_offset.?;
2043 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
20082044 const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
2009 code_sig_cmd.dataoff = fileoff;
2045 code_sig_cmd.dataoff = @intCast(u32, fileoff);
20102046 code_sig_cmd.datasize = datasize;
20112047
2012 self.linkedit_segment_next_offset = fileoff + datasize;
20132048 // Advance size of __LINKEDIT segment
2014 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2015 linkedit.inner.filesize += datasize;
2016 if (linkedit.inner.vmsize < linkedit.inner.filesize) {
2017 linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size);
2049 linkedit_segment.inner.filesize += datasize;
2050 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2051 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
20182052 }
20192053 log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });
20202054 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
......@@ -2023,6 +2057,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
20232057}
20242058
20252059fn writeCodeSignature(self: *MachO) !void {
2060 const tracy = trace(@src());
2061 defer tracy.end();
2062
20262063 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
20272064 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
20282065
......@@ -2048,6 +2085,9 @@ fn writeCodeSignature(self: *MachO) !void {
20482085fn writeExportTrie(self: *MachO) !void {
20492086 if (self.global_symbols.items.len == 0) return;
20502087
2088 const tracy = trace(@src());
2089 defer tracy.end();
2090
20512091 var trie = Trie.init(self.base.allocator);
20522092 defer trie.deinit();
20532093
......@@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void {
20702110 const nwritten = try trie.write(stream.writer());
20712111 assert(nwritten == trie.size);
20722112
2113 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
20732114 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
2074 const export_size = @intCast(u32, mem.alignForward(buffer.len, @sizeOf(u64)));
2075 dyld_info.export_off = self.linkedit_segment_next_offset.?;
2076 dyld_info.export_size = export_size;
2077
2078 log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + export_size });
2115 const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.export_off);
2116 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
20792117
2080 if (export_size > buffer.len) {
2081 // Pad out to align(8).
2082 try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size);
2118 if (needed_size > allocated_size) {
2119 dyld_info.export_off = 0;
2120 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
20832121 }
2084 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
2122 dyld_info.export_size = @intCast(u32, needed_size);
2123 log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
20852124
2086 self.linkedit_segment_next_offset = dyld_info.export_off + dyld_info.export_size;
2087 // Advance size of __LINKEDIT segment
2088 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2089 linkedit.inner.filesize += dyld_info.export_size;
2090 if (linkedit.inner.vmsize < linkedit.inner.filesize) {
2091 linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size);
2092 }
2125 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
20932126 self.cmd_table_dirty = true;
20942127}
20952128
......@@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
21562189}
21572190
21582191fn writeStringTable(self: *MachO) !void {
2159 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2160 const needed_size = self.string_table.items.len;
2192 const tracy = trace(@src());
2193 defer tracy.end();
21612194
2162 symtab.stroff = self.linkedit_segment_next_offset.?;
2163 symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64)));
2195 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2196 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
2197 const allocated_size = self.allocatedSize(&linkedit_segment, symtab.stroff);
2198 const needed_size = mem.alignForwardGeneric(u64, self.string_table.items.len, @alignOf(u64));
21642199
2200 if (needed_size > allocated_size) {
2201 symtab.strsize = 0;
2202 symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
2203 }
2204 symtab.strsize = @intCast(u32, needed_size);
21652205 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
21662206
2167 if (symtab.strsize > needed_size) {
2168 // Pad out to align(8);
2169 try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize);
2170 }
21712207 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
2172
2173 self.linkedit_segment_next_offset = symtab.stroff + symtab.strsize;
2174 // Advance size of __LINKEDIT segment
2175 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2176 linkedit.inner.filesize += symtab.strsize;
2177 if (linkedit.inner.vmsize < linkedit.inner.filesize) {
2178 linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size);
2179 }
21802208 self.cmd_table_dirty = true;
21812209}
21822210
2211fn updateLinkeditSegmentSizes(self: *MachO) !void {
2212 const tracy = trace(@src());
2213 defer tracy.end();
2214
2215 // Now, we are in position to update __LINKEDIT segment sizes.
2216 // TODO Add checkpointing so that we don't have to do this every single time.
2217 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2218 var final_offset = linkedit_segment.inner.fileoff;
2219
2220 if (self.dyld_info_cmd_index) |idx| {
2221 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
2222 final_offset = std.math.max(final_offset, dyld_info.rebase_off + dyld_info.rebase_size);
2223 final_offset = std.math.max(final_offset, dyld_info.bind_off + dyld_info.bind_size);
2224 final_offset = std.math.max(final_offset, dyld_info.weak_bind_off + dyld_info.weak_bind_size);
2225 final_offset = std.math.max(final_offset, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size);
2226 final_offset = std.math.max(final_offset, dyld_info.export_off + dyld_info.export_size);
2227 }
2228 if (self.function_starts_cmd_index) |idx| {
2229 const fstart = self.load_commands.items[idx].LinkeditData;
2230 final_offset = std.math.max(final_offset, fstart.dataoff + fstart.datasize);
2231 }
2232 if (self.data_in_code_cmd_index) |idx| {
2233 const dic = self.load_commands.items[idx].LinkeditData;
2234 final_offset = std.math.max(final_offset, dic.dataoff + dic.datasize);
2235 }
2236 if (self.dysymtab_cmd_index) |idx| {
2237 const dysymtab = self.load_commands.items[idx].Dysymtab;
2238 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
2239 final_offset = std.math.max(final_offset, dysymtab.indirectsymoff + nindirectsize);
2240 // TODO Handle more dynamic symbol table sections.
2241 }
2242 if (self.symtab_cmd_index) |idx| {
2243 const symtab = self.load_commands.items[idx].Symtab;
2244 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
2245 final_offset = std.math.max(final_offset, symtab.symoff + symsize);
2246 final_offset = std.math.max(final_offset, symtab.stroff + symtab.strsize);
2247 }
2248
2249 const filesize = final_offset - linkedit_segment.inner.fileoff;
2250 linkedit_segment.inner.filesize = filesize;
2251 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
2252}
2253
21832254/// Writes all load commands and section headers.
21842255fn writeLoadCommands(self: *MachO) !void {
21852256 var sizeofcmds: usize = 0;