| ... | @@ -125,6 +125,9 @@ got_section_index: ?u16 = null, | ... | @@ -125,6 +125,9 @@ got_section_index: ?u16 = null, |
| 125 | | 125 | |
| 126 | entry_addr: ?u64 = null, | 126 | entry_addr: ?u64 = null, |
| 127 | | 127 | |
| | 128 | // TODO move this into each Segment aggregator |
| | 129 | linkedit_segment_next_offset: ?u32 = null, |
| | 130 | |
| 128 | /// Table of all local symbols | 131 | /// Table of all local symbols |
| 129 | /// Internally references string table for names (which are optional). | 132 | /// Internally references string table for names (which are optional). |
| 130 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 133 | local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| ... | @@ -330,35 +333,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -330,35 +333,14 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 330 | const tracy = trace(@src()); | 333 | const tracy = trace(@src()); |
| 331 | defer tracy.end(); | 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 | switch (self.base.options.output_mode) { | 336 | switch (self.base.options.output_mode) { |
| 341 | .Exe => { | 337 | .Exe => { |
| 342 | // Write export trie. | | |
| 343 | try self.writeExportTrie(); | | |
| 344 | if (self.entry_addr) |addr| { | 338 | if (self.entry_addr) |addr| { |
| 345 | // Update LC_MAIN with entry offset. | 339 | // Update LC_MAIN with entry offset. |
| 346 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 340 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 347 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; | 341 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| 348 | main_cmd.entryoff = addr - text_segment.vmaddr; | 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 | if (self.dylinker_cmd_dirty) { | 344 | if (self.dylinker_cmd_dirty) { |
| 363 | // Write path to dyld loader. | 345 | // Write path to dyld loader. |
| 364 | var off: usize = @sizeOf(macho.mach_header_64); | 346 | var off: usize = @sizeOf(macho.mach_header_64); |
| ... | @@ -385,32 +367,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { | ... | @@ -385,32 +367,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 385 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); | 367 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); |
| 386 | self.libsystem_cmd_dirty = false; | 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 | .Obj => {}, | 382 | .Obj => {}, |
| 390 | .Lib => return error.TODOImplementWritingLibFiles, | 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 | if (self.cmd_table_dirty) { | 386 | if (self.cmd_table_dirty) { |
| 415 | try self.writeCmdHeaders(); | 387 | try self.writeCmdHeaders(); |
| 416 | try self.writeMachOHeader(); | 388 | try self.writeMachOHeader(); |
| ... | @@ -1003,8 +975,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1003,8 +975,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1003 | symbol.n_type = macho.N_SECT; | 975 | symbol.n_type = macho.N_SECT; |
| 1004 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; | 976 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; |
| 1005 | symbol.n_desc = 0; | 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 | } else { | 978 | } else { |
| 1009 | const decl_name = mem.spanZ(decl.name); | 979 | const decl_name = mem.spanZ(decl.name); |
| 1010 | const name_str_index = try self.makeString(decl_name); | 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,8 +990,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1020 | .n_value = addr, | 990 | .n_value = addr, |
| 1021 | }; | 991 | }; |
| 1022 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; | 992 | self.offset_table.items[decl.link.macho.offset_table_index] = addr; |
| 1023 | | | |
| 1024 | try self.writeSymbol(decl.link.macho.local_sym_index); | | |
| 1025 | try self.writeOffsetTableEntry(decl.link.macho.offset_table_index); | 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,7 +1209,9 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1241 | data_segment.nsects += 1; | 1209 | data_segment.nsects += 1; |
| 1242 | | 1210 | |
| 1243 | const file_size = @sizeOf(u64) * self.base.options.symbol_count_hint; | 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 | log.debug("found __got section free space 0x{x} to 0x{x}\n", .{ off, off + file_size }); | 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,7 +1233,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1263 | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); | 1233 | const segment_size = mem.alignForwardGeneric(u64, file_size, self.page_size); |
| 1264 | data_segment.vmsize = segment_size; | 1234 | data_segment.vmsize = segment_size; |
| 1265 | data_segment.filesize = segment_size; | 1235 | data_segment.filesize = segment_size; |
| 1266 | data_segment.fileoff = off; | | |
| 1267 | self.cmd_table_dirty = true; | 1236 | self.cmd_table_dirty = true; |
| 1268 | } | 1237 | } |
| 1269 | if (self.linkedit_segment_cmd_index == null) { | 1238 | if (self.linkedit_segment_cmd_index == null) { |
| ... | @@ -1271,6 +1240,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1271,6 +1240,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1271 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; | 1240 | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1272 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; | 1241 | const maxprot = macho.VM_PROT_READ | macho.VM_PROT_WRITE | macho.VM_PROT_EXECUTE; |
| 1273 | const initprot = macho.VM_PROT_READ; | 1242 | const initprot = macho.VM_PROT_READ; |
| | 1243 | const off = data_segment.fileoff + data_segment.filesize; |
| 1274 | try self.load_commands.append(self.base.allocator, .{ | 1244 | try self.load_commands.append(self.base.allocator, .{ |
| 1275 | .Segment = .{ | 1245 | .Segment = .{ |
| 1276 | .cmd = macho.LC_SEGMENT_64, | 1246 | .cmd = macho.LC_SEGMENT_64, |
| ... | @@ -1278,7 +1248,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1278,7 +1248,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1278 | .segname = makeStaticString("__LINKEDIT"), | 1248 | .segname = makeStaticString("__LINKEDIT"), |
| 1279 | .vmaddr = data_segment.vmaddr + data_segment.vmsize, | 1249 | .vmaddr = data_segment.vmaddr + data_segment.vmsize, |
| 1280 | .vmsize = 0, | 1250 | .vmsize = 0, |
| 1281 | .fileoff = 0, | 1251 | .fileoff = off, |
| 1282 | .filesize = 0, | 1252 | .filesize = 0, |
| 1283 | .maxprot = maxprot, | 1253 | .maxprot = maxprot, |
| 1284 | .initprot = initprot, | 1254 | .initprot = initprot, |
| ... | @@ -1286,6 +1256,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -1286,6 +1256,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1286 | .flags = 0, | 1256 | .flags = 0, |
| 1287 | }, | 1257 | }, |
| 1288 | }); | 1258 | }); |
| | 1259 | self.linkedit_segment_next_offset = @intCast(u32, off); |
| 1289 | self.cmd_table_dirty = true; | 1260 | self.cmd_table_dirty = true; |
| 1290 | } | 1261 | } |
| 1291 | if (self.dyld_info_cmd_index == null) { | 1262 | if (self.dyld_info_cmd_index == null) { |
| ... | @@ -1438,62 +1409,6 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -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 | if (self.dyld_stub_binder_index == null) { | 1412 | if (self.dyld_stub_binder_index == null) { |
| 1498 | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); | 1413 | self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len); |
| 1499 | const name = try self.makeString("dyld_stub_binder"); | 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,17 +1634,6 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u16) u64 { |
| 1719 | return start; | 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 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 1637 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1734 | const sect = &self.sections.items[self.got_section_index.?]; | 1638 | const sect = &self.sections.items[self.got_section_index.?]; |
| 1735 | const endian = self.base.options.target.cpu.arch.endian(); | 1639 | const endian = self.base.options.target.cpu.arch.endian(); |
| ... | @@ -1740,30 +1644,72 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | ... | @@ -1740,30 +1644,72 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1740 | try self.base.file.?.pwriteAll(&buf, off); | 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 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 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 { | 1651 | const locals_off = self.linkedit_segment_next_offset.?; |
| 1752 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1652 | const locals_size = self.local_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1753 | const nlocals = self.local_symbols.items.len; | 1653 | log.debug("writing local symbols from 0x{x} to 0x{x}\n", .{ locals_off, locals_size + locals_off }); |
| 1754 | const nglobals = self.global_symbols.items.len; | 1654 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.local_symbols.items), locals_off); |
| 1755 | const off = symtab.symoff + (nlocals + nglobals) * @sizeOf(macho.nlist_64); | 1655 | |
| 1756 | const file_size = self.undef_symbols.items.len * @sizeOf(macho.nlist_64); | 1656 | const globals_off = locals_off + locals_size; |
| 1757 | log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ off, file_size + off }); | 1657 | const globals_size = self.global_symbols.items.len * @sizeOf(macho.nlist_64); |
| 1758 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), off); | 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 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; | 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 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file | 1706 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 1764 | // except for code signature data. | 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 | var code_sig = CodeSignature.init(self.base.allocator); | 1713 | var code_sig = CodeSignature.init(self.base.allocator); |
| 1768 | defer code_sig.deinit(); | 1714 | defer code_sig.deinit(); |
| 1769 | | 1715 | |
| ... | @@ -1780,7 +1726,7 @@ fn writeCodeSignature(self: *MachO) !void { | ... | @@ -1780,7 +1726,7 @@ fn writeCodeSignature(self: *MachO) !void { |
| 1780 | } | 1726 | } |
| 1781 | | 1727 | |
| 1782 | fn writeExportTrie(self: *MachO) !void { | 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 | var trie: Trie = .{}; | 1731 | var trie: Trie = .{}; |
| 1786 | defer trie.deinit(self.base.allocator); | 1732 | defer trie.deinit(self.base.allocator); |
| ... | @@ -1803,23 +1749,51 @@ fn writeExportTrie(self: *MachO) !void { | ... | @@ -1803,23 +1749,51 @@ fn writeExportTrie(self: *MachO) !void { |
| 1803 | try trie.writeULEB128Mem(self.base.allocator, &buffer); | 1749 | try trie.writeULEB128Mem(self.base.allocator, &buffer); |
| 1804 | | 1750 | |
| 1805 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfo; | 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 | try self.base.file.?.pwriteAll(buffer.items, dyld_info.export_off); | 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 | fn writeStringTable(self: *MachO) !void { | 1774 | fn writeStringTable(self: *MachO) !void { |
| 1810 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; | 1775 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 1811 | const allocated_size = self.allocatedSize(symtab.stroff); | | |
| 1812 | const needed_size = self.string_table.items.len; | 1776 | const needed_size = self.string_table.items.len; |
| 1813 | | 1777 | |
| 1814 | if (needed_size > allocated_size) { | 1778 | symtab.stroff = self.linkedit_segment_next_offset.?; |
| 1815 | symtab.strsize = 0; | 1779 | symtab.strsize = @intCast(u32, mem.alignForward(needed_size, @sizeOf(u64))); |
| 1816 | symtab.stroff = @intCast(u32, self.findFreeSpace(needed_size, 1)); | | |
| 1817 | } | | |
| 1818 | symtab.strsize = @intCast(u32, needed_size); | | |
| 1819 | | 1780 | |
| 1820 | log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize }); | 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 | try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff); | 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 | fn writeCmdHeaders(self: *MachO) !void { | 1799 | fn writeCmdHeaders(self: *MachO) !void { |