authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-15 13:32:51+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-12-16 18:05:58+01:00
log09dee744145fc423feb2b74ffa22cc1679a2749e
treed61d4f49c14890b0dbd8d63956784cf94c7f2fcf
parent3af6a4e887bb3cd986a52ea94202a0079f442e9b

macho: store LC headers to often updated LINKEDIT sections


5 files changed, 268 insertions(+), 416 deletions(-)

lib/std/macho.zig+46-46
...@@ -58,10 +58,10 @@ pub const uuid_command = extern struct {...@@ -58,10 +58,10 @@ pub const uuid_command = extern struct {
58 cmd: LC = .UUID,58 cmd: LC = .UUID,
5959
60 /// sizeof(struct uuid_command)60 /// sizeof(struct uuid_command)
61 cmdsize: u32,61 cmdsize: u32 = @sizeOf(uuid_command),
6262
63 /// the 128-bit uuid63 /// the 128-bit uuid
64 uuid: [16]u8,64 uuid: [16]u8 = undefined,
65};65};
6666
67/// The version_min_command contains the min OS version on which this67/// The version_min_command contains the min OS version on which this
...@@ -71,7 +71,7 @@ pub const version_min_command = extern struct {...@@ -71,7 +71,7 @@ pub const version_min_command = extern struct {
71 cmd: LC,71 cmd: LC,
7272
73 /// sizeof(struct version_min_command)73 /// sizeof(struct version_min_command)
74 cmdsize: u32,74 cmdsize: u32 = @sizeOf(version_min_command),
7575
76 /// X.Y.Z is encoded in nibbles xxxx.yy.zz76 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
77 version: u32,77 version: u32,
...@@ -87,7 +87,7 @@ pub const source_version_command = extern struct {...@@ -87,7 +87,7 @@ pub const source_version_command = extern struct {
87 cmd: LC = .SOURCE_VERSION,87 cmd: LC = .SOURCE_VERSION,
8888
89 /// sizeof(source_version_command)89 /// sizeof(source_version_command)
90 cmdsize: u32,90 cmdsize: u32 = @sizeOf(source_version_command),
9191
92 /// A.B.C.D.E packed as a24.b10.c10.d10.e1092 /// A.B.C.D.E packed as a24.b10.c10.d10.e10
93 version: u64,93 version: u64,
...@@ -155,13 +155,13 @@ pub const entry_point_command = extern struct {...@@ -155,13 +155,13 @@ pub const entry_point_command = extern struct {
155 cmd: LC = .MAIN,155 cmd: LC = .MAIN,
156156
157 /// sizeof(struct entry_point_command)157 /// sizeof(struct entry_point_command)
158 cmdsize: u32,158 cmdsize: u32 = @sizeOf(entry_point_command),
159159
160 /// file (__TEXT) offset of main()160 /// file (__TEXT) offset of main()
161 entryoff: u64,161 entryoff: u64 = 0,
162162
163 /// if not zero, initial stack size163 /// if not zero, initial stack size
164 stacksize: u64,164 stacksize: u64 = 0,
165};165};
166166
167/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD167/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
...@@ -172,19 +172,19 @@ pub const symtab_command = extern struct {...@@ -172,19 +172,19 @@ pub const symtab_command = extern struct {
172 cmd: LC = .SYMTAB,172 cmd: LC = .SYMTAB,
173173
174 /// sizeof(struct symtab_command)174 /// sizeof(struct symtab_command)
175 cmdsize: u32,175 cmdsize: u32 = @sizeOf(symtab_command),
176176
177 /// symbol table offset177 /// symbol table offset
178 symoff: u32,178 symoff: u32 = 0,
179179
180 /// number of symbol table entries180 /// number of symbol table entries
181 nsyms: u32,181 nsyms: u32 = 0,
182182
183 /// string table offset183 /// string table offset
184 stroff: u32,184 stroff: u32 = 0,
185185
186 /// string table size in bytes186 /// string table size in bytes
187 strsize: u32,187 strsize: u32 = 0,
188};188};
189189
190/// This is the second set of the symbolic information which is used to support190/// This is the second set of the symbolic information which is used to support
...@@ -230,7 +230,7 @@ pub const dysymtab_command = extern struct {...@@ -230,7 +230,7 @@ pub const dysymtab_command = extern struct {
230 cmd: LC = .DYSYMTAB,230 cmd: LC = .DYSYMTAB,
231231
232 /// sizeof(struct dysymtab_command)232 /// sizeof(struct dysymtab_command)
233 cmdsize: u32,233 cmdsize: u32 = @sizeOf(dysymtab_command),
234234
235 // The symbols indicated by symoff and nsyms of the LC_SYMTAB load command235 // The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
236 // are grouped into the following three groups:236 // are grouped into the following three groups:
...@@ -247,22 +247,22 @@ pub const dysymtab_command = extern struct {...@@ -247,22 +247,22 @@ pub const dysymtab_command = extern struct {
247 // table when this is a dynamically linked shared library file).247 // table when this is a dynamically linked shared library file).
248248
249 /// index of local symbols249 /// index of local symbols
250 ilocalsym: u32,250 ilocalsym: u32 = 0,
251251
252 /// number of local symbols252 /// number of local symbols
253 nlocalsym: u32,253 nlocalsym: u32 = 0,
254254
255 /// index to externally defined symbols255 /// index to externally defined symbols
256 iextdefsym: u32,256 iextdefsym: u32 = 0,
257257
258 /// number of externally defined symbols258 /// number of externally defined symbols
259 nextdefsym: u32,259 nextdefsym: u32 = 0,
260260
261 /// index to undefined symbols261 /// index to undefined symbols
262 iundefsym: u32,262 iundefsym: u32 = 0,
263263
264 /// number of undefined symbols264 /// number of undefined symbols
265 nundefsym: u32,265 nundefsym: u32 = 0,
266266
267 // For the for the dynamic binding process to find which module a symbol267 // For the for the dynamic binding process to find which module a symbol
268 // is defined in the table of contents is used (analogous to the ranlib268 // is defined in the table of contents is used (analogous to the ranlib
...@@ -272,10 +272,10 @@ pub const dysymtab_command = extern struct {...@@ -272,10 +272,10 @@ pub const dysymtab_command = extern struct {
272 // symbols are sorted by name and is use as the table of contents.272 // symbols are sorted by name and is use as the table of contents.
273273
274 /// file offset to table of contents274 /// file offset to table of contents
275 tocoff: u32,275 tocoff: u32 = 0,
276276
277 /// number of entries in table of contents277 /// number of entries in table of contents
278 ntoc: u32,278 ntoc: u32 = 0,
279279
280 // To support dynamic binding of "modules" (whole object files) the symbol280 // To support dynamic binding of "modules" (whole object files) the symbol
281 // table must reflect the modules that the file was created from. This is281 // table must reflect the modules that the file was created from. This is
...@@ -286,10 +286,10 @@ pub const dysymtab_command = extern struct {...@@ -286,10 +286,10 @@ pub const dysymtab_command = extern struct {
286 // contains one module so everything in the file belongs to the module.286 // contains one module so everything in the file belongs to the module.
287287
288 /// file offset to module table288 /// file offset to module table
289 modtaboff: u32,289 modtaboff: u32 = 0,
290290
291 /// number of module table entries291 /// number of module table entries
292 nmodtab: u32,292 nmodtab: u32 = 0,
293293
294 // To support dynamic module binding the module structure for each module294 // To support dynamic module binding the module structure for each module
295 // indicates the external references (defined and undefined) each module295 // indicates the external references (defined and undefined) each module
...@@ -300,10 +300,10 @@ pub const dysymtab_command = extern struct {...@@ -300,10 +300,10 @@ pub const dysymtab_command = extern struct {
300 // undefined external symbols indicates the external references.300 // undefined external symbols indicates the external references.
301301
302 /// offset to referenced symbol table302 /// offset to referenced symbol table
303 extrefsymoff: u32,303 extrefsymoff: u32 = 0,
304304
305 /// number of referenced symbol table entries305 /// number of referenced symbol table entries
306 nextrefsyms: u32,306 nextrefsyms: u32 = 0,
307307
308 // The sections that contain "symbol pointers" and "routine stubs" have308 // The sections that contain "symbol pointers" and "routine stubs" have
309 // indexes and (implied counts based on the size of the section and fixed309 // indexes and (implied counts based on the size of the section and fixed
...@@ -315,10 +315,10 @@ pub const dysymtab_command = extern struct {...@@ -315,10 +315,10 @@ pub const dysymtab_command = extern struct {
315 // The indirect symbol table is ordered to match the entries in the section.315 // The indirect symbol table is ordered to match the entries in the section.
316316
317 /// file offset to the indirect symbol table317 /// file offset to the indirect symbol table
318 indirectsymoff: u32,318 indirectsymoff: u32 = 0,
319319
320 /// number of indirect symbol table entries320 /// number of indirect symbol table entries
321 nindirectsyms: u32,321 nindirectsyms: u32 = 0,
322322
323 // To support relocating an individual module in a library file quickly the323 // To support relocating an individual module in a library file quickly the
324 // external relocation entries for each module in the library need to be324 // external relocation entries for each module in the library need to be
...@@ -347,20 +347,20 @@ pub const dysymtab_command = extern struct {...@@ -347,20 +347,20 @@ pub const dysymtab_command = extern struct {
347 // remaining relocation entries must be local).347 // remaining relocation entries must be local).
348348
349 /// offset to external relocation entries349 /// offset to external relocation entries
350 extreloff: u32,350 extreloff: u32 = 0,
351351
352 /// number of external relocation entries352 /// number of external relocation entries
353 nextrel: u32,353 nextrel: u32 = 0,
354354
355 // All the local relocation entries are grouped together (they are not355 // All the local relocation entries are grouped together (they are not
356 // grouped by their module since they are only used if the object is moved356 // grouped by their module since they are only used if the object is moved
357 // from it staticly link edited address).357 // from it staticly link edited address).
358358
359 /// offset to local relocation entries359 /// offset to local relocation entries
360 locreloff: u32,360 locreloff: u32 = 0,
361361
362 /// number of local relocation entries362 /// number of local relocation entries
363 nlocrel: u32,363 nlocrel: u32 = 0,
364};364};
365365
366/// The linkedit_data_command contains the offsets and sizes of a blob366/// The linkedit_data_command contains the offsets and sizes of a blob
...@@ -370,13 +370,13 @@ pub const linkedit_data_command = extern struct {...@@ -370,13 +370,13 @@ pub const linkedit_data_command = extern struct {
370 cmd: LC,370 cmd: LC,
371371
372 /// sizeof(struct linkedit_data_command)372 /// sizeof(struct linkedit_data_command)
373 cmdsize: u32,373 cmdsize: u32 = @sizeOf(linkedit_data_command),
374374
375 /// file offset of data in __LINKEDIT segment375 /// file offset of data in __LINKEDIT segment
376 dataoff: u32,376 dataoff: u32 = 0,
377377
378 /// file size of data in __LINKEDIT segment378 /// file size of data in __LINKEDIT segment
379 datasize: u32,379 datasize: u32 = 0,
380};380};
381381
382/// The dyld_info_command contains the file offsets and sizes of382/// The dyld_info_command contains the file offsets and sizes of
...@@ -387,10 +387,10 @@ pub const linkedit_data_command = extern struct {...@@ -387,10 +387,10 @@ pub const linkedit_data_command = extern struct {
387/// to interpret it.387/// to interpret it.
388pub const dyld_info_command = extern struct {388pub const dyld_info_command = extern struct {
389 /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY389 /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
390 cmd: LC,390 cmd: LC = .DYLD_INFO_ONLY,
391391
392 /// sizeof(struct dyld_info_command)392 /// sizeof(struct dyld_info_command)
393 cmdsize: u32,393 cmdsize: u32 = @sizeOf(dyld_info_command),
394394
395 // Dyld rebases an image whenever dyld loads it at an address different395 // Dyld rebases an image whenever dyld loads it at an address different
396 // from its preferred address. The rebase information is a stream396 // from its preferred address. The rebase information is a stream
...@@ -403,10 +403,10 @@ pub const dyld_info_command = extern struct {...@@ -403,10 +403,10 @@ pub const dyld_info_command = extern struct {
403 // bytes.403 // bytes.
404404
405 /// file offset to rebase info405 /// file offset to rebase info
406 rebase_off: u32,406 rebase_off: u32 = 0,
407407
408 /// size of rebase info408 /// size of rebase info
409 rebase_size: u32,409 rebase_size: u32 = 0,
410410
411 // Dyld binds an image during the loading process, if the image411 // Dyld binds an image during the loading process, if the image
412 // requires any pointers to be initialized to symbols in other images.412 // requires any pointers to be initialized to symbols in other images.
...@@ -420,10 +420,10 @@ pub const dyld_info_command = extern struct {...@@ -420,10 +420,10 @@ pub const dyld_info_command = extern struct {
420 // encoded in a few bytes.420 // encoded in a few bytes.
421421
422 /// file offset to binding info422 /// file offset to binding info
423 bind_off: u32,423 bind_off: u32 = 0,
424424
425 /// size of binding info425 /// size of binding info
426 bind_size: u32,426 bind_size: u32 = 0,
427427
428 // Some C++ programs require dyld to unique symbols so that all428 // Some C++ programs require dyld to unique symbols so that all
429 // images in the process use the same copy of some code/data.429 // images in the process use the same copy of some code/data.
...@@ -440,10 +440,10 @@ pub const dyld_info_command = extern struct {...@@ -440,10 +440,10 @@ pub const dyld_info_command = extern struct {
440 // and the call to operator new is then rebound.440 // and the call to operator new is then rebound.
441441
442 /// file offset to weak binding info442 /// file offset to weak binding info
443 weak_bind_off: u32,443 weak_bind_off: u32 = 0,
444444
445 /// size of weak binding info445 /// size of weak binding info
446 weak_bind_size: u32,446 weak_bind_size: u32 = 0,
447447
448 // Some uses of external symbols do not need to be bound immediately.448 // Some uses of external symbols do not need to be bound immediately.
449 // Instead they can be lazily bound on first use. The lazy_bind449 // Instead they can be lazily bound on first use. The lazy_bind
...@@ -457,10 +457,10 @@ pub const dyld_info_command = extern struct {...@@ -457,10 +457,10 @@ pub const dyld_info_command = extern struct {
457 // to bind.457 // to bind.
458458
459 /// file offset to lazy binding info459 /// file offset to lazy binding info
460 lazy_bind_off: u32,460 lazy_bind_off: u32 = 0,
461461
462 /// size of lazy binding info462 /// size of lazy binding info
463 lazy_bind_size: u32,463 lazy_bind_size: u32 = 0,
464464
465 // The symbols exported by a dylib are encoded in a trie. This465 // The symbols exported by a dylib are encoded in a trie. This
466 // is a compact representation that factors out common prefixes.466 // is a compact representation that factors out common prefixes.
...@@ -494,10 +494,10 @@ pub const dyld_info_command = extern struct {...@@ -494,10 +494,10 @@ pub const dyld_info_command = extern struct {
494 // edge points to.494 // edge points to.
495495
496 /// file offset to lazy binding info496 /// file offset to lazy binding info
497 export_off: u32,497 export_off: u32 = 0,
498498
499 /// size of lazy binding info499 /// size of lazy binding info
500 export_size: u32,500 export_size: u32 = 0,
501};501};
502502
503/// A program that uses a dynamic linker contains a dylinker_command to identify503/// A program that uses a dynamic linker contains a dylinker_command to identify
src/link/MachO.zig+69-120
...@@ -99,10 +99,11 @@ page_size: u16,...@@ -99,10 +99,11 @@ page_size: u16,
99/// fashion (default for LLVM backend).99/// fashion (default for LLVM backend).
100mode: enum { incremental, one_shot },100mode: enum { incremental, one_shot },
101101
102uuid: struct {102dyld_info_cmd: macho.dyld_info_command = .{},
103 buf: [16]u8 = undefined,103symtab_cmd: macho.symtab_command = .{},
104 final: bool = false,104dysymtab_cmd: macho.dysymtab_command = .{},
105} = .{},105uuid_cmd: macho.uuid_command = .{},
106codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
106107
107dylibs: std.ArrayListUnmanaged(Dylib) = .{},108dylibs: std.ArrayListUnmanaged(Dylib) = .{},
108dylibs_map: std.StringHashMapUnmanaged(u16) = .{},109dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
...@@ -554,12 +555,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -554,12 +555,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
554 self.logAtoms();555 self.logAtoms();
555 }556 }
556557
558 try self.writeLinkeditSegmentData();
559
560 // Write load commands
557 var lc_buffer = std.ArrayList(u8).init(arena);561 var lc_buffer = std.ArrayList(u8).init(arena);
558 const lc_writer = lc_buffer.writer();562 const lc_writer = lc_buffer.writer();
559 var ncmds: u32 = 0;
560563
561 try self.writeLinkeditSegmentData(&ncmds, lc_writer);564 try self.writeSegmentHeaders(lc_writer);
562 try load_commands.writeDylinkerLC(&ncmds, lc_writer);565 try lc_writer.writeStruct(self.dyld_info_cmd);
566 try lc_writer.writeStruct(self.symtab_cmd);
567 try lc_writer.writeStruct(self.dysymtab_cmd);
568 try load_commands.writeDylinkerLC(lc_writer);
563569
564 switch (self.base.options.output_mode) {570 switch (self.base.options.output_mode) {
565 .Exe => blk: {571 .Exe => blk: {
...@@ -573,33 +579,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -573,33 +579,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
573 else => |e| return e,579 else => |e| return e,
574 };580 };
575 const sym = self.getSymbol(global);581 const sym = self.getSymbol(global);
576 try load_commands.writeMainLC(@intCast(u32, sym.n_value - seg.vmaddr), &self.base.options, &ncmds, lc_writer);582 try lc_writer.writeStruct(macho.entry_point_command{
583 .entryoff = @intCast(u32, sym.n_value - seg.vmaddr),
584 .stacksize = self.base.options.stack_size_override orelse 0,
585 });
577 },586 },
578 .Lib => if (self.base.options.link_mode == .Dynamic) {587 .Lib => if (self.base.options.link_mode == .Dynamic) {
579 try load_commands.writeDylibIdLC(self.base.allocator, &self.base.options, &ncmds, lc_writer);588 try load_commands.writeDylibIdLC(self.base.allocator, &self.base.options, lc_writer);
580 },589 },
581 else => {},590 else => {},
582 }591 }
583592
584 try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, &ncmds, lc_writer);593 try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, lc_writer);
585594 try lc_writer.writeStruct(macho.source_version_command{
586 {595 .version = 0,
587 try lc_writer.writeStruct(macho.source_version_command{596 });
588 .cmdsize = @sizeOf(macho.source_version_command),597 try load_commands.writeBuildVersionLC(&self.base.options, lc_writer);
589 .version = 0x0,
590 });
591 ncmds += 1;
592 }
593
594 try load_commands.writeBuildVersionLC(&self.base.options, &ncmds, lc_writer);
595598
596 if (!self.uuid.final) {599 if (self.cold_start) {
597 std.crypto.random.bytes(&self.uuid.buf);600 std.crypto.random.bytes(&self.uuid_cmd.uuid);
598 self.uuid.final = true;
599 }601 }
600 try load_commands.writeUuidLC(&self.uuid.buf, &ncmds, lc_writer);602 try lc_writer.writeStruct(self.uuid_cmd);
601603
602 try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), &ncmds, lc_writer);604 try load_commands.writeLoadDylibLCs(self.dylibs.items, self.referenced_dylibs.keys(), lc_writer);
603605
604 const target = self.base.options.target;606 const target = self.base.options.target;
605 const requires_codesig = blk: {607 const requires_codesig = blk: {
...@@ -608,7 +610,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No...@@ -608,7 +610,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
608 break :blk true;610 break :blk true;
609 break :blk false;611 break :blk false;
610 };612 };
611 var codesig_offset: ?u32 = null;
612 var codesig: ?CodeSignature = if (requires_codesig) blk: {613 var codesig: ?CodeSignature = if (requires_codesig) blk: {
613 // Preallocate space for the code signature.614 // Preallocate space for the code signature.
614 // We need to do this at this stage so that we have the load commands with proper values615 // 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...@@ -620,20 +621,18 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
620 if (self.base.options.entitlements) |path| {621 if (self.base.options.entitlements) |path| {
621 try codesig.addEntitlements(arena, path);622 try codesig.addEntitlements(arena, path);
622 }623 }
623 codesig_offset = try self.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);624 try self.writeCodeSignaturePadding(&codesig);
625 try lc_writer.writeStruct(self.codesig_cmd);
624 break :blk codesig;626 break :blk codesig;
625 } else null;627 } else null;
626628
627 var headers_buf = std.ArrayList(u8).init(arena);629 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
628 try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
629630
630 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));631 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
631 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);632 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len));
632
633 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
634633
635 if (codesig) |*csig| {634 if (codesig) |*csig| {
636 try self.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last635 try self.writeCodeSignature(comp, csig); // code signing always comes last
637 }636 }
638637
639 if (self.d_sym) |*d_sym| {638 if (self.d_sym) |*d_sym| {
...@@ -3146,18 +3145,17 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {...@@ -3146,18 +3145,17 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
3146 return global_index;3145 return global_index;
3147}3146}
31483147
3149fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {3148fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
3150 for (self.segments.items) |seg, i| {3149 for (self.segments.items) |seg, i| {
3151 const indexes = self.getSectionIndexes(@intCast(u8, i));3150 const indexes = self.getSectionIndexes(@intCast(u8, i));
3152 try writer.writeStruct(seg);3151 try writer.writeStruct(seg);
3153 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {3152 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
3154 try writer.writeStruct(header);3153 try writer.writeStruct(header);
3155 }3154 }
3156 ncmds.* += 1;
3157 }3155 }
3158}3156}
31593157
3160fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {3158fn writeLinkeditSegmentData(self: *MachO) !void {
3161 const seg = self.getLinkeditSegmentPtr();3159 const seg = self.getLinkeditSegmentPtr();
3162 seg.filesize = 0;3160 seg.filesize = 0;
3163 seg.vmsize = 0;3161 seg.vmsize = 0;
...@@ -3172,8 +3170,8 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void...@@ -3172,8 +3170,8 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void
3172 }3170 }
3173 }3171 }
31743172
3175 try self.writeDyldInfoData(ncmds, lc_writer);3173 try self.writeDyldInfoData();
3176 try self.writeSymtabs(ncmds, lc_writer);3174 try self.writeSymtabs();
31773175
3178 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);3176 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
3179}3177}
...@@ -3325,7 +3323,7 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {...@@ -3325,7 +3323,7 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
3325 try trie.finalize(gpa);3323 try trie.finalize(gpa);
3326}3324}
33273325
3328fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {3326fn writeDyldInfoData(self: *MachO) !void {
3329 const tracy = trace(@src());3327 const tracy = trace(@src());
3330 defer tracy.end();3328 defer tracy.end();
33313329
...@@ -3396,21 +3394,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {...@@ -3396,21 +3394,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3396 const end = start + (math.cast(usize, lazy_bind_size) orelse return error.Overflow);3394 const end = start + (math.cast(usize, lazy_bind_size) orelse return error.Overflow);
3397 try self.populateLazyBindOffsetsInStubHelper(buffer[start..end]);3395 try self.populateLazyBindOffsetsInStubHelper(buffer[start..end]);
33983396
3399 try lc_writer.writeStruct(macho.dyld_info_command{3397 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
3400 .cmd = .DYLD_INFO_ONLY,3398 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
3401 .cmdsize = @sizeOf(macho.dyld_info_command),3399 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
3402 .rebase_off = @intCast(u32, rebase_off),3400 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
3403 .rebase_size = @intCast(u32, rebase_size),3401 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
3404 .bind_off = @intCast(u32, bind_off),3402 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
3405 .bind_size = @intCast(u32, bind_size),3403 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
3406 .weak_bind_off = 0,3404 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
3407 .weak_bind_size = 0,
3408 .lazy_bind_off = @intCast(u32, lazy_bind_off),
3409 .lazy_bind_size = @intCast(u32, lazy_bind_size),
3410 .export_off = @intCast(u32, export_off),
3411 .export_size = @intCast(u32, export_size),
3412 });
3413 ncmds.* += 1;
3414}3405}
34153406
3416fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {3407fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
...@@ -3512,45 +3503,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -3512,45 +3503,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
3512 }3503 }
3513}3504}
35143505
3515fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {3506fn writeSymtabs(self: *MachO) !void {
3516 var symtab_cmd = macho.symtab_command{3507 var ctx = try self.writeSymtab();
3517 .cmdsize = @sizeOf(macho.symtab_command),
3518 .symoff = 0,
3519 .nsyms = 0,
3520 .stroff = 0,
3521 .strsize = 0,
3522 };
3523 var dysymtab_cmd = macho.dysymtab_command{
3524 .cmdsize = @sizeOf(macho.dysymtab_command),
3525 .ilocalsym = 0,
3526 .nlocalsym = 0,
3527 .iextdefsym = 0,
3528 .nextdefsym = 0,
3529 .iundefsym = 0,
3530 .nundefsym = 0,
3531 .tocoff = 0,
3532 .ntoc = 0,
3533 .modtaboff = 0,
3534 .nmodtab = 0,
3535 .extrefsymoff = 0,
3536 .nextrefsyms = 0,
3537 .indirectsymoff = 0,
3538 .nindirectsyms = 0,
3539 .extreloff = 0,
3540 .nextrel = 0,
3541 .locreloff = 0,
3542 .nlocrel = 0,
3543 };
3544 var ctx = try self.writeSymtab(&symtab_cmd);
3545 defer ctx.imports_table.deinit();3508 defer ctx.imports_table.deinit();
3546 try self.writeDysymtab(ctx, &dysymtab_cmd);3509 try self.writeDysymtab(ctx);
3547 try self.writeStrtab(&symtab_cmd);3510 try self.writeStrtab();
3548 try lc_writer.writeStruct(symtab_cmd);
3549 try lc_writer.writeStruct(dysymtab_cmd);
3550 ncmds.* += 2;
3551}3511}
35523512
3553fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {3513fn writeSymtab(self: *MachO) !SymtabCtx {
3554 const gpa = self.base.allocator;3514 const gpa = self.base.allocator;
35553515
3556 var locals = std.ArrayList(macho.nlist_64).init(gpa);3516 var locals = std.ArrayList(macho.nlist_64).init(gpa);
...@@ -3615,8 +3575,8 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -3615,8 +3575,8 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
3615 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });3575 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
3616 try self.base.file.?.pwriteAll(buffer.items, offset);3576 try self.base.file.?.pwriteAll(buffer.items, offset);
36173577
3618 lc.symoff = @intCast(u32, offset);3578 self.symtab_cmd.symoff = @intCast(u32, offset);
3619 lc.nsyms = nsyms;3579 self.symtab_cmd.nsyms = nsyms;
36203580
3621 return SymtabCtx{3581 return SymtabCtx{
3622 .nlocalsym = nlocals,3582 .nlocalsym = nlocals,
...@@ -3626,7 +3586,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {...@@ -3626,7 +3586,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
3626 };3586 };
3627}3587}
36283588
3629fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {3589fn writeStrtab(self: *MachO) !void {
3630 const seg = self.getLinkeditSegmentPtr();3590 const seg = self.getLinkeditSegmentPtr();
3631 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));3591 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
3632 const needed_size = self.strtab.buffer.items.len;3592 const needed_size = self.strtab.buffer.items.len;
...@@ -3636,8 +3596,8 @@ fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {...@@ -3636,8 +3596,8 @@ fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
36363596
3637 try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);3597 try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);
36383598
3639 lc.stroff = @intCast(u32, offset);3599 self.symtab_cmd.stroff = @intCast(u32, offset);
3640 lc.strsize = @intCast(u32, needed_size);3600 self.symtab_cmd.strsize = @intCast(u32, needed_size);
3641}3601}
36423602
3643const SymtabCtx = struct {3603const SymtabCtx = struct {
...@@ -3647,7 +3607,7 @@ const SymtabCtx = struct {...@@ -3647,7 +3607,7 @@ const SymtabCtx = struct {
3647 imports_table: std.AutoHashMap(SymbolWithLoc, u32),3607 imports_table: std.AutoHashMap(SymbolWithLoc, u32),
3648};3608};
36493609
3650fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {3610fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
3651 const gpa = self.base.allocator;3611 const gpa = self.base.allocator;
3652 const nstubs = @intCast(u32, self.stubs_table.count());3612 const nstubs = @intCast(u32, self.stubs_table.count());
3653 const ngot_entries = @intCast(u32, self.got_entries_table.count());3613 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...@@ -3706,21 +3666,16 @@ fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !voi
3706 assert(buf.items.len == needed_size);3666 assert(buf.items.len == needed_size);
3707 try self.base.file.?.pwriteAll(buf.items, offset);3667 try self.base.file.?.pwriteAll(buf.items, offset);
37083668
3709 lc.nlocalsym = ctx.nlocalsym;3669 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
3710 lc.iextdefsym = iextdefsym;3670 self.dysymtab_cmd.iextdefsym = iextdefsym;
3711 lc.nextdefsym = ctx.nextdefsym;3671 self.dysymtab_cmd.nextdefsym = ctx.nextdefsym;
3712 lc.iundefsym = iundefsym;3672 self.dysymtab_cmd.iundefsym = iundefsym;
3713 lc.nundefsym = ctx.nundefsym;3673 self.dysymtab_cmd.nundefsym = ctx.nundefsym;
3714 lc.indirectsymoff = @intCast(u32, offset);3674 self.dysymtab_cmd.indirectsymoff = @intCast(u32, offset);
3715 lc.nindirectsyms = nindirectsyms;3675 self.dysymtab_cmd.nindirectsyms = nindirectsyms;
3716}3676}
37173677
3718fn writeCodeSignaturePadding(3678fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
3719 self: *MachO,
3720 code_sig: *CodeSignature,
3721 ncmds: *u32,
3722 lc_writer: anytype,
3723) !u32 {
3724 const seg = self.getLinkeditSegmentPtr();3679 const seg = self.getLinkeditSegmentPtr();
3725 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file3680 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
3726 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L2713681 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
...@@ -3733,19 +3688,13 @@ fn writeCodeSignaturePadding(...@@ -3733,19 +3688,13 @@ fn writeCodeSignaturePadding(
3733 // except for code signature data.3688 // except for code signature data.
3734 try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);3689 try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
37353690
3736 try lc_writer.writeStruct(macho.linkedit_data_command{3691 self.codesig_cmd.dataoff = @intCast(u32, offset);
3737 .cmd = .CODE_SIGNATURE,3692 self.codesig_cmd.datasize = @intCast(u32, needed_size);
3738 .cmdsize = @sizeOf(macho.linkedit_data_command),
3739 .dataoff = @intCast(u32, offset),
3740 .datasize = @intCast(u32, needed_size),
3741 });
3742 ncmds.* += 1;
3743
3744 return @intCast(u32, offset);
3745}3693}
37463694
3747fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature, offset: u32) !void {3695fn writeCodeSignature(self: *MachO, comp: *const Compilation, code_sig: *CodeSignature) !void {
3748 const seg = self.getSegment(self.text_section_index.?);3696 const seg = self.getSegment(self.text_section_index.?);
3697 const offset = self.codesig_cmd.dataoff;
37493698
3750 var buffer = std.ArrayList(u8).init(self.base.allocator);3699 var buffer = std.ArrayList(u8).init(self.base.allocator);
3751 defer buffer.deinit();3700 defer buffer.deinit();
src/link/MachO/DebugSymbols.zig+28-50
...@@ -26,6 +26,8 @@ dwarf: Dwarf,...@@ -26,6 +26,8 @@ dwarf: Dwarf,
26file: fs.File,26file: fs.File,
27page_size: u16,27page_size: u16,
2828
29symtab_cmd: macho.symtab_command = .{},
30
29segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},31segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
30sections: std.ArrayListUnmanaged(macho.section_64) = .{},32sections: std.ArrayListUnmanaged(macho.section_64) = .{},
3133
...@@ -296,28 +298,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {...@@ -296,28 +298,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
296 }298 }
297 }299 }
298300
301 self.finalizeDwarfSegment(macho_file);
302 try self.writeLinkeditSegmentData(macho_file);
303
304 // Write load commands
299 var lc_buffer = std.ArrayList(u8).init(self.allocator);305 var lc_buffer = std.ArrayList(u8).init(self.allocator);
300 defer lc_buffer.deinit();306 defer lc_buffer.deinit();
301 const lc_writer = lc_buffer.writer();307 const lc_writer = lc_buffer.writer();
302 var ncmds: u32 = 0;
303
304 self.finalizeDwarfSegment(macho_file);
305 try self.writeLinkeditSegmentData(macho_file, &ncmds, lc_writer);
306308
307 try load_commands.writeUuidLC(&macho_file.uuid.buf, &ncmds, lc_writer);309 try self.writeSegmentHeaders(macho_file, lc_writer);
310 try lc_writer.writeStruct(self.symtab_cmd);
311 try lc_writer.writeStruct(macho_file.uuid_cmd);
308312
309 var headers_buf = std.ArrayList(u8).init(self.allocator);313 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
310 defer headers_buf.deinit();314 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
311 try self.writeSegmentHeaders(macho_file, &ncmds, headers_buf.writer());315 try self.writeHeader(macho_file, ncmds, @intCast(u32, lc_buffer.items.len));
312
313 try self.file.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
314 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
315
316 try self.writeHeader(
317 macho_file,
318 ncmds,
319 @intCast(u32, lc_buffer.items.len + headers_buf.items.len),
320 );
321316
322 assert(!self.debug_abbrev_section_dirty);317 assert(!self.debug_abbrev_section_dirty);
323 assert(!self.debug_aranges_section_dirty);318 assert(!self.debug_aranges_section_dirty);
...@@ -384,7 +379,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {...@@ -384,7 +379,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
384 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});379 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});
385}380}
386381
387fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, writer: anytype) !void {382fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, writer: anytype) !void {
388 // Write segment/section headers from the binary file first.383 // Write segment/section headers from the binary file first.
389 const end = macho_file.linkedit_segment_cmd_index.?;384 const end = macho_file.linkedit_segment_cmd_index.?;
390 for (macho_file.segments.items[0..end]) |seg, i| {385 for (macho_file.segments.items[0..end]) |seg, i| {
...@@ -414,8 +409,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri...@@ -414,8 +409,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri
414 out_header.offset = 0;409 out_header.offset = 0;
415 try writer.writeStruct(out_header);410 try writer.writeStruct(out_header);
416 }411 }
417
418 ncmds.* += 1;
419 }412 }
420 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.413 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
421 for (self.segments.items) |seg, i| {414 for (self.segments.items) |seg, i| {
...@@ -424,7 +417,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri...@@ -424,7 +417,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri
424 for (self.sections.items[indexes.start..indexes.end]) |header| {417 for (self.sections.items[indexes.start..indexes.end]) |header| {
425 try writer.writeStruct(header);418 try writer.writeStruct(header);
426 }419 }
427 ncmds.* += 1;
428 }420 }
429}421}
430422
...@@ -463,33 +455,19 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 {...@@ -463,33 +455,19 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
463 return min_pos - start;455 return min_pos - start;
464}456}
465457
466fn writeLinkeditSegmentData(458fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {
467 self: *DebugSymbols,
468 macho_file: *MachO,
469 ncmds: *u32,
470 lc_writer: anytype,
471) !void {
472 const tracy = trace(@src());459 const tracy = trace(@src());
473 defer tracy.end();460 defer tracy.end();
474461
475 var symtab_cmd = macho.symtab_command{462 try self.writeSymtab(macho_file);
476 .cmdsize = @sizeOf(macho.symtab_command),463 try self.writeStrtab();
477 .symoff = 0,
478 .nsyms = 0,
479 .stroff = 0,
480 .strsize = 0,
481 };
482 try self.writeSymtab(macho_file, &symtab_cmd);
483 try self.writeStrtab(&symtab_cmd);
484 try lc_writer.writeStruct(symtab_cmd);
485 ncmds.* += 1;
486464
487 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];465 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
488 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);466 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
489 seg.vmsize = aligned_size;467 seg.vmsize = aligned_size;
490}468}
491469
492fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_command) !void {470fn writeSymtab(self: *DebugSymbols, macho_file: *MachO) !void {
493 const tracy = trace(@src());471 const tracy = trace(@src());
494 defer tracy.end();472 defer tracy.end();
495473
...@@ -528,10 +506,10 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman...@@ -528,10 +506,10 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman
528 const needed_size = nsyms * @sizeOf(macho.nlist_64);506 const needed_size = nsyms * @sizeOf(macho.nlist_64);
529 seg.filesize = offset + needed_size - seg.fileoff;507 seg.filesize = offset + needed_size - seg.fileoff;
530508
531 lc.symoff = @intCast(u32, offset);509 self.symtab_cmd.symoff = @intCast(u32, offset);
532 lc.nsyms = @intCast(u32, nsyms);510 self.symtab_cmd.nsyms = @intCast(u32, nsyms);
533511
534 const locals_off = lc.symoff;512 const locals_off = @intCast(u32, offset);
535 const locals_size = nlocals * @sizeOf(macho.nlist_64);513 const locals_size = nlocals * @sizeOf(macho.nlist_64);
536 const exports_off = locals_off + locals_size;514 const exports_off = locals_off + locals_size;
537 const exports_size = nexports * @sizeOf(macho.nlist_64);515 const exports_size = nexports * @sizeOf(macho.nlist_64);
...@@ -543,26 +521,26 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman...@@ -543,26 +521,26 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman
543 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);521 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);
544}522}
545523
546fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {524fn writeStrtab(self: *DebugSymbols) !void {
547 const tracy = trace(@src());525 const tracy = trace(@src());
548 defer tracy.end();526 defer tracy.end();
549527
550 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];528 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
551 const symtab_size = @intCast(u32, lc.nsyms * @sizeOf(macho.nlist_64));529 const symtab_size = @intCast(u32, self.symtab_cmd.nsyms * @sizeOf(macho.nlist_64));
552 const offset = mem.alignForwardGeneric(u64, lc.symoff + symtab_size, @alignOf(u64));530 const offset = mem.alignForwardGeneric(u64, self.symtab_cmd.symoff + symtab_size, @alignOf(u64));
553 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));531 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));
554532
555 seg.filesize = offset + needed_size - seg.fileoff;533 seg.filesize = offset + needed_size - seg.fileoff;
556 lc.stroff = @intCast(u32, offset);534 self.symtab_cmd.stroff = @intCast(u32, offset);
557 lc.strsize = @intCast(u32, needed_size);535 self.symtab_cmd.strsize = @intCast(u32, needed_size);
558536
559 log.debug("writing string table from 0x{x} to 0x{x}", .{ lc.stroff, lc.stroff + lc.strsize });537 log.debug("writing string table from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
560538
561 try self.file.pwriteAll(self.strtab.buffer.items, lc.stroff);539 try self.file.pwriteAll(self.strtab.buffer.items, offset);
562540
563 if (self.strtab.buffer.items.len < needed_size) {541 if (self.strtab.buffer.items.len < needed_size) {
564 // Ensure we are always padded to the actual length of the file.542 // Ensure we are always padded to the actual length of the file.
565 try self.file.pwriteAll(&[_]u8{0}, lc.stroff + lc.strsize);543 try self.file.pwriteAll(&[_]u8{0}, offset + needed_size);
566 }544 }
567}545}
568546
src/link/MachO/load_commands.zig+20-40
...@@ -131,7 +131,19 @@ pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcL...@@ -131,7 +131,19 @@ pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcL
131 return offset;131 return offset;
132}132}
133133
134pub fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void {134pub fn calcNumOfLCs(lc_buffer: []const u8) u32 {
135 var ncmds: u32 = 0;
136 var pos: usize = 0;
137 while (true) {
138 if (pos >= lc_buffer.len) break;
139 const cmd = @ptrCast(*align(1) const macho.load_command, lc_buffer.ptr + pos).*;
140 ncmds += 1;
141 pos += cmd.cmdsize;
142 }
143 return ncmds;
144}
145
146pub fn writeDylinkerLC(lc_writer: anytype) !void {
135 const name_len = mem.sliceTo(default_dyld_path, 0).len;147 const name_len = mem.sliceTo(default_dyld_path, 0).len;
136 const cmdsize = @intCast(u32, mem.alignForwardGeneric(148 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
137 u64,149 u64,
...@@ -148,7 +160,6 @@ pub fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void {...@@ -148,7 +160,6 @@ pub fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void {
148 if (padding > 0) {160 if (padding > 0) {
149 try lc_writer.writeByteNTimes(0, padding);161 try lc_writer.writeByteNTimes(0, padding);
150 }162 }
151 ncmds.* += 1;
152}163}
153164
154const WriteDylibLCCtx = struct {165const WriteDylibLCCtx = struct {
...@@ -159,7 +170,7 @@ const WriteDylibLCCtx = struct {...@@ -159,7 +170,7 @@ const WriteDylibLCCtx = struct {
159 compatibility_version: u32 = 0x10000,170 compatibility_version: u32 = 0x10000,
160};171};
161172
162fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {173fn writeDylibLC(ctx: WriteDylibLCCtx, lc_writer: anytype) !void {
163 const name_len = ctx.name.len + 1;174 const name_len = ctx.name.len + 1;
164 const cmdsize = @intCast(u32, mem.alignForwardGeneric(175 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
165 u64,176 u64,
...@@ -182,10 +193,9 @@ fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {...@@ -182,10 +193,9 @@ fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {
182 if (padding > 0) {193 if (padding > 0) {
183 try lc_writer.writeByteNTimes(0, padding);194 try lc_writer.writeByteNTimes(0, padding);
184 }195 }
185 ncmds.* += 1;
186}196}
187197
188pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, ncmds: *u32, lc_writer: anytype) !void {198pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void {
189 assert(options.output_mode == .Lib and options.link_mode == .Dynamic);199 assert(options.output_mode == .Lib and options.link_mode == .Dynamic);
190 const emit = options.emit.?;200 const emit = options.emit.?;
191 const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path});201 const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path});
...@@ -205,18 +215,7 @@ pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, ncmds: *u32,...@@ -205,18 +215,7 @@ pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, ncmds: *u32,
205 .name = install_name,215 .name = install_name,
206 .current_version = curr.major << 16 | curr.minor << 8 | curr.patch,216 .current_version = curr.major << 16 | curr.minor << 8 | curr.patch,
207 .compatibility_version = compat.major << 16 | compat.minor << 8 | compat.patch,217 .compatibility_version = compat.major << 16 | compat.minor << 8 | compat.patch,
208 }, ncmds, lc_writer);218 }, lc_writer);
209}
210
211pub fn writeMainLC(entryoff: u32, options: *const link.Options, ncmds: *u32, lc_writer: anytype) !void {
212 assert(options.output_mode == .Exe);
213 try lc_writer.writeStruct(macho.entry_point_command{
214 .cmd = .MAIN,
215 .cmdsize = @sizeOf(macho.entry_point_command),
216 .entryoff = entryoff,
217 .stacksize = options.stack_size_override orelse 0,
218 });
219 ncmds.* += 1;
220}219}
221220
222const RpathIterator = struct {221const RpathIterator = struct {
...@@ -244,7 +243,7 @@ const RpathIterator = struct {...@@ -244,7 +243,7 @@ const RpathIterator = struct {
244 }243 }
245};244};
246245
247pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, ncmds: *u32, lc_writer: anytype) !void {246pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void {
248 var it = RpathIterator.init(gpa, options.rpath_list);247 var it = RpathIterator.init(gpa, options.rpath_list);
249 defer it.deinit();248 defer it.deinit();
250249
...@@ -265,11 +264,10 @@ pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, ncmds: *u32,...@@ -265,11 +264,10 @@ pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, ncmds: *u32,
265 if (padding > 0) {264 if (padding > 0) {
266 try lc_writer.writeByteNTimes(0, padding);265 try lc_writer.writeByteNTimes(0, padding);
267 }266 }
268 ncmds.* += 1;
269 }267 }
270}268}
271269
272pub fn writeBuildVersionLC(options: *const link.Options, ncmds: *u32, lc_writer: anytype) !void {270pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !void {
273 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);271 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
274 const platform_version = blk: {272 const platform_version = blk: {
275 const ver = options.target.os.version_range.semver.min;273 const ver = options.target.os.version_range.semver.min;
...@@ -299,10 +297,9 @@ pub fn writeBuildVersionLC(options: *const link.Options, ncmds: *u32, lc_writer:...@@ -299,10 +297,9 @@ pub fn writeBuildVersionLC(options: *const link.Options, ncmds: *u32, lc_writer:
299 .tool = .LD,297 .tool = .LD,
300 .version = 0x0,298 .version = 0x0,
301 }));299 }));
302 ncmds.* += 1;
303}300}
304301
305pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, ncmds: *u32, lc_writer: anytype) !void {302pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, lc_writer: anytype) !void {
306 for (referenced) |index| {303 for (referenced) |index| {
307 const dylib = dylibs[index];304 const dylib = dylibs[index];
308 const dylib_id = dylib.id orelse unreachable;305 const dylib_id = dylib.id orelse unreachable;
...@@ -312,23 +309,6 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, ncmds: *u32,...@@ -312,23 +309,6 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, ncmds: *u32,
312 .timestamp = dylib_id.timestamp,309 .timestamp = dylib_id.timestamp,
313 .current_version = dylib_id.current_version,310 .current_version = dylib_id.current_version,
314 .compatibility_version = dylib_id.compatibility_version,311 .compatibility_version = dylib_id.compatibility_version,
315 }, ncmds, lc_writer);312 }, lc_writer);
316 }313 }
317}314}
318
319pub fn writeSourceVersionLC(ncmds: *u32, lc_writer: anytype) !void {
320 try lc_writer.writeStruct(macho.source_version_command{
321 .cmdsize = @sizeOf(macho.source_version_command),
322 .version = 0x0,
323 });
324 ncmds.* += 1;
325}
326
327pub fn writeUuidLC(uuid: *const [16]u8, ncmds: *u32, lc_writer: anytype) !void {
328 var uuid_lc = macho.uuid_command{
329 .cmdsize = @sizeOf(macho.uuid_command),
330 .uuid = uuid.*,
331 };
332 try lc_writer.writeStruct(uuid_lc);
333 ncmds.* += 1;
334}
src/link/MachO/zld.zig+105-160
...@@ -38,6 +38,14 @@ pub const Zld = struct {...@@ -38,6 +38,14 @@ pub const Zld = struct {
38 page_size: u16,38 page_size: u16,
39 options: *const link.Options,39 options: *const link.Options,
4040
41 dyld_info_cmd: macho.dyld_info_command = .{},
42 symtab_cmd: macho.symtab_command = .{},
43 dysymtab_cmd: macho.dysymtab_command = .{},
44 function_starts_cmd: macho.linkedit_data_command = .{ .cmd = .FUNCTION_STARTS },
45 data_in_code_cmd: macho.linkedit_data_command = .{ .cmd = .DATA_IN_CODE },
46 uuid_cmd: macho.uuid_command = .{},
47 codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
48
41 objects: std.ArrayListUnmanaged(Object) = .{},49 objects: std.ArrayListUnmanaged(Object) = .{},
42 archives: std.ArrayListUnmanaged(Archive) = .{},50 archives: std.ArrayListUnmanaged(Archive) = .{},
43 dylibs: std.ArrayListUnmanaged(Dylib) = .{},51 dylibs: std.ArrayListUnmanaged(Dylib) = .{},
...@@ -1728,7 +1736,7 @@ pub const Zld = struct {...@@ -1728,7 +1736,7 @@ pub const Zld = struct {
1728 return (@intCast(u8, segment_precedence) << 4) + section_precedence;1736 return (@intCast(u8, segment_precedence) << 4) + section_precedence;
1729 }1737 }
17301738
1731 fn writeSegmentHeaders(self: *Zld, ncmds: *u32, writer: anytype) !void {1739 fn writeSegmentHeaders(self: *Zld, writer: anytype) !void {
1732 for (self.segments.items) |seg, i| {1740 for (self.segments.items) |seg, i| {
1733 const indexes = self.getSectionIndexes(@intCast(u8, i));1741 const indexes = self.getSectionIndexes(@intCast(u8, i));
1734 var out_seg = seg;1742 var out_seg = seg;
...@@ -1752,16 +1760,14 @@ pub const Zld = struct {...@@ -1752,16 +1760,14 @@ pub const Zld = struct {
1752 if (header.size == 0) continue;1760 if (header.size == 0) continue;
1753 try writer.writeStruct(header);1761 try writer.writeStruct(header);
1754 }1762 }
1755
1756 ncmds.* += 1;
1757 }1763 }
1758 }1764 }
17591765
1760 fn writeLinkeditSegmentData(self: *Zld, ncmds: *u32, lc_writer: anytype, reverse_lookups: [][]u32) !void {1766 fn writeLinkeditSegmentData(self: *Zld, reverse_lookups: [][]u32) !void {
1761 try self.writeDyldInfoData(ncmds, lc_writer, reverse_lookups);1767 try self.writeDyldInfoData(reverse_lookups);
1762 try self.writeFunctionStarts(ncmds, lc_writer);1768 try self.writeFunctionStarts();
1763 try self.writeDataInCode(ncmds, lc_writer);1769 try self.writeDataInCode();
1764 try self.writeSymtabs(ncmds, lc_writer);1770 try self.writeSymtabs();
17651771
1766 const seg = self.getLinkeditSegmentPtr();1772 const seg = self.getLinkeditSegmentPtr();
1767 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);1773 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
...@@ -2150,7 +2156,7 @@ pub const Zld = struct {...@@ -2150,7 +2156,7 @@ pub const Zld = struct {
2150 try trie.finalize(gpa);2156 try trie.finalize(gpa);
2151 }2157 }
21522158
2153 fn writeDyldInfoData(self: *Zld, ncmds: *u32, lc_writer: anytype, reverse_lookups: [][]u32) !void {2159 fn writeDyldInfoData(self: *Zld, reverse_lookups: [][]u32) !void {
2154 const gpa = self.gpa;2160 const gpa = self.gpa;
21552161
2156 var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa);2162 var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa);
...@@ -2219,21 +2225,14 @@ pub const Zld = struct {...@@ -2219,21 +2225,14 @@ pub const Zld = struct {
2219 const size = math.cast(usize, lazy_bind_size) orelse return error.Overflow;2225 const size = math.cast(usize, lazy_bind_size) orelse return error.Overflow;
2220 try self.populateLazyBindOffsetsInStubHelper(buffer[offset..][0..size]);2226 try self.populateLazyBindOffsetsInStubHelper(buffer[offset..][0..size]);
22212227
2222 try lc_writer.writeStruct(macho.dyld_info_command{2228 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
2223 .cmd = .DYLD_INFO_ONLY,2229 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
2224 .cmdsize = @sizeOf(macho.dyld_info_command),2230 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
2225 .rebase_off = @intCast(u32, rebase_off),2231 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
2226 .rebase_size = @intCast(u32, rebase_size),2232 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
2227 .bind_off = @intCast(u32, bind_off),2233 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
2228 .bind_size = @intCast(u32, bind_size),2234 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
2229 .weak_bind_off = 0,2235 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
2230 .weak_bind_size = 0,
2231 .lazy_bind_off = @intCast(u32, lazy_bind_off),
2232 .lazy_bind_size = @intCast(u32, lazy_bind_size),
2233 .export_off = @intCast(u32, export_off),
2234 .export_size = @intCast(u32, export_size),
2235 });
2236 ncmds.* += 1;
2237 }2236 }
22382237
2239 fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {2238 fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
...@@ -2351,7 +2350,7 @@ pub const Zld = struct {...@@ -2351,7 +2350,7 @@ pub const Zld = struct {
23512350
2352 const asc_u64 = std.sort.asc(u64);2351 const asc_u64 = std.sort.asc(u64);
23532352
2354 fn writeFunctionStarts(self: *Zld, ncmds: *u32, lc_writer: anytype) !void {2353 fn writeFunctionStarts(self: *Zld) !void {
2355 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;2354 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;
2356 const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;2355 const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;
2357 const text_seg = self.segments.items[text_seg_index];2356 const text_seg = self.segments.items[text_seg_index];
...@@ -2410,13 +2409,8 @@ pub const Zld = struct {...@@ -2410,13 +2409,8 @@ pub const Zld = struct {
24102409
2411 try self.file.pwriteAll(buffer.items, offset);2410 try self.file.pwriteAll(buffer.items, offset);
24122411
2413 try lc_writer.writeStruct(macho.linkedit_data_command{2412 self.function_starts_cmd.dataoff = @intCast(u32, offset);
2414 .cmd = .FUNCTION_STARTS,2413 self.function_starts_cmd.datasize = @intCast(u32, needed_size);
2415 .cmdsize = @sizeOf(macho.linkedit_data_command),
2416 .dataoff = @intCast(u32, offset),
2417 .datasize = @intCast(u32, needed_size),
2418 });
2419 ncmds.* += 1;
2420 }2414 }
24212415
2422 fn filterDataInCode(2416 fn filterDataInCode(
...@@ -2438,7 +2432,7 @@ pub const Zld = struct {...@@ -2438,7 +2432,7 @@ pub const Zld = struct {
2438 return dices[start..end];2432 return dices[start..end];
2439 }2433 }
24402434
2441 fn writeDataInCode(self: *Zld, ncmds: *u32, lc_writer: anytype) !void {2435 fn writeDataInCode(self: *Zld) !void {
2442 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa);2436 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa);
2443 defer out_dice.deinit();2437 defer out_dice.deinit();
24442438
...@@ -2488,54 +2482,19 @@ pub const Zld = struct {...@@ -2488,54 +2482,19 @@ pub const Zld = struct {
2488 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size });2482 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
24892483
2490 try self.file.pwriteAll(mem.sliceAsBytes(out_dice.items), offset);2484 try self.file.pwriteAll(mem.sliceAsBytes(out_dice.items), offset);
2491 try lc_writer.writeStruct(macho.linkedit_data_command{2485
2492 .cmd = .DATA_IN_CODE,2486 self.data_in_code_cmd.dataoff = @intCast(u32, offset);
2493 .cmdsize = @sizeOf(macho.linkedit_data_command),2487 self.data_in_code_cmd.datasize = @intCast(u32, needed_size);
2494 .dataoff = @intCast(u32, offset),
2495 .datasize = @intCast(u32, needed_size),
2496 });
2497 ncmds.* += 1;
2498 }2488 }
24992489
2500 fn writeSymtabs(self: *Zld, ncmds: *u32, lc_writer: anytype) !void {2490 fn writeSymtabs(self: *Zld) !void {
2501 var symtab_cmd = macho.symtab_command{2491 var ctx = try self.writeSymtab();
2502 .cmdsize = @sizeOf(macho.symtab_command),
2503 .symoff = 0,
2504 .nsyms = 0,
2505 .stroff = 0,
2506 .strsize = 0,
2507 };
2508 var dysymtab_cmd = macho.dysymtab_command{
2509 .cmdsize = @sizeOf(macho.dysymtab_command),
2510 .ilocalsym = 0,
2511 .nlocalsym = 0,
2512 .iextdefsym = 0,
2513 .nextdefsym = 0,
2514 .iundefsym = 0,
2515 .nundefsym = 0,
2516 .tocoff = 0,
2517 .ntoc = 0,
2518 .modtaboff = 0,
2519 .nmodtab = 0,
2520 .extrefsymoff = 0,
2521 .nextrefsyms = 0,
2522 .indirectsymoff = 0,
2523 .nindirectsyms = 0,
2524 .extreloff = 0,
2525 .nextrel = 0,
2526 .locreloff = 0,
2527 .nlocrel = 0,
2528 };
2529 var ctx = try self.writeSymtab(&symtab_cmd);
2530 defer ctx.imports_table.deinit();2492 defer ctx.imports_table.deinit();
2531 try self.writeDysymtab(ctx, &dysymtab_cmd);2493 try self.writeDysymtab(ctx);
2532 try self.writeStrtab(&symtab_cmd);2494 try self.writeStrtab();
2533 try lc_writer.writeStruct(symtab_cmd);
2534 try lc_writer.writeStruct(dysymtab_cmd);
2535 ncmds.* += 2;
2536 }2495 }
25372496
2538 fn writeSymtab(self: *Zld, lc: *macho.symtab_command) !SymtabCtx {2497 fn writeSymtab(self: *Zld) !SymtabCtx {
2539 const gpa = self.gpa;2498 const gpa = self.gpa;
25402499
2541 var locals = std.ArrayList(macho.nlist_64).init(gpa);2500 var locals = std.ArrayList(macho.nlist_64).init(gpa);
...@@ -2618,8 +2577,8 @@ pub const Zld = struct {...@@ -2618,8 +2577,8 @@ pub const Zld = struct {
2618 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });2577 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
2619 try self.file.pwriteAll(buffer.items, offset);2578 try self.file.pwriteAll(buffer.items, offset);
26202579
2621 lc.symoff = @intCast(u32, offset);2580 self.symtab_cmd.symoff = @intCast(u32, offset);
2622 lc.nsyms = nsyms;2581 self.symtab_cmd.nsyms = nsyms;
26232582
2624 return SymtabCtx{2583 return SymtabCtx{
2625 .nlocalsym = nlocals,2584 .nlocalsym = nlocals,
...@@ -2629,7 +2588,7 @@ pub const Zld = struct {...@@ -2629,7 +2588,7 @@ pub const Zld = struct {
2629 };2588 };
2630 }2589 }
26312590
2632 fn writeStrtab(self: *Zld, lc: *macho.symtab_command) !void {2591 fn writeStrtab(self: *Zld) !void {
2633 const seg = self.getLinkeditSegmentPtr();2592 const seg = self.getLinkeditSegmentPtr();
2634 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));2593 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
2635 const needed_size = self.strtab.buffer.items.len;2594 const needed_size = self.strtab.buffer.items.len;
...@@ -2639,8 +2598,8 @@ pub const Zld = struct {...@@ -2639,8 +2598,8 @@ pub const Zld = struct {
26392598
2640 try self.file.pwriteAll(self.strtab.buffer.items, offset);2599 try self.file.pwriteAll(self.strtab.buffer.items, offset);
26412600
2642 lc.stroff = @intCast(u32, offset);2601 self.symtab_cmd.stroff = @intCast(u32, offset);
2643 lc.strsize = @intCast(u32, needed_size);2602 self.symtab_cmd.strsize = @intCast(u32, needed_size);
2644 }2603 }
26452604
2646 const SymtabCtx = struct {2605 const SymtabCtx = struct {
...@@ -2650,7 +2609,7 @@ pub const Zld = struct {...@@ -2650,7 +2609,7 @@ pub const Zld = struct {
2650 imports_table: std.AutoHashMap(SymbolWithLoc, u32),2609 imports_table: std.AutoHashMap(SymbolWithLoc, u32),
2651 };2610 };
26522611
2653 fn writeDysymtab(self: *Zld, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {2612 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {
2654 const gpa = self.gpa;2613 const gpa = self.gpa;
2655 const nstubs = @intCast(u32, self.stubs.items.len);2614 const nstubs = @intCast(u32, self.stubs.items.len);
2656 const ngot_entries = @intCast(u32, self.got_entries.items.len);2615 const ngot_entries = @intCast(u32, self.got_entries.items.len);
...@@ -2706,21 +2665,33 @@ pub const Zld = struct {...@@ -2706,21 +2665,33 @@ pub const Zld = struct {
2706 assert(buf.items.len == needed_size);2665 assert(buf.items.len == needed_size);
2707 try self.file.pwriteAll(buf.items, offset);2666 try self.file.pwriteAll(buf.items, offset);
27082667
2709 lc.nlocalsym = ctx.nlocalsym;2668 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
2710 lc.iextdefsym = iextdefsym;2669 self.dysymtab_cmd.iextdefsym = iextdefsym;
2711 lc.nextdefsym = ctx.nextdefsym;2670 self.dysymtab_cmd.nextdefsym = ctx.nextdefsym;
2712 lc.iundefsym = iundefsym;2671 self.dysymtab_cmd.iundefsym = iundefsym;
2713 lc.nundefsym = ctx.nundefsym;2672 self.dysymtab_cmd.nundefsym = ctx.nundefsym;
2714 lc.indirectsymoff = @intCast(u32, offset);2673 self.dysymtab_cmd.indirectsymoff = @intCast(u32, offset);
2715 lc.nindirectsyms = nindirectsyms;2674 self.dysymtab_cmd.nindirectsyms = nindirectsyms;
2716 }2675 }
27172676
2718 fn writeCodeSignaturePadding(2677 fn writeUuid(self: *Zld, comp: *const Compilation, offset: u32) !void {
2719 self: *Zld,2678 switch (self.options.optimize_mode) {
2720 code_sig: *CodeSignature,2679 .Debug => {
2721 ncmds: *u32,2680 // In Debug we don't really care about reproducibility, so put in a random value
2722 lc_writer: anytype,2681 // and be done with it.
2723 ) !u32 {2682 std.crypto.random.bytes(&self.uuid_cmd.uuid);
2683 },
2684 else => {
2685 const seg = self.getLinkeditSegmentPtr();
2686 const file_size = seg.fileoff + seg.filesize;
2687 try uuid.calcUuidParallel(comp, self.file, file_size, &self.uuid_cmd.uuid);
2688 },
2689 }
2690 const in_file = @sizeOf(macho.mach_header_64) + offset + @sizeOf(macho.load_command);
2691 try self.file.pwriteAll(&self.uuid_cmd.uuid, in_file);
2692 }
2693
2694 fn writeCodeSignaturePadding(self: *Zld, code_sig: *CodeSignature) !void {
2724 const seg = self.getLinkeditSegmentPtr();2695 const seg = self.getLinkeditSegmentPtr();
2725 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file2696 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
2726 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L2712697 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
...@@ -2733,23 +2704,11 @@ pub const Zld = struct {...@@ -2733,23 +2704,11 @@ pub const Zld = struct {
2733 // except for code signature data.2704 // except for code signature data.
2734 try self.file.pwriteAll(&[_]u8{0}, offset + needed_size - 1);2705 try self.file.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
27352706
2736 try lc_writer.writeStruct(macho.linkedit_data_command{2707 self.codesig_cmd.dataoff = @intCast(u32, offset);
2737 .cmd = .CODE_SIGNATURE,2708 self.codesig_cmd.datasize = @intCast(u32, needed_size);
2738 .cmdsize = @sizeOf(macho.linkedit_data_command),
2739 .dataoff = @intCast(u32, offset),
2740 .datasize = @intCast(u32, needed_size),
2741 });
2742 ncmds.* += 1;
2743
2744 return @intCast(u32, offset);
2745 }2709 }
27462710
2747 fn writeCodeSignature(2711 fn writeCodeSignature(self: *Zld, comp: *const Compilation, code_sig: *CodeSignature) !void {
2748 self: *Zld,
2749 comp: *const Compilation,
2750 code_sig: *CodeSignature,
2751 offset: u32,
2752 ) !void {
2753 const seg_id = self.getSegmentByName("__TEXT").?;2712 const seg_id = self.getSegmentByName("__TEXT").?;
2754 const seg = self.segments.items[seg_id];2713 const seg = self.segments.items[seg_id];
27552714
...@@ -2760,17 +2719,17 @@ pub const Zld = struct {...@@ -2760,17 +2719,17 @@ pub const Zld = struct {
2760 .file = self.file,2719 .file = self.file,
2761 .exec_seg_base = seg.fileoff,2720 .exec_seg_base = seg.fileoff,
2762 .exec_seg_limit = seg.filesize,2721 .exec_seg_limit = seg.filesize,
2763 .file_size = offset,2722 .file_size = self.codesig_cmd.dataoff,
2764 .output_mode = self.options.output_mode,2723 .output_mode = self.options.output_mode,
2765 }, buffer.writer());2724 }, buffer.writer());
2766 assert(buffer.items.len == code_sig.size());2725 assert(buffer.items.len == code_sig.size());
27672726
2768 log.debug("writing code signature from 0x{x} to 0x{x}", .{2727 log.debug("writing code signature from 0x{x} to 0x{x}", .{
2769 offset,2728 self.codesig_cmd.dataoff,
2770 offset + buffer.items.len,2729 self.codesig_cmd.dataoff + buffer.items.len,
2771 });2730 });
27722731
2773 try self.file.pwriteAll(buffer.items, offset);2732 try self.file.pwriteAll(buffer.items, self.codesig_cmd.dataoff);
2774 }2733 }
27752734
2776 /// Writes Mach-O file header.2735 /// Writes Mach-O file header.
...@@ -3986,13 +3945,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3986,13 +3945,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3986 }3945 }
39873946
3988 try zld.writeAtoms(reverse_lookups);3947 try zld.writeAtoms(reverse_lookups);
39893948 try zld.writeLinkeditSegmentData(reverse_lookups);
3990 var lc_buffer = std.ArrayList(u8).init(arena);
3991 const lc_writer = lc_buffer.writer();
3992
3993 var ncmds: u32 = 0;
3994
3995 try zld.writeLinkeditSegmentData(&ncmds, lc_writer, reverse_lookups);
39963949
3997 // If the last section of __DATA segment is zerofill section, we need to ensure3950 // If the last section of __DATA segment is zerofill section, we need to ensure
3998 // that the free space between the end of the last non-zerofill section of __DATA3951 // that the free space between the end of the last non-zerofill section of __DATA
...@@ -4017,47 +3970,48 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -4017,47 +3970,48 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
4017 }3970 }
4018 }3971 }
40193972
4020 try load_commands.writeDylinkerLC(&ncmds, lc_writer);3973 // Write load commands
3974 var lc_buffer = std.ArrayList(u8).init(arena);
3975 const lc_writer = lc_buffer.writer();
3976
3977 try zld.writeSegmentHeaders(lc_writer);
3978 try lc_writer.writeStruct(zld.dyld_info_cmd);
3979 try lc_writer.writeStruct(zld.function_starts_cmd);
3980 try lc_writer.writeStruct(zld.data_in_code_cmd);
3981 try lc_writer.writeStruct(zld.symtab_cmd);
3982 try lc_writer.writeStruct(zld.dysymtab_cmd);
3983 try load_commands.writeDylinkerLC(lc_writer);
40213984
4022 if (zld.options.output_mode == .Exe) {3985 if (zld.options.output_mode == .Exe) {
4023 const seg_id = zld.getSegmentByName("__TEXT").?;3986 const seg_id = zld.getSegmentByName("__TEXT").?;
4024 const seg = zld.segments.items[seg_id];3987 const seg = zld.segments.items[seg_id];
4025 const global = zld.getEntryPoint();3988 const global = zld.getEntryPoint();
4026 const sym = zld.getSymbol(global);3989 const sym = zld.getSymbol(global);
4027 try load_commands.writeMainLC(@intCast(u32, sym.n_value - seg.vmaddr), options, &ncmds, lc_writer);3990 try lc_writer.writeStruct(macho.entry_point_command{
3991 .entryoff = @intCast(u32, sym.n_value - seg.vmaddr),
3992 .stacksize = options.stack_size_override orelse 0,
3993 });
4028 } else {3994 } else {
4029 assert(zld.options.output_mode == .Lib);3995 assert(zld.options.output_mode == .Lib);
4030 try load_commands.writeDylibIdLC(zld.gpa, zld.options, &ncmds, lc_writer);3996 try load_commands.writeDylibIdLC(zld.gpa, zld.options, lc_writer);
4031 }3997 }
40323998
4033 try load_commands.writeRpathLCs(zld.gpa, zld.options, &ncmds, lc_writer);3999 try load_commands.writeRpathLCs(zld.gpa, zld.options, lc_writer);
4034 try load_commands.writeSourceVersionLC(&ncmds, lc_writer);4000 try lc_writer.writeStruct(macho.source_version_command{
4035 try load_commands.writeBuildVersionLC(zld.options, &ncmds, lc_writer);4001 .version = 0,
40364002 });
4037 // Looking forward into the future, we will want to offer `-no_uuid` support in which case4003 try load_commands.writeBuildVersionLC(zld.options, lc_writer);
4038 // there will be nothing to backpatch.
4039 const uuid_offset_backpatch: ?usize = blk: {
4040 const index = lc_buffer.items.len;
4041 var uuid_buf: [16]u8 = [_]u8{0} ** 16;
4042
4043 if (zld.options.optimize_mode == .Debug) {
4044 // In Debug we don't really care about reproducibility, so put in a random value
4045 // and be done with it.
4046 std.crypto.random.bytes(&uuid_buf);
4047 }
40484004
4049 try load_commands.writeUuidLC(&uuid_buf, &ncmds, lc_writer);4005 const uuid_offset = @intCast(u32, lc_buffer.items.len);
4050 break :blk if (zld.options.optimize_mode == .Debug) null else index;4006 try lc_writer.writeStruct(zld.uuid_cmd);
4051 };
40524007
4053 try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), &ncmds, lc_writer);4008 try load_commands.writeLoadDylibLCs(zld.dylibs.items, zld.referenced_dylibs.keys(), lc_writer);
40544009
4055 const requires_codesig = blk: {4010 const requires_codesig = blk: {
4056 if (options.entitlements) |_| break :blk true;4011 if (options.entitlements) |_| break :blk true;
4057 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;4012 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
4058 break :blk false;4013 break :blk false;
4059 };4014 };
4060 var codesig_offset: ?u32 = null;
4061 var codesig: ?CodeSignature = if (requires_codesig) blk: {4015 var codesig: ?CodeSignature = if (requires_codesig) blk: {
4062 // Preallocate space for the code signature.4016 // Preallocate space for the code signature.
4063 // We need to do this at this stage so that we have the load commands with proper values4017 // We need to do this at this stage so that we have the load commands with proper values
...@@ -4069,29 +4023,20 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -4069,29 +4023,20 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
4069 if (options.entitlements) |path| {4023 if (options.entitlements) |path| {
4070 try codesig.addEntitlements(gpa, path);4024 try codesig.addEntitlements(gpa, path);
4071 }4025 }
4072 codesig_offset = try zld.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);4026 try zld.writeCodeSignaturePadding(&codesig);
4027 try lc_writer.writeStruct(zld.codesig_cmd);
4073 break :blk codesig;4028 break :blk codesig;
4074 } else null;4029 } else null;
4075 defer if (codesig) |*csig| csig.deinit(gpa);4030 defer if (codesig) |*csig| csig.deinit(gpa);
40764031
4077 var headers_buf = std.ArrayList(u8).init(arena);4032 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
4078 try zld.writeSegmentHeaders(&ncmds, headers_buf.writer());4033 try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
4034 try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len));
40794035
4080 try zld.file.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));4036 try zld.writeUuid(comp, uuid_offset);
4081 try zld.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
4082 try zld.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
4083
4084 if (uuid_offset_backpatch) |backpatch| {
4085 const seg = zld.getLinkeditSegmentPtr();
4086 const file_size = seg.fileoff + seg.filesize;
4087 var uuid_buf: [16]u8 = undefined;
4088 try uuid.calcUuidParallel(comp, zld.file, file_size, &uuid_buf);
4089 const offset = @sizeOf(macho.mach_header_64) + headers_buf.items.len + backpatch + @sizeOf(macho.load_command);
4090 try zld.file.pwriteAll(&uuid_buf, offset);
4091 }
40924037
4093 if (codesig) |*csig| {4038 if (codesig) |*csig| {
4094 try zld.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last4039 try zld.writeCodeSignature(comp, csig); // code signing always comes last
4095 }4040 }
4096 }4041 }
40974042