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 {
326326 const tracy = trace(@src());
327327 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
329337 switch (self.base.options.output_mode) {
330338 .Exe => {
339 // Write export trie.
340 try self.writeExportTrie();
331341 if (self.entry_addr) |addr| {
332342 // Update LC_MAIN with entry offset.
333343 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
334344 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
335345 main_cmd.entryoff = addr - text_segment.vmaddr;
336346 }
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 }
337359 if (self.dylinker_cmd_dirty) {
338360 // Write path to dyld loader.
339361 var off: usize = @sizeOf(macho.mach_header_64);
......@@ -360,40 +382,25 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
360382 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
361383 self.libsystem_cmd_dirty = false;
362384 }
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;
371385 },
372386 .Obj => {},
373387 .Lib => return error.TODOImplementWritingLibFiles,
374388 }
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
387390 {
388 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of
389 // doing dynamic updates like this.
390 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
391 // Update symbol table.
392 const nlocals = @intCast(u32, self.local_symbols.items.len);
393 const nglobals = @intCast(u32, self.global_symbols.items.len);
394 const nundefs = @intCast(u32, self.undef_symbols.items.len);
391395 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
392 const file_size = symtab.stroff + symtab.strsize - linkedit.fileoff;
393 linkedit.filesize = file_size;
394 linkedit.vmsize = mem.alignForwardGeneric(u64, file_size, self.page_size);
396 symtab.nsyms = nlocals + nglobals + nundefs;
397 // TODO could we drop this when we add our own codesigning mechanims?
398 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
395399 }
396400
401 // TODO remove when we add our own codesigning mechanism
402 try self.writeStringTable();
403
397404 if (self.cmd_table_dirty) {
398405 try self.writeCmdHeaders();
399406 try self.writeMachOHeader();
......@@ -982,7 +989,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
982989 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
983990 symbol.n_desc = 0;
984991 // 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);
986993 } else {
987994 const decl_name = mem.spanZ(decl.name);
988995 const name_str_index = try self.makeString(decl_name);
......@@ -999,7 +1006,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
9991006 };
10001007 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);
10031010 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
10041011 }
10051012
......@@ -1220,8 +1227,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
12201227 data_segment.nsects += 1;
12211228
12221229 const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
1223 // const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
1224 const off = @intCast(u32, data_segment.fileoff);
1230 const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size));
12251231
12261232 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 {
12881294 });
12891295 self.cmd_table_dirty = true;
12901296 }
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 }
12911313 if (self.symtab_cmd_index == null) {
12921314 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
12931315 try self.load_commands.append(self.base.allocator, .{
......@@ -1330,6 +1352,35 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13301352 });
13311353 self.cmd_table_dirty = true;
13321354 }
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 }
13331384 if (self.dylinker_cmd_index == null) {
13341385 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
13351386 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 {
16531704 try self.base.file.?.pwriteAll(&buf, off);
16541705}
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
17031707fn writeAllGlobalSymbols(self: *MachO) !void {
17041708 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
17051709 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);
......@@ -1741,26 +1745,27 @@ fn writeExportTrie(self: *MachO) !void {
17411745
17421746 try trie.writeULEB128Mem(self.base.allocator, &buffer);
17431747
1744 const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
17451748 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));
17481749 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);
17491750}
17501751
17511752fn writeStringTable(self: *MachO) !void {
17521753 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);
17541755 const needed_size = self.string_table.items.len;
17551756
1756 // if (needed_size > allocated_size) {
1757 // symtab.strsize = 0;
1758 // symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
1759 // }
1760 symtab.strsize = mem.alignForwardGeneric(u32, @intCast(u32, needed_size), @sizeOf(u64));
1761 try self.base.file.?.pwriteAll(&[_]u8{0}, symtab.stroff + symtab.strsize - 1);
1757 if (needed_size > allocated_size) {
1758 symtab.strsize = 0;
1759 symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
1760 }
1761 symtab.strsize = @intCast(u32, needed_size);
17621762 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + needed_size });
17631763 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;
17641769}
17651770
17661771fn writeCmdHeaders(self: *MachO) !void {