| ... | @@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{}, | ... | @@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{}, |
| 111 | | 111 | |
| 112 | error_flags: File.ErrorFlags = File.ErrorFlags{}, | 112 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 113 | | 113 | |
| 114 | cmd_table_dirty: bool = false, | 114 | offset_table_count_dirty: bool = false, |
| | 115 | header_dirty: bool = false, |
| | 116 | load_commands_dirty: bool = false, |
| | 117 | export_info_dirty: bool = false, |
| | 118 | string_table_dirty: bool = false, |
| 115 | | 119 | |
| 116 | /// A list of text blocks that have surplus capacity. This list can have false | 120 | /// 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 added | 121 | /// 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 | } |
| 338 | | 342 | |
| 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 | } | | |
| 344 | | 345 | |
| 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 | } |
| 352 | | 353 | |
| 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); |
| 354 | | 359 | |
| 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; |
| 770 | | 775 | |
| 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 | } |
| 777 | | 782 | |
| ... | @@ -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; |
| 810 | | 817 | |
| 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 | } |
| 816 | | 823 | |
| ... | @@ -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; |
| 864 | | 871 | |
| 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 | } |
| 871 | | 878 | |
| ... | @@ -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; |
| 882 | | 891 | |
| 883 | // Pad out space for code signature | 892 | // 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); |
| 1001 | | 1010 | |
| 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 | } |
| 1017 | | 1027 | |
| 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); |
| 1080 | | 1090 | |
| 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); |
| 1306 | | 1317 | |
| 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 }); |
| 1308 | | 1319 | |
| 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); |
| 1338 | | 1350 | |
| 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 }); |
| 1340 | | 1352 | |
| 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. |
| 1366 | | 1379 | |
| 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 }); |
| 1368 | | 1381 | |
| 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(); |
| 1391 | | 1405 | |
| 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}); |
| 1393 | | 1407 | |
| 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); |
| 1418 | | 1433 | |
| 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 }); |
| 1420 | | 1435 | |
| 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)); |
| 1445 | | 1461 | |
| 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 }); |
| 1447 | | 1463 | |
| 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); |
| 1451 | | 1467 | |
| 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 }); |
| 1453 | | 1469 | |
| 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; |
| 1676 | | 1701 | |
| 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; |
| 1680 | | 1705 | |
| ... | @@ -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 | } |
| 1717 | | 1743 | |
| ... | @@ -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 | } |
| 1909 | | 1935 | |
| 1910 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { | 1936 | fn 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; |
| 1915 | | 1941 | |
| | 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 architecture | 1968 | 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 | } |
| 1942 | | 1973 | |
| ... | @@ -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 | } |
| 1973 | | 2004 | |
| ... | @@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 1996 | | 2027 | |
| 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); |
| 2001 | | 2032 | |
| 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); |
| 2006 | | 2037 | |
| 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 | } |
| 2016 | | 2047 | |
| 2017 | fn writeCodeSignaturePadding(self: *MachO) !void { | 2048 | fn 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; | | |
| 2027 | | 2056 | |
| 2028 | // Advance size of __LINKEDIT segment | 2057 | 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 file | 2063 | 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 | } |
| 2038 | | 2073 | |
| 2039 | fn writeCodeSignature(self: *MachO) !void { | 2074 | fn 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); |
| 2059 | | 2094 | |
| 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 }); |
| 2061 | | 2096 | |
| 2062 | try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); | 2097 | try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); |
| 2063 | } | 2098 | } |
| 2064 | | 2099 | |
| 2065 | fn writeExportTrie(self: *MachO) !void { | 2100 | fn 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; |
| 2067 | | 2103 | |
| 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 }); |
| 2104 | | 2140 | |
| 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 | } |
| 2108 | | 2145 | |
| 2109 | fn writeBindingInfoTable(self: *MachO) !void { | 2146 | fn 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; |
| 2121 | | 2158 | |
| 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 }); |
| 2123 | | 2160 | |
| 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; |
| 2152 | | 2189 | |
| 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 }); |
| 2154 | | 2191 | |
| 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 | } |
| 2170 | | 2207 | |
| 2171 | fn writeStringTable(self: *MachO) !void { | 2208 | fn 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(); |
| 2174 | | 2213 | |
| ... | @@ -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 }); |
| 2186 | | 2225 | |
| 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 | } |
| 2190 | | 2230 | |
| 2191 | fn updateLinkeditSegmentSizes(self: *MachO) !void { | 2231 | fn 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(); |
| 2194 | | 2236 | |
| ... | @@ -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 | } |
| 2233 | | 2276 | |
| 2234 | /// Writes all load commands and section headers. | 2277 | /// Writes all load commands and section headers. |
| 2235 | fn writeLoadCommands(self: *MachO) !void { | 2278 | fn 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 | } |
| 2247 | | 2292 | |
| 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 | } |
| 2250 | | 2296 | |
| 2251 | /// Writes Mach-O file header. | 2297 | /// Writes Mach-O file header. |
| 2252 | fn writeHeader(self: *MachO) !void { | 2298 | fn 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 | } |
| 2263 | | 2311 | |
| 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); |