| ... | ... | @@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{}, |
| 111 | 111 | |
| 112 | 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 | 120 | /// A list of text blocks that have surplus capacity. This list can have false |
| 117 | 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 | 320 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 317 | 321 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main; |
| 318 | 322 | main_cmd.entryoff = addr - text_segment.inner.vmaddr; |
| 319 | | self.cmd_table_dirty = true; |
| 323 | self.load_commands_dirty = true; |
| 320 | 324 | } |
| 321 | 325 | try self.writeExportTrie(); |
| 322 | 326 | try self.writeAllGlobalAndUndefSymbols(); |
| ... | ... | @@ -336,21 +340,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 336 | 340 | .Lib => return error.TODOImplementWritingLibFiles, |
| 337 | 341 | } |
| 338 | 342 | |
| 339 | | if (self.cmd_table_dirty) { |
| 340 | | try self.writeLoadCommands(); |
| 341 | | try self.writeHeader(); |
| 342 | | self.cmd_table_dirty = false; |
| 343 | | } |
| 343 | try self.writeLoadCommands(); |
| 344 | try self.writeHeader(); |
| 344 | 345 | |
| 345 | 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 | 348 | self.error_flags.no_entry_point_found = true; |
| 348 | 349 | } else { |
| 349 | | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 350 | log.debug("flushing. no_entry_point_found = false", .{}); |
| 350 | 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 | 360 | if (target.cpu.arch == .aarch64) { |
| 356 | 361 | switch (output_mode) { |
| ... | ... | @@ -769,9 +774,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 769 | 774 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 770 | 775 | |
| 771 | 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.", .{}); |
| 773 | | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 774 | | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 777 | log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 778 | log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 779 | log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 775 | 780 | return error.NotEnoughPadding; |
| 776 | 781 | } |
| 777 | 782 | |
| ... | ... | @@ -807,10 +812,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 807 | 812 | mem.set(u8, dylib_cmd.data, 0); |
| 808 | 813 | mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); |
| 809 | 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 | 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!", .{}); |
| 813 | | std.log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{}); |
| 819 | log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{}); |
| 820 | log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{}); |
| 814 | 821 | return error.NoSymbolTableFound; |
| 815 | 822 | } |
| 816 | 823 | |
| ... | ... | @@ -863,9 +870,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 863 | 870 | const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den; |
| 864 | 871 | |
| 865 | 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.", .{}); |
| 867 | | std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 868 | | std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 873 | log.err("Unable to extend padding between the end of load commands and start of __text section.", .{}); |
| 874 | log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size}); |
| 875 | log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{}); |
| 869 | 876 | return error.NotEnoughPadding; |
| 870 | 877 | } |
| 871 | 878 | |
| ... | ... | @@ -879,6 +886,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| 879 | 886 | .datasize = 0, |
| 880 | 887 | }, |
| 881 | 888 | }); |
| 889 | self.header_dirty = true; |
| 890 | self.load_commands_dirty = true; |
| 882 | 891 | |
| 883 | 892 | // Pad out space for code signature |
| 884 | 893 | try self.writeCodeSignaturePadding(); |
| ... | ... | @@ -1000,10 +1009,10 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1000 | 1009 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); |
| 1001 | 1010 | |
| 1002 | 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 | 1013 | decl.link.macho.local_sym_index = i; |
| 1005 | 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 | 1016 | decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len); |
| 1008 | 1017 | _ = self.local_symbols.addOneAssumeCapacity(); |
| 1009 | 1018 | } |
| ... | ... | @@ -1013,6 +1022,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 1013 | 1022 | } else { |
| 1014 | 1023 | decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len); |
| 1015 | 1024 | _ = self.offset_table.addOneAssumeCapacity(); |
| 1025 | self.offset_table_count_dirty = true; |
| 1016 | 1026 | } |
| 1017 | 1027 | |
| 1018 | 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 | 1064 | const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment); |
| 1055 | 1065 | if (need_realloc) { |
| 1056 | 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 | 1068 | if (vaddr != symbol.n_value) { |
| 1059 | 1069 | symbol.n_value = vaddr; |
| 1060 | | log.debug(" (writing new offset table entry)\n", .{}); |
| 1070 | log.debug(" (writing new offset table entry)", .{}); |
| 1061 | 1071 | self.offset_table.items[decl.link.macho.offset_table_index] = vaddr; |
| 1062 | 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 | 1085 | const decl_name = mem.spanZ(decl.name); |
| 1076 | 1086 | const name_str_index = try self.makeString(decl_name); |
| 1077 | 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 | 1089 | errdefer self.freeTextBlock(&decl.link.macho); |
| 1080 | 1090 | |
| 1081 | 1091 | symbol.* = .{ |
| ... | ... | @@ -1153,7 +1163,6 @@ pub fn updateDeclExports( |
| 1153 | 1163 | .Strong => blk: { |
| 1154 | 1164 | if (mem.eql(u8, exp.options.name, "_start")) { |
| 1155 | 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 | 1167 | break :blk macho.REFERENCE_FLAG_DEFINED; |
| 1159 | 1168 | }, |
| ... | ... | @@ -1181,6 +1190,7 @@ pub fn updateDeclExports( |
| 1181 | 1190 | const name_str_index = try self.makeString(exp.options.name); |
| 1182 | 1191 | const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: { |
| 1183 | 1192 | _ = self.global_symbols.addOneAssumeCapacity(); |
| 1193 | self.export_info_dirty = true; |
| 1184 | 1194 | break :blk self.global_symbols.items.len - 1; |
| 1185 | 1195 | }; |
| 1186 | 1196 | self.global_symbols.items[i] = .{ |
| ... | ... | @@ -1273,7 +1283,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1273 | 1283 | } |
| 1274 | 1284 | header.reserved = 0; |
| 1275 | 1285 | self.header = header; |
| 1276 | | self.cmd_table_dirty = true; |
| 1286 | self.header_dirty = true; |
| 1277 | 1287 | } |
| 1278 | 1288 | if (self.pagezero_segment_cmd_index == null) { |
| 1279 | 1289 | self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1292,7 +1302,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1292 | 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 | 1308 | if (self.text_segment_cmd_index == null) { |
| 1298 | 1309 | self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1304,7 +1315,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1304 | 1315 | const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint; |
| 1305 | 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 | 1320 | try self.load_commands.append(self.base.allocator, .{ |
| 1310 | 1321 | .Segment = SegmentCommand.empty(.{ |
| ... | ... | @@ -1321,7 +1332,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1321 | 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 | 1338 | if (self.text_section_index == null) { |
| 1327 | 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 | 1348 | const needed_size = self.base.options.program_code_size_hint; |
| 1337 | 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 | 1353 | try text_segment.addSection(self.base.allocator, .{ |
| 1342 | 1354 | .sectname = makeStaticString("__text"), |
| ... | ... | @@ -1352,7 +1364,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1352 | 1364 | .reserved2 = 0, |
| 1353 | 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 | 1370 | if (self.got_section_index == null) { |
| 1358 | 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 | 1377 | const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64)); |
| 1365 | 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 | 1382 | try text_segment.addSection(self.base.allocator, .{ |
| 1370 | 1383 | .sectname = makeStaticString("__ziggot"), |
| ... | ... | @@ -1380,7 +1393,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1380 | 1393 | .reserved2 = 0, |
| 1381 | 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 | 1399 | if (self.linkedit_segment_cmd_index == null) { |
| 1386 | 1400 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1389,7 +1403,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1389 | 1403 | const initprot = macho.VM_PROT_READ; |
| 1390 | 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 | 1408 | try self.load_commands.append(self.base.allocator, .{ |
| 1395 | 1409 | .Segment = SegmentCommand.empty(.{ |
| ... | ... | @@ -1406,7 +1420,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1406 | 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 | 1426 | if (self.dyld_info_cmd_index == null) { |
| 1412 | 1427 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1416,7 +1431,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1416 | 1431 | const export_size = 2; |
| 1417 | 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 | 1436 | try self.load_commands.append(self.base.allocator, .{ |
| 1422 | 1437 | .DyldInfoOnly = .{ |
| ... | ... | @@ -1434,7 +1449,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1434 | 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 | 1455 | if (self.symtab_cmd_index == null) { |
| 1440 | 1456 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1443,13 +1459,13 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1443 | 1459 | const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64); |
| 1444 | 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 | 1464 | try self.string_table.append(self.base.allocator, 0); // Need a null at position 0. |
| 1449 | 1465 | const strtab_size = self.string_table.items.len; |
| 1450 | 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 | 1470 | try self.load_commands.append(self.base.allocator, .{ |
| 1455 | 1471 | .Symtab = .{ |
| ... | ... | @@ -1461,8 +1477,10 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1461 | 1477 | .strsize = @intCast(u32, strtab_size), |
| 1462 | 1478 | }, |
| 1463 | 1479 | }); |
| 1464 | | self.cmd_table_dirty = true; |
| 1465 | 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 | 1485 | if (self.dysymtab_cmd_index == null) { |
| 1468 | 1486 | self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1493,7 +1511,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1493 | 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 | 1517 | if (self.dylinker_cmd_index == null) { |
| 1499 | 1518 | self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1507,7 +1526,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1507 | 1526 | mem.set(u8, dylinker_cmd.data, 0); |
| 1508 | 1527 | mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH)); |
| 1509 | 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 | 1532 | if (self.libsystem_cmd_index == null) { |
| 1513 | 1533 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1529,7 +1549,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1529 | 1549 | mem.set(u8, dylib_cmd.data, 0); |
| 1530 | 1550 | mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH)); |
| 1531 | 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 | 1555 | if (self.main_cmd_index == null) { |
| 1535 | 1556 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1541,7 +1562,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1541 | 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 | 1568 | if (self.version_min_cmd_index == null) { |
| 1547 | 1569 | self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1562,7 +1584,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1562 | 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 | 1590 | if (self.source_version_cmd_index == null) { |
| 1568 | 1591 | self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1573,7 +1596,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1573 | 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 | 1602 | if (self.code_signature_cmd_index == null) { |
| 1579 | 1603 | self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1586,7 +1610,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1586 | 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 | 1616 | if (self.dyld_stub_binder_index == null) { |
| 1592 | 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 | 1699 | self.last_text_block = text_block; |
| 1675 | 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 | 1704 | text_block.size = new_block_size; |
| 1680 | 1705 | |
| ... | ... | @@ -1712,6 +1737,7 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 { |
| 1712 | 1737 | const result = self.string_table.items.len; |
| 1713 | 1738 | self.string_table.appendSliceAssumeCapacity(bytes); |
| 1714 | 1739 | self.string_table.appendAssumeCapacity(0); |
| 1740 | self.string_table_dirty = true; |
| 1715 | 1741 | return @intCast(u32, result); |
| 1716 | 1742 | } |
| 1717 | 1743 | |
| ... | ... | @@ -1908,11 +1934,16 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) { |
| 1908 | 1934 | } |
| 1909 | 1935 | |
| 1910 | 1936 | fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1911 | | const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1912 | | const sect = &text_semgent.sections.items[self.got_section_index.?]; |
| 1937 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1938 | const sect = &text_segment.sections.items[self.got_section_index.?]; |
| 1913 | 1939 | const off = sect.offset + @sizeOf(u64) * index; |
| 1914 | 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 | 1947 | var code: [8]u8 = undefined; |
| 1917 | 1948 | switch (self.base.options.target.cpu.arch) { |
| 1918 | 1949 | .x86_64 => { |
| ... | ... | @@ -1936,7 +1967,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void { |
| 1936 | 1967 | }, |
| 1937 | 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 | 1971 | try self.base.file.?.pwriteAll(&code, off); |
| 1941 | 1972 | } |
| 1942 | 1973 | |
| ... | ... | @@ -1967,7 +1998,7 @@ fn relocateSymbolTable(self: *MachO) !void { |
| 1967 | 1998 | symtab.symoff = @intCast(u32, new_symoff); |
| 1968 | 1999 | } |
| 1969 | 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 | 2027 | |
| 1997 | 2028 | const globals_off = locals_off + locals_size; |
| 1998 | 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 | 2031 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off); |
| 2001 | 2032 | |
| 2002 | 2033 | const undefs_off = globals_off + globals_size; |
| 2003 | 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 | 2036 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off); |
| 2006 | 2037 | |
| 2007 | 2038 | // Update dynamic symbol table. |
| ... | ... | @@ -2011,7 +2042,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2011 | 2042 | dysymtab.nextdefsym = @intCast(u32, nglobals); |
| 2012 | 2043 | dysymtab.iundefsym = @intCast(u32, nlocals + nglobals); |
| 2013 | 2044 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 2014 | | self.cmd_table_dirty = true; |
| 2045 | self.load_commands_dirty = true; |
| 2015 | 2046 | } |
| 2016 | 2047 | |
| 2017 | 2048 | fn writeCodeSignaturePadding(self: *MachO) !void { |
| ... | ... | @@ -2021,19 +2052,23 @@ fn writeCodeSignaturePadding(self: *MachO) !void { |
| 2021 | 2052 | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2022 | 2053 | const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData; |
| 2023 | 2054 | const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize; |
| 2024 | | const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff); |
| 2025 | | code_sig_cmd.dataoff = @intCast(u32, fileoff); |
| 2026 | | code_sig_cmd.datasize = datasize; |
| 2055 | const needed_size = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff); |
| 2027 | 2056 | |
| 2028 | | // Advance size of __LINKEDIT segment |
| 2029 | | linkedit_segment.inner.filesize += datasize; |
| 2030 | | if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { |
| 2031 | | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); |
| 2032 | | } |
| 2033 | | log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize }); |
| 2034 | | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 2035 | | // except for code signature data. |
| 2036 | | try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + datasize - 1); |
| 2057 | if (code_sig_cmd.datasize < needed_size) { |
| 2058 | code_sig_cmd.dataoff = @intCast(u32, fileoff); |
| 2059 | code_sig_cmd.datasize = needed_size; |
| 2060 | |
| 2061 | // Advance size of __LINKEDIT segment |
| 2062 | linkedit_segment.inner.filesize += needed_size; |
| 2063 | if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) { |
| 2064 | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size); |
| 2065 | } |
| 2066 | log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size }); |
| 2067 | // Pad out the space. We need to do this to calculate valid hashes for everything in the file |
| 2068 | // except for code signature data. |
| 2069 | try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1); |
| 2070 | self.load_commands_dirty = true; |
| 2071 | } |
| 2037 | 2072 | } |
| 2038 | 2073 | |
| 2039 | 2074 | fn writeCodeSignature(self: *MachO) !void { |
| ... | ... | @@ -2057,12 +2092,13 @@ fn writeCodeSignature(self: *MachO) !void { |
| 2057 | 2092 | defer self.base.allocator.free(buffer); |
| 2058 | 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 | 2097 | try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff); |
| 2063 | 2098 | } |
| 2064 | 2099 | |
| 2065 | 2100 | fn writeExportTrie(self: *MachO) !void { |
| 2101 | if (!self.export_info_dirty) return; |
| 2066 | 2102 | if (self.global_symbols.items.len == 0) return; |
| 2067 | 2103 | |
| 2068 | 2104 | const tracy = trace(@src()); |
| ... | ... | @@ -2100,10 +2136,11 @@ fn writeExportTrie(self: *MachO) !void { |
| 2100 | 2136 | dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2101 | 2137 | } |
| 2102 | 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 | 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 | 2146 | fn writeBindingInfoTable(self: *MachO) !void { |
| ... | ... | @@ -2119,7 +2156,7 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2119 | 2156 | dyld_info.bind_off = self.linkedit_segment_next_offset.?; |
| 2120 | 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 | 2161 | if (bind_size > buffer.len) { |
| 2125 | 2162 | // Pad out to align(8). |
| ... | ... | @@ -2150,7 +2187,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2150 | 2187 | dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?; |
| 2151 | 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 | 2192 | if (bind_size > buffer.len) { |
| 2156 | 2193 | // Pad out to align(8). |
| ... | ... | @@ -2169,6 +2206,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 2169 | 2206 | } |
| 2170 | 2207 | |
| 2171 | 2208 | fn writeStringTable(self: *MachO) !void { |
| 2209 | if (!self.string_table_dirty) return; |
| 2210 | |
| 2172 | 2211 | const tracy = trace(@src()); |
| 2173 | 2212 | defer tracy.end(); |
| 2174 | 2213 | |
| ... | ... | @@ -2182,13 +2221,16 @@ fn writeStringTable(self: *MachO) !void { |
| 2182 | 2221 | symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1)); |
| 2183 | 2222 | } |
| 2184 | 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 | 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 | 2231 | fn updateLinkeditSegmentSizes(self: *MachO) !void { |
| 2232 | if (!self.load_commands_dirty) return; |
| 2233 | |
| 2192 | 2234 | const tracy = trace(@src()); |
| 2193 | 2235 | defer tracy.end(); |
| 2194 | 2236 | |
| ... | ... | @@ -2229,10 +2271,13 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void { |
| 2229 | 2271 | const filesize = final_offset - linkedit_segment.inner.fileoff; |
| 2230 | 2272 | linkedit_segment.inner.filesize = filesize; |
| 2231 | 2273 | linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size); |
| 2274 | self.load_commands_dirty = true; |
| 2232 | 2275 | } |
| 2233 | 2276 | |
| 2234 | 2277 | /// Writes all load commands and section headers. |
| 2235 | 2278 | fn writeLoadCommands(self: *MachO) !void { |
| 2279 | if (!self.load_commands_dirty) return; |
| 2280 | |
| 2236 | 2281 | var sizeofcmds: usize = 0; |
| 2237 | 2282 | for (self.load_commands.items) |lc| { |
| 2238 | 2283 | sizeofcmds += lc.cmdsize(); |
| ... | ... | @@ -2246,19 +2291,22 @@ fn writeLoadCommands(self: *MachO) !void { |
| 2246 | 2291 | } |
| 2247 | 2292 | |
| 2248 | 2293 | try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64)); |
| 2294 | self.load_commands_dirty = false; |
| 2249 | 2295 | } |
| 2250 | 2296 | |
| 2251 | 2297 | /// Writes Mach-O file header. |
| 2252 | 2298 | fn writeHeader(self: *MachO) !void { |
| 2299 | if (!self.header_dirty) return; |
| 2300 | |
| 2253 | 2301 | self.header.?.ncmds = @intCast(u32, self.load_commands.items.len); |
| 2254 | 2302 | var sizeofcmds: u32 = 0; |
| 2255 | 2303 | for (self.load_commands.items) |cmd| { |
| 2256 | 2304 | sizeofcmds += cmd.cmdsize(); |
| 2257 | 2305 | } |
| 2258 | 2306 | self.header.?.sizeofcmds = sizeofcmds; |
| 2259 | | log.debug("writing Mach-O header {}\n", .{self.header.?}); |
| 2260 | | const slice = [1]macho.mach_header_64{self.header.?}; |
| 2261 | | try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0); |
| 2307 | log.debug("writing Mach-O header {}", .{self.header.?}); |
| 2308 | try self.base.file.?.pwriteAll(mem.asBytes(&self.header.?), 0); |
| 2309 | self.header_dirty = false; |
| 2262 | 2310 | } |
| 2263 | 2311 | |
| 2264 | 2312 | /// Parse MachO contents from existing binary file. |
| ... | ... | @@ -2327,7 +2375,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void { |
| 2327 | 2375 | self.code_signature_cmd_index = i; |
| 2328 | 2376 | }, |
| 2329 | 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 | 2381 | self.load_commands.appendAssumeCapacity(cmd); |