aboutsummaryrefslogtreecommitdiff
path: root/src/link/MachO.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/link/MachO.zig')
-rw-r--r--src/link/MachO.zig189
1 files changed, 69 insertions, 120 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 0422a983dc..b06552bc2a 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -99,10 +99,11 @@ page_size: u16,
/// fashion (default for LLVM backend).
mode: enum { incremental, one_shot },
-uuid: struct {
- buf: [16]u8 = undefined,
- final: bool = false,
-} = .{},
+dyld_info_cmd: macho.dyld_info_command = .{},
+symtab_cmd: macho.symtab_command = .{},
+dysymtab_cmd: macho.dysymtab_command = .{},
+uuid_cmd: macho.uuid_command = .{},
+codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
dylibs: std.ArrayListUnmanaged(Dylib) = .{},
dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
@@ -554,12 +555,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
self.logAtoms();
}
+ try self.writeLinkeditSegmentData();
+
+ // Write load commands
var lc_buffer = std.ArrayList(u8).init(arena);
const lc_writer = lc_buffer.writer();
- var ncmds: u32 = 0;
- try self.writeLinkeditSegmentData(&ncmds, lc_writer);
- try load_commands.writeDylinkerLC(&ncmds, lc_writer);
+ try self.writeSegmentHeaders(lc_writer);
+ try lc_writer.writeStruct(self.dyld_info_cmd);
+ try lc_writer.writeStruct(self.symtab_cmd);
+ try lc_writer.writeStruct(self.dysymtab_cmd);
+ try load_commands.writeDylinkerLC(lc_writer);
switch (self.base.options.output_mode) {
.Exe => blk: {
@@ -573,33 +579,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
else => |e| return e,
};
const sym = self.getSymbol(global);
- try load_commands.writeMainLC(@intCast(u32, sym.n_value - seg.vmaddr), &self.base.options, &ncmds, lc_writer);
+ try lc_writer.writeStruct(macho.entry_point_command{
+ .entryoff = @intCast(u32, sym.n_value - seg.vmaddr),
+ .stacksize = self.base.options.stack_size_override orelse 0,
+ });
},
.Lib => if (self.base.options.link_mode == .Dynamic) {
- try load_commands.writeDylibIdLC(self.base.allocator, &self.base.options, &ncmds, lc_writer);
+ try load_commands.writeDylibIdLC(self.base.allocator, &self.base.options, lc_writer);
},
else => {},
}
- try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, &ncmds, lc_writer);
-
- {
- try lc_writer.writeStruct(macho.source_version_command{
- .cmdsize = @sizeOf(macho.source_version_command),
- .version = 0x0,
- });
- ncmds += 1;
- }
-
- try load_commands.writeBuildVersionLC(&self.base.options, &ncmds, lc_writer);
+ try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, lc_writer);
+ try lc_writer.writeStruct(macho.source_version_command{
+ .version = 0,
+ });
+ try load_commands.writeBuildVersionLC(&self.base.options, lc_writer);
- if (!self.uuid.final) {
- std.crypto.random.bytes(&self.uuid.buf);
- self.uuid.final = true;
+ if (self.cold_start) {
+ std.crypto.random.bytes(&self.uuid_cmd.uuid);
}
- try load_commands.writeUuidLC(&self.uuid.buf, &ncmds, lc_writer);
+ try lc_writer.writeStruct(self.uuid_cmd);
- try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), &ncmds, lc_writer);
+ try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer);
const target = self.base.options.target;
const requires_codesig = blk: {
@@ -608,7 +610,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
break :blk true;
break :blk false;
};
- var codesig_offset: ?u32 = null;
var codesig: ?CodeSignature = if (requires_codesig) blk: {
// Preallocate space for the code signature.
// We need to do this at this stage so that we have the load commands with proper values
@@ -620,20 +621,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
if (self.base.options.entitlements) |path| {
try codesig.addEntitlements(arena, path);
}
- codesig_offset = try self.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);
+ try self.writeCodeSignaturePadding(&codesig);
+ try lc_writer.writeStruct(self.codesig_cmd);
break :blk codesig;
} else null;
- var headers_buf = std.ArrayList(u8).init(arena);
- try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
+ try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
- try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
- try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
-
- try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
+ const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
+ try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len));
if (codesig) |*csig| {
- try self.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last
+ try self.writeCodeSignature(comp, csig); // code signing always comes last
}
if (self.d_sym) |*d_sym| {
@@ -3146,18 +3145,17 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
return global_index;
}
-fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {
+fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
for (self.segments.items) |seg, i| {
const indexes = self.getSectionIndexes(@intCast(u8, i));
try writer.writeStruct(seg);
for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
try writer.writeStruct(header);
}
- ncmds.* += 1;
}
}
-fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
+fn writeLinkeditSegmentData(self: *MachO) !void {
const seg = self.getLinkeditSegmentPtr();
seg.filesize = 0;
seg.vmsize = 0;
@@ -3172,8 +3170,8 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void
}
}
- try self.writeDyldInfoData(ncmds, lc_writer);
- try self.writeSymtabs(ncmds, lc_writer);
+ try self.writeDyldInfoData();
+ try self.writeSymtabs();
seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
}
@@ -3325,7 +3323,7 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
try trie.finalize(gpa);
}
-fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
+fn writeDyldInfoData(self: *MachO) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -3396,21 +3394,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
const end = start + (math.cast(usize, lazy_bind_size) orelse return error.Overflow);
try self.populateLazyBindOffsetsInStubHelper(buffer[start..end]);
- try lc_writer.writeStruct(macho.dyld_info_command{
- .cmd = .DYLD_INFO_ONLY,
- .cmdsize = @sizeOf(macho.dyld_info_command),
- .rebase_off = @intCast(u32, rebase_off),
- .rebase_size = @intCast(u32, rebase_size),
- .bind_off = @intCast(u32, bind_off),
- .bind_size = @intCast(u32, bind_size),
- .weak_bind_off = 0,
- .weak_bind_size = 0,
- .lazy_bind_off = @intCast(u32, lazy_bind_off),
- .lazy_bind_size = @intCast(u32, lazy_bind_size),
- .export_off = @intCast(u32, export_off),
- .export_size = @intCast(u32, export_size),
- });
- ncmds.* += 1;
+ self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
+ self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
+ self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
+ self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
+ self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
+ self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
+ self.dyld_info_cmd.export_off = @intCast(u32, export_off);
+ self.dyld_info_cmd.export_size = @intCast(u32, export_size);
}
fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
@@ -3512,45 +3503,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
}
}
-fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
- var symtab_cmd = macho.symtab_command{
- .cmdsize = @sizeOf(macho.symtab_command),
- .symoff = 0,
- .nsyms = 0,
- .stroff = 0,
- .strsize = 0,
- };
- var dysymtab_cmd = macho.dysymtab_command{
- .cmdsize = @sizeOf(macho.dysymtab_command),
- .ilocalsym = 0,
- .nlocalsym = 0,
- .iextdefsym = 0,
- .nextdefsym = 0,
- .iundefsym = 0,
- .nundefsym = 0,
- .tocoff = 0,
- .ntoc = 0,
- .modtaboff = 0,
- .nmodtab = 0,
- .extrefsymoff = 0,
- .nextrefsyms = 0,
- .indirectsymoff = 0,
- .nindirectsyms = 0,
- .extreloff = 0,
- .nextrel = 0,
- .locreloff = 0,
- .nlocrel = 0,
- };
- var ctx = try self.writeSymtab(&symtab_cmd);
+fn writeSymtabs(self: *MachO) !void {
+ var ctx = try self.writeSymtab();
defer ctx.imports_table.deinit();
- try self.writeDysymtab(ctx, &dysymtab_cmd);
- try self.writeStrtab(&symtab_cmd);
- try lc_writer.writeStruct(symtab_cmd);
- try lc_writer.writeStruct(dysymtab_cmd);
- ncmds.* += 2;
+ try self.writeDysymtab(ctx);
+ try self.writeStrtab();
}
-fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
+fn writeSymtab(self: *MachO) !SymtabCtx {
const gpa = self.base.allocator;
var locals = std.ArrayList(macho.nlist_64).init(gpa);
@@ -3615,8 +3575,8 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
try self.base.file.?.pwriteAll(buffer.items, offset);
- lc.symoff = @intCast(u32, offset);
- lc.nsyms = nsyms;
+ self.symtab_cmd.symoff = @intCast(u32, offset);
+ self.symtab_cmd.nsyms = nsyms;
return SymtabCtx{
.nlocalsym = nlocals,
@@ -3626,7 +3586,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
};
}
-fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
+fn writeStrtab(self: *MachO) !void {
const seg = self.getLinkeditSegmentPtr();
const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
const needed_size = self.strtab.buffer.items.len;
@@ -3636,8 +3596,8 @@ fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);
- lc.stroff = @intCast(u32, offset);
- lc.strsize = @intCast(u32, needed_size);
+ self.symtab_cmd.stroff = @intCast(u32, offset);
+ self.symtab_cmd.strsize = @intCast(u32, needed_size);
}
const SymtabCtx = struct {
@@ -3647,7 +3607,7 @@ const SymtabCtx = struct {
imports_table: std.AutoHashMap(SymbolWithLoc, u32),
};
-fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {
+fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
const gpa = self.base.allocator;
const nstubs = @intCast(u32, self.stubs_table.count());
const ngot_entries = @intCast(u32, self.got_entries_table.count());
@@ -3706,21 +3666,16 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !voi
assert(buf.items.len == needed_size);
try self.base.file.?.pwriteAll(buf.items, offset);
- lc.nlocalsym = ctx.nlocalsym;
- lc.iextdefsym = iextdefsym;
- lc.nextdefsym = ctx.nextdefsym;
- lc.iundefsym = iundefsym;
- lc.nundefsym = ctx.nundefsym;
- lc.indirectsymoff = @intCast(u32, offset);
- lc.nindirectsyms = nindirectsyms;
+ self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
+ self.dysymtab_cmd.iextdefsym = iextdefsym;
+ self.dysymtab_cmd.nextdefsym = ctx.nextdefsym;
+ self.dysymtab_cmd.iundefsym = iundefsym;
+ self.dysymtab_cmd.nundefsym = ctx.nundefsym;
+ self.dysymtab_cmd.indirectsymoff = @intCast(u32, offset);
+ self.dysymtab_cmd.nindirectsyms = nindirectsyms;
}
-fn writeCodeSignaturePadding(
- self: *MachO,
- code_sig: *CodeSignature,
- ncmds: *u32,
- lc_writer: anytype,
-) !u32 {
+fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
const seg = self.getLinkeditSegmentPtr();
// Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
// https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
@@ -3733,19 +3688,13 @@ fn writeCodeSignaturePadding(
// except for code signature data.
try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
- try lc_writer.writeStruct(macho.linkedit_data_command{
- .cmd = .CODE_SIGNATURE,
- .cmdsize = @sizeOf(macho.linkedit_data_command),
- .dataoff = @intCast(u32, offset),
- .datasize = @intCast(u32, needed_size),
- });
- ncmds.* += 1;
-
- return @intCast(u32, offset);
+ self.codesig_cmd.dataoff = @intCast(u32, offset);
+ self.codesig_cmd.datasize = @intCast(u32, needed_size);
}
-fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature, offset: u32) !void {
+fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void {
const seg = self.getSegment(self.text_section_index.?);
+ const offset = self.codesig_cmd.dataoff;
var buffer = std.ArrayList(u8).init(self.base.allocator);
defer buffer.deinit();