authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-16 12:04:55+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
log6ac7e99dadfe14a0f4fb8a4fd19e9324747d9545
tree8bfb45b68b7c39c284c1eb15b781048d49c62e9e
parentb3fdfe5ca055245e0184f09684329736fd020409

Write local symbols when flushing


1 files changed, 79 insertions(+), 88 deletions(-)

src/link/MachO.zig+79-88
...@@ -322,33 +322,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -322,33 +322,15 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
322 const tracy = trace(@src());322 const tracy = trace(@src());
323 defer tracy.end();323 defer tracy.end();
324324
325 // Unfortunately these have to be buffered and done at the end because MachO does not allow
326 // mixing local, global and undefined symbols within a symbol table.
327 try self.writeAllGlobalSymbols();
328 try self.writeAllUndefSymbols();
329325
330 switch (self.base.options.output_mode) {326 switch (self.base.options.output_mode) {
331 .Exe => {327 .Exe => {
332 // Write export trie.
333 try self.writeExportTrie();
334 if (self.entry_addr) |addr| {328 if (self.entry_addr) |addr| {
335 // Update LC_MAIN with entry offset.329 // Update LC_MAIN with entry offset.
336 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;330 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
337 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;331 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint;
338 main_cmd.entryoff = addr - text_segment.vmaddr;332 main_cmd.entryoff = addr - text_segment.vmaddr;
339 }333 }
340 {
341 // Update dynamic symbol table.
342 const nlocals = @intCast(u32, self.local_symbols.items.len);
343 const nglobals = @intCast(u32, self.global_symbols.items.len);
344 const nundefs = @intCast(u32, self.undef_symbols.items.len);
345 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
346 dysymtab.nlocalsym = nlocals;
347 dysymtab.iextdefsym = nlocals;
348 dysymtab.nextdefsym = nglobals;
349 dysymtab.iundefsym = nlocals + nglobals;
350 dysymtab.nundefsym = nundefs;
351 }
352 if (self.dylinker_cmd_dirty) {334 if (self.dylinker_cmd_dirty) {
353 // Write path to dyld loader.335 // Write path to dyld loader.
354 var off: usize = @sizeOf(macho.mach_header_64);336 var off: usize = @sizeOf(macho.mach_header_64);
...@@ -375,27 +357,34 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -375,27 +357,34 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
375 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);357 try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off);
376 self.libsystem_cmd_dirty = false;358 self.libsystem_cmd_dirty = false;
377 }359 }
360
361 // Write export trie.
362 try self.writeExportTrie();
363 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
364 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
365 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
366 linkedit.fileoff = dyld_info.export_off;
367 symtab.symoff = dyld_info.export_off + dyld_info.export_size;
378 },368 },
379 .Obj => {},369 .Obj => {},
380 .Lib => return error.TODOImplementWritingLibFiles,370 .Lib => return error.TODOImplementWritingLibFiles,
381 }371 }
382372
373 // Unfortunately these have to be buffered and done at the end because MachO does not allow
374 // mixing local, global and undefined symbols within a symbol table.
375 try self.writeSymbolTable();
376 try self.writeStringTable();
377
383 {378 {
384 // Update symbol table.379 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of
385 const nlocals = @intCast(u32, self.local_symbols.items.len);380 // doing dynamic updates like this.
386 const nglobals = @intCast(u32, self.global_symbols.items.len);381 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
387 const nundefs = @intCast(u32, self.undef_symbols.items.len);
388 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;382 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
389 symtab.nsyms = nlocals + nglobals + nundefs;383 const file_size = symtab.stroff + symtab.strsize - linkedit.fileoff;
390 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);384 linkedit.filesize = file_size;
391385 linkedit.vmsize = mem.alignForwardGeneric(u64, file_size, 0x1000);
392 // Extend dynamic linker info until start of symbol table
393 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
394 dyld_info.export_size = symtab.symoff - dyld_info.export_off;
395 }386 }
396387
397 try self.writeStringTable();
398
399 if (self.cmd_table_dirty) {388 if (self.cmd_table_dirty) {
400 try self.writeCmdHeaders();389 try self.writeCmdHeaders();
401 try self.writeMachOHeader();390 try self.writeMachOHeader();
...@@ -984,7 +973,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -984,7 +973,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
984 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;973 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
985 symbol.n_desc = 0;974 symbol.n_desc = 0;
986 // TODO this write could be avoided if no fields of the symbol were changed.975 // TODO this write could be avoided if no fields of the symbol were changed.
987 try self.writeSymbol(decl.link.macho.local_sym_index);976 // try self.writeSymbol(decl.link.macho.local_sym_index);
988 } else {977 } else {
989 const decl_name = mem.spanZ(decl.name);978 const decl_name = mem.spanZ(decl.name);
990 const name_str_index = try self.makeString(decl_name);979 const name_str_index = try self.makeString(decl_name);
...@@ -1001,7 +990,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1001,7 +990,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1001 };990 };
1002 self.offset_table.items[decl.link.macho.offset_table_index] = addr;991 self.offset_table.items[decl.link.macho.offset_table_index] = addr;
1003992
1004 try self.writeSymbol(decl.link.macho.local_sym_index);993 // try self.writeSymbol(decl.link.macho.local_sym_index);
1005 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);994 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
1006 }995 }
1007996
...@@ -1399,48 +1388,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1399,48 +1388,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1399 },1388 },
1400 });1389 });
1401 }1390 }
1402 {
1403 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1404 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1405 if (dyld_info.export_off == 0) {
1406 const nsyms = self.base.options.symbol_count_hint;
1407 const file_size = @sizeOf(u64) * nsyms;
1408 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
1409 log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1410 dyld_info.export_off = off;
1411 dyld_info.export_size = @intCast(u32, file_size);
1412
1413 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1414 linkedit.vmsize += segment_size;
1415 linkedit.fileoff = off;
1416 }
1417 }
1418 {
1419 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1420 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1421 if (symtab.symoff == 0) {
1422 const nsyms = self.base.options.symbol_count_hint;
1423 const file_size = @sizeOf(macho.nlist_64) * nsyms;
1424 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
1425 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1426 symtab.symoff = off;
1427 symtab.nsyms = @intCast(u32, nsyms);
1428
1429 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1430 linkedit.vmsize += segment_size;
1431 }
1432 if (symtab.stroff == 0) {
1433 try self.string_table.append(self.base.allocator, 0);
1434 const file_size = @intCast(u32, self.string_table.items.len);
1435 const off = @intCast(u32, self.findFreeSpace(file_size, 0x1000));
1436 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
1437 symtab.stroff = off;
1438 symtab.strsize = file_size;
1439
1440 const segment_size = mem.alignForwardGeneric(u64, file_size, 0x1000);
1441 linkedit.vmsize += segment_size;
1442 }
1443 }
1444 if (self.dyld_stub_binder_index == null) {1391 if (self.dyld_stub_binder_index == null) {
1445 self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);1392 self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);
1446 const name = try self.makeString("dyld_stub_binder");1393 const name = try self.makeString("dyld_stub_binder");
...@@ -1687,6 +1634,53 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1687,6 +1634,53 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1687 try self.base.file.?.pwriteAll(&buf, off);1634 try self.base.file.?.pwriteAll(&buf, off);
1688}1635}
16891636
1637fn writeSymbolTable(self: *MachO) !void {
1638 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1639 const locals_off = symtab.symoff;
1640
1641 var locals = try self.base.allocator.alloc(macho.nlist_64, self.local_symbols.items.len - 1);
1642 defer self.base.allocator.free(locals);
1643
1644 for (locals) |*sym, i| {
1645 sym.* = .{
1646 .n_strx = self.local_symbols.items[i + 1].n_strx,
1647 .n_type = self.local_symbols.items[i + 1].n_type,
1648 .n_sect = self.local_symbols.items[i + 1].n_sect,
1649 .n_desc = self.local_symbols.items[i + 1].n_desc,
1650 .n_value = self.local_symbols.items[i + 1].n_value,
1651 };
1652 }
1653
1654 const locals_size = locals.len * @sizeOf(macho.nlist_64);
1655 log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off });
1656 try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals), locals_off);
1657
1658 const globals_off = locals_off + locals_size;
1659 const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64);
1660 log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ globals_off, globals_size + globals_off });
1661 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);
1662
1663 const undefs_off = globals_off + globals_size;
1664 const undefs_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64);
1665 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
1666 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
1667
1668 // Update symbol table.
1669 const nlocals = @intCast(u32, locals.len);
1670 const nglobals = @intCast(u32, self.global_symbols.items.len);
1671 const nundefs = @intCast(u32, self.undef_symbols.items.len);
1672 symtab.nsyms = nlocals + nglobals + nundefs;
1673 symtab.stroff = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64);
1674
1675 // Update dynamic symbol table.
1676 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
1677 dysymtab.nlocalsym = nlocals;
1678 dysymtab.iextdefsym = nlocals;
1679 dysymtab.nextdefsym = nglobals;
1680 dysymtab.iundefsym = nlocals + nglobals;
1681 dysymtab.nundefsym = nundefs;
1682}
1683
1690fn writeAllGlobalSymbols(self: *MachO) !void {1684fn writeAllGlobalSymbols(self: *MachO) !void {
1691 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;1685 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1692 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);1686 const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64);
...@@ -1728,29 +1722,26 @@ fn writeExportTrie(self: *MachO) !void {...@@ -1728,29 +1722,26 @@ fn writeExportTrie(self: *MachO) !void {
17281722
1729 try trie.writeULEB128Mem(self.base.allocator, &buffer);1723 try trie.writeULEB128Mem(self.base.allocator, &buffer);
17301724
1725 const data = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1731 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;1726 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo;
1727 dyld_info.export_off = @intCast(u32, data.fileoff + data.filesize);
1728 dyld_info.export_size = mem.alignForwardGeneric(u32, @intCast(u32, buffer.items.len), @sizeOf(u64));
1732 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);1729 try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off);
1733}1730}
17341731
1735fn writeStringTable(self: *MachO) !void {1732fn writeStringTable(self: *MachO) !void {
1736 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;1733 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
1737 const allocated_size = self.allocatedSize(symtab.stroff);1734 // const allocated_size = self.allocatedSize(symtab.stroff);
1738 const needed_size = self.string_table.items.len;1735 const needed_size = self.string_table.items.len;
17391736
1740 if (needed_size > allocated_size) {1737 // if (needed_size > allocated_size) {
1741 symtab.strsize = 0;1738 // symtab.strsize = 0;
1742 symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));1739 // symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1));
1743 }1740 // }
1744 symtab.strsize = @intCast(u32, needed_size);1741 symtab.strsize = mem.alignForwardGeneric(u32, @intCast(u32, needed_size), @sizeOf(u64));
17451742 try self.base.file.?.pwriteAll(&[_]u8{ 0 }, symtab.stroff + symtab.strsize - 1);
1746 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });1743 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + needed_size });
1747
1748 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);1744 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
1749
1750 // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of
1751 // doing dynamic updates like this.
1752 const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
1753 linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff;
1754}1745}
17551746
1756fn writeCmdHeaders(self: *MachO) !void {1747fn writeCmdHeaders(self: *MachO) !void {