authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-22 12:33:39+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
log59fe3d447d8cdd5dda34d7a77459c2c6761857ea
tree2dcaf176d76a7243126e006f574d50a4324b882a
parente7db37286459b30e5cb95666aac25d1f9406dd3e

stage2 macho: make file structure compatible with codesign tool


1 files changed, 113 insertions(+), 139 deletions(-)

src/link/MachO.zig+113-139
...@@ -125,6 +125,9 @@ got_section_index: ?u16 = null,...@@ -125,6 +125,9 @@ got_section_index: ?u16 = null,
125125
126entry_addr: ?u64 = null,126entry_addr: ?u64 = null,
127127
128// TODO move this into each Segment aggregator
129linkedit_segment_next_offset: ?u32 = null,
130
128/// Table of all local symbols131/// 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).
130local_symbols: std.ArrayListUnmanaged(macho.nlist_64) = .{},133local_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();
332335
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 }
392385
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 }
1027995
...@@ -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;
12421210
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);
12451215
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 });
12471217
...@@ -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}
17211636
1722fn 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
1733fn writeOffsetTableEntry(self: *MachO, index: usize) !void {1637fn 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}
17421646
1743fn writeAllGlobalSymbols(self: *MachO) !void {1647fn 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}
17501650
1751fn 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}
17601690
1761fn writeCodeSignature(self: *MachO) !void {1691fn 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 file1706 // 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}
17661710
1711fn 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();
17691715
...@@ -1780,7 +1726,7 @@ fn writeCodeSignature(self: *MachO) !void {...@@ -1780,7 +1726,7 @@ fn writeCodeSignature(self: *MachO) !void {
1780}1726}
17811727
1782fn writeExportTrie(self: *MachO) !void {1728fn 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);
17841730
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);
18041750
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}
18081773
1809fn writeStringTable(self: *MachO) !void {1774fn 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;
18131777
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);
18191780
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 });
18211782
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}
18241798
1825fn writeCmdHeaders(self: *MachO) !void {1799fn writeCmdHeaders(self: *MachO) !void {