macho: write only bits that changed

Refactor use of `log` to not include an additional newline char.
This commit is contained in:
Jakub Konka 2020-12-21 19:59:40 +01:00
parent de5421a0a6
commit 3f21f9155f

View File

@ -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);
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;
}
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);
}
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);