| ... | ... | @@ -125,6 +125,9 @@ got_section_index: ?u16 = null, |
| 125 | 125 | |
| 126 | 126 | entry_addr: ?u64 = null, |
| 127 | 127 | |
| 128 | // TODO move this into each Segment aggregator |
| 129 | linkedit_segment_next_offset: ?u32 = null, |
| 130 | |
| 128 | 131 | /// Table of all local symbols |
| 129 | 132 | /// Internally references string table for names (which are optional). |
| 130 | 133 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | ... | @@ -330,35 +333,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 330 | 333 | const tracy = trace(@src()); |
| 331 | 334 | defer tracy.end(); |
| 332 | 335 | |
| 333 | | // Unfortunately these have to be buffered and done at the end because MachO does not allow |
| 334 | | // mixing local, global and undefined symbols within a symbol table. |
| 335 | | try self.writeAllGlobalSymbols(); |
| 336 | | try self.writeAllUndefSymbols(); |
| 337 | | |
| 338 | | try self.writeStringTable(); |
| 339 | | |
| 340 | 336 | switch (self.base.options.output_mode) { |
| 341 | 337 | .Exe => { |
| 342 | | // Write export trie. |
| 343 | | try self.writeExportTrie(); |
| 344 | 338 | if (self.entry_addr) |addr| { |
| 345 | 339 | // Update LC_MAIN with entry offset. |
| 346 | 340 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 347 | 341 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| 348 | 342 | main_cmd.entryoff = addr - text_segment.vmaddr; |
| 349 | 343 | } |
| 350 | | { |
| 351 | | // Update dynamic symbol table. |
| 352 | | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| 353 | | const nglobals = @intCast(u32, self.global_symbols.items.len); |
| 354 | | const nundefs = @intCast(u32, self.undef_symbols.items.len); |
| 355 | | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 356 | | dysymtab.nlocalsym = nlocals; |
| 357 | | dysymtab.iextdefsym = nlocals; |
| 358 | | dysymtab.nextdefsym = nglobals; |
| 359 | | dysymtab.iundefsym = nlocals + nglobals; |
| 360 | | dysymtab.nundefsym = nundefs; |
| 361 | | } |
| 362 | 344 | if (self.dylinker_cmd_dirty) { |
| 363 | 345 | // Write path to dyld loader. |
| 364 | 346 | var off: usize = @sizeOf(macho.mach_header_64); |
| ... | ... | @@ -385,32 +367,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 385 | 367 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); |
| 386 | 368 | self.libsystem_cmd_dirty = false; |
| 387 | 369 | } |
| 370 | |
| 371 | try self.writeExportTrie(); |
| 372 | try self.writeSymbolTable(); |
| 373 | try self.writeStringTable(); |
| 374 | |
| 375 | // Preallocate space for the code signature. |
| 376 | // We need to do this at this stage so that we have the load commands with proper values |
| 377 | // written out to the file. |
| 378 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment |
| 379 | // where the code signature goes into. |
| 380 | try self.writeCodeSignaturePadding(); |
| 388 | 381 | }, |
| 389 | 382 | .Obj => {}, |
| 390 | 383 | .Lib => return error.TODOImplementWritingLibFiles, |
| 391 | 384 | } |
| 392 | 385 | |
| 393 | | { |
| 394 | | // Update symbol table. |
| 395 | | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| 396 | | const nglobals = @intCast(u32, self.global_symbols.items.len); |
| 397 | | const nundefs = @intCast(u32, self.undef_symbols.items.len); |
| 398 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 399 | | symtab.nsyms = nlocals + nglobals + nundefs; |
| 400 | | } |
| 401 | | |
| 402 | | // TODO rework how we preallocate space for the entire __LINKEDIT segment instead of |
| 403 | | // doing dynamic updates like this. |
| 404 | | if (self.code_signature_cmd_index) |i| { |
| 405 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 406 | | const code_sig = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 407 | | linkedit.filesize = code_sig.dataoff + code_sig.datasize - linkedit.fileoff; |
| 408 | | } else { |
| 409 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 410 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 411 | | linkedit.filesize = symtab.stroff + symtab.strsize - linkedit.fileoff; |
| 412 | | } |
| 413 | | |
| 414 | 386 | if (self.cmd_table_dirty) { |
| 415 | 387 | try self.writeCmdHeaders(); |
| 416 | 388 | try self.writeMachOHeader(); |
| ... | ... | @@ -1003,8 +975,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1003 | 975 | symbol.n_type = macho.N_SECT; |
| 1004 | 976 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; |
| 1005 | 977 | symbol.n_desc = 0; |
| 1006 | | // TODO this write could be avoided if no fields of the symbol were changed. |
| 1007 | | try self.writeSymbol(decl.link.macho.local_sym_index); |
| 1008 | 978 | } else { |
| 1009 | 979 | const decl_name = mem.spanZ(decl.name); |
| 1010 | 980 | const name_str_index = try self.makeString(decl_name); |
| ... | ... | @@ -1020,8 +990,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1020 | 990 | .n_value = addr, |
| 1021 | 991 | }; |
| 1022 | 992 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| 1023 | | |
| 1024 | | try self.writeSymbol(decl.link.macho.local_sym_index); |
| 1025 | 993 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); |
| 1026 | 994 | } |
| 1027 | 995 | |
| ... | ... | @@ -1241,7 +1209,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1241 | 1209 | data_segment.nsects += 1; |
| 1242 | 1210 | |
| 1243 | 1211 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 1244 | | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1212 | // TODO looking for free space should be done *within* a segment it belongs to |
| 1213 | // const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1214 | const off = @intCast(u32, data_segment.fileoff); |
| 1245 | 1215 | |
| 1246 | 1216 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1247 | 1217 | |
| ... | ... | @@ -1263,7 +1233,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1263 | 1233 | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1264 | 1234 | data_segment.vmsize = segment_size; |
| 1265 | 1235 | data_segment.filesize = segment_size; |
| 1266 | | data_segment.fileoff = off; |
| 1267 | 1236 | self.cmd_table_dirty = true; |
| 1268 | 1237 | } |
| 1269 | 1238 | if (self.linkedit_segment_cmd_index == null) { |
| ... | ... | @@ -1271,6 +1240,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1271 | 1240 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1272 | 1241 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1273 | 1242 | const initprot = macho.VM_PROT_READ; |
| 1243 | const off = data_segment.fileoff + data_segment.filesize; |
| 1274 | 1244 | try self.load_commands.append(self.base.allocator, .{ |
| 1275 | 1245 | .Segment = .{ |
| 1276 | 1246 | .cmd = macho.LC_SEGMENT_64, |
| ... | ... | @@ -1278,7 +1248,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1278 | 1248 | .segname = makeStaticString("__LINKEDIT"), |
| 1279 | 1249 | .vmaddr = data_segment.vmaddr + data_segment.vmsize, |
| 1280 | 1250 | .vmsize = 0, |
| 1281 | | .fileoff = 0, |
| 1251 | .fileoff = off, |
| 1282 | 1252 | .filesize = 0, |
| 1283 | 1253 | .maxprot = maxprot, |
| 1284 | 1254 | .initprot = initprot, |
| ... | ... | @@ -1286,6 +1256,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1286 | 1256 | .flags = 0, |
| 1287 | 1257 | }, |
| 1288 | 1258 | }); |
| 1259 | self.linkedit_segment_next_offset = @intCast(u32, off); |
| 1289 | 1260 | self.cmd_table_dirty = true; |
| 1290 | 1261 | } |
| 1291 | 1262 | if (self.dyld_info_cmd_index == null) { |
| ... | ... | @@ -1438,62 +1409,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1438 | 1409 | }, |
| 1439 | 1410 | }); |
| 1440 | 1411 | } |
| 1441 | | { |
| 1442 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1443 | | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| 1444 | | if (dyld_info.export_off == 0) { |
| 1445 | | const nsyms = self.base.options.symbol_count_hint; |
| 1446 | | const file_size = @sizeOf(u64) * nsyms; |
| 1447 | | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1448 | | log.debug("found export trie free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1449 | | dyld_info.export_off = off; |
| 1450 | | dyld_info.export_size = @intCast(u32, file_size); |
| 1451 | | |
| 1452 | | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1453 | | linkedit.vmsize += segment_size; |
| 1454 | | linkedit.fileoff = off; |
| 1455 | | } |
| 1456 | | } |
| 1457 | | { |
| 1458 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1459 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1460 | | if (symtab.symoff == 0) { |
| 1461 | | const nsyms = self.base.options.symbol_count_hint; |
| 1462 | | const file_size = @sizeOf(macho.nlist_64) * nsyms; |
| 1463 | | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1464 | | log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1465 | | symtab.symoff = off; |
| 1466 | | symtab.nsyms = @intCast(u32, nsyms); |
| 1467 | | |
| 1468 | | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1469 | | linkedit.vmsize += segment_size; |
| 1470 | | } |
| 1471 | | if (symtab.stroff == 0) { |
| 1472 | | try self.string_table.append(self.base.allocator, 0); |
| 1473 | | const file_size = @intCast(u32, self.string_table.items.len); |
| 1474 | | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1475 | | log.debug("found string table free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1476 | | symtab.stroff = off; |
| 1477 | | symtab.strsize = file_size; |
| 1478 | | |
| 1479 | | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1480 | | linkedit.vmsize += segment_size; |
| 1481 | | } |
| 1482 | | } |
| 1483 | | { |
| 1484 | | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1485 | | const code_sig = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 1486 | | if (code_sig.dataoff == 0) { |
| 1487 | | const file_size = 0x1000; // TODO what is a good guesstimate for initial code signature? |
| 1488 | | const off = @intCast(u32, self.findFreeSpace(file_size, self.page_size)); |
| 1489 | | log.debug("found code signature free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); |
| 1490 | | code_sig.dataoff = off; |
| 1491 | | code_sig.datasize = file_size; |
| 1492 | | |
| 1493 | | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1494 | | linkedit.vmsize += segment_size; |
| 1495 | | } |
| 1496 | | } |
| 1497 | 1412 | if (self.dyld_stub_binder_index == null) { |
| 1498 | 1413 | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); |
| 1499 | 1414 | const name = try self.makeString("dyld_stub_binder"); |
| ... | ... | @@ -1719,17 +1634,6 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { |
| 1719 | 1634 | return start; |
| 1720 | 1635 | } |
| 1721 | 1636 | |
| 1722 | | fn writeSymbol(self: *MachO, index: usize) !void { |
| 1723 | | const tracy = trace(@src()); |
| 1724 | | defer tracy.end(); |
| 1725 | | |
| 1726 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1727 | | const sym = [1]macho.nlist_64{self.local_symbols.items[index]}; |
| 1728 | | const off = symtab.symoff + @sizeOf(macho.nlist_64) * index; |
| 1729 | | log.debug("writing symbol {} at 0x{x}\n", .{ sym[0], off }); |
| 1730 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); |
| 1731 | | } |
| 1732 | | |
| 1733 | 1637 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1734 | 1638 | const sect = &self.sections.items[self.got_section_index.?]; |
| 1735 | 1639 | const endian = self.base.options.target.cpu.arch.endian(); |
| ... | ... | @@ -1740,30 +1644,72 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1740 | 1644 | try self.base.file.?.pwriteAll(&buf, off); |
| 1741 | 1645 | } |
| 1742 | 1646 | |
| 1743 | | fn writeAllGlobalSymbols(self: *MachO) !void { |
| 1647 | fn writeSymbolTable(self: *MachO) !void { |
| 1648 | // TODO workout how we can cache these so that we only overwrite symbols that were updated |
| 1744 | 1649 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1745 | | const off = symtab.symoff + self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1746 | | const file_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1747 | | log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off }); |
| 1748 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), off); |
| 1749 | | } |
| 1750 | 1650 | |
| 1751 | | fn writeAllUndefSymbols(self: *MachO) !void { |
| 1752 | | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1753 | | const nlocals = self.local_symbols.items.len; |
| 1754 | | const nglobals = self.global_symbols.items.len; |
| 1755 | | const off = symtab.symoff + (nlocals + nglobals) * @sizeOf(macho.nlist_64); |
| 1756 | | const file_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1757 | | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off }); |
| 1758 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), off); |
| 1651 | const locals_off = self.linkedit_segment_next_offset.?; |
| 1652 | const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1653 | log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off }); |
| 1654 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.local_symbols.items), locals_off); |
| 1655 | |
| 1656 | const globals_off = locals_off + locals_size; |
| 1657 | const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1658 | log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ globals_off, globals_size + globals_off }); |
| 1659 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off); |
| 1660 | |
| 1661 | const undefs_off = globals_off + globals_size; |
| 1662 | const undefs_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1663 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off }); |
| 1664 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); |
| 1665 | |
| 1666 | // Update symbol table. |
| 1667 | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| 1668 | const nglobals = @intCast(u32, self.global_symbols.items.len); |
| 1669 | const nundefs = @intCast(u32, self.undef_symbols.items.len); |
| 1670 | symtab.symoff = self.linkedit_segment_next_offset.?; |
| 1671 | symtab.nsyms = nlocals + nglobals + nundefs; |
| 1672 | self.linkedit_segment_next_offset = symtab.symoff + symtab.nsyms * @sizeOf(macho.nlist_64); |
| 1673 | |
| 1674 | // Update dynamic symbol table. |
| 1675 | const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab; |
| 1676 | dysymtab.nlocalsym = nlocals; |
| 1677 | dysymtab.iextdefsym = nlocals; |
| 1678 | dysymtab.nextdefsym = nglobals; |
| 1679 | dysymtab.iundefsym = nlocals + nglobals; |
| 1680 | dysymtab.nundefsym = nundefs; |
| 1681 | |
| 1682 | // Advance size of __LINKEDIT segment |
| 1683 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1684 | linkedit.filesize += symtab.nsyms * @sizeOf(macho.nlist_64); |
| 1685 | if (linkedit.vmsize < linkedit.filesize) { |
| 1686 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); |
| 1687 | } |
| 1688 | self.cmd_table_dirty = true; |
| 1759 | 1689 | } |
| 1760 | 1690 | |
| 1761 | | fn writeCodeSignature(self: *MachO) !void { |
| 1691 | fn writeCodeSignaturePadding(self: *MachO) !void { |
| 1762 | 1692 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 1693 | const fileoff = self.linkedit_segment_next_offset.?; |
| 1694 | const datasize: u32 = 0x1000; // TODO Calculate the expected size of the signature. |
| 1695 | code_sig_cmd.dataoff = fileoff; |
| 1696 | code_sig_cmd.datasize = datasize; |
| 1697 | |
| 1698 | self.linkedit_segment_next_offset = fileoff + datasize; |
| 1699 | // Advance size of __LINKEDIT segment |
| 1700 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1701 | linkedit.filesize += datasize; |
| 1702 | if (linkedit.vmsize < linkedit.filesize) { |
| 1703 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); |
| 1704 | } |
| 1705 | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); |
| 1763 | 1706 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 1764 | 1707 | // except for code signature data. |
| 1765 | | try self.base.file.?.pwriteAll(&[_]u8{0}, code_sig_cmd.dataoff + code_sig_cmd.datasize - 1); |
| 1708 | try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + datasize - 1); |
| 1709 | } |
| 1766 | 1710 | |
| 1711 | fn writeCodeSignature(self: *MachO) !void { |
| 1712 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 1767 | 1713 | var code_sig = CodeSignature.init(self.base.allocator); |
| 1768 | 1714 | defer code_sig.deinit(); |
| 1769 | 1715 | |
| ... | ... | @@ -1780,7 +1726,7 @@ fn writeCodeSignature(self: *MachO) !void { |
| 1780 | 1726 | } |
| 1781 | 1727 | |
| 1782 | 1728 | fn writeExportTrie(self: *MachO) !void { |
| 1783 | | if (self.global_symbols.items.len == 0) return; // No exports, nothing to do. |
| 1729 | assert(self.global_symbols.items.len > 0); |
| 1784 | 1730 | |
| 1785 | 1731 | var trie: Trie = .{}; |
| 1786 | 1732 | defer trie.deinit(self.base.allocator); |
| ... | ... | @@ -1803,23 +1749,51 @@ fn writeExportTrie(self: *MachO) !void { |
| 1803 | 1749 | try trie.writeULEB128Mem(self.base.allocator, &buffer); |
| 1804 | 1750 | |
| 1805 | 1751 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; |
| 1752 | const export_size = @intCast(u32, mem.alignForward(buffer.items.len, @sizeOf(u64))); |
| 1753 | dyld_info.export_off = self.linkedit_segment_next_offset.?; |
| 1754 | dyld_info.export_size = export_size; |
| 1755 | |
| 1756 | log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + export_size }); |
| 1757 | |
| 1758 | if (export_size > buffer.items.len) { |
| 1759 | // Pad out to align(8). |
| 1760 | try self.base.file.?.pwriteAll(&[_]u8{ 0 }, dyld_info.export_off + export_size); |
| 1761 | } |
| 1806 | 1762 | try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off); |
| 1763 | |
| 1764 | self.linkedit_segment_next_offset = dyld_info.export_off + dyld_info.export_size; |
| 1765 | // Advance size of __LINKEDIT segment |
| 1766 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1767 | linkedit.filesize += dyld_info.export_size; |
| 1768 | if (linkedit.vmsize < linkedit.filesize) { |
| 1769 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); |
| 1770 | } |
| 1771 | self.cmd_table_dirty = true; |
| 1807 | 1772 | } |
| 1808 | 1773 | |
| 1809 | 1774 | fn writeStringTable(self: *MachO) !void { |
| 1810 | 1775 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1811 | | const allocated_size = self.allocatedSize(symtab.stroff); |
| 1812 | 1776 | const needed_size = self.string_table.items.len; |
| 1813 | 1777 | |
| 1814 | | if (needed_size > allocated_size) { |
| 1815 | | symtab.strsize = 0; |
| 1816 | | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); |
| 1817 | | } |
| 1818 | | symtab.strsize = @intCast(u32, needed_size); |
| 1778 | symtab.stroff = self.linkedit_segment_next_offset.?; |
| 1779 | symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64))); |
| 1819 | 1780 | |
| 1820 | 1781 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); |
| 1821 | 1782 | |
| 1783 | if (symtab.strsize > needed_size) { |
| 1784 | // Pad out to align(8); |
| 1785 | try self.base.file.?.pwriteAll(&[_]u8{ 0 }, symtab.stroff + symtab.strsize); |
| 1786 | } |
| 1822 | 1787 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); |
| 1788 | |
| 1789 | self.linkedit_segment_next_offset = symtab.stroff + symtab.strsize; |
| 1790 | // Advance size of __LINKEDIT segment |
| 1791 | const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 1792 | linkedit.filesize += symtab.strsize; |
| 1793 | if (linkedit.vmsize < linkedit.filesize) { |
| 1794 | linkedit.vmsize = mem.alignForwardGeneric(u64, linkedit.filesize, self.page_size); |
| 1795 | } |
| 1796 | self.cmd_table_dirty = true; |
| 1823 | 1797 | } |
| 1824 | 1798 | |
| 1825 | 1799 | fn writeCmdHeaders(self: *MachO) !void { |