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 = .{},...@@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{},
111111
112error_flags: File.ErrorFlags = File.ErrorFlags{},112error_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
116/// A list of text blocks that have surplus capacity. This list can have false120/// A list of text blocks that have surplus capacity. This list can have false
117/// positives, as functions grow and shrink over time, only sometimes being added121/// positives, as functions grow and shrink over time, only sometimes being added
...@@ -316,7 +320,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -316,7 +320,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
316 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;320 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
317 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;321 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
318 main_cmd.entryoff = addr - text_segment.inner.vmaddr;322 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
319 self.cmd_table_dirty = true;323 self.load_commands_dirty = true;
320 }324 }
321 try self.writeExportTrie();325 try self.writeExportTrie();
322 try self.writeAllGlobalAndUndefSymbols();326 try self.writeAllGlobalAndUndefSymbols();
...@@ -336,21 +340,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -336,21 +340,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
336 .Lib => return error.TODOImplementWritingLibFiles,340 .Lib => return error.TODOImplementWritingLibFiles,
337 }341 }
338342
339 if (self.cmd_table_dirty) {343 try self.writeLoadCommands();
340 try self.writeLoadCommands();344 try self.writeHeader();
341 try self.writeHeader();
342 self.cmd_table_dirty = false;
343 }
344345
345 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {346 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", .{});
347 self.error_flags.no_entry_point_found = true;348 self.error_flags.no_entry_point_found = true;
348 } else {349 } else {
349 log.debug("flushing. no_entry_point_found = false\n", .{});350 log.debug("flushing. no_entry_point_found = false", .{});
350 self.error_flags.no_entry_point_found = false;351 self.error_flags.no_entry_point_found = false;
351 }352 }
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
355 if (target.cpu.arch == .aarch64) {360 if (target.cpu.arch == .aarch64) {
356 switch (output_mode) {361 switch (output_mode) {
...@@ -769,9 +774,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -769,9 +774,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
769 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;774 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
770775
771 if (needed_size + after_last_cmd_offset > text_section.offset) {776 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.", .{});777 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});778 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'.", .{});779 log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
775 return error.NotEnoughPadding;780 return error.NotEnoughPadding;
776 }781 }
777782
...@@ -807,10 +812,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -807,10 +812,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
807 mem.set(u8, dylib_cmd.data, 0);812 mem.set(u8, dylib_cmd.data, 0);
808 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));813 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
809 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });814 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
815 self.header_dirty = true;
816 self.load_commands_dirty = true;
810817
811 if (self.symtab_cmd_index == null or self.dysymtab_cmd_index == null) {818 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!", .{});819 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.", .{});820 log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
814 return error.NoSymbolTableFound;821 return error.NoSymbolTableFound;
815 }822 }
816823
...@@ -863,9 +870,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -863,9 +870,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
863 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;870 const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
864871
865 if (needed_size + after_last_cmd_offset > text_section.offset) {872 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.", .{});873 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});874 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'.", .{});875 log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
869 return error.NotEnoughPadding;876 return error.NotEnoughPadding;
870 }877 }
871878
...@@ -879,6 +886,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -879,6 +886,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
879 .datasize = 0,886 .datasize = 0,
880 },887 },
881 });888 });
889 self.header_dirty = true;
890 self.load_commands_dirty = true;
882891
883 // Pad out space for code signature892 // Pad out space for code signature
884 try self.writeCodeSignaturePadding();893 try self.writeCodeSignaturePadding();
...@@ -1000,10 +1009,10 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -1000,10 +1009,10 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
1000 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);1009 try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
10011010
1002 if (self.local_symbol_free_list.popOrNull()) |i| {1011 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 });
1004 decl.link.macho.local_sym_index = i;1013 decl.link.macho.local_sym_index = i;
1005 } else {1014 } 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 });
1007 decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);1016 decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);
1008 _ = self.local_symbols.addOneAssumeCapacity();1017 _ = self.local_symbols.addOneAssumeCapacity();
1009 }1018 }
...@@ -1013,6 +1022,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -1013,6 +1022,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
1013 } else {1022 } else {
1014 decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);1023 decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);
1015 _ = self.offset_table.addOneAssumeCapacity();1024 _ = self.offset_table.addOneAssumeCapacity();
1025 self.offset_table_count_dirty = true;
1016 }1026 }
10171027
1018 self.local_symbols.items[decl.link.macho.local_sym_index] = .{1028 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 {...@@ -1054,10 +1064,10 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1054 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);1064 const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
1055 if (need_realloc) {1065 if (need_realloc) {
1056 const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment);1066 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 });
1058 if (vaddr != symbol.n_value) {1068 if (vaddr != symbol.n_value) {
1059 symbol.n_value = vaddr;1069 symbol.n_value = vaddr;
1060 log.debug(" (writing new offset table entry)\n", .{});1070 log.debug(" (writing new offset table entry)", .{});
1061 self.offset_table.items[decl.link.macho.offset_table_index] = vaddr;1071 self.offset_table.items[decl.link.macho.offset_table_index] = vaddr;
1062 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);1072 try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
1063 }1073 }
...@@ -1075,7 +1085,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1075,7 +1085,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1075 const decl_name = mem.spanZ(decl.name);1085 const decl_name = mem.spanZ(decl.name);
1076 const name_str_index = try self.makeString(decl_name);1086 const name_str_index = try self.makeString(decl_name);
1077 const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);1087 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 });
1079 errdefer self.freeTextBlock(&decl.link.macho);1089 errdefer self.freeTextBlock(&decl.link.macho);
10801090
1081 symbol.* = .{1091 symbol.* = .{
...@@ -1153,7 +1163,6 @@ pub fn updateDeclExports(...@@ -1153,7 +1163,6 @@ pub fn updateDeclExports(
1153 .Strong => blk: {1163 .Strong => blk: {
1154 if (mem.eql(u8, exp.options.name, "_start")) {1164 if (mem.eql(u8, exp.options.name, "_start")) {
1155 self.entry_addr = decl_sym.n_value;1165 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.
1157 }1166 }
1158 break :blk macho.REFERENCE_FLAG_DEFINED;1167 break :blk macho.REFERENCE_FLAG_DEFINED;
1159 },1168 },
...@@ -1181,6 +1190,7 @@ pub fn updateDeclExports(...@@ -1181,6 +1190,7 @@ pub fn updateDeclExports(
1181 const name_str_index = try self.makeString(exp.options.name);1190 const name_str_index = try self.makeString(exp.options.name);
1182 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {1191 const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
1183 _ = self.global_symbols.addOneAssumeCapacity();1192 _ = self.global_symbols.addOneAssumeCapacity();
1193 self.export_info_dirty = true;
1184 break :blk self.global_symbols.items.len - 1;1194 break :blk self.global_symbols.items.len - 1;
1185 };1195 };
1186 self.global_symbols.items[i] = .{1196 self.global_symbols.items[i] = .{
...@@ -1273,7 +1283,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1273,7 +1283,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1273 }1283 }
1274 header.reserved = 0;1284 header.reserved = 0;
1275 self.header = header;1285 self.header = header;
1276 self.cmd_table_dirty = true;1286 self.header_dirty = true;
1277 }1287 }
1278 if (self.pagezero_segment_cmd_index == null) {1288 if (self.pagezero_segment_cmd_index == null) {
1279 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1289 self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1292,7 +1302,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1292,7 +1302,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1292 .flags = 0,1302 .flags = 0,
1293 }),1303 }),
1294 });1304 });
1295 self.cmd_table_dirty = true;1305 self.header_dirty = true;
1306 self.load_commands_dirty = true;
1296 }1307 }
1297 if (self.text_segment_cmd_index == null) {1308 if (self.text_segment_cmd_index == null) {
1298 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1309 self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1304,7 +1315,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1304,7 +1315,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1304 const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint;1315 const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint;
1305 const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size);1316 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
1309 try self.load_commands.append(self.base.allocator, .{1320 try self.load_commands.append(self.base.allocator, .{
1310 .Segment = SegmentCommand.empty(.{1321 .Segment = SegmentCommand.empty(.{
...@@ -1321,7 +1332,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1321,7 +1332,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1321 .flags = 0,1332 .flags = 0,
1322 }),1333 }),
1323 });1334 });
1324 self.cmd_table_dirty = true;1335 self.header_dirty = true;
1336 self.load_commands_dirty = true;
1325 }1337 }
1326 if (self.text_section_index == null) {1338 if (self.text_section_index == null) {
1327 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1339 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
...@@ -1336,7 +1348,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1336,7 +1348,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1336 const needed_size = self.base.options.program_code_size_hint;1348 const needed_size = self.base.options.program_code_size_hint;
1337 const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment);1349 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
1341 try text_segment.addSection(self.base.allocator, .{1353 try text_segment.addSection(self.base.allocator, .{
1342 .sectname = makeStaticString("__text"),1354 .sectname = makeStaticString("__text"),
...@@ -1352,7 +1364,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1352,7 +1364,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1352 .reserved2 = 0,1364 .reserved2 = 0,
1353 .reserved3 = 0,1365 .reserved3 = 0,
1354 });1366 });
1355 self.cmd_table_dirty = true;1367 self.header_dirty = true;
1368 self.load_commands_dirty = true;
1356 }1369 }
1357 if (self.got_section_index == null) {1370 if (self.got_section_index == null) {
1358 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1371 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
...@@ -1364,7 +1377,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1364,7 +1377,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1364 const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));1377 const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));
1365 assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.1378 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
1369 try text_segment.addSection(self.base.allocator, .{1382 try text_segment.addSection(self.base.allocator, .{
1370 .sectname = makeStaticString("__ziggot"),1383 .sectname = makeStaticString("__ziggot"),
...@@ -1380,7 +1393,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1380,7 +1393,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1380 .reserved2 = 0,1393 .reserved2 = 0,
1381 .reserved3 = 0,1394 .reserved3 = 0,
1382 });1395 });
1383 self.cmd_table_dirty = true;1396 self.header_dirty = true;
1397 self.load_commands_dirty = true;
1384 }1398 }
1385 if (self.linkedit_segment_cmd_index == null) {1399 if (self.linkedit_segment_cmd_index == null) {
1386 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);1400 self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1389,7 +1403,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1389,7 +1403,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1389 const initprot = macho.VM_PROT_READ;1403 const initprot = macho.VM_PROT_READ;
1390 const address_and_offset = self.nextSegmentAddressAndOffset();1404 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
1394 try self.load_commands.append(self.base.allocator, .{1408 try self.load_commands.append(self.base.allocator, .{
1395 .Segment = SegmentCommand.empty(.{1409 .Segment = SegmentCommand.empty(.{
...@@ -1406,7 +1420,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1406,7 +1420,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1406 .flags = 0,1420 .flags = 0,
1407 }),1421 }),
1408 });1422 });
1409 self.cmd_table_dirty = true;1423 self.header_dirty = true;
1424 self.load_commands_dirty = true;
1410 }1425 }
1411 if (self.dyld_info_cmd_index == null) {1426 if (self.dyld_info_cmd_index == null) {
1412 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);1427 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1416,7 +1431,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1416,7 +1431,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1416 const export_size = 2;1431 const export_size = 2;
1417 const export_off = self.findFreeSpace(&linkedit_segment, export_size, 1);1432 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
1421 try self.load_commands.append(self.base.allocator, .{1436 try self.load_commands.append(self.base.allocator, .{
1422 .DyldInfoOnly = .{1437 .DyldInfoOnly = .{
...@@ -1434,7 +1449,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1434,7 +1449,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1434 .export_size = export_size,1449 .export_size = export_size,
1435 },1450 },
1436 });1451 });
1437 self.cmd_table_dirty = true;1452 self.header_dirty = true;
1453 self.load_commands_dirty = true;
1438 }1454 }
1439 if (self.symtab_cmd_index == null) {1455 if (self.symtab_cmd_index == null) {
1440 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);1456 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1443,13 +1459,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1443,13 +1459,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1443 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);1459 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);
1444 const symtab_off = self.findFreeSpace(&linkedit_segment, symtab_size, @sizeOf(macho.nlist_64));1460 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
1448 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.1464 try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
1449 const strtab_size = self.string_table.items.len;1465 const strtab_size = self.string_table.items.len;
1450 const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);1466 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
1454 try self.load_commands.append(self.base.allocator, .{1470 try self.load_commands.append(self.base.allocator, .{
1455 .Symtab = .{1471 .Symtab = .{
...@@ -1461,8 +1477,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1461,8 +1477,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1461 .strsize = @intCast(u32, strtab_size),1477 .strsize = @intCast(u32, strtab_size),
1462 },1478 },
1463 });1479 });
1464 self.cmd_table_dirty = true;
1465 try self.writeLocalSymbol(0);1480 try self.writeLocalSymbol(0);
1481 self.header_dirty = true;
1482 self.load_commands_dirty = true;
1483 self.string_table_dirty = true;
1466 }1484 }
1467 if (self.dysymtab_cmd_index == null) {1485 if (self.dysymtab_cmd_index == null) {
1468 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);1486 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1493,7 +1511,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1493,7 +1511,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1493 .nlocrel = 0,1511 .nlocrel = 0,
1494 },1512 },
1495 });1513 });
1496 self.cmd_table_dirty = true;1514 self.header_dirty = true;
1515 self.load_commands_dirty = true;
1497 }1516 }
1498 if (self.dylinker_cmd_index == null) {1517 if (self.dylinker_cmd_index == null) {
1499 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);1518 self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1507,7 +1526,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1507,7 +1526,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1507 mem.set(u8, dylinker_cmd.data, 0);1526 mem.set(u8, dylinker_cmd.data, 0);
1508 mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH));1527 mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH));
1509 try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });1528 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;
1511 }1531 }
1512 if (self.libsystem_cmd_index == null) {1532 if (self.libsystem_cmd_index == null) {
1513 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);1533 self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1529,7 +1549,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1529,7 +1549,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1529 mem.set(u8, dylib_cmd.data, 0);1549 mem.set(u8, dylib_cmd.data, 0);
1530 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));1550 mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
1531 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });1551 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;
1533 }1554 }
1534 if (self.main_cmd_index == null) {1555 if (self.main_cmd_index == null) {
1535 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);1556 self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1541,7 +1562,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1541,7 +1562,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1541 .stacksize = 0,1562 .stacksize = 0,
1542 },1563 },
1543 });1564 });
1544 self.cmd_table_dirty = true;1565 self.header_dirty = true;
1566 self.load_commands_dirty = true;
1545 }1567 }
1546 if (self.version_min_cmd_index == null) {1568 if (self.version_min_cmd_index == null) {
1547 self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);1569 self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1562,7 +1584,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1562,7 +1584,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1562 .sdk = version,1584 .sdk = version,
1563 },1585 },
1564 });1586 });
1565 self.cmd_table_dirty = true;1587 self.header_dirty = true;
1588 self.load_commands_dirty = true;
1566 }1589 }
1567 if (self.source_version_cmd_index == null) {1590 if (self.source_version_cmd_index == null) {
1568 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);1591 self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1573,7 +1596,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1573,7 +1596,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1573 .version = 0x0,1596 .version = 0x0,
1574 },1597 },
1575 });1598 });
1576 self.cmd_table_dirty = true;1599 self.header_dirty = true;
1600 self.load_commands_dirty = true;
1577 }1601 }
1578 if (self.code_signature_cmd_index == null) {1602 if (self.code_signature_cmd_index == null) {
1579 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);1603 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
...@@ -1586,7 +1610,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -1586,7 +1610,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
1586 .datasize = 0,1610 .datasize = 0,
1587 },1611 },
1588 });1612 });
1589 self.cmd_table_dirty = true;1613 self.header_dirty = true;
1614 self.load_commands_dirty = true;
1590 }1615 }
1591 if (self.dyld_stub_binder_index == null) {1616 if (self.dyld_stub_binder_index == null) {
1592 self.dyld_stub_binder_index = @intCast(u16, self.undef_symbols.items.len);1617 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,...@@ -1674,7 +1699,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
1674 self.last_text_block = text_block;1699 self.last_text_block = text_block;
1675 text_section.size = needed_size;1700 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.
1678 }1703 }
1679 text_block.size = new_block_size;1704 text_block.size = new_block_size;
16801705
...@@ -1712,6 +1737,7 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {...@@ -1712,6 +1737,7 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
1712 const result = self.string_table.items.len;1737 const result = self.string_table.items.len;
1713 self.string_table.appendSliceAssumeCapacity(bytes);1738 self.string_table.appendSliceAssumeCapacity(bytes);
1714 self.string_table.appendAssumeCapacity(0);1739 self.string_table.appendAssumeCapacity(0);
1740 self.string_table_dirty = true;
1715 return @intCast(u32, result);1741 return @intCast(u32, result);
1716}1742}
17171743
...@@ -1908,11 +1934,16 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {...@@ -1908,11 +1934,16 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
1908}1934}
19091935
1910fn writeOffsetTableEntry(self: *MachO, index: usize) !void {1936fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1911 const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;1937 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1912 const sect = &text_semgent.sections.items[self.got_section_index.?];1938 const sect = &text_segment.sections.items[self.got_section_index.?];
1913 const off = sect.offset + @sizeOf(u64) * index;1939 const off = sect.offset + @sizeOf(u64) * index;
1914 const vmaddr = sect.addr + @sizeOf(u64) * index;1940 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
1916 var code: [8]u8 = undefined;1947 var code: [8]u8 = undefined;
1917 switch (self.base.options.target.cpu.arch) {1948 switch (self.base.options.target.cpu.arch) {
1918 .x86_64 => {1949 .x86_64 => {
...@@ -1936,7 +1967,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1936,7 +1967,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1936 },1967 },
1937 else => unreachable, // unsupported target architecture1968 else => unreachable, // unsupported target architecture
1938 }1969 }
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 });
1940 try self.base.file.?.pwriteAll(&code, off);1971 try self.base.file.?.pwriteAll(&code, off);
1941}1972}
19421973
...@@ -1967,7 +1998,7 @@ fn relocateSymbolTable(self: *MachO) !void {...@@ -1967,7 +1998,7 @@ fn relocateSymbolTable(self: *MachO) !void {
1967 symtab.symoff = @intCast(u32, new_symoff);1998 symtab.symoff = @intCast(u32, new_symoff);
1968 }1999 }
1969 symtab.nsyms = @intCast(u32, nsyms);2000 symtab.nsyms = @intCast(u32, nsyms);
1970 self.cmd_table_dirty = true;2001 self.load_commands_dirty = true;
1971 }2002 }
1972}2003}
19732004
...@@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
19962027
1997 const globals_off = locals_off + locals_size;2028 const globals_off = locals_off + locals_size;
1998 const globals_size = nglobals * @sizeOf(macho.nlist_64);2029 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 });
2000 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);2031 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);
20012032
2002 const undefs_off = globals_off + globals_size;2033 const undefs_off = globals_off + globals_size;
2003 const undefs_size = nundefs * @sizeOf(macho.nlist_64);2034 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 });
2005 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);2036 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
20062037
2007 // Update dynamic symbol table.2038 // Update dynamic symbol table.
...@@ -2011,7 +2042,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {...@@ -2011,7 +2042,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
2011 dysymtab.nextdefsym = @intCast(u32, nglobals);2042 dysymtab.nextdefsym = @intCast(u32, nglobals);
2012 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);2043 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
2013 dysymtab.nundefsym = @intCast(u32, nundefs);2044 dysymtab.nundefsym = @intCast(u32, nundefs);
2014 self.cmd_table_dirty = true;2045 self.load_commands_dirty = true;
2015}2046}
20162047
2017fn writeCodeSignaturePadding(self: *MachO) !void {2048fn writeCodeSignaturePadding(self: *MachO) !void {
...@@ -2021,19 +2052,23 @@ fn writeCodeSignaturePadding(self: *MachO) !void {...@@ -2021,19 +2052,23 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
2021 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2052 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2022 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;2053 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
2023 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;2054 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
2024 const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);2055 const needed_size = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
2025 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2026 code_sig_cmd.datasize = datasize;
20272056
2028 // Advance size of __LINKEDIT segment2057 if (code_sig_cmd.datasize < needed_size) {
2029 linkedit_segment.inner.filesize += datasize;2058 code_sig_cmd.dataoff = @intCast(u32, fileoff);
2030 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {2059 code_sig_cmd.datasize = needed_size;
2031 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);2060
2032 }2061 // Advance size of __LINKEDIT segment
2033 log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });2062 linkedit_segment.inner.filesize += needed_size;
2034 // Pad out the space. We need to do this to calculate valid hashes for everything in the file2063 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
2035 // except for code signature data.2064 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
2036 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + datasize - 1);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 }
2037}2072}
20382073
2039fn writeCodeSignature(self: *MachO) !void {2074fn writeCodeSignature(self: *MachO) !void {
...@@ -2057,12 +2092,13 @@ fn writeCodeSignature(self: *MachO) !void {...@@ -2057,12 +2092,13 @@ fn writeCodeSignature(self: *MachO) !void {
2057 defer self.base.allocator.free(buffer);2092 defer self.base.allocator.free(buffer);
2058 code_sig.write(buffer);2093 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
2062 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);2097 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
2063}2098}
20642099
2065fn writeExportTrie(self: *MachO) !void {2100fn writeExportTrie(self: *MachO) !void {
2101 if (!self.export_info_dirty) return;
2066 if (self.global_symbols.items.len == 0) return;2102 if (self.global_symbols.items.len == 0) return;
20672103
2068 const tracy = trace(@src());2104 const tracy = trace(@src());
...@@ -2100,10 +2136,11 @@ fn writeExportTrie(self: *MachO) !void {...@@ -2100,10 +2136,11 @@ fn writeExportTrie(self: *MachO) !void {
2100 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2136 dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
2101 }2137 }
2102 dyld_info.export_size = @intCast(u32, needed_size);2138 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
2105 try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);2141 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;
2107}2144}
21082145
2109fn writeBindingInfoTable(self: *MachO) !void {2146fn writeBindingInfoTable(self: *MachO) !void {
...@@ -2119,7 +2156,7 @@ fn writeBindingInfoTable(self: *MachO) !void {...@@ -2119,7 +2156,7 @@ fn writeBindingInfoTable(self: *MachO) !void {
2119 dyld_info.bind_off = self.linkedit_segment_next_offset.?;2156 dyld_info.bind_off = self.linkedit_segment_next_offset.?;
2120 dyld_info.bind_size = bind_size;2157 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
2124 if (bind_size > buffer.len) {2161 if (bind_size > buffer.len) {
2125 // Pad out to align(8).2162 // Pad out to align(8).
...@@ -2150,7 +2187,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2150,7 +2187,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2150 dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?;2187 dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?;
2151 dyld_info.lazy_bind_size = bind_size;2188 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
2155 if (bind_size > buffer.len) {2192 if (bind_size > buffer.len) {
2156 // Pad out to align(8).2193 // Pad out to align(8).
...@@ -2169,6 +2206,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {...@@ -2169,6 +2206,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
2169}2206}
21702207
2171fn writeStringTable(self: *MachO) !void {2208fn writeStringTable(self: *MachO) !void {
2209 if (!self.string_table_dirty) return;
2210
2172 const tracy = trace(@src());2211 const tracy = trace(@src());
2173 defer tracy.end();2212 defer tracy.end();
21742213
...@@ -2182,13 +2221,16 @@ fn writeStringTable(self: *MachO) !void {...@@ -2182,13 +2221,16 @@ fn writeStringTable(self: *MachO) !void {
2182 symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));2221 symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
2183 }2222 }
2184 symtab.strsize = @intCast(u32, needed_size);2223 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
2187 try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);2226 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;
2189}2229}
21902230
2191fn updateLinkeditSegmentSizes(self: *MachO) !void {2231fn updateLinkeditSegmentSizes(self: *MachO) !void {
2232 if (!self.load_commands_dirty) return;
2233
2192 const tracy = trace(@src());2234 const tracy = trace(@src());
2193 defer tracy.end();2235 defer tracy.end();
21942236
...@@ -2229,10 +2271,13 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {...@@ -2229,10 +2271,13 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {
2229 const filesize = final_offset - linkedit_segment.inner.fileoff;2271 const filesize = final_offset - linkedit_segment.inner.fileoff;
2230 linkedit_segment.inner.filesize = filesize;2272 linkedit_segment.inner.filesize = filesize;
2231 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);2273 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
2274 self.load_commands_dirty = true;
2232}2275}
22332276
2234/// Writes all load commands and section headers.2277/// Writes all load commands and section headers.
2235fn writeLoadCommands(self: *MachO) !void {2278fn writeLoadCommands(self: *MachO) !void {
2279 if (!self.load_commands_dirty) return;
2280
2236 var sizeofcmds: usize = 0;2281 var sizeofcmds: usize = 0;
2237 for (self.load_commands.items) |lc| {2282 for (self.load_commands.items) |lc| {
2238 sizeofcmds += lc.cmdsize();2283 sizeofcmds += lc.cmdsize();
...@@ -2246,19 +2291,22 @@ fn writeLoadCommands(self: *MachO) !void {...@@ -2246,19 +2291,22 @@ fn writeLoadCommands(self: *MachO) !void {
2246 }2291 }
22472292
2248 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));2293 try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
2294 self.load_commands_dirty = false;
2249}2295}
22502296
2251/// Writes Mach-O file header.2297/// Writes Mach-O file header.
2252fn writeHeader(self: *MachO) !void {2298fn writeHeader(self: *MachO) !void {
2299 if (!self.header_dirty) return;
2300
2253 self.header.?.ncmds = @intCast(u32, self.load_commands.items.len);2301 self.header.?.ncmds = @intCast(u32, self.load_commands.items.len);
2254 var sizeofcmds: u32 = 0;2302 var sizeofcmds: u32 = 0;
2255 for (self.load_commands.items) |cmd| {2303 for (self.load_commands.items) |cmd| {
2256 sizeofcmds += cmd.cmdsize();2304 sizeofcmds += cmd.cmdsize();
2257 }2305 }
2258 self.header.?.sizeofcmds = sizeofcmds;2306 self.header.?.sizeofcmds = sizeofcmds;
2259 log.debug("writing Mach-O header {}\n", .{self.header.?});2307 log.debug("writing Mach-O header {}", .{self.header.?});
2260 const slice = [1]macho.mach_header_64{self.header.?};2308 try self.base.file.?.pwriteAll(mem.asBytes(&self.header.?), 0);
2261 try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0);2309 self.header_dirty = false;
2262}2310}
22632311
2264/// Parse MachO contents from existing binary file.2312/// Parse MachO contents from existing binary file.
...@@ -2327,7 +2375,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {...@@ -2327,7 +2375,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
2327 self.code_signature_cmd_index = i;2375 self.code_signature_cmd_index = i;
2328 },2376 },
2329 else => {2377 else => {
2330 std.log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});2378 log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
2331 },2379 },
2332 }2380 }
2333 self.load_commands.appendAssumeCapacity(cmd);2381 self.load_commands.appendAssumeCapacity(cmd);