| ... | ... | @@ -133,6 +133,8 @@ offset_table: std.ArrayListUnmanaged(u64) = .{}, |
| 133 | 133 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 134 | 134 | |
| 135 | 135 | cmd_table_dirty: bool = false, |
| 136 | dylinker_cmd_dirty: bool = false, |
| 137 | libsystem_cmd_dirty: bool = false, |
| 136 | 138 | |
| 137 | 139 | /// A list of text blocks that have surplus capacity. This list can have false |
| 138 | 140 | /// positives, as functions grow and shrink over time, only sometimes being added |
| ... | ... | @@ -318,14 +320,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 318 | 320 | .Exe => { |
| 319 | 321 | // Write export trie. |
| 320 | 322 | try self.writeExportTrie(); |
| 321 | | |
| 322 | 323 | if (self.entry_addr) |addr| { |
| 323 | | // Update LC_MAIN with entry offset |
| 324 | // Update LC_MAIN with entry offset. |
| 324 | 325 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 325 | 326 | const main_cmd = &self.load_commands.items[self.main_cmd_index.?].EntryPoint; |
| 326 | 327 | main_cmd.entryoff = addr - text_segment.vmaddr; |
| 327 | 328 | } |
| 328 | | |
| 329 | 329 | { |
| 330 | 330 | // Update dynamic symbol table. |
| 331 | 331 | const nlocals = @intCast(u32, self.local_symbols.items.len); |
| ... | ... | @@ -338,7 +338,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 338 | 338 | dysymtab.iundefsym = nlocals + nglobals; |
| 339 | 339 | dysymtab.nundefsym = nundefs; |
| 340 | 340 | } |
| 341 | | { |
| 341 | if (self.dylinker_cmd_dirty) { |
| 342 | 342 | // Write path to dyld loader. |
| 343 | 343 | var off: usize = @sizeOf(macho.mach_header_64); |
| 344 | 344 | for (self.load_commands.items) |cmd| { |
| ... | ... | @@ -349,8 +349,9 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 349 | 349 | off += cmd.name; |
| 350 | 350 | log.debug("writing LC_LOAD_DYLINKER path to dyld at 0x{x}\n", .{off}); |
| 351 | 351 | try self.base.file.?.pwriteAll(mem.spanZ(DEFAULT_DYLD_PATH), off); |
| 352 | self.dylinker_cmd_dirty = false; |
| 352 | 353 | } |
| 353 | | { |
| 354 | if (self.libsystem_cmd_dirty) { |
| 354 | 355 | // Write path to libSystem. |
| 355 | 356 | var off: usize = @sizeOf(macho.mach_header_64); |
| 356 | 357 | for (self.load_commands.items) |cmd| { |
| ... | ... | @@ -361,6 +362,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 361 | 362 | off += cmd.dylib.name; |
| 362 | 363 | log.debug("writing LC_LOAD_DYLIB path to libSystem at 0x{x}\n", .{off}); |
| 363 | 364 | try self.base.file.?.pwriteAll(mem.spanZ(LIB_SYSTEM_PATH), off); |
| 365 | self.libsystem_cmd_dirty = false; |
| 364 | 366 | } |
| 365 | 367 | }, |
| 366 | 368 | .Obj => {}, |
| ... | ... | @@ -376,7 +378,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 376 | 378 | symtab.nsyms = nlocals + nglobals + nundefs; |
| 377 | 379 | } |
| 378 | 380 | |
| 379 | | if (self.cmd_table_dirty) try self.writeCmdHeaders(); |
| 381 | if (self.cmd_table_dirty) { |
| 382 | try self.writeCmdHeaders(); |
| 383 | try self.writeMachOHeader(); |
| 384 | self.cmd_table_dirty = false; |
| 385 | } |
| 380 | 386 | |
| 381 | 387 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| 382 | 388 | log.debug("flushing. no_entry_point_found = true\n", .{}); |
| ... | ... | @@ -384,8 +390,11 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 384 | 390 | } else { |
| 385 | 391 | log.debug("flushing. no_entry_point_found = false\n", .{}); |
| 386 | 392 | self.error_flags.no_entry_point_found = false; |
| 387 | | try self.writeMachOHeader(); |
| 388 | 393 | } |
| 394 | |
| 395 | assert(!self.cmd_table_dirty); |
| 396 | assert(!self.dylinker_cmd_dirty); |
| 397 | assert(!self.libsystem_cmd_dirty); |
| 389 | 398 | } |
| 390 | 399 | |
| 391 | 400 | fn linkWithLLD(self: *MachO, comp: *Compilation) !void { |
| ... | ... | @@ -846,7 +855,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 846 | 855 | try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1); |
| 847 | 856 | |
| 848 | 857 | if (self.local_symbol_free_list.popOrNull()) |i| { |
| 849 | | log.debug("reusing symbol index {} for {}\n", .{i, decl.name}); |
| 858 | log.debug("reusing symbol index {} for {}\n", .{ i, decl.name }); |
| 850 | 859 | decl.link.macho.local_sym_index = i; |
| 851 | 860 | } else { |
| 852 | 861 | log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name }); |
| ... | ... | @@ -980,6 +989,7 @@ pub fn updateDeclExports( |
| 980 | 989 | .Strong => blk: { |
| 981 | 990 | if (mem.eql(u8, exp.options.name, "_start")) { |
| 982 | 991 | self.entry_addr = decl_sym.n_value; |
| 992 | self.cmd_table_dirty = true; // TODO This should be handled more granularly instead of invalidating all commands. |
| 983 | 993 | } |
| 984 | 994 | break :blk macho.REFERENCE_FLAG_DEFINED; |
| 985 | 995 | }, |
| ... | ... | @@ -1121,6 +1131,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1121 | 1131 | |
| 1122 | 1132 | text_segment.vmsize = file_size + off; // We add off here since __TEXT segment includes everything prior to __text section. |
| 1123 | 1133 | text_segment.filesize = file_size + off; |
| 1134 | self.cmd_table_dirty = true; |
| 1124 | 1135 | } |
| 1125 | 1136 | if (self.data_segment_cmd_index == null) { |
| 1126 | 1137 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1173,6 +1184,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1173 | 1184 | data_segment.vmsize = segment_size; |
| 1174 | 1185 | data_segment.filesize = segment_size; |
| 1175 | 1186 | data_segment.fileoff = off; |
| 1187 | self.cmd_table_dirty = true; |
| 1176 | 1188 | } |
| 1177 | 1189 | if (self.linkedit_segment_cmd_index == null) { |
| 1178 | 1190 | self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1268,6 +1280,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1268 | 1280 | }, |
| 1269 | 1281 | }); |
| 1270 | 1282 | self.cmd_table_dirty = true; |
| 1283 | self.dylinker_cmd_dirty = true; |
| 1271 | 1284 | } |
| 1272 | 1285 | if (self.libsystem_cmd_index == null) { |
| 1273 | 1286 | self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1289,6 +1302,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 1289 | 1302 | }, |
| 1290 | 1303 | }); |
| 1291 | 1304 | self.cmd_table_dirty = true; |
| 1305 | self.libsystem_cmd_dirty = true; |
| 1292 | 1306 | } |
| 1293 | 1307 | if (self.main_cmd_index == null) { |
| 1294 | 1308 | self.main_cmd_index = @intCast(u16, self.load_commands.items.len); |
| ... | ... | @@ -1407,8 +1421,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 1407 | 1421 | free_list_removal = i; |
| 1408 | 1422 | } |
| 1409 | 1423 | break :blk new_start_vaddr; |
| 1410 | | } |
| 1411 | | else if (self.last_text_block) |last| { |
| 1424 | } else if (self.last_text_block) |last| { |
| 1412 | 1425 | const last_symbol = self.local_symbols.items[last.local_sym_index]; |
| 1413 | 1426 | // TODO We should pad out the excess capacity with NOPs. For executables, |
| 1414 | 1427 | // no padding seems to be OK, but it will probably not be for objects. |
| ... | ... | @@ -1431,7 +1444,7 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64, |
| 1431 | 1444 | self.last_text_block = text_block; |
| 1432 | 1445 | text_section.size = needed_size; |
| 1433 | 1446 | |
| 1434 | | self.cmd_table_dirty = true; |
| 1447 | self.cmd_table_dirty = true; // TODO Make more granular. |
| 1435 | 1448 | } |
| 1436 | 1449 | text_block.size = new_block_size; |
| 1437 | 1450 | |
| ... | ... | @@ -1684,7 +1697,7 @@ fn writeCmdHeaders(self: *MachO) !void { |
| 1684 | 1697 | return error.TODOImplementWritingObjFiles; |
| 1685 | 1698 | }; |
| 1686 | 1699 | const idx = self.text_section_index.?; |
| 1687 | | log.debug("writing text section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off }); |
| 1700 | log.debug("writing text section header at 0x{x}\n", .{off}); |
| 1688 | 1701 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); |
| 1689 | 1702 | } |
| 1690 | 1703 | { |
| ... | ... | @@ -1702,7 +1715,7 @@ fn writeCmdHeaders(self: *MachO) !void { |
| 1702 | 1715 | return error.TODOImplementWritingObjFiles; |
| 1703 | 1716 | }; |
| 1704 | 1717 | const idx = self.got_section_index.?; |
| 1705 | | log.debug("writing got section {} at 0x{x}\n", .{ self.sections.items[idx .. idx + 1], off }); |
| 1718 | log.debug("writing got section header at 0x{x}\n", .{off}); |
| 1706 | 1719 | try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.sections.items[idx .. idx + 1]), off); |
| 1707 | 1720 | } |
| 1708 | 1721 | } |