authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-21 19:59:40+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-12-21 19:59:40+01:00
log3f21f9155fe8e10e3990ee5738b190accbdffd3a
treec4ba81c7ad1f628fa58ee9c6cdb3a152adba12dd
parentde5421a0a666000908527503af8f511b9b3095ed

macho: write only bits that changed

Refactor use of `log` to not include an additional newline char.

1 files changed, 125 insertions(+), 77 deletions(-)

src/link/MachO.zig+125-77
......@@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{},
111111
112112error_flags: File.ErrorFlags = File.ErrorFlags{},
113113
114cmd_table_dirty: bool = false,
114offset_table_count_dirty: bool = false,
115header_dirty: bool = false,
116load_commands_dirty: bool = false,
117export_info_dirty: bool = false,
118string_table_dirty: bool = false,
115119
116120/// A list of text blocks that have surplus capacity. This list can have false
117121/// positives, as functions grow and shrink over time, only sometimes being added
......@@ -316,7 +320,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
316320 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
317321 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
318322 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
319 self.cmd_table_dirty = true;
323 self.load_commands_dirty = true;
320324 }
321325 try self.writeExportTrie();
322326 try self.writeAllGlobalAndUndefSymbols();
......@@ -336,21 +340,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
336340 .Lib => return error.TODOImplementWritingLibFiles,
337341 }
338342
339 if (self.cmd_table_dirty) {
340 try self.writeLoadCommands();
341 try self.writeHeader();
342 self.cmd_table_dirty = false;
343 }
343 try self.writeLoadCommands();
344 try self.writeHeader();
344345
345346 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
346 log.debug("flushing. no_entry_point_found = true\n", .{});
347 log.debug("flushing. no_entry_point_found = true", .{});
347348 self.error_flags.no_entry_point_found = true;
348349 } else {
349 log.debug("flushing. no_entry_point_found = false\n", .{});
350 log.debug("flushing. no_entry_point_found = false", .{});
350351 self.error_flags.no_entry_point_found = false;
351352 }
352353
353 assert(!self.cmd_table_dirty);
354 assert(!self.offset_table_count_dirty);
355 assert(!self.header_dirty);
356 assert(!self.load_commands_dirty);
357 assert(!self.export_info_dirty);
358 assert(!self.string_table_dirty);
354359
355360 if (target.cpu.arch == .aarch64) {
356361 switch (output_mode) {
......@@ -769,9 +774,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
769774 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
770775
771776 if (needed_size + after_last_cmd_offset > text_section.offset) {
772 std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
773 std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
774 std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
777 log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
778 log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
779 log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
775780 return error.NotEnoughPadding;
776781 }
777782
......@@ -807,10 +812,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
807812 mem.set(u8, dylib_cmd.data, 0);
808813 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
809814 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
815 self.header_dirty = true;
816 self.load_commands_dirty = true;
810817
811818 if (self.symtab_cmd_index == null or self.dysymtab_cmd_index == null) {
812 std.log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{});
813 std.log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
819 log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{});
820 log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
814821 return error.NoSymbolTableFound;
815822 }
816823
......@@ -863,9 +870,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
863870 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
864871
865872 if (needed_size + after_last_cmd_offset > text_section.offset) {
866 std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
867 std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
868 std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
873 log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
874 log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
875 log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
869876 return error.NotEnoughPadding;
870877 }
871878
......@@ -879,6 +886,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
879886 .datasize = 0,
880887 },
881888 });
889 self.header_dirty = true;
890 self.load_commands_dirty = true;
882891
883892 // Pad out space for code signature
884893 try self.writeCodeSignaturePadding();
......@@ -1000,10 +1009,10 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
10001009 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
10011010
10021011 if (self.local_symbol_free_list.popOrNull()) |i| {
1003 log.debug("reusing symbol index {} for {}\n", .{ i, decl.name });
1012 log.debug("reusing symbol index {} for {}", .{ i, decl.name });
10041013 decl.link.macho.local_sym_index = i;
10051014 } else {
1006 log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
1015 log.debug("allocating symbol index {} for {}", .{ self.local_symbols.items.len, decl.name });
10071016 decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);
10081017 _ = self.local_symbols.addOneAssumeCapacity();
10091018 }
......@@ -1013,6 +1022,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
10131022 } else {
10141023 decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);
10151024 _ = self.offset_table.addOneAssumeCapacity();
1025 self.offset_table_count_dirty = true;
10161026 }
10171027
10181028 self.local_symbols.items[decl.link.macho.local_sym_index] = .{
......@@ -1054,10 +1064,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
10541064 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
10551065 if (need_realloc) {
10561066 const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment);
1057 log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, symbol.n_value, vaddr });
1067 log.debug("growing {} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
10581068 if (vaddr != symbol.n_value) {
10591069 symbol.n_value = vaddr;
1060 log.debug(" (writing new offset table entry)\n", .{});
1070 log.debug(" (writing new offset table entry)", .{});
10611071 self.offset_table.items[decl.link.macho.offset_table_index] = vaddr;
10621072 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
10631073 }
......@@ -1075,7 +1085,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
10751085 const decl_name = mem.spanZ(decl.name);
10761086 const name_str_index = try self.makeString(decl_name);
10771087 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
1078 log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, addr });
1088 log.debug("allocated text block for {} at 0x{x}", .{ decl_name, addr });
10791089 errdefer self.freeTextBlock(&decl.link.macho);
10801090
10811091 symbol.* = .{
......@@ -1153,7 +1163,6 @@ pub fn updateDeclExports(
11531163 .Strong => blk: {
11541164 if (mem.eql(u8, exp.options.name, "_start")) {
11551165 self.entry_addr = decl_sym.n_value;
1156 self.cmd_table_dirty = true; // TODO This should be handled more granularly instead of invalidating all commands.
11571166 }
11581167 break :blk macho.REFERENCE_FLAG_DEFINED;
11591168 },
......@@ -1181,6 +1190,7 @@ pub fn updateDeclExports(
11811190 const name_str_index = try self.makeString(exp.options.name);
11821191 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
11831192 _ = self.global_symbols.addOneAssumeCapacity();
1193 self.export_info_dirty = true;
11841194 break :blk self.global_symbols.items.len - 1;
11851195 };
11861196 self.global_symbols.items[i] = .{
......@@ -1273,7 +1283,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
12731283 }
12741284 header.reserved = 0;
12751285 self.header = header;
1276 self.cmd_table_dirty = true;
1286 self.header_dirty = true;
12771287 }
12781288 if (self.pagezero_segment_cmd_index == null) {
12791289 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1292,7 +1302,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
12921302 .flags = 0,
12931303 }),
12941304 });
1295 self.cmd_table_dirty = true;
1305 self.header_dirty = true;
1306 self.load_commands_dirty = true;
12961307 }
12971308 if (self.text_segment_cmd_index == null) {
12981309 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1304,7 +1315,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13041315 const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint;
13051316 const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size);
13061317
1307 log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size });
1318 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
13081319
13091320 try self.load_commands.append(self.base.allocator, .{
13101321 .Segment = SegmentCommand.empty(.{
......@@ -1321,7 +1332,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13211332 .flags = 0,
13221333 }),
13231334 });
1324 self.cmd_table_dirty = true;
1335 self.header_dirty = true;
1336 self.load_commands_dirty = true;
13251337 }
13261338 if (self.text_section_index == null) {
13271339 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
......@@ -1336,7 +1348,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13361348 const needed_size = self.base.options.program_code_size_hint;
13371349 const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment);
13381350
1339 log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });
1351 log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
13401352
13411353 try text_segment.addSection(self.base.allocator, .{
13421354 .sectname = makeStaticString("__text"),
......@@ -1352,7 +1364,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13521364 .reserved2 = 0,
13531365 .reserved3 = 0,
13541366 });
1355 self.cmd_table_dirty = true;
1367 self.header_dirty = true;
1368 self.load_commands_dirty = true;
13561369 }
13571370 if (self.got_section_index == null) {
13581371 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
......@@ -1364,7 +1377,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13641377 const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));
13651378 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
13661379
1367 log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });
1380 log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
13681381
13691382 try text_segment.addSection(self.base.allocator, .{
13701383 .sectname = makeStaticString("__ziggot"),
......@@ -1380,7 +1393,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13801393 .reserved2 = 0,
13811394 .reserved3 = 0,
13821395 });
1383 self.cmd_table_dirty = true;
1396 self.header_dirty = true;
1397 self.load_commands_dirty = true;
13841398 }
13851399 if (self.linkedit_segment_cmd_index == null) {
13861400 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1389,7 +1403,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
13891403 const initprot = macho.VM_PROT_READ;
13901404 const address_and_offset = self.nextSegmentAddressAndOffset();
13911405
1392 log.debug("found __LINKEDIT segment free space at 0x{x}\n", .{address_and_offset.offset});
1406 log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
13931407
13941408 try self.load_commands.append(self.base.allocator, .{
13951409 .Segment = SegmentCommand.empty(.{
......@@ -1406,7 +1420,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14061420 .flags = 0,
14071421 }),
14081422 });
1409 self.cmd_table_dirty = true;
1423 self.header_dirty = true;
1424 self.load_commands_dirty = true;
14101425 }
14111426 if (self.dyld_info_cmd_index == null) {
14121427 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1416,7 +1431,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14161431 const export_size = 2;
14171432 const export_off = self.findFreeSpace(&linkedit_segment, export_size, 1);
14181433
1419 log.debug("found export info free space 0x{x} to 0x{x}\n", .{ export_off, export_off + export_size });
1434 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
14201435
14211436 try self.load_commands.append(self.base.allocator, .{
14221437 .DyldInfoOnly = .{
......@@ -1434,7 +1449,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14341449 .export_size = export_size,
14351450 },
14361451 });
1437 self.cmd_table_dirty = true;
1452 self.header_dirty = true;
1453 self.load_commands_dirty = true;
14381454 }
14391455 if (self.symtab_cmd_index == null) {
14401456 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1443,13 +1459,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14431459 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);
14441460 const symtab_off = self.findFreeSpace(&linkedit_segment, symtab_size, @sizeOf(macho.nlist_64));
14451461
1446 log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size });
1462 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
14471463
14481464 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
14491465 const strtab_size = self.string_table.items.len;
14501466 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);
14511467
1452 log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size });
1468 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
14531469
14541470 try self.load_commands.append(self.base.allocator, .{
14551471 .Symtab = .{
......@@ -1461,8 +1477,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14611477 .strsize = @intCast(u32, strtab_size),
14621478 },
14631479 });
1464 self.cmd_table_dirty = true;
14651480 try self.writeLocalSymbol(0);
1481 self.header_dirty = true;
1482 self.load_commands_dirty = true;
1483 self.string_table_dirty = true;
14661484 }
14671485 if (self.dysymtab_cmd_index == null) {
14681486 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1493,7 +1511,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
14931511 .nlocrel = 0,
14941512 },
14951513 });
1496 self.cmd_table_dirty = true;
1514 self.header_dirty = true;
1515 self.load_commands_dirty = true;
14971516 }
14981517 if (self.dylinker_cmd_index == null) {
14991518 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1507,7 +1526,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15071526 mem.set(u8, dylinker_cmd.data, 0);
15081527 mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH));
15091528 try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });
1510 self.cmd_table_dirty = true;
1529 self.header_dirty = true;
1530 self.load_commands_dirty = true;
15111531 }
15121532 if (self.libsystem_cmd_index == null) {
15131533 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1529,7 +1549,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15291549 mem.set(u8, dylib_cmd.data, 0);
15301550 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
15311551 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
1532 self.cmd_table_dirty = true;
1552 self.header_dirty = true;
1553 self.load_commands_dirty = true;
15331554 }
15341555 if (self.main_cmd_index == null) {
15351556 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1541,7 +1562,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15411562 .stacksize = 0,
15421563 },
15431564 });
1544 self.cmd_table_dirty = true;
1565 self.header_dirty = true;
1566 self.load_commands_dirty = true;
15451567 }
15461568 if (self.version_min_cmd_index == null) {
15471569 self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1562,7 +1584,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15621584 .sdk = version,
15631585 },
15641586 });
1565 self.cmd_table_dirty = true;
1587 self.header_dirty = true;
1588 self.load_commands_dirty = true;
15661589 }
15671590 if (self.source_version_cmd_index == null) {
15681591 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1573,7 +1596,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15731596 .version = 0x0,
15741597 },
15751598 });
1576 self.cmd_table_dirty = true;
1599 self.header_dirty = true;
1600 self.load_commands_dirty = true;
15771601 }
15781602 if (self.code_signature_cmd_index == null) {
15791603 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
......@@ -1586,7 +1610,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
15861610 .datasize = 0,
15871611 },
15881612 });
1589 self.cmd_table_dirty = true;
1613 self.header_dirty = true;
1614 self.load_commands_dirty = true;
15901615 }
15911616 if (self.dyld_stub_binder_index == null) {
15921617 self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);
......@@ -1674,7 +1699,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
16741699 self.last_text_block = text_block;
16751700 text_section.size = needed_size;
16761701
1677 self.cmd_table_dirty = true; // TODO Make more granular.
1702 self.load_commands_dirty = true; // TODO Make more granular.
16781703 }
16791704 text_block.size = new_block_size;
16801705
......@@ -1712,6 +1737,7 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
17121737 const result = self.string_table.items.len;
17131738 self.string_table.appendSliceAssumeCapacity(bytes);
17141739 self.string_table.appendAssumeCapacity(0);
1740 self.string_table_dirty = true;
17151741 return @intCast(u32, result);
17161742}
17171743
......@@ -1908,11 +1934,16 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
19081934}
19091935
19101936fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1911 const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1912 const sect = &text_semgent.sections.items[self.got_section_index.?];
1937 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1938 const sect = &text_segment.sections.items[self.got_section_index.?];
19131939 const off = sect.offset + @sizeOf(u64) * index;
19141940 const vmaddr = sect.addr + @sizeOf(u64) * index;
19151941
1942 if (self.offset_table_count_dirty) {
1943 // TODO relocate.
1944 self.offset_table_count_dirty = false;
1945 }
1946
19161947 var code: [8]u8 = undefined;
19171948 switch (self.base.options.target.cpu.arch) {
19181949 .x86_64 => {
......@@ -1936,7 +1967,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
19361967 },
19371968 else => unreachable, // unsupported target architecture
19381969 }
1939 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
1970 log.debug("writing offset table entry 0x{x} at 0x{x}", .{ self.offset_table.items[index], off });
19401971 try self.base.file.?.pwriteAll(&code, off);
19411972}
19421973
......@@ -1967,7 +1998,7 @@ fn relocateSymbolTable(self: *MachO) !void {
19671998 symtab.symoff = @intCast(u32, new_symoff);
19681999 }
19692000 symtab.nsyms = @intCast(u32, nsyms);
1970 self.cmd_table_dirty = true;
2001 self.load_commands_dirty = true;
19712002 }
19722003}
19732004
......@@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
19962027
19972028 const globals_off = locals_off + locals_size;
19982029 const globals_size = nglobals * @sizeOf(macho.nlist_64);
1999 log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ globals_off, globals_size + globals_off });
2030 log.debug("writing global symbols from 0x{x} to 0x{x}", .{ globals_off, globals_size + globals_off });
20002031 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);
20012032
20022033 const undefs_off = globals_off + globals_size;
20032034 const undefs_size = nundefs * @sizeOf(macho.nlist_64);
2004 log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
2035 log.debug("writing undef symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
20052036 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
20062037
20072038 // Update dynamic symbol table.
......@@ -2011,7 +2042,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
20112042 dysymtab.nextdefsym = @intCast(u32, nglobals);
20122043 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
20132044 dysymtab.nundefsym = @intCast(u32, nundefs);
2014 self.cmd_table_dirty = true;
2045 self.load_commands_dirty = true;
20152046}
20162047
20172048fn writeCodeSignaturePadding(self: *MachO) !void {
......@@ -2021,19 +2052,23 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
20212052 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
20222053 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
20232054 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
2024 const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
2025 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2026 code_sig_cmd.datasize = datasize;
2055 const needed_size = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
20272056
2028 // Advance size of __LINKEDIT segment
2029 linkedit_segment.inner.filesize += datasize;
2030 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2031 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2032 }
2033 log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });
2034 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2035 // except for code signature data.
2036 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + datasize - 1);
2057 if (code_sig_cmd.datasize < needed_size) {
2058 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2059 code_sig_cmd.datasize = needed_size;
2060
2061 // Advance size of __LINKEDIT segment
2062 linkedit_segment.inner.filesize += needed_size;
2063 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2064 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2065 }
2066 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
2067 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
2068 // except for code signature data.
2069 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
2070 self.load_commands_dirty = true;
2071 }
20372072}
20382073
20392074fn writeCodeSignature(self: *MachO) !void {
......@@ -2057,12 +2092,13 @@ fn writeCodeSignature(self: *MachO) !void {
20572092 defer self.base.allocator.free(buffer);
20582093 code_sig.write(buffer);
20592094
2060 log.debug("writing code signature from 0x{x} to 0x{x}\n", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
2095 log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
20612096
20622097 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
20632098}
20642099
20652100fn writeExportTrie(self: *MachO) !void {
2101 if (!self.export_info_dirty) return;
20662102 if (self.global_symbols.items.len == 0) return;
20672103
20682104 const tracy = trace(@src());
......@@ -2100,10 +2136,11 @@ fn writeExportTrie(self: *MachO) !void {
21002136 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
21012137 }
21022138 dyld_info.export_size = @intCast(u32, needed_size);
2103 log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
2139 log.debug("writing export trie from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
21042140
21052141 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
2106 self.cmd_table_dirty = true;
2142 self.load_commands_dirty = true;
2143 self.export_info_dirty = false;
21072144}
21082145
21092146fn writeBindingInfoTable(self: *MachO) !void {
......@@ -2119,7 +2156,7 @@ fn writeBindingInfoTable(self: *MachO) !void {
21192156 dyld_info.bind_off = self.linkedit_segment_next_offset.?;
21202157 dyld_info.bind_size = bind_size;
21212158
2122 log.debug("writing binding info table from 0x{x} to 0x{x}\n", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size });
2159 log.debug("writing binding info table from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size });
21232160
21242161 if (bind_size > buffer.len) {
21252162 // Pad out to align(8).
......@@ -2150,7 +2187,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
21502187 dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?;
21512188 dyld_info.lazy_bind_size = bind_size;
21522189
2153 log.debug("writing lazy binding info table from 0x{x} to 0x{x}\n", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + bind_size });
2190 log.debug("writing lazy binding info table from 0x{x} to 0x{x}", .{ dyld_info.lazy_bind_off, dyld_info.lazy_bind_off + bind_size });
21542191
21552192 if (bind_size > buffer.len) {
21562193 // Pad out to align(8).
......@@ -2169,6 +2206,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
21692206}
21702207
21712208fn writeStringTable(self: *MachO) !void {
2209 if (!self.string_table_dirty) return;
2210
21722211 const tracy = trace(@src());
21732212 defer tracy.end();
21742213
......@@ -2182,13 +2221,16 @@ fn writeStringTable(self: *MachO) !void {
21822221 symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
21832222 }
21842223 symtab.strsize = @intCast(u32, needed_size);
2185 log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
2224 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
21862225
21872226 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
2188 self.cmd_table_dirty = true;
2227 self.load_commands_dirty = true;
2228 self.string_table_dirty = false;
21892229}
21902230
21912231fn updateLinkeditSegmentSizes(self: *MachO) !void {
2232 if (!self.load_commands_dirty) return;
2233
21922234 const tracy = trace(@src());
21932235 defer tracy.end();
21942236
......@@ -2229,10 +2271,13 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {
22292271 const filesize = final_offset - linkedit_segment.inner.fileoff;
22302272 linkedit_segment.inner.filesize = filesize;
22312273 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
2274 self.load_commands_dirty = true;
22322275}
22332276
22342277/// Writes all load commands and section headers.
22352278fn writeLoadCommands(self: *MachO) !void {
2279 if (!self.load_commands_dirty) return;
2280
22362281 var sizeofcmds: usize = 0;
22372282 for (self.load_commands.items) |lc| {
22382283 sizeofcmds += lc.cmdsize();
......@@ -2246,19 +2291,22 @@ fn writeLoadCommands(self: *MachO) !void {
22462291 }
22472292
22482293 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
2294 self.load_commands_dirty = false;
22492295}
22502296
22512297/// Writes Mach-O file header.
22522298fn writeHeader(self: *MachO) !void {
2299 if (!self.header_dirty) return;
2300
22532301 self.header.?.ncmds = @intCast(u32, self.load_commands.items.len);
22542302 var sizeofcmds: u32 = 0;
22552303 for (self.load_commands.items) |cmd| {
22562304 sizeofcmds += cmd.cmdsize();
22572305 }
22582306 self.header.?.sizeofcmds = sizeofcmds;
2259 log.debug("writing Mach-O header {}\n", .{self.header.?});
2260 const slice = [1]macho.mach_header_64{self.header.?};
2261 try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0);
2307 log.debug("writing Mach-O header {}", .{self.header.?});
2308 try self.base.file.?.pwriteAll(mem.asBytes(&self.header.?), 0);
2309 self.header_dirty = false;
22622310}
22632311
22642312/// Parse MachO contents from existing binary file.
......@@ -2327,7 +2375,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
23272375 self.code_signature_cmd_index = i;
23282376 },
23292377 else => {
2330 std.log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
2378 log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
23312379 },
23322380 }
23332381 self.load_commands.appendAssumeCapacity(cmd);