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,...@@ -84,9 +84,6 @@ got_section_index: ?u16 = null,
84/// The absolute address of the entry point.84/// The absolute address of the entry point.
85entry_addr: ?u64 = null,85entry_addr: ?u64 = null,
8686
87/// TODO move this into each Segment aggregator
88linkedit_segment_next_offset: ?u32 = null,
89
90/// Table of all local symbols87/// Table of all local symbols
91/// Internally references string table for names (which are optional).88/// Internally references string table for names (which are optional).
92local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},89local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},
...@@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -319,10 +316,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
319 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;316 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
320 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;317 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
321 main_cmd.entryoff = addr - text_segment.inner.vmaddr;318 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
319 self.cmd_table_dirty = true;
322 }320 }
323 try self.writeExportTrie();321 try self.writeExportTrie();
324 try self.writeSymbolTable();322 try self.writeAllGlobalAndUndefSymbols();
325 try self.writeStringTable();323 try self.writeStringTable();
324 try self.updateLinkeditSegmentSizes();
326325
327 if (target.cpu.arch == .aarch64) {326 if (target.cpu.arch == .aarch64) {
328 // Preallocate space for the code signature.327 // Preallocate space for the code signature.
...@@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -870,9 +869,6 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
870 return error.NotEnoughPadding;869 return error.NotEnoughPadding;
871 }870 }
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)));
876 // Add code signature load command872 // Add code signature load command
877 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);873 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
878 try self.load_commands.append(self.base.allocator, .{874 try self.load_commands.append(self.base.allocator, .{
...@@ -1073,6 +1069,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1073,6 +1069,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1073 symbol.n_type = macho.N_SECT;1069 symbol.n_type = macho.N_SECT;
1074 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;1070 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
1075 symbol.n_desc = 0;1071 symbol.n_desc = 0;
1072
1073 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
1076 } else {1074 } else {
1077 const decl_name = mem.spanZ(decl.name);1075 const decl_name = mem.spanZ(decl.name);
1078 const name_str_index = try self.makeString(decl_name);1076 const name_str_index = try self.makeString(decl_name);
...@@ -1088,6 +1086,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1088,6 +1086,8 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1088 .n_value = addr,1086 .n_value = addr,
1089 };1087 };
1090 self.offset_table.items[decl.link.macho.offset_table_index] = addr;1088 self.offset_table.items[decl.link.macho.offset_table_index] = addr;
1089
1090 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
1091 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);1091 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
1092 }1092 }
10931093
...@@ -1361,7 +1361,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1361,7 +1361,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13611361
1362 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;1362 const flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS;
1363 const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;1363 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));
1365 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.1365 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
13661366
1367 log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });1367 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 {...@@ -1406,7 +1406,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1406 .flags = 0,1406 .flags = 0,
1407 }),1407 }),
1408 });1408 });
1409 self.linkedit_segment_next_offset = @intCast(u32, address_and_offset.offset);
1410 self.cmd_table_dirty = true;1409 self.cmd_table_dirty = true;
1411 }1410 }
1412 if (self.dyld_info_cmd_index == null) {1411 if (self.dyld_info_cmd_index == null) {
...@@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1431,8 +1430,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1431 .weak_bind_size = 0,1430 .weak_bind_size = 0,
1432 .lazy_bind_off = 0,1431 .lazy_bind_off = 0,
1433 .lazy_bind_size = 0,1432 .lazy_bind_size = 0,
1434 .export_off = 0,1433 .export_off = @intCast(u32, export_off),
1435 .export_size = 0,1434 .export_size = export_size,
1436 },1435 },
1437 });1436 });
1438 self.cmd_table_dirty = true;1437 self.cmd_table_dirty = true;
...@@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1446,7 +1445,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14461445
1447 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size });1446 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;
1450 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);1450 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);
14511451
1452 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size });1452 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 {...@@ -1455,13 +1455,14 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1455 .Symtab = .{1455 .Symtab = .{
1456 .cmd = macho.LC_SYMTAB,1456 .cmd = macho.LC_SYMTAB,
1457 .cmdsize = @sizeOf(macho.symtab_command),1457 .cmdsize = @sizeOf(macho.symtab_command),
1458 .symoff = 0,1458 .symoff = @intCast(u32, symtab_off),
1459 .nsyms = 0,1459 .nsyms = @intCast(u32, self.base.options.symbol_count_hint),
1460 .stroff = 0,1460 .stroff = @intCast(u32, strtab_off),
1461 .strsize = 0,1461 .strsize = @intCast(u32, strtab_size),
1462 },1462 },
1463 });1463 });
1464 self.cmd_table_dirty = true;1464 self.cmd_table_dirty = true;
1465 try self.writeLocalSymbol(0);
1465 }1466 }
1466 if (self.dysymtab_cmd_index == null) {1467 if (self.dysymtab_cmd_index == null) {
1467 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);1468 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1577,12 +1578,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1577 if (self.code_signature_cmd_index == null) {1578 if (self.code_signature_cmd_index == null) {
1578 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);1579 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 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
1586 try self.load_commands.append(self.base.allocator, .{1581 try self.load_commands.append(self.base.allocator, .{
1587 .LinkeditData = .{1582 .LinkeditData = .{
1588 .cmd = macho.LC_CODE_SIGNATURE,1583 .cmd = macho.LC_CODE_SIGNATURE,
...@@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 {...@@ -1767,42 +1762,37 @@ fn allocatedSize(self: *MachO, segment: *const SegmentCommand, start: u64) u64 {
1767 // special-case it.1762 // special-case it.
1768 if (self.dyld_info_cmd_index) |idx| {1763 if (self.dyld_info_cmd_index) |idx| {
1769 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;1764 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;1765 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
1771 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = off;1766 if (dyld_info.bind_off > start and dyld_info.bind_off < min_pos) min_pos = dyld_info.bind_off;
1772 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = off;1767 if (dyld_info.weak_bind_off > start and dyld_info.weak_bind_off < min_pos) min_pos = dyld_info.weak_bind_off;
1773 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = off;1768 if (dyld_info.lazy_bind_off > start and dyld_info.lazy_bind_off < min_pos) min_pos = dyld_info.lazy_bind_off;
1774 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = off;1769 if (dyld_info.export_off > start and dyld_info.export_off < min_pos) min_pos = dyld_info.export_off;
1775 }1770 }
17761771
1777 if (self.function_starts_cmd_index) |idx| {1772 if (self.function_starts_cmd_index) |idx| {
1778 const fstart = self.load_commands.items[idx].LinkeditData;1773 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;
1780 }1775 }
17811776
1782 if (self.data_in_code_cmd_index) |idx| {1777 if (self.data_in_code_cmd_index) |idx| {
1783 const dic = self.load_commands.items[idx].LinkeditData;1778 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;
1785 }1780 }
17861781
1787 if (self.dysymtab_cmd_index) |idx| {1782 if (self.dysymtab_cmd_index) |idx| {
1788 const dysymtab = self.load_commands.items[idx].Dysymtab;1783 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;
1790 // TODO Handle more dynamic symbol table sections.1785 // TODO Handle more dynamic symbol table sections.
1791 }1786 }
17921787
1793 if (self.symtab_cmd_index) |idx| {1788 if (self.symtab_cmd_index) |idx| {
1794 const symtab = self.load_commands.items[idx].Symtab;1789 const symtab = self.load_commands.items[idx].Symtab;
1795 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = off;1790 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
1796 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = off;1791 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;
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;
1802 }1792 }
1803 } else {1793 } else {
1804 for (segment.sections.items) |section| {1794 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;
1806 }1796 }
1807 }1797 }
18081798
...@@ -1889,14 +1879,6 @@ fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64...@@ -1889,14 +1879,6 @@ fn detectAllocCollision(self: *MachO, segment: *const SegmentCommand, start: u64
1889 return pos;1879 return pos;
1890 }1880 }
1891 }1881 }
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 }
1900 } else {1882 } else {
1901 for (segment.sections.items) |section| {1883 for (segment.sections.items) |section| {
1902 if (checkForCollision(start, end, section.offset, section.size)) |pos| {1884 if (checkForCollision(start, end, section.offset, section.size)) |pos| {
...@@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1958,14 +1940,79 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1958 try self.base.file.?.pwriteAll(&code, off);1940 try self.base.file.?.pwriteAll(&code, off);
1959}1941}
19601942
1961fn writeSymbolTable(self: *MachO) !void {1943fn writeLocalSymbol(self: *MachO, index: usize) !void {
1962 // TODO workout how we can cache these so that we only overwrite symbols that were updated1944 const tracy = trace(@src());
1945 defer tracy.end();
1946
1963 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;1947 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;
1966 const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64);2015 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
1970 const globals_off = locals_off + locals_size;2017 const globals_off = locals_off + locals_size;
1971 const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);2018 const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);
...@@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -1977,44 +2024,31 @@ fn writeSymbolTable(self: *MachO) !void {
1977 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });2024 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
1978 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);2025 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
1988 // Update dynamic symbol table.2027 // Update dynamic symbol table.
1989 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;2028 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
1990 dysymtab.nlocalsym = nlocals;2029 dysymtab.nlocalsym = @intCast(u32, nlocals);
1991 dysymtab.iextdefsym = nlocals;2030 dysymtab.iextdefsym = @intCast(u32, nlocals);
1992 dysymtab.nextdefsym = nglobals;2031 dysymtab.nextdefsym = @intCast(u32, nglobals);
1993 dysymtab.iundefsym = nlocals + nglobals;2032 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
1994 dysymtab.nundefsym = nundefs;2033 dysymtab.nundefsym = @intCast(u32, 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 }
2002 self.cmd_table_dirty = true;2034 self.cmd_table_dirty = true;
2003}2035}
20042036
2005fn writeCodeSignaturePadding(self: *MachO) !void {2037fn 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;
2006 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;2042 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;
2008 const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);2044 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);
2010 code_sig_cmd.datasize = datasize;2046 code_sig_cmd.datasize = datasize;
20112047
2012 self.linkedit_segment_next_offset = fileoff + datasize;
2013 // Advance size of __LINKEDIT segment2048 // Advance size of __LINKEDIT segment
2014 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2049 linkedit_segment.inner.filesize += datasize;
2015 linkedit.inner.filesize += datasize;2050 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2016 if (linkedit.inner.vmsize < linkedit.inner.filesize) {2051 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2017 linkedit.inner.vmsize = mem.alignForwardGeneric(u64, linkedit.inner.filesize, self.page_size);
2018 }2052 }
2019 log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });2053 log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });
2020 // Pad out the space. We need to do this to calculate valid hashes for everything in the file2054 // 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 {...@@ -2023,6 +2057,9 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
2023}2057}
20242058
2025fn writeCodeSignature(self: *MachO) !void {2059fn writeCodeSignature(self: *MachO) !void {
2060 const tracy = trace(@src());
2061 defer tracy.end();
2062
2026 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2063 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2027 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;2064 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
20282065
...@@ -2048,6 +2085,9 @@ fn writeCodeSignature(self: *MachO) !void {...@@ -2048,6 +2085,9 @@ fn writeCodeSignature(self: *MachO) !void {
2048fn writeExportTrie(self: *MachO) !void {2085fn writeExportTrie(self: *MachO) !void {
2049 if (self.global_symbols.items.len == 0) return;2086 if (self.global_symbols.items.len == 0) return;
20502087
2088 const tracy = trace(@src());
2089 defer tracy.end();
2090
2051 var trie = Trie.init(self.base.allocator);2091 var trie = Trie.init(self.base.allocator);
2052 defer trie.deinit();2092 defer trie.deinit();
20532093
...@@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void {...@@ -2070,26 +2110,19 @@ fn writeExportTrie(self: *MachO) !void {
2070 const nwritten = try trie.write(stream.writer());2110 const nwritten = try trie.write(stream.writer());
2071 assert(nwritten == trie.size);2111 assert(nwritten == trie.size);
20722112
2113 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2073 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;2114 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)));2115 const allocated_size = self.allocatedSize(&linkedit_segment, dyld_info.export_off);
2075 dyld_info.export_off = self.linkedit_segment_next_offset.?;2116 const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64));
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 });
20792117
2080 if (export_size > buffer.len) {2118 if (needed_size > allocated_size) {
2081 // Pad out to align(8).2119 dyld_info.export_off = 0;
2082 try self.base.file.?.pwriteAll(&[_]u8{0}, dyld_info.export_off + export_size);2120 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
2083 }2121 }
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;2125 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
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 }
2093 self.cmd_table_dirty = true;2126 self.cmd_table_dirty = true;
2094}2127}
20952128
...@@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2156,30 +2189,68 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2156}2189}
21572190
2158fn writeStringTable(self: *MachO) !void {2191fn writeStringTable(self: *MachO) !void {
2159 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2192 const tracy = trace(@src());
2160 const needed_size = self.string_table.items.len;2193 defer tracy.end();
21612194
2162 symtab.stroff = self.linkedit_segment_next_offset.?;2195 const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2163 symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64)));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);
2165 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });2205 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 }
2171 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);2207 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 }
2180 self.cmd_table_dirty = true;2208 self.cmd_table_dirty = true;
2181}2209}
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
2183/// Writes all load commands and section headers.2254/// Writes all load commands and section headers.
2184fn writeLoadCommands(self: *MachO) !void {2255fn writeLoadCommands(self: *MachO) !void {
2185 var sizeofcmds: usize = 0;2256 var sizeofcmds: usize = 0;