| ... | @@ -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(); |
| 324 | | 324 | |
| 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(); | | |
| 329 | | 325 | |
| 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 | } |
| 382 | | 372 | |
| | 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; |
| 391 | | 385 | 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 | } |
| 396 | | 387 | |
| 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; |
| 1003 | | 992 | |
| 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 | } |
| 1007 | | 996 | |
| ... | @@ -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 | } |
| 1689 | | 1636 | |
| | 1637 | fn 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 | |
| 1690 | fn writeAllGlobalSymbols(self: *MachO) !void { | 1684 | fn 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 { |
| 1728 | | 1722 | |
| 1729 | try trie.writeULEB128Mem(self.base.allocator, &buffer); | 1723 | try trie.writeULEB128Mem(self.base.allocator, &buffer); |
| 1730 | | 1724 | |
| | 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 | } |
| 1734 | | 1731 | |
| 1735 | fn writeStringTable(self: *MachO) !void { | 1732 | fn 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; |
| 1739 | | 1736 | |
| 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)); |
| 1745 | | 1742 | 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 | } |
| 1755 | | 1746 | |
| 1756 | fn writeCmdHeaders(self: *MachO) !void { | 1747 | fn writeCmdHeaders(self: *MachO) !void { |