aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2020-12-21 19:59:40 +0100
committerJakub Konka <kubkon@jakubkonka.com>2020-12-21 19:59:40 +0100
commit3f21f9155fe8e10e3990ee5738b190accbdffd3a (patch)
treec4ba81c7ad1f628fa58ee9c6cdb3a152adba12dd /src
parentde5421a0a666000908527503af8f511b9b3095ed (diff)
downloadzig-3f21f9155fe8e10e3990ee5738b190accbdffd3a.tar.gz
zig-3f21f9155fe8e10e3990ee5738b190accbdffd3a.zip
macho: write only bits that changed
Refactor use of `log` to not include an additional newline char.
Diffstat (limited to 'src')
-rw-r--r--src/link/MachO.zig202
1 files changed, 125 insertions, 77 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 455bfcc922..a712f31608 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -111,7 +111,11 @@ lazy_binding_info_table: LazyBindingInfoTable = .{},
error_flags: File.ErrorFlags = File.ErrorFlags{},
-cmd_table_dirty: bool = false,
+offset_table_count_dirty: bool = false,
+header_dirty: bool = false,
+load_commands_dirty: bool = false,
+export_info_dirty: bool = false,
+string_table_dirty: bool = false,
/// A list of text blocks that have surplus capacity. This list can have false
/// positives, as functions grow and shrink over time, only sometimes being added
@@ -316,7 +320,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
main_cmd.entryoff = addr - text_segment.inner.vmaddr;
- self.cmd_table_dirty = true;
+ self.load_commands_dirty = true;
}
try self.writeExportTrie();
try self.writeAllGlobalAndUndefSymbols();
@@ -336,21 +340,22 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
.Lib => return error.TODOImplementWritingLibFiles,
}
- if (self.cmd_table_dirty) {
- try self.writeLoadCommands();
- try self.writeHeader();
- self.cmd_table_dirty = false;
- }
+ try self.writeLoadCommands();
+ try self.writeHeader();
if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
- log.debug("flushing. no_entry_point_found = true\n", .{});
+ log.debug("flushing. no_entry_point_found = true", .{});
self.error_flags.no_entry_point_found = true;
} else {
- log.debug("flushing. no_entry_point_found = false\n", .{});
+ log.debug("flushing. no_entry_point_found = false", .{});
self.error_flags.no_entry_point_found = false;
}
- assert(!self.cmd_table_dirty);
+ assert(!self.offset_table_count_dirty);
+ assert(!self.header_dirty);
+ assert(!self.load_commands_dirty);
+ assert(!self.export_info_dirty);
+ assert(!self.string_table_dirty);
if (target.cpu.arch == .aarch64) {
switch (output_mode) {
@@ -769,9 +774,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
if (needed_size + after_last_cmd_offset > text_section.offset) {
- std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
- std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
- std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
+ log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
+ log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
+ log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
return error.NotEnoughPadding;
}
@@ -807,10 +812,12 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
mem.set(u8, dylib_cmd.data, 0);
mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
if (self.symtab_cmd_index == null or self.dysymtab_cmd_index == null) {
- std.log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{});
- std.log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
+ log.err("Incomplete Mach-O binary: no LC_SYMTAB or LC_DYSYMTAB load command found!", .{});
+ log.err("Without the symbol table, it is not possible to patch up the binary for cross-compilation.", .{});
return error.NoSymbolTableFound;
}
@@ -863,9 +870,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
const needed_size = @sizeOf(macho.linkedit_data_command) * alloc_num / alloc_den;
if (needed_size + after_last_cmd_offset > text_section.offset) {
- std.log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
- std.log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
- std.log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
+ log.err("Unable to extend padding between the end of load commands and start of __text section.", .{});
+ log.err("Re-run the linker with '-headerpad 0x{x}' option if available, or", .{needed_size});
+ log.err("fall back to the system linker by exporting 'ZIG_SYSTEM_LINKER_HACK=1'.", .{});
return error.NotEnoughPadding;
}
@@ -879,6 +886,8 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
.datasize = 0,
},
});
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
// Pad out space for code signature
try self.writeCodeSignaturePadding();
@@ -1000,10 +1009,10 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
try self.offset_table.ensureCapacity(self.base.allocator, self.offset_table.items.len + 1);
if (self.local_symbol_free_list.popOrNull()) |i| {
- log.debug("reusing symbol index {} for {}\n", .{ i, decl.name });
+ log.debug("reusing symbol index {} for {}", .{ i, decl.name });
decl.link.macho.local_sym_index = i;
} else {
- log.debug("allocating symbol index {} for {}\n", .{ self.local_symbols.items.len, decl.name });
+ log.debug("allocating symbol index {} for {}", .{ self.local_symbols.items.len, decl.name });
decl.link.macho.local_sym_index = @intCast(u32, self.local_symbols.items.len);
_ = self.local_symbols.addOneAssumeCapacity();
}
@@ -1013,6 +1022,7 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
} else {
decl.link.macho.offset_table_index = @intCast(u32, self.offset_table.items.len);
_ = self.offset_table.addOneAssumeCapacity();
+ self.offset_table_count_dirty = true;
}
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 {
const need_realloc = code.len > capacity or !mem.isAlignedGeneric(u64, symbol.n_value, required_alignment);
if (need_realloc) {
const vaddr = try self.growTextBlock(&decl.link.macho, code.len, required_alignment);
- log.debug("growing {} from 0x{x} to 0x{x}\n", .{ decl.name, symbol.n_value, vaddr });
+ log.debug("growing {} from 0x{x} to 0x{x}", .{ decl.name, symbol.n_value, vaddr });
if (vaddr != symbol.n_value) {
symbol.n_value = vaddr;
- log.debug(" (writing new offset table entry)\n", .{});
+ log.debug(" (writing new offset table entry)", .{});
self.offset_table.items[decl.link.macho.offset_table_index] = vaddr;
try self.writeOffsetTableEntry(decl.link.macho.offset_table_index);
}
@@ -1075,7 +1085,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
const decl_name = mem.spanZ(decl.name);
const name_str_index = try self.makeString(decl_name);
const addr = try self.allocateTextBlock(&decl.link.macho, code.len, required_alignment);
- log.debug("allocated text block for {} at 0x{x}\n", .{ decl_name, addr });
+ log.debug("allocated text block for {} at 0x{x}", .{ decl_name, addr });
errdefer self.freeTextBlock(&decl.link.macho);
symbol.* = .{
@@ -1153,7 +1163,6 @@ pub fn updateDeclExports(
.Strong => blk: {
if (mem.eql(u8, exp.options.name, "_start")) {
self.entry_addr = decl_sym.n_value;
- self.cmd_table_dirty = true; // TODO This should be handled more granularly instead of invalidating all commands.
}
break :blk macho.REFERENCE_FLAG_DEFINED;
},
@@ -1181,6 +1190,7 @@ pub fn updateDeclExports(
const name_str_index = try self.makeString(exp.options.name);
const i = if (self.global_symbol_free_list.popOrNull()) |i| i else blk: {
_ = self.global_symbols.addOneAssumeCapacity();
+ self.export_info_dirty = true;
break :blk self.global_symbols.items.len - 1;
};
self.global_symbols.items[i] = .{
@@ -1273,7 +1283,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
}
header.reserved = 0;
self.header = header;
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
}
if (self.pagezero_segment_cmd_index == null) {
self.pagezero_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1292,7 +1302,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.flags = 0,
}),
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.text_segment_cmd_index == null) {
self.text_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1304,7 +1315,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const ideal_size = self.header_pad + program_code_size_hint + offset_table_size_hint;
const needed_size = mem.alignForwardGeneric(u64, satMul(ideal_size, alloc_num) / alloc_den, self.page_size);
- log.debug("found __TEXT segment free space 0x{x} to 0x{x}\n", .{ 0, needed_size });
+ log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
@@ -1321,7 +1332,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.flags = 0,
}),
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.text_section_index == null) {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
@@ -1336,7 +1348,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const needed_size = self.base.options.program_code_size_hint;
const off = self.findFreeSpace(text_segment, needed_size, @as(u16, 1) << alignment);
- log.debug("found __text section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });
+ log.debug("found __text section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try text_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__text"),
@@ -1352,7 +1364,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.reserved2 = 0,
.reserved3 = 0,
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.got_section_index == null) {
const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
@@ -1364,7 +1377,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const off = self.findFreeSpace(text_segment, needed_size, @alignOf(u64));
assert(off + needed_size <= text_segment.inner.fileoff + text_segment.inner.filesize); // TODO Must expand __TEXT segment.
- log.debug("found __ziggot section free space 0x{x} to 0x{x}\n", .{ off, off + needed_size });
+ log.debug("found __ziggot section free space 0x{x} to 0x{x}", .{ off, off + needed_size });
try text_segment.addSection(self.base.allocator, .{
.sectname = makeStaticString("__ziggot"),
@@ -1380,7 +1393,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.reserved2 = 0,
.reserved3 = 0,
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1389,7 +1403,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const initprot = macho.VM_PROT_READ;
const address_and_offset = self.nextSegmentAddressAndOffset();
- log.debug("found __LINKEDIT segment free space at 0x{x}\n", .{address_and_offset.offset});
+ log.debug("found __LINKEDIT segment free space at 0x{x}", .{address_and_offset.offset});
try self.load_commands.append(self.base.allocator, .{
.Segment = SegmentCommand.empty(.{
@@ -1406,7 +1420,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.flags = 0,
}),
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.dyld_info_cmd_index == null) {
self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1416,7 +1431,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const export_size = 2;
const export_off = self.findFreeSpace(&linkedit_segment, export_size, 1);
- log.debug("found export info free space 0x{x} to 0x{x}\n", .{ export_off, export_off + export_size });
+ log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + export_size });
try self.load_commands.append(self.base.allocator, .{
.DyldInfoOnly = .{
@@ -1434,7 +1449,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.export_size = export_size,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.symtab_cmd_index == null) {
self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1443,13 +1459,13 @@ pub fn populateMissingMetadata(self: *MachO) !void {
const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);
const symtab_off = self.findFreeSpace(&linkedit_segment, symtab_size, @sizeOf(macho.nlist_64));
- log.debug("found symbol table free space 0x{x} to 0x{x}\n", .{ symtab_off, symtab_off + symtab_size });
+ log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
try self.string_table.append(self.base.allocator, 0); // Need a null at position 0.
const strtab_size = self.string_table.items.len;
const strtab_off = self.findFreeSpace(&linkedit_segment, strtab_size, 1);
- log.debug("found string table free space 0x{x} to 0x{x}\n", .{ strtab_off, strtab_off + strtab_size });
+ log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
try self.load_commands.append(self.base.allocator, .{
.Symtab = .{
@@ -1461,8 +1477,10 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.strsize = @intCast(u32, strtab_size),
},
});
- self.cmd_table_dirty = true;
try self.writeLocalSymbol(0);
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
+ self.string_table_dirty = true;
}
if (self.dysymtab_cmd_index == null) {
self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1493,7 +1511,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.nlocrel = 0,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.dylinker_cmd_index == null) {
self.dylinker_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1507,7 +1526,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
mem.set(u8, dylinker_cmd.data, 0);
mem.copy(u8, dylinker_cmd.data, mem.spanZ(DEFAULT_DYLD_PATH));
try self.load_commands.append(self.base.allocator, .{ .Dylinker = dylinker_cmd });
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.libsystem_cmd_index == null) {
self.libsystem_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1529,7 +1549,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
mem.set(u8, dylib_cmd.data, 0);
mem.copy(u8, dylib_cmd.data, mem.spanZ(LIB_SYSTEM_PATH));
try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.main_cmd_index == null) {
self.main_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1541,7 +1562,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.stacksize = 0,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.version_min_cmd_index == null) {
self.version_min_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1562,7 +1584,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.sdk = version,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.source_version_cmd_index == null) {
self.source_version_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1573,7 +1596,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.version = 0x0,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.code_signature_cmd_index == null) {
self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
@@ -1586,7 +1610,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.datasize = 0,
},
});
- self.cmd_table_dirty = true;
+ self.header_dirty = true;
+ self.load_commands_dirty = true;
}
if (self.dyld_stub_binder_index == null) {
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,
self.last_text_block = text_block;
text_section.size = needed_size;
- self.cmd_table_dirty = true; // TODO Make more granular.
+ self.load_commands_dirty = true; // TODO Make more granular.
}
text_block.size = new_block_size;
@@ -1712,6 +1737,7 @@ fn makeString(self: *MachO, bytes: []const u8) !u32 {
const result = self.string_table.items.len;
self.string_table.appendSliceAssumeCapacity(bytes);
self.string_table.appendAssumeCapacity(0);
+ self.string_table_dirty = true;
return @intCast(u32, result);
}
@@ -1908,11 +1934,16 @@ fn satMul(a: anytype, b: anytype) @TypeOf(a, b) {
}
fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
- const text_semgent = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
- const sect = &text_semgent.sections.items[self.got_section_index.?];
+ const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
+ const sect = &text_segment.sections.items[self.got_section_index.?];
const off = sect.offset + @sizeOf(u64) * index;
const vmaddr = sect.addr + @sizeOf(u64) * index;
+ if (self.offset_table_count_dirty) {
+ // TODO relocate.
+ self.offset_table_count_dirty = false;
+ }
+
var code: [8]u8 = undefined;
switch (self.base.options.target.cpu.arch) {
.x86_64 => {
@@ -1936,7 +1967,7 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
},
else => unreachable, // unsupported target architecture
}
- log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
+ log.debug("writing offset table entry 0x{x} at 0x{x}", .{ self.offset_table.items[index], off });
try self.base.file.?.pwriteAll(&code, off);
}
@@ -1967,7 +1998,7 @@ fn relocateSymbolTable(self: *MachO) !void {
symtab.symoff = @intCast(u32, new_symoff);
}
symtab.nsyms = @intCast(u32, nsyms);
- self.cmd_table_dirty = true;
+ self.load_commands_dirty = true;
}
}
@@ -1996,12 +2027,12 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
const globals_off = locals_off + locals_size;
const globals_size = nglobals * @sizeOf(macho.nlist_64);
- log.debug("writing global symbols from 0x{x} to 0x{x}\n", .{ globals_off, globals_size + globals_off });
+ log.debug("writing global symbols from 0x{x} to 0x{x}", .{ globals_off, globals_size + globals_off });
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.global_symbols.items), globals_off);
const undefs_off = globals_off + globals_size;
const undefs_size = nundefs * @sizeOf(macho.nlist_64);
- log.debug("writing undef symbols from 0x{x} to 0x{x}\n", .{ undefs_off, undefs_size + undefs_off });
+ log.debug("writing undef symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undef_symbols.items), undefs_off);
// Update dynamic symbol table.
@@ -2011,7 +2042,7 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
dysymtab.nextdefsym = @intCast(u32, nglobals);
dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
dysymtab.nundefsym = @intCast(u32, nundefs);
- self.cmd_table_dirty = true;
+ self.load_commands_dirty = true;
}
fn writeCodeSignaturePadding(self: *MachO) !void {
@@ -2021,19 +2052,23 @@ fn writeCodeSignaturePadding(self: *MachO) !void {
const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
- const datasize = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
- code_sig_cmd.dataoff = @intCast(u32, fileoff);
- code_sig_cmd.datasize = datasize;
+ const needed_size = CodeSignature.calcCodeSignaturePadding(self.base.options.emit.?.sub_path, fileoff);
- // Advance size of __LINKEDIT segment
- linkedit_segment.inner.filesize += datasize;
- if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
- linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
- }
- log.debug("writing code signature padding from 0x{x} to 0x{x}\n", .{ fileoff, fileoff + datasize });
- // Pad out the space. We need to do this to calculate valid hashes for everything in the file
- // except for code signature data.
- try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + datasize - 1);
+ if (code_sig_cmd.datasize < needed_size) {
+ code_sig_cmd.dataoff = @intCast(u32, fileoff);
+ code_sig_cmd.datasize = needed_size;
+
+ // Advance size of __LINKEDIT segment
+ linkedit_segment.inner.filesize += needed_size;
+ if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
+ linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
+ }
+ log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
+ // Pad out the space. We need to do this to calculate valid hashes for everything in the file
+ // except for code signature data.
+ try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
+ self.load_commands_dirty = true;
+ }
}
fn writeCodeSignature(self: *MachO) !void {
@@ -2057,12 +2092,13 @@ fn writeCodeSignature(self: *MachO) !void {
defer self.base.allocator.free(buffer);
code_sig.write(buffer);
- log.debug("writing code signature from 0x{x} to 0x{x}\n", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
+ log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
}
fn writeExportTrie(self: *MachO) !void {
+ if (!self.export_info_dirty) return;
if (self.global_symbols.items.len == 0) return;
const tracy = trace(@src());
@@ -2100,10 +2136,11 @@ fn writeExportTrie(self: *MachO) !void {
dyld_info.export_off = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
}
dyld_info.export_size = @intCast(u32, needed_size);
- log.debug("writing export trie from 0x{x} to 0x{x}\n", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
+ log.debug("writing export trie from 0x{x} to 0x{x}", .{ dyld_info.export_off, dyld_info.export_off + dyld_info.export_size });
try self.base.file.?.pwriteAll(buffer, dyld_info.export_off);
- self.cmd_table_dirty = true;
+ self.load_commands_dirty = true;
+ self.export_info_dirty = false;
}
fn writeBindingInfoTable(self: *MachO) !void {
@@ -2119,7 +2156,7 @@ fn writeBindingInfoTable(self: *MachO) !void {
dyld_info.bind_off = self.linkedit_segment_next_offset.?;
dyld_info.bind_size = bind_size;
- log.debug("writing binding info table from 0x{x} to 0x{x}\n", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size });
+ log.debug("writing binding info table from 0x{x} to 0x{x}", .{ dyld_info.bind_off, dyld_info.bind_off + bind_size });
if (bind_size > buffer.len) {
// Pad out to align(8).
@@ -2150,7 +2187,7 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
dyld_info.lazy_bind_off = self.linkedit_segment_next_offset.?;
dyld_info.lazy_bind_size = bind_size;
- 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 });
+ 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 });
if (bind_size > buffer.len) {
// Pad out to align(8).
@@ -2169,6 +2206,8 @@ fn writeLazyBindingInfoTable(self: *MachO) !void {
}
fn writeStringTable(self: *MachO) !void {
+ if (!self.string_table_dirty) return;
+
const tracy = trace(@src());
defer tracy.end();
@@ -2182,13 +2221,16 @@ fn writeStringTable(self: *MachO) !void {
symtab.stroff = @intCast(u32, self.findFreeSpace(&linkedit_segment, needed_size, 1));
}
symtab.strsize = @intCast(u32, needed_size);
- log.debug("writing string table from 0x{x} to 0x{x}\n", .{ symtab.stroff, symtab.stroff + symtab.strsize });
+ log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
try self.base.file.?.pwriteAll(self.string_table.items, symtab.stroff);
- self.cmd_table_dirty = true;
+ self.load_commands_dirty = true;
+ self.string_table_dirty = false;
}
fn updateLinkeditSegmentSizes(self: *MachO) !void {
+ if (!self.load_commands_dirty) return;
+
const tracy = trace(@src());
defer tracy.end();
@@ -2229,10 +2271,13 @@ fn updateLinkeditSegmentSizes(self: *MachO) !void {
const filesize = final_offset - linkedit_segment.inner.fileoff;
linkedit_segment.inner.filesize = filesize;
linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
+ self.load_commands_dirty = true;
}
/// Writes all load commands and section headers.
fn writeLoadCommands(self: *MachO) !void {
+ if (!self.load_commands_dirty) return;
+
var sizeofcmds: usize = 0;
for (self.load_commands.items) |lc| {
sizeofcmds += lc.cmdsize();
@@ -2246,19 +2291,22 @@ fn writeLoadCommands(self: *MachO) !void {
}
try self.base.file.?.pwriteAll(buffer, @sizeOf(macho.mach_header_64));
+ self.load_commands_dirty = false;
}
/// Writes Mach-O file header.
fn writeHeader(self: *MachO) !void {
+ if (!self.header_dirty) return;
+
self.header.?.ncmds = @intCast(u32, self.load_commands.items.len);
var sizeofcmds: u32 = 0;
for (self.load_commands.items) |cmd| {
sizeofcmds += cmd.cmdsize();
}
self.header.?.sizeofcmds = sizeofcmds;
- log.debug("writing Mach-O header {}\n", .{self.header.?});
- const slice = [1]macho.mach_header_64{self.header.?};
- try self.base.file.?.pwriteAll(mem.sliceAsBytes(slice[0..1]), 0);
+ log.debug("writing Mach-O header {}", .{self.header.?});
+ try self.base.file.?.pwriteAll(mem.asBytes(&self.header.?), 0);
+ self.header_dirty = false;
}
/// Parse MachO contents from existing binary file.
@@ -2327,7 +2375,7 @@ fn parseFromFile(self: *MachO, file: fs.File) !void {
self.code_signature_cmd_index = i;
},
else => {
- std.log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
+ log.warn("Unknown load command detected: 0x{x}.", .{cmd.cmd()});
},
}
self.load_commands.appendAssumeCapacity(cmd);