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 {
5858 cmd: LC = .UUID,
5959
6060 /// sizeof(struct uuid_command)
61 cmdsize: u32,
61 cmdsize: u32 = @sizeOf(uuid_command),
6262
6363 /// the 128-bit uuid
64 uuid: [16]u8,
64 uuid: [16]u8 = undefined,
6565};
6666
6767/// The version_min_command contains the min OS version on which this
......@@ -71,7 +71,7 @@ pub const version_min_command = extern struct {
7171 cmd: LC,
7272
7373 /// sizeof(struct version_min_command)
74 cmdsize: u32,
74 cmdsize: u32 = @sizeOf(version_min_command),
7575
7676 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
7777 version: u32,
......@@ -87,7 +87,7 @@ pub const source_version_command = extern struct {
8787 cmd: LC = .SOURCE_VERSION,
8888
8989 /// sizeof(source_version_command)
90 cmdsize: u32,
90 cmdsize: u32 = @sizeOf(source_version_command),
9191
9292 /// A.B.C.D.E packed as a24.b10.c10.d10.e10
9393 version: u64,
......@@ -155,13 +155,13 @@ pub const entry_point_command = extern struct {
155155 cmd: LC = .MAIN,
156156
157157 /// sizeof(struct entry_point_command)
158 cmdsize: u32,
158 cmdsize: u32 = @sizeOf(entry_point_command),
159159
160160 /// file (__TEXT) offset of main()
161 entryoff: u64,
161 entryoff: u64 = 0,
162162
163163 /// if not zero, initial stack size
164 stacksize: u64,
164 stacksize: u64 = 0,
165165};
166166
167167/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
......@@ -172,19 +172,19 @@ pub const symtab_command = extern struct {
172172 cmd: LC = .SYMTAB,
173173
174174 /// sizeof(struct symtab_command)
175 cmdsize: u32,
175 cmdsize: u32 = @sizeOf(symtab_command),
176176
177177 /// symbol table offset
178 symoff: u32,
178 symoff: u32 = 0,
179179
180180 /// number of symbol table entries
181 nsyms: u32,
181 nsyms: u32 = 0,
182182
183183 /// string table offset
184 stroff: u32,
184 stroff: u32 = 0,
185185
186186 /// string table size in bytes
187 strsize: u32,
187 strsize: u32 = 0,
188188};
189189
190190/// This is the second set of the symbolic information which is used to support
......@@ -230,7 +230,7 @@ pub const dysymtab_command = extern struct {
230230 cmd: LC = .DYSYMTAB,
231231
232232 /// sizeof(struct dysymtab_command)
233 cmdsize: u32,
233 cmdsize: u32 = @sizeOf(dysymtab_command),
234234
235235 // The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
236236 // are grouped into the following three groups:
......@@ -247,22 +247,22 @@ pub const dysymtab_command = extern struct {
247247 // table when this is a dynamically linked shared library file).
248248
249249 /// index of local symbols
250 ilocalsym: u32,
250 ilocalsym: u32 = 0,
251251
252252 /// number of local symbols
253 nlocalsym: u32,
253 nlocalsym: u32 = 0,
254254
255255 /// index to externally defined symbols
256 iextdefsym: u32,
256 iextdefsym: u32 = 0,
257257
258258 /// number of externally defined symbols
259 nextdefsym: u32,
259 nextdefsym: u32 = 0,
260260
261261 /// index to undefined symbols
262 iundefsym: u32,
262 iundefsym: u32 = 0,
263263
264264 /// number of undefined symbols
265 nundefsym: u32,
265 nundefsym: u32 = 0,
266266
267267 // For the for the dynamic binding process to find which module a symbol
268268 // is defined in the table of contents is used (analogous to the ranlib
......@@ -272,10 +272,10 @@ pub const dysymtab_command = extern struct {
272272 // symbols are sorted by name and is use as the table of contents.
273273
274274 /// file offset to table of contents
275 tocoff: u32,
275 tocoff: u32 = 0,
276276
277277 /// number of entries in table of contents
278 ntoc: u32,
278 ntoc: u32 = 0,
279279
280280 // To support dynamic binding of "modules" (whole object files) the symbol
281281 // table must reflect the modules that the file was created from. This is
......@@ -286,10 +286,10 @@ pub const dysymtab_command = extern struct {
286286 // contains one module so everything in the file belongs to the module.
287287
288288 /// file offset to module table
289 modtaboff: u32,
289 modtaboff: u32 = 0,
290290
291291 /// number of module table entries
292 nmodtab: u32,
292 nmodtab: u32 = 0,
293293
294294 // To support dynamic module binding the module structure for each module
295295 // indicates the external references (defined and undefined) each module
......@@ -300,10 +300,10 @@ pub const dysymtab_command = extern struct {
300300 // undefined external symbols indicates the external references.
301301
302302 /// offset to referenced symbol table
303 extrefsymoff: u32,
303 extrefsymoff: u32 = 0,
304304
305305 /// number of referenced symbol table entries
306 nextrefsyms: u32,
306 nextrefsyms: u32 = 0,
307307
308308 // The sections that contain "symbol pointers" and "routine stubs" have
309309 // indexes and (implied counts based on the size of the section and fixed
......@@ -315,10 +315,10 @@ pub const dysymtab_command = extern struct {
315315 // The indirect symbol table is ordered to match the entries in the section.
316316
317317 /// file offset to the indirect symbol table
318 indirectsymoff: u32,
318 indirectsymoff: u32 = 0,
319319
320320 /// number of indirect symbol table entries
321 nindirectsyms: u32,
321 nindirectsyms: u32 = 0,
322322
323323 // To support relocating an individual module in a library file quickly the
324324 // external relocation entries for each module in the library need to be
......@@ -347,20 +347,20 @@ pub const dysymtab_command = extern struct {
347347 // remaining relocation entries must be local).
348348
349349 /// offset to external relocation entries
350 extreloff: u32,
350 extreloff: u32 = 0,
351351
352352 /// number of external relocation entries
353 nextrel: u32,
353 nextrel: u32 = 0,
354354
355355 // All the local relocation entries are grouped together (they are not
356356 // grouped by their module since they are only used if the object is moved
357357 // from it staticly link edited address).
358358
359359 /// offset to local relocation entries
360 locreloff: u32,
360 locreloff: u32 = 0,
361361
362362 /// number of local relocation entries
363 nlocrel: u32,
363 nlocrel: u32 = 0,
364364};
365365
366366/// The linkedit_data_command contains the offsets and sizes of a blob
......@@ -370,13 +370,13 @@ pub const linkedit_data_command = extern struct {
370370 cmd: LC,
371371
372372 /// sizeof(struct linkedit_data_command)
373 cmdsize: u32,
373 cmdsize: u32 = @sizeOf(linkedit_data_command),
374374
375375 /// file offset of data in __LINKEDIT segment
376 dataoff: u32,
376 dataoff: u32 = 0,
377377
378378 /// file size of data in __LINKEDIT segment
379 datasize: u32,
379 datasize: u32 = 0,
380380};
381381
382382/// The dyld_info_command contains the file offsets and sizes of
......@@ -387,10 +387,10 @@ pub const linkedit_data_command = extern struct {
387387/// to interpret it.
388388pub const dyld_info_command = extern struct {
389389 /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
390 cmd: LC,
390 cmd: LC = .DYLD_INFO_ONLY,
391391
392392 /// sizeof(struct dyld_info_command)
393 cmdsize: u32,
393 cmdsize: u32 = @sizeOf(dyld_info_command),
394394
395395 // Dyld rebases an image whenever dyld loads it at an address different
396396 // from its preferred address. The rebase information is a stream
......@@ -403,10 +403,10 @@ pub const dyld_info_command = extern struct {
403403 // bytes.
404404
405405 /// file offset to rebase info
406 rebase_off: u32,
406 rebase_off: u32 = 0,
407407
408408 /// size of rebase info
409 rebase_size: u32,
409 rebase_size: u32 = 0,
410410
411411 // Dyld binds an image during the loading process, if the image
412412 // requires any pointers to be initialized to symbols in other images.
......@@ -420,10 +420,10 @@ pub const dyld_info_command = extern struct {
420420 // encoded in a few bytes.
421421
422422 /// file offset to binding info
423 bind_off: u32,
423 bind_off: u32 = 0,
424424
425425 /// size of binding info
426 bind_size: u32,
426 bind_size: u32 = 0,
427427
428428 // Some C++ programs require dyld to unique symbols so that all
429429 // images in the process use the same copy of some code/data.
......@@ -440,10 +440,10 @@ pub const dyld_info_command = extern struct {
440440 // and the call to operator new is then rebound.
441441
442442 /// file offset to weak binding info
443 weak_bind_off: u32,
443 weak_bind_off: u32 = 0,
444444
445445 /// size of weak binding info
446 weak_bind_size: u32,
446 weak_bind_size: u32 = 0,
447447
448448 // Some uses of external symbols do not need to be bound immediately.
449449 // Instead they can be lazily bound on first use. The lazy_bind
......@@ -457,10 +457,10 @@ pub const dyld_info_command = extern struct {
457457 // to bind.
458458
459459 /// file offset to lazy binding info
460 lazy_bind_off: u32,
460 lazy_bind_off: u32 = 0,
461461
462462 /// size of lazy binding info
463 lazy_bind_size: u32,
463 lazy_bind_size: u32 = 0,
464464
465465 // The symbols exported by a dylib are encoded in a trie. This
466466 // is a compact representation that factors out common prefixes.
......@@ -494,10 +494,10 @@ pub const dyld_info_command = extern struct {
494494 // edge points to.
495495
496496 /// file offset to lazy binding info
497 export_off: u32,
497 export_off: u32 = 0,
498498
499499 /// size of lazy binding info
500 export_size: u32,
500 export_size: u32 = 0,
501501};
502502
503503/// 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,
9999/// fashion (default for LLVM backend).
100100mode: enum { incremental, one_shot },
101101
102uuid: struct {
103 buf: [16]u8 = undefined,
104 final: bool = false,
105} = .{},
102dyld_info_cmd: macho.dyld_info_command = .{},
103symtab_cmd: macho.symtab_command = .{},
104dysymtab_cmd: macho.dysymtab_command = .{},
105uuid_cmd: macho.uuid_command = .{},
106codesig_cmd: macho.linkedit_data_command = .{ .cmd = .CODE_SIGNATURE },
106107
107108dylibs: std.ArrayListUnmanaged(Dylib) = .{},
108109dylibs_map: std.StringHashMapUnmanaged(u16) = .{},
......@@ -554,12 +555,17 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
554555 self.logAtoms();
555556 }
556557
558 try self.writeLinkeditSegmentData();
559
560 // Write load commands
557561 var lc_buffer = std.ArrayList(u8).init(arena);
558562 const lc_writer = lc_buffer.writer();
559 var ncmds: u32 = 0;
560563
561 try self.writeLinkeditSegmentData(&ncmds, lc_writer);
562 try load_commands.writeDylinkerLC(&ncmds, lc_writer);
564 try self.writeSegmentHeaders(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
564570 switch (self.base.options.output_mode) {
565571 .Exe => blk: {
......@@ -573,33 +579,29 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
573579 else => |e| return e,
574580 };
575581 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 });
577586 },
578587 .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);
580589 },
581590 else => {},
582591 }
583592
584 try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, &ncmds, lc_writer);
585
586 {
587 try lc_writer.writeStruct(macho.source_version_command{
588 .cmdsize = @sizeOf(macho.source_version_command),
589 .version = 0x0,
590 });
591 ncmds += 1;
592 }
593
594 try load_commands.writeBuildVersionLC(&self.base.options, &ncmds, lc_writer);
593 try load_commands.writeRpathLCs(self.base.allocator, &self.base.options, lc_writer);
594 try lc_writer.writeStruct(macho.source_version_command{
595 .version = 0,
596 });
597 try load_commands.writeBuildVersionLC(&self.base.options, lc_writer);
595598
596 if (!self.uuid.final) {
597 std.crypto.random.bytes(&self.uuid.buf);
598 self.uuid.final = true;
599 if (self.cold_start) {
600 std.crypto.random.bytes(&self.uuid_cmd.uuid);
599601 }
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
604606 const target = self.base.options.target;
605607 const requires_codesig = blk: {
......@@ -608,7 +610,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
608610 break :blk true;
609611 break :blk false;
610612 };
611 var codesig_offset: ?u32 = null;
612613 var codesig: ?CodeSignature = if (requires_codesig) blk: {
613614 // Preallocate space for the code signature.
614615 // 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
620621 if (self.base.options.entitlements) |path| {
621622 try codesig.addEntitlements(arena, path);
622623 }
623 codesig_offset = try self.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);
624 try self.writeCodeSignaturePadding(&codesig);
625 try lc_writer.writeStruct(self.codesig_cmd);
624626 break :blk codesig;
625627 } else null;
626628
627 var headers_buf = std.ArrayList(u8).init(arena);
628 try self.writeSegmentHeaders(&ncmds, headers_buf.writer());
629 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
629630
630 try self.base.file.?.pwriteAll(headers_buf.items, @sizeOf(macho.mach_header_64));
631 try self.base.file.?.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64) + headers_buf.items.len);
632
633 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len + headers_buf.items.len));
631 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
632 try self.writeHeader(ncmds, @intCast(u32, lc_buffer.items.len));
634633
635634 if (codesig) |*csig| {
636 try self.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last
635 try self.writeCodeSignature(comp, csig); // code signing always comes last
637636 }
638637
639638 if (self.d_sym) |*d_sym| {
......@@ -3146,18 +3145,17 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 {
31463145 return global_index;
31473146}
31483147
3149fn writeSegmentHeaders(self: *MachO, ncmds: *u32, writer: anytype) !void {
3148fn writeSegmentHeaders(self: *MachO, writer: anytype) !void {
31503149 for (self.segments.items) |seg, i| {
31513150 const indexes = self.getSectionIndexes(@intCast(u8, i));
31523151 try writer.writeStruct(seg);
31533152 for (self.sections.items(.header)[indexes.start..indexes.end]) |header| {
31543153 try writer.writeStruct(header);
31553154 }
3156 ncmds.* += 1;
31573155 }
31583156}
31593157
3160fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3158fn writeLinkeditSegmentData(self: *MachO) !void {
31613159 const seg = self.getLinkeditSegmentPtr();
31623160 seg.filesize = 0;
31633161 seg.vmsize = 0;
......@@ -3172,8 +3170,8 @@ fn writeLinkeditSegmentData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void
31723170 }
31733171 }
31743172
3175 try self.writeDyldInfoData(ncmds, lc_writer);
3176 try self.writeSymtabs(ncmds, lc_writer);
3173 try self.writeDyldInfoData();
3174 try self.writeSymtabs();
31773175
31783176 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
31793177}
......@@ -3325,7 +3323,7 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
33253323 try trie.finalize(gpa);
33263324}
33273325
3328fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3326fn writeDyldInfoData(self: *MachO) !void {
33293327 const tracy = trace(@src());
33303328 defer tracy.end();
33313329
......@@ -3396,21 +3394,14 @@ fn writeDyldInfoData(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
33963394 const end = start + (math.cast(usize, lazy_bind_size) orelse return error.Overflow);
33973395 try self.populateLazyBindOffsetsInStubHelper(buffer[start..end]);
33983396
3399 try lc_writer.writeStruct(macho.dyld_info_command{
3400 .cmd = .DYLD_INFO_ONLY,
3401 .cmdsize = @sizeOf(macho.dyld_info_command),
3402 .rebase_off = @intCast(u32, rebase_off),
3403 .rebase_size = @intCast(u32, rebase_size),
3404 .bind_off = @intCast(u32, bind_off),
3405 .bind_size = @intCast(u32, bind_size),
3406 .weak_bind_off = 0,
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;
3397 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
3398 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
3399 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
3400 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
3401 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
3402 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
3403 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
3404 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
34143405}
34153406
34163407fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
......@@ -3512,45 +3503,14 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
35123503 }
35133504}
35143505
3515fn writeSymtabs(self: *MachO, ncmds: *u32, lc_writer: anytype) !void {
3516 var symtab_cmd = macho.symtab_command{
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);
3506fn writeSymtabs(self: *MachO) !void {
3507 var ctx = try self.writeSymtab();
35453508 defer ctx.imports_table.deinit();
3546 try self.writeDysymtab(ctx, &dysymtab_cmd);
3547 try self.writeStrtab(&symtab_cmd);
3548 try lc_writer.writeStruct(symtab_cmd);
3549 try lc_writer.writeStruct(dysymtab_cmd);
3550 ncmds.* += 2;
3509 try self.writeDysymtab(ctx);
3510 try self.writeStrtab();
35513511}
35523512
3553fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
3513fn writeSymtab(self: *MachO) !SymtabCtx {
35543514 const gpa = self.base.allocator;
35553515
35563516 var locals = std.ArrayList(macho.nlist_64).init(gpa);
......@@ -3615,8 +3575,8 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
36153575 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
36163576 try self.base.file.?.pwriteAll(buffer.items, offset);
36173577
3618 lc.symoff = @intCast(u32, offset);
3619 lc.nsyms = nsyms;
3578 self.symtab_cmd.symoff = @intCast(u32, offset);
3579 self.symtab_cmd.nsyms = nsyms;
36203580
36213581 return SymtabCtx{
36223582 .nlocalsym = nlocals,
......@@ -3626,7 +3586,7 @@ fn writeSymtab(self: *MachO, lc: *macho.symtab_command) !SymtabCtx {
36263586 };
36273587}
36283588
3629fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
3589fn writeStrtab(self: *MachO) !void {
36303590 const seg = self.getLinkeditSegmentPtr();
36313591 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
36323592 const needed_size = self.strtab.buffer.items.len;
......@@ -3636,8 +3596,8 @@ fn writeStrtab(self: *MachO, lc: *macho.symtab_command) !void {
36363596
36373597 try self.base.file.?.pwriteAll(self.strtab.buffer.items, offset);
36383598
3639 lc.stroff = @intCast(u32, offset);
3640 lc.strsize = @intCast(u32, needed_size);
3599 self.symtab_cmd.stroff = @intCast(u32, offset);
3600 self.symtab_cmd.strsize = @intCast(u32, needed_size);
36413601}
36423602
36433603const SymtabCtx = struct {
......@@ -3647,7 +3607,7 @@ const SymtabCtx = struct {
36473607 imports_table: std.AutoHashMap(SymbolWithLoc, u32),
36483608};
36493609
3650fn writeDysymtab(self: *MachO, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {
3610fn writeDysymtab(self: *MachO, ctx: SymtabCtx) !void {
36513611 const gpa = self.base.allocator;
36523612 const nstubs = @intCast(u32, self.stubs_table.count());
36533613 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
37063666 assert(buf.items.len == needed_size);
37073667 try self.base.file.?.pwriteAll(buf.items, offset);
37083668
3709 lc.nlocalsym = ctx.nlocalsym;
3710 lc.iextdefsym = iextdefsym;
3711 lc.nextdefsym = ctx.nextdefsym;
3712 lc.iundefsym = iundefsym;
3713 lc.nundefsym = ctx.nundefsym;
3714 lc.indirectsymoff = @intCast(u32, offset);
3715 lc.nindirectsyms = nindirectsyms;
3669 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
3670 self.dysymtab_cmd.iextdefsym = iextdefsym;
3671 self.dysymtab_cmd.nextdefsym = ctx.nextdefsym;
3672 self.dysymtab_cmd.iundefsym = iundefsym;
3673 self.dysymtab_cmd.nundefsym = ctx.nundefsym;
3674 self.dysymtab_cmd.indirectsymoff = @intCast(u32, offset);
3675 self.dysymtab_cmd.nindirectsyms = nindirectsyms;
37163676}
37173677
3718fn writeCodeSignaturePadding(
3719 self: *MachO,
3720 code_sig: *CodeSignature,
3721 ncmds: *u32,
3722 lc_writer: anytype,
3723) !u32 {
3678fn writeCodeSignaturePadding(self: *MachO, code_sig: *CodeSignature) !void {
37243679 const seg = self.getLinkeditSegmentPtr();
37253680 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
37263681 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
......@@ -3733,19 +3688,13 @@ fn writeCodeSignaturePadding(
37333688 // except for code signature data.
37343689 try self.base.file.?.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
37353690
3736 try lc_writer.writeStruct(macho.linkedit_data_command{
3737 .cmd = .CODE_SIGNATURE,
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);
3691 self.codesig_cmd.dataoff = @intCast(u32, offset);
3692 self.codesig_cmd.datasize = @intCast(u32, needed_size);
37453693}
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 {
37483696 const seg = self.getSegment(self.text_section_index.?);
3697 const offset = self.codesig_cmd.dataoff;
37493698
37503699 var buffer = std.ArrayList(u8).init(self.base.allocator);
37513700 defer buffer.deinit();
src/link/MachO/DebugSymbols.zig+28-50
......@@ -26,6 +26,8 @@ dwarf: Dwarf,
2626file: fs.File,
2727page_size: u16,
2828
29symtab_cmd: macho.symtab_command = .{},
30
2931segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
3032sections: std.ArrayListUnmanaged(macho.section_64) = .{},
3133
......@@ -296,28 +298,21 @@ pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
296298 }
297299 }
298300
301 self.finalizeDwarfSegment(macho_file);
302 try self.writeLinkeditSegmentData(macho_file);
303
304 // Write load commands
299305 var lc_buffer = std.ArrayList(u8).init(self.allocator);
300306 defer lc_buffer.deinit();
301307 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);
310 defer headers_buf.deinit();
311 try self.writeSegmentHeaders(macho_file, &ncmds, headers_buf.writer());
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 );
313 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
314 try self.file.pwriteAll(lc_buffer.items, @sizeOf(macho.mach_header_64));
315 try self.writeHeader(macho_file, ncmds, @intCast(u32, lc_buffer.items.len));
321316
322317 assert(!self.debug_abbrev_section_dirty);
323318 assert(!self.debug_aranges_section_dirty);
......@@ -384,7 +379,7 @@ fn finalizeDwarfSegment(self: *DebugSymbols, macho_file: *MachO) void {
384379 log.debug("found __LINKEDIT segment free space at 0x{x}", .{linkedit.fileoff});
385380}
386381
387fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, writer: anytype) !void {
382fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, writer: anytype) !void {
388383 // Write segment/section headers from the binary file first.
389384 const end = macho_file.linkedit_segment_cmd_index.?;
390385 for (macho_file.segments.items[0..end]) |seg, i| {
......@@ -414,8 +409,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri
414409 out_header.offset = 0;
415410 try writer.writeStruct(out_header);
416411 }
417
418 ncmds.* += 1;
419412 }
420413 // Next, commit DSYM's __LINKEDIT and __DWARF segments headers.
421414 for (self.segments.items) |seg, i| {
......@@ -424,7 +417,6 @@ fn writeSegmentHeaders(self: *DebugSymbols, macho_file: *MachO, ncmds: *u32, wri
424417 for (self.sections.items[indexes.start..indexes.end]) |header| {
425418 try writer.writeStruct(header);
426419 }
427 ncmds.* += 1;
428420 }
429421}
430422
......@@ -463,33 +455,19 @@ fn allocatedSize(self: *DebugSymbols, start: u64) u64 {
463455 return min_pos - start;
464456}
465457
466fn writeLinkeditSegmentData(
467 self: *DebugSymbols,
468 macho_file: *MachO,
469 ncmds: *u32,
470 lc_writer: anytype,
471) !void {
458fn writeLinkeditSegmentData(self: *DebugSymbols, macho_file: *MachO) !void {
472459 const tracy = trace(@src());
473460 defer tracy.end();
474461
475 var symtab_cmd = macho.symtab_command{
476 .cmdsize = @sizeOf(macho.symtab_command),
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;
462 try self.writeSymtab(macho_file);
463 try self.writeStrtab();
486464
487465 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
488466 const aligned_size = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
489467 seg.vmsize = aligned_size;
490468}
491469
492fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_command) !void {
470fn writeSymtab(self: *DebugSymbols, macho_file: *MachO) !void {
493471 const tracy = trace(@src());
494472 defer tracy.end();
495473
......@@ -528,10 +506,10 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman
528506 const needed_size = nsyms * @sizeOf(macho.nlist_64);
529507 seg.filesize = offset + needed_size - seg.fileoff;
530508
531 lc.symoff = @intCast(u32, offset);
532 lc.nsyms = @intCast(u32, nsyms);
509 self.symtab_cmd.symoff = @intCast(u32, offset);
510 self.symtab_cmd.nsyms = @intCast(u32, nsyms);
533511
534 const locals_off = lc.symoff;
512 const locals_off = @intCast(u32, offset);
535513 const locals_size = nlocals * @sizeOf(macho.nlist_64);
536514 const exports_off = locals_off + locals_size;
537515 const exports_size = nexports * @sizeOf(macho.nlist_64);
......@@ -543,26 +521,26 @@ fn writeSymtab(self: *DebugSymbols, macho_file: *MachO, lc: *macho.symtab_comman
543521 try self.file.pwriteAll(mem.sliceAsBytes(exports.items), exports_off);
544522}
545523
546fn writeStrtab(self: *DebugSymbols, lc: *macho.symtab_command) !void {
524fn writeStrtab(self: *DebugSymbols) !void {
547525 const tracy = trace(@src());
548526 defer tracy.end();
549527
550528 const seg = &self.segments.items[self.linkedit_segment_cmd_index.?];
551 const symtab_size = @intCast(u32, lc.nsyms * @sizeOf(macho.nlist_64));
552 const offset = mem.alignForwardGeneric(u64, lc.symoff + symtab_size, @alignOf(u64));
529 const symtab_size = @intCast(u32, self.symtab_cmd.nsyms * @sizeOf(macho.nlist_64));
530 const offset = mem.alignForwardGeneric(u64, self.symtab_cmd.symoff + symtab_size, @alignOf(u64));
553531 const needed_size = mem.alignForwardGeneric(u64, self.strtab.buffer.items.len, @alignOf(u64));
554532
555533 seg.filesize = offset + needed_size - seg.fileoff;
556 lc.stroff = @intCast(u32, offset);
557 lc.strsize = @intCast(u32, needed_size);
534 self.symtab_cmd.stroff = @intCast(u32, offset);
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
563541 if (self.strtab.buffer.items.len < needed_size) {
564542 // 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);
566544 }
567545}
568546
src/link/MachO/load_commands.zig+20-40
......@@ -131,7 +131,19 @@ pub fn calcMinHeaderPad(gpa: Allocator, options: *const link.Options, ctx: CalcL
131131 return offset;
132132}
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 {
135147 const name_len = mem.sliceTo(default_dyld_path, 0).len;
136148 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
137149 u64,
......@@ -148,7 +160,6 @@ pub fn writeDylinkerLC(ncmds: *u32, lc_writer: anytype) !void {
148160 if (padding > 0) {
149161 try lc_writer.writeByteNTimes(0, padding);
150162 }
151 ncmds.* += 1;
152163}
153164
154165const WriteDylibLCCtx = struct {
......@@ -159,7 +170,7 @@ const WriteDylibLCCtx = struct {
159170 compatibility_version: u32 = 0x10000,
160171};
161172
162fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {
173fn writeDylibLC(ctx: WriteDylibLCCtx, lc_writer: anytype) !void {
163174 const name_len = ctx.name.len + 1;
164175 const cmdsize = @intCast(u32, mem.alignForwardGeneric(
165176 u64,
......@@ -182,10 +193,9 @@ fn writeDylibLC(ctx: WriteDylibLCCtx, ncmds: *u32, lc_writer: anytype) !void {
182193 if (padding > 0) {
183194 try lc_writer.writeByteNTimes(0, padding);
184195 }
185 ncmds.* += 1;
186196}
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 {
189199 assert(options.output_mode == .Lib and options.link_mode == .Dynamic);
190200 const emit = options.emit.?;
191201 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,
205215 .name = install_name,
206216 .current_version = curr.major << 16 | curr.minor << 8 | curr.patch,
207217 .compatibility_version = compat.major << 16 | compat.minor << 8 | compat.patch,
208 }, ncmds, 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;
218 }, lc_writer);
220219}
221220
222221const RpathIterator = struct {
......@@ -244,7 +243,7 @@ const RpathIterator = struct {
244243 }
245244};
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 {
248247 var it = RpathIterator.init(gpa, options.rpath_list);
249248 defer it.deinit();
250249
......@@ -265,11 +264,10 @@ pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, ncmds: *u32,
265264 if (padding > 0) {
266265 try lc_writer.writeByteNTimes(0, padding);
267266 }
268 ncmds.* += 1;
269267 }
270268}
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 {
273271 const cmdsize = @sizeOf(macho.build_version_command) + @sizeOf(macho.build_tool_version);
274272 const platform_version = blk: {
275273 const ver = options.target.os.version_range.semver.min;
......@@ -299,10 +297,9 @@ pub fn writeBuildVersionLC(options: *const link.Options, ncmds: *u32, lc_writer:
299297 .tool = .LD,
300298 .version = 0x0,
301299 }));
302 ncmds.* += 1;
303300}
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 {
306303 for (referenced) |index| {
307304 const dylib = dylibs[index];
308305 const dylib_id = dylib.id orelse unreachable;
......@@ -312,23 +309,6 @@ pub fn writeLoadDylibLCs(dylibs: []const Dylib, referenced: []u16, ncmds: *u32,
312309 .timestamp = dylib_id.timestamp,
313310 .current_version = dylib_id.current_version,
314311 .compatibility_version = dylib_id.compatibility_version,
315 }, ncmds, lc_writer);
312 }, lc_writer);
316313 }
317314}
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 {
3838 page_size: u16,
3939 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
4149 objects: std.ArrayListUnmanaged(Object) = .{},
4250 archives: std.ArrayListUnmanaged(Archive) = .{},
4351 dylibs: std.ArrayListUnmanaged(Dylib) = .{},
......@@ -1728,7 +1736,7 @@ pub const Zld = struct {
17281736 return (@intCast(u8, segment_precedence) << 4) + section_precedence;
17291737 }
17301738
1731 fn writeSegmentHeaders(self: *Zld, ncmds: *u32, writer: anytype) !void {
1739 fn writeSegmentHeaders(self: *Zld, writer: anytype) !void {
17321740 for (self.segments.items) |seg, i| {
17331741 const indexes = self.getSectionIndexes(@intCast(u8, i));
17341742 var out_seg = seg;
......@@ -1752,16 +1760,14 @@ pub const Zld = struct {
17521760 if (header.size == 0) continue;
17531761 try writer.writeStruct(header);
17541762 }
1755
1756 ncmds.* += 1;
17571763 }
17581764 }
17591765
1760 fn writeLinkeditSegmentData(self: *Zld, ncmds: *u32, lc_writer: anytype, reverse_lookups: [][]u32) !void {
1761 try self.writeDyldInfoData(ncmds, lc_writer, reverse_lookups);
1762 try self.writeFunctionStarts(ncmds, lc_writer);
1763 try self.writeDataInCode(ncmds, lc_writer);
1764 try self.writeSymtabs(ncmds, lc_writer);
1766 fn writeLinkeditSegmentData(self: *Zld, reverse_lookups: [][]u32) !void {
1767 try self.writeDyldInfoData(reverse_lookups);
1768 try self.writeFunctionStarts();
1769 try self.writeDataInCode();
1770 try self.writeSymtabs();
17651771
17661772 const seg = self.getLinkeditSegmentPtr();
17671773 seg.vmsize = mem.alignForwardGeneric(u64, seg.filesize, self.page_size);
......@@ -2150,7 +2156,7 @@ pub const Zld = struct {
21502156 try trie.finalize(gpa);
21512157 }
21522158
2153 fn writeDyldInfoData(self: *Zld, ncmds: *u32, lc_writer: anytype, reverse_lookups: [][]u32) !void {
2159 fn writeDyldInfoData(self: *Zld, reverse_lookups: [][]u32) !void {
21542160 const gpa = self.gpa;
21552161
21562162 var rebase_pointers = std.ArrayList(bind.Pointer).init(gpa);
......@@ -2219,21 +2225,14 @@ pub const Zld = struct {
22192225 const size = math.cast(usize, lazy_bind_size) orelse return error.Overflow;
22202226 try self.populateLazyBindOffsetsInStubHelper(buffer[offset..][0..size]);
22212227
2222 try lc_writer.writeStruct(macho.dyld_info_command{
2223 .cmd = .DYLD_INFO_ONLY,
2224 .cmdsize = @sizeOf(macho.dyld_info_command),
2225 .rebase_off = @intCast(u32, rebase_off),
2226 .rebase_size = @intCast(u32, rebase_size),
2227 .bind_off = @intCast(u32, bind_off),
2228 .bind_size = @intCast(u32, bind_size),
2229 .weak_bind_off = 0,
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;
2228 self.dyld_info_cmd.rebase_off = @intCast(u32, rebase_off);
2229 self.dyld_info_cmd.rebase_size = @intCast(u32, rebase_size);
2230 self.dyld_info_cmd.bind_off = @intCast(u32, bind_off);
2231 self.dyld_info_cmd.bind_size = @intCast(u32, bind_size);
2232 self.dyld_info_cmd.lazy_bind_off = @intCast(u32, lazy_bind_off);
2233 self.dyld_info_cmd.lazy_bind_size = @intCast(u32, lazy_bind_size);
2234 self.dyld_info_cmd.export_off = @intCast(u32, export_off);
2235 self.dyld_info_cmd.export_size = @intCast(u32, export_size);
22372236 }
22382237
22392238 fn populateLazyBindOffsetsInStubHelper(self: *Zld, buffer: []const u8) !void {
......@@ -2351,7 +2350,7 @@ pub const Zld = struct {
23512350
23522351 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 {
23552354 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;
23562355 const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;
23572356 const text_seg = self.segments.items[text_seg_index];
......@@ -2410,13 +2409,8 @@ pub const Zld = struct {
24102409
24112410 try self.file.pwriteAll(buffer.items, offset);
24122411
2413 try lc_writer.writeStruct(macho.linkedit_data_command{
2414 .cmd = .FUNCTION_STARTS,
2415 .cmdsize = @sizeOf(macho.linkedit_data_command),
2416 .dataoff = @intCast(u32, offset),
2417 .datasize = @intCast(u32, needed_size),
2418 });
2419 ncmds.* += 1;
2412 self.function_starts_cmd.dataoff = @intCast(u32, offset);
2413 self.function_starts_cmd.datasize = @intCast(u32, needed_size);
24202414 }
24212415
24222416 fn filterDataInCode(
......@@ -2438,7 +2432,7 @@ pub const Zld = struct {
24382432 return dices[start..end];
24392433 }
24402434
2441 fn writeDataInCode(self: *Zld, ncmds: *u32, lc_writer: anytype) !void {
2435 fn writeDataInCode(self: *Zld) !void {
24422436 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa);
24432437 defer out_dice.deinit();
24442438
......@@ -2488,54 +2482,19 @@ pub const Zld = struct {
24882482 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
24892483
24902484 try self.file.pwriteAll(mem.sliceAsBytes(out_dice.items), offset);
2491 try lc_writer.writeStruct(macho.linkedit_data_command{
2492 .cmd = .DATA_IN_CODE,
2493 .cmdsize = @sizeOf(macho.linkedit_data_command),
2494 .dataoff = @intCast(u32, offset),
2495 .datasize = @intCast(u32, needed_size),
2496 });
2497 ncmds.* += 1;
2485
2486 self.data_in_code_cmd.dataoff = @intCast(u32, offset);
2487 self.data_in_code_cmd.datasize = @intCast(u32, needed_size);
24982488 }
24992489
2500 fn writeSymtabs(self: *Zld, ncmds: *u32, lc_writer: anytype) !void {
2501 var symtab_cmd = macho.symtab_command{
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);
2490 fn writeSymtabs(self: *Zld) !void {
2491 var ctx = try self.writeSymtab();
25302492 defer ctx.imports_table.deinit();
2531 try self.writeDysymtab(ctx, &dysymtab_cmd);
2532 try self.writeStrtab(&symtab_cmd);
2533 try lc_writer.writeStruct(symtab_cmd);
2534 try lc_writer.writeStruct(dysymtab_cmd);
2535 ncmds.* += 2;
2493 try self.writeDysymtab(ctx);
2494 try self.writeStrtab();
25362495 }
25372496
2538 fn writeSymtab(self: *Zld, lc: *macho.symtab_command) !SymtabCtx {
2497 fn writeSymtab(self: *Zld) !SymtabCtx {
25392498 const gpa = self.gpa;
25402499
25412500 var locals = std.ArrayList(macho.nlist_64).init(gpa);
......@@ -2618,8 +2577,8 @@ pub const Zld = struct {
26182577 log.debug("writing symtab from 0x{x} to 0x{x}", .{ offset, offset + needed_size });
26192578 try self.file.pwriteAll(buffer.items, offset);
26202579
2621 lc.symoff = @intCast(u32, offset);
2622 lc.nsyms = nsyms;
2580 self.symtab_cmd.symoff = @intCast(u32, offset);
2581 self.symtab_cmd.nsyms = nsyms;
26232582
26242583 return SymtabCtx{
26252584 .nlocalsym = nlocals,
......@@ -2629,7 +2588,7 @@ pub const Zld = struct {
26292588 };
26302589 }
26312590
2632 fn writeStrtab(self: *Zld, lc: *macho.symtab_command) !void {
2591 fn writeStrtab(self: *Zld) !void {
26332592 const seg = self.getLinkeditSegmentPtr();
26342593 const offset = mem.alignForwardGeneric(u64, seg.fileoff + seg.filesize, @alignOf(u64));
26352594 const needed_size = self.strtab.buffer.items.len;
......@@ -2639,8 +2598,8 @@ pub const Zld = struct {
26392598
26402599 try self.file.pwriteAll(self.strtab.buffer.items, offset);
26412600
2642 lc.stroff = @intCast(u32, offset);
2643 lc.strsize = @intCast(u32, needed_size);
2601 self.symtab_cmd.stroff = @intCast(u32, offset);
2602 self.symtab_cmd.strsize = @intCast(u32, needed_size);
26442603 }
26452604
26462605 const SymtabCtx = struct {
......@@ -2650,7 +2609,7 @@ pub const Zld = struct {
26502609 imports_table: std.AutoHashMap(SymbolWithLoc, u32),
26512610 };
26522611
2653 fn writeDysymtab(self: *Zld, ctx: SymtabCtx, lc: *macho.dysymtab_command) !void {
2612 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {
26542613 const gpa = self.gpa;
26552614 const nstubs = @intCast(u32, self.stubs.items.len);
26562615 const ngot_entries = @intCast(u32, self.got_entries.items.len);
......@@ -2706,21 +2665,33 @@ pub const Zld = struct {
27062665 assert(buf.items.len == needed_size);
27072666 try self.file.pwriteAll(buf.items, offset);
27082667
2709 lc.nlocalsym = ctx.nlocalsym;
2710 lc.iextdefsym = iextdefsym;
2711 lc.nextdefsym = ctx.nextdefsym;
2712 lc.iundefsym = iundefsym;
2713 lc.nundefsym = ctx.nundefsym;
2714 lc.indirectsymoff = @intCast(u32, offset);
2715 lc.nindirectsyms = nindirectsyms;
2668 self.dysymtab_cmd.nlocalsym = ctx.nlocalsym;
2669 self.dysymtab_cmd.iextdefsym = iextdefsym;
2670 self.dysymtab_cmd.nextdefsym = ctx.nextdefsym;
2671 self.dysymtab_cmd.iundefsym = iundefsym;
2672 self.dysymtab_cmd.nundefsym = ctx.nundefsym;
2673 self.dysymtab_cmd.indirectsymoff = @intCast(u32, offset);
2674 self.dysymtab_cmd.nindirectsyms = nindirectsyms;
27162675 }
27172676
2718 fn writeCodeSignaturePadding(
2719 self: *Zld,
2720 code_sig: *CodeSignature,
2721 ncmds: *u32,
2722 lc_writer: anytype,
2723 ) !u32 {
2677 fn writeUuid(self: *Zld, comp: *const Compilation, offset: u32) !void {
2678 switch (self.options.optimize_mode) {
2679 .Debug => {
2680 // In Debug we don't really care about reproducibility, so put in a random value
2681 // and be done with it.
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 {
27242695 const seg = self.getLinkeditSegmentPtr();
27252696 // Code signature data has to be 16-bytes aligned for Apple tools to recognize the file
27262697 // https://github.com/opensource-apple/cctools/blob/fdb4825f303fd5c0751be524babd32958181b3ed/libstuff/checkout.c#L271
......@@ -2733,23 +2704,11 @@ pub const Zld = struct {
27332704 // except for code signature data.
27342705 try self.file.pwriteAll(&[_]u8{0}, offset + needed_size - 1);
27352706
2736 try lc_writer.writeStruct(macho.linkedit_data_command{
2737 .cmd = .CODE_SIGNATURE,
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);
2707 self.codesig_cmd.dataoff = @intCast(u32, offset);
2708 self.codesig_cmd.datasize = @intCast(u32, needed_size);
27452709 }
27462710
2747 fn writeCodeSignature(
2748 self: *Zld,
2749 comp: *const Compilation,
2750 code_sig: *CodeSignature,
2751 offset: u32,
2752 ) !void {
2711 fn writeCodeSignature(self: *Zld, comp: *const Compilation, code_sig: *CodeSignature) !void {
27532712 const seg_id = self.getSegmentByName("__TEXT").?;
27542713 const seg = self.segments.items[seg_id];
27552714
......@@ -2760,17 +2719,17 @@ pub const Zld = struct {
27602719 .file = self.file,
27612720 .exec_seg_base = seg.fileoff,
27622721 .exec_seg_limit = seg.filesize,
2763 .file_size = offset,
2722 .file_size = self.codesig_cmd.dataoff,
27642723 .output_mode = self.options.output_mode,
27652724 }, buffer.writer());
27662725 assert(buffer.items.len == code_sig.size());
27672726
27682727 log.debug("writing code signature from 0x{x} to 0x{x}", .{
2769 offset,
2770 offset + buffer.items.len,
2728 self.codesig_cmd.dataoff,
2729 self.codesig_cmd.dataoff + buffer.items.len,
27712730 });
27722731
2773 try self.file.pwriteAll(buffer.items, offset);
2732 try self.file.pwriteAll(buffer.items, self.codesig_cmd.dataoff);
27742733 }
27752734
27762735 /// Writes Mach-O file header.
......@@ -3986,13 +3945,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
39863945 }
39873946
39883947 try zld.writeAtoms(reverse_lookups);
3989
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);
3948 try zld.writeLinkeditSegmentData(reverse_lookups);
39963949
39973950 // If the last section of __DATA segment is zerofill section, we need to ensure
39983951 // 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
40173970 }
40183971 }
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
40223985 if (zld.options.output_mode == .Exe) {
40233986 const seg_id = zld.getSegmentByName("__TEXT").?;
40243987 const seg = zld.segments.items[seg_id];
40253988 const global = zld.getEntryPoint();
40263989 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 });
40283994 } else {
40293995 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);
40313997 }
40323998
4033 try load_commands.writeRpathLCs(zld.gpa, zld.options, &ncmds, lc_writer);
4034 try load_commands.writeSourceVersionLC(&ncmds, lc_writer);
4035 try load_commands.writeBuildVersionLC(zld.options, &ncmds, lc_writer);
4036
4037 // Looking forward into the future, we will want to offer `-no_uuid` support in which case
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 }
3999 try load_commands.writeRpathLCs(zld.gpa, zld.options, lc_writer);
4000 try lc_writer.writeStruct(macho.source_version_command{
4001 .version = 0,
4002 });
4003 try load_commands.writeBuildVersionLC(zld.options, lc_writer);
40484004
4049 try load_commands.writeUuidLC(&uuid_buf, &ncmds, lc_writer);
4050 break :blk if (zld.options.optimize_mode == .Debug) null else index;
4051 };
4005 const uuid_offset = @intCast(u32, lc_buffer.items.len);
4006 try lc_writer.writeStruct(zld.uuid_cmd);
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
40554010 const requires_codesig = blk: {
40564011 if (options.entitlements) |_| break :blk true;
40574012 if (cpu_arch == .aarch64 and (os_tag == .macos or abi == .simulator)) break :blk true;
40584013 break :blk false;
40594014 };
4060 var codesig_offset: ?u32 = null;
40614015 var codesig: ?CodeSignature = if (requires_codesig) blk: {
40624016 // Preallocate space for the code signature.
40634017 // 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
40694023 if (options.entitlements) |path| {
40704024 try codesig.addEntitlements(gpa, path);
40714025 }
4072 codesig_offset = try zld.writeCodeSignaturePadding(&codesig, &ncmds, lc_writer);
4026 try zld.writeCodeSignaturePadding(&codesig);
4027 try lc_writer.writeStruct(zld.codesig_cmd);
40734028 break :blk codesig;
40744029 } else null;
40754030 defer if (codesig) |*csig| csig.deinit(gpa);
40764031
4077 var headers_buf = std.ArrayList(u8).init(arena);
4078 try zld.writeSegmentHeaders(&ncmds, headers_buf.writer());
4032 const ncmds = load_commands.calcNumOfLCs(lc_buffer.items);
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));
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 }
4036 try zld.writeUuid(comp, uuid_offset);
40924037
40934038 if (codesig) |*csig| {
4094 try zld.writeCodeSignature(comp, csig, codesig_offset.?); // code signing always comes last
4039 try zld.writeCodeSignature(comp, csig); // code signing always comes last
40954040 }
40964041 }
40974042