authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-17 14:57:47+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
loga2e0e33249c786e766e185223875b3cef6c946fb
treee3fa899a38bd2b6dd09081b8868613388f682887
parente1b65ff8d211066d0856ad3535b96dcdc88e76dc

stage2 macho: bring back incremental symbol commits


1 files changed, 91 insertions(+), 86 deletions(-)

src/link/MachO.zig+91-86
...@@ -326,14 +326,36 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -326,14 +326,36 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
326 const tracy = trace(@src());326 const tracy = trace(@src());
327 defer tracy.end();327 defer tracy.end();
328328
329 // Unfortunately these have to be buffered and done at the end because MachO does not allow
330 // mixing local, global and undefined symbols within a symbol table.
331 try self.writeAllGlobalSymbols();
332 try self.writeAllUndefSymbols();
333
334 // TODO uncomment when we add our own codesigning mechanim
335 // try self.writeStringTable();
336
329 switch (self.base.options.output_mode) {337 switch (self.base.options.output_mode) {
330 .Exe => {338 .Exe => {
339 // Write export trie.
340 try self.writeExportTrie();
331 if (self.entry_addr) |addr| {341 if (self.entry_addr) |addr| {
332 // Update LC_MAIN with entry offset.342 // Update LC_MAIN with entry offset.
333 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;343 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
334 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;344 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
335 main_cmd.entryoff = addr - text_segment.vmaddr;345 main_cmd.entryoff = addr - text_segment.vmaddr;
336 }346 }
347 {
348 // Update dynamic symbol table.
349 const nlocals = @intCast(u32, self.local_symbols.items.len);
350 const nglobals = @intCast(u32, self.global_symbols.items.len);
351 const nundefs = @intCast(u32, self.undef_symbols.items.len);
352 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
353 dysymtab.nlocalsym = nlocals;
354 dysymtab.iextdefsym = nlocals;
355 dysymtab.nextdefsym = nglobals;
356 dysymtab.iundefsym = nlocals + nglobals;
357 dysymtab.nundefsym = nundefs;
358 }
337 if (self.dylinker_cmd_dirty) {359 if (self.dylinker_cmd_dirty) {
338 // Write path to dyld loader.360 // Write path to dyld loader.
339 var off: usize = @sizeOf(macho.mach_header_64);361 var off: usize = @sizeOf(macho.mach_header_64);
...@@ -360,40 +382,25 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -360,40 +382,25 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
360 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);382 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
361 self.libsystem_cmd_dirty = false;383 self.libsystem_cmd_dirty = false;
362 }384 }
363
364 // Write export trie.
365 try self.writeExportTrie();
366 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
367 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
368 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
369 linkedit.fileoff = dyld_info.export_off;
370 symtab.symoff = dyld_info.export_off + dyld_info.export_size;
371 },385 },
372 .Obj => {},386 .Obj => {},
373 .Lib => return error.TODOImplementWritingLibFiles,387 .Lib => return error.TODOImplementWritingLibFiles,
374 }388 }
375389
376 // Unfortunately these have to be buffered and done at the end because MachO does not allow
377 // mixing local, global and undefined symbols within a symbol table.
378 try self.writeSymbolTable();
379 try self.writeStringTable();
380
381 {
382 // Seal __DATA,__got section size
383 const got = &self.sections.items[self.got_section_index.?];
384 got.size = @intCast(u32, self.offset_table.items.len * @sizeOf(u64));
385 }
386
387 {390 {
388 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of391 // Update symbol table.
389 // doing dynamic updates like this.392 const nlocals = @intCast(u32, self.local_symbols.items.len);
390 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;393 const nglobals = @intCast(u32, self.global_symbols.items.len);
394 const nundefs = @intCast(u32, self.undef_symbols.items.len);
391 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;395 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
392 const file_size = symtab.stroff + symtab.strsize - linkedit.fileoff;396 symtab.nsyms = nlocals + nglobals + nundefs;
393 linkedit.filesize = file_size;397 // TODO could we drop this when we add our own codesigning mechanims?
394 linkedit.vmsize = mem.alignForwardGeneric(u64, file_size, self.page_size);398 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
395 }399 }
396400
401 // TODO remove when we add our own codesigning mechanism
402 try self.writeStringTable();
403
397 if (self.cmd_table_dirty) {404 if (self.cmd_table_dirty) {
398 try self.writeCmdHeaders();405 try self.writeCmdHeaders();
399 try self.writeMachOHeader();406 try self.writeMachOHeader();
...@@ -982,7 +989,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -982,7 +989,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
982 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;989 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
983 symbol.n_desc = 0;990 symbol.n_desc = 0;
984 // TODO this write could be avoided if no fields of the symbol were changed.991 // TODO this write could be avoided if no fields of the symbol were changed.
985 // try self.writeSymbol(decl.link.macho.local_sym_index);992 try self.writeSymbol(decl.link.macho.local_sym_index);
986 } else {993 } else {
987 const decl_name = mem.spanZ(decl.name);994 const decl_name = mem.spanZ(decl.name);
988 const name_str_index = try self.makeString(decl_name);995 const name_str_index = try self.makeString(decl_name);
...@@ -999,7 +1006,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -999,7 +1006,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
999 };1006 };
1000 self.offset_table.items[decl.link.macho.offset_table_index] = addr;1007 self.offset_table.items[decl.link.macho.offset_table_index] = addr;
10011008
1002 // try self.writeSymbol(decl.link.macho.local_sym_index);1009 try self.writeSymbol(decl.link.macho.local_sym_index);
1003 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);1010 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
1004 }1011 }
10051012
...@@ -1220,8 +1227,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1220,8 +1227,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1220 data_segment.nsects += 1;1227 data_segment.nsects += 1;
12211228
1222 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;1229 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
1223 // const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));1230 const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));
1224 const off = @intCast(u32, data_segment.fileoff);
12251231
1226 log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });1232 log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
12271233
...@@ -1288,6 +1294,22 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1288,6 +1294,22 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1288 });1294 });
1289 self.cmd_table_dirty = true;1295 self.cmd_table_dirty = true;
1290 }1296 }
1297 {
1298 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1299 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1300 if (dyld_info.export_off == 0) {
1301 const nsyms = self.base.options.symbol_count_hint;
1302 const file_size = @sizeOf(u64) * nsyms;
1303 const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));
1304 log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1305 dyld_info.export_off = off;
1306 dyld_info.export_size = @intCast(u32, file_size);
1307
1308 const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size);
1309 linkedit.vmsize += segment_size;
1310 linkedit.fileoff = off;
1311 }
1312 }
1291 if (self.symtab_cmd_index == null) {1313 if (self.symtab_cmd_index == null) {
1292 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);1314 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
1293 try self.load_commands.append(self.base.allocator, .{1315 try self.load_commands.append(self.base.allocator, .{
...@@ -1330,6 +1352,35 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1330,6 +1352,35 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1330 });1352 });
1331 self.cmd_table_dirty = true;1353 self.cmd_table_dirty = true;
1332 }1354 }
1355 {
1356 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1357 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1358 if (symtab.symoff == 0) {
1359 const nsyms = self.base.options.symbol_count_hint;
1360 const file_size = @sizeOf(macho.nlist_64) * nsyms;
1361 const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));
1362 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1363 symtab.symoff = off;
1364 symtab.nsyms = @intCast(u32, nsyms);
1365
1366 const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size);
1367 linkedit.vmsize += segment_size;
1368 // TODO this is needed to please codesign_allocate
1369 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1370 dyld_info.export_size = off - dyld_info.export_off;
1371 }
1372 if (symtab.stroff == 0) {
1373 try self.string_table.append(self.base.allocator, 0);
1374 const file_size = @intCast(u32, self.string_table.items.len);
1375 const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));
1376 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1377 symtab.stroff = off;
1378 symtab.strsize = file_size;
1379
1380 const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size);
1381 linkedit.vmsize += segment_size;
1382 }
1383 }
1333 if (self.dylinker_cmd_index == null) {1384 if (self.dylinker_cmd_index == null) {
1334 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);1385 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
1335 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64));1386 const cmdsize = mem.alignForwardGeneric(u64, @sizeOf(macho.dylinker_command) + mem.lenZ(DEFAULT_DYLD_PATH), @sizeOf(u64));
...@@ -1653,53 +1704,6 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1653,53 +1704,6 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1653 try self.base.file.?.pwriteAll(&buf, off);1704 try self.base.file.?.pwriteAll(&buf, off);
1654}1705}
16551706
1656fn writeSymbolTable(self: *MachO) !void {
1657 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1658 const locals_off = symtab.symoff;
1659
1660 var locals = try self.base.allocator.alloc(macho.nlist_64, self.local_symbols.items.len - 1);
1661 defer self.base.allocator.free(locals);
1662
1663 for (locals) |*sym, i| {
1664 sym.* = .{
1665 .n_strx = self.local_symbols.items[i + 1].n_strx,
1666 .n_type = self.local_symbols.items[i + 1].n_type,
1667 .n_sect = self.local_symbols.items[i + 1].n_sect,
1668 .n_desc = self.local_symbols.items[i + 1].n_desc,
1669 .n_value = self.local_symbols.items[i + 1].n_value,
1670 };
1671 }
1672
1673 const locals_size = locals.len * @sizeOf(macho.nlist_64);
1674 log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off });
1675 try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals), locals_off);
1676
1677 const globals_off = locals_off + locals_size;
1678 const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);
1679 log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ globals_off, globals_size + globals_off });
1680 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);
1681
1682 const undefs_off = globals_off + globals_size;
1683 const undefs_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64);
1684 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
1685 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
1686
1687 // Update symbol table.
1688 const nlocals = @intCast(u32, locals.len);
1689 const nglobals = @intCast(u32, self.global_symbols.items.len);
1690 const nundefs = @intCast(u32, self.undef_symbols.items.len);
1691 symtab.nsyms = nlocals + nglobals + nundefs;
1692 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
1693
1694 // Update dynamic symbol table.
1695 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
1696 dysymtab.nlocalsym = nlocals;
1697 dysymtab.iextdefsym = nlocals;
1698 dysymtab.nextdefsym = nglobals;
1699 dysymtab.iundefsym = nlocals + nglobals;
1700 dysymtab.nundefsym = nundefs;
1701}
1702
1703fn writeAllGlobalSymbols(self: *MachO) !void {1707fn writeAllGlobalSymbols(self: *MachO) !void {
1704 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;1708 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1705 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);1709 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);
...@@ -1741,26 +1745,27 @@ fn writeExportTrie(self: *MachO) !void {...@@ -1741,26 +1745,27 @@ fn writeExportTrie(self: *MachO) !void {
17411745
1742 try trie.writeULEB128Mem(self.base.allocator, &buffer);1746 try trie.writeULEB128Mem(self.base.allocator, &buffer);
17431747
1744 const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1745 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;1748 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1746 dyld_info.export_off = @intCast(u32, data.fileoff + data.filesize);
1747 dyld_info.export_size = mem.alignForwardGeneric(u32, @intCast(u32, buffer.items.len), @sizeOf(u64));
1748 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);1749 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);
1749}1750}
17501751
1751fn writeStringTable(self: *MachO) !void {1752fn writeStringTable(self: *MachO) !void {
1752 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;1753 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1753 // const allocated_size = self.allocatedSize(symtab.stroff);1754 const allocated_size = self.allocatedSize(symtab.stroff);
1754 const needed_size = self.string_table.items.len;1755 const needed_size = self.string_table.items.len;
17551756
1756 // if (needed_size > allocated_size) {1757 if (needed_size > allocated_size) {
1757 // symtab.strsize = 0;1758 symtab.strsize = 0;
1758 // symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));1759 symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
1759 // }1760 }
1760 symtab.strsize = mem.alignForwardGeneric(u32, @intCast(u32, needed_size), @sizeOf(u64));1761 symtab.strsize = @intCast(u32, needed_size);
1761 try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize - 1);
1762 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + needed_size });1762 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + needed_size });
1763 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);1763 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
1764
1765 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of
1766 // doing dynamic updates like this.
1767 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1768 linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff;
1764}1769}
17651770
1766fn writeCmdHeaders(self: *MachO) !void {1771fn writeCmdHeaders(self: *MachO) !void {