authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-04 22:34:16+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-09-04 22:59:16+02:00
log7e87f93e068af192a3c39bdeebfe8e9b612311b0
tree20d608f7b80dccd7be5d3fde7d72772d0ee312b2
parent80e1c244b6c9d5f3e855878d92ecc09dc8eb970a

macho: unfortunately, LINKEDIT commands NEED to be in order

Otherwise, Apple's tooling goes mental and reports that the executable is malformed/fails strict validation. We absolutely have to get it right to support tools such `codesign` which are required to successfully launch an app on an iOS device for instance. When Zig matures enough so that we can ditch any Apple tooling and still be able to successfully codesign for iOS and other, we can revisit this area. Until then however, we are stuck in having to rewrite the LINKEDIT segment at every update run of the self-hosted. FYI, the strict layout for the MachO binary apparently is (please, read this with a pinch of salt as this is inferred by me): * __TEXT segment * __DATA_CONST segment * __DATA segment * __LINKEDIT segment * dyld info (rebase, bind, weak bind, lazy bind, export) * symbol table * dynamic symbol table * string table * code signature (if expected)

2 files changed, 343 insertions(+), 570 deletions(-)

src/link/MachO.zig+343-569
......@@ -162,10 +162,6 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},
162162error_flags: File.ErrorFlags = File.ErrorFlags{},
163163
164164load_commands_dirty: bool = false,
165dyld_info_dirty: bool = false,
166
167strtab_dirty: bool = false,
168strtab_needs_relocation: bool = false,
169165
170166has_dices: bool = false,
171167has_stabs: bool = false,
......@@ -368,13 +364,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
368364 .n_desc = 0,
369365 .n_value = 0,
370366 });
367 try self.strtab.append(allocator, 0);
371368
372369 try self.populateMissingMetadata();
373 try self.writeLocalSymbol(0);
374370
375371 if (self.d_sym) |*ds| {
376372 try ds.populateMissingMetadata(allocator);
377 try ds.writeLocalSymbol(0);
378373 }
379374
380375 return self;
......@@ -553,6 +548,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
553548 .n_desc = 0,
554549 .n_value = 0,
555550 });
551 try self.strtab.append(self.base.allocator, 0);
556552 }
557553
558554 // Positional arguments to the linker such as object files and static archives.
......@@ -784,7 +780,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
784780 }
785781 }
786782 try self.writeAtoms();
787 try self.writeDices();
788783 try self.flushModule(comp);
789784 }
790785
......@@ -792,11 +787,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
792787 // Update the file with the digest. If it fails we can continue; it only
793788 // means that the next invocation will have an unnecessary cache miss.
794789 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
795 log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
790 log.debug("failed to save linking hash digest file: {s}", .{@errorName(err)});
796791 };
797792 // Again failure here only means an unnecessary cache miss.
798793 man.writeManifest() catch |err| {
799 log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)});
794 log.debug("failed to write cache manifest when linking: {s}", .{@errorName(err)});
800795 };
801796 // We hang on to this lock so that the output file path can be used without
802797 // other processes clobbering it.
......@@ -811,11 +806,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
811806 defer tracy.end();
812807
813808 try self.setEntryPoint();
814 try self.writeDyldInfoData();
815 try self.writeAllGlobalAndUndefSymbols();
816 try self.writeIndirectSymbolTable();
817 try self.writeStringTable();
818 try self.updateLinkeditSegmentSizes();
809 try self.writeLinkeditSegment();
819810
820811 if (self.d_sym) |*ds| {
821812 // Flush debug symbols bundle.
......@@ -843,9 +834,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
843834 }
844835
845836 assert(!self.load_commands_dirty);
846 assert(!self.dyld_info_dirty);
847 assert(!self.strtab_dirty);
848 assert(!self.strtab_needs_relocation);
849837
850838 if (self.requires_adhoc_codesig) {
851839 try self.writeCodeSignature(); // code signing always comes last
......@@ -1769,7 +1757,6 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
17691757 try atom.resolveRelocs(self);
17701758 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset });
17711759 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
1772 try self.writeLocalSymbol(atom.local_sym_index);
17731760}
17741761
17751762fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void {
......@@ -1830,7 +1817,7 @@ fn writeAtoms(self: *MachO) !void {
18301817pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
18311818 const local_sym_index = @intCast(u32, self.locals.items.len);
18321819 try self.locals.append(self.base.allocator, .{
1833 .n_strx = try self.makeString("got_entry"),
1820 .n_strx = try self.makeString("l_zld_got_entry"),
18341821 .n_type = macho.N_SECT,
18351822 .n_sect = 0,
18361823 .n_desc = 0,
......@@ -1866,7 +1853,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
18661853fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
18671854 const local_sym_index = @intCast(u32, self.locals.items.len);
18681855 try self.locals.append(self.base.allocator, .{
1869 .n_strx = try self.makeString("dyld_private"),
1856 .n_strx = try self.makeString("l_zld_dyld_private"),
18701857 .n_type = macho.N_SECT,
18711858 .n_sect = 0,
18721859 .n_desc = 0,
......@@ -1890,7 +1877,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
18901877 };
18911878 const local_sym_index = @intCast(u32, self.locals.items.len);
18921879 try self.locals.append(self.base.allocator, .{
1893 .n_strx = try self.makeString("stub_preamble"),
1880 .n_strx = try self.makeString("l_zld_stub_preamble"),
18941881 .n_type = macho.N_SECT,
18951882 .n_sect = 0,
18961883 .n_desc = 0,
......@@ -2023,7 +2010,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
20232010 };
20242011 const local_sym_index = @intCast(u32, self.locals.items.len);
20252012 try self.locals.append(self.base.allocator, .{
2026 .n_strx = try self.makeString("stub_in_stub_helper"),
2013 .n_strx = try self.makeString("l_zld_stub_in_stub_helper"),
20272014 .n_type = macho.N_SECT,
20282015 .n_sect = 0,
20292016 .n_desc = 0,
......@@ -2078,7 +2065,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
20782065pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {
20792066 const local_sym_index = @intCast(u32, self.locals.items.len);
20802067 try self.locals.append(self.base.allocator, .{
2081 .n_strx = try self.makeString("lazy_ptr"),
2068 .n_strx = try self.makeString("l_zld_lazy_ptr"),
20822069 .n_type = macho.N_SECT,
20832070 .n_sect = 0,
20842071 .n_desc = 0,
......@@ -2102,7 +2089,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym
21022089 .local_sym_index = lazy_binding_sym_index,
21032090 .offset = 0,
21042091 });
2105 self.dyld_info_dirty = true;
21062092 return atom;
21072093}
21082094
......@@ -2120,7 +2106,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
21202106 };
21212107 const local_sym_index = @intCast(u32, self.locals.items.len);
21222108 try self.locals.append(self.base.allocator, .{
2123 .n_strx = try self.makeString("stub"),
2109 .n_strx = try self.makeString("l_zld_stub"),
21242110 .n_type = macho.N_SECT,
21252111 .n_sect = 0,
21262112 .n_desc = 0,
......@@ -2303,7 +2289,6 @@ fn resolveSymbolsInObject(
23032289 .local_sym_index = local_sym_index,
23042290 .file = object_id,
23052291 };
2306 self.dyld_info_dirty = true;
23072292 } else if (symbolIsTentative(sym)) {
23082293 // Symbol is a tentative definition.
23092294 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
......@@ -2638,7 +2623,6 @@ fn resolveDyldStubBinder(self: *MachO) !void {
26382623 .sect = self.got_section_index.?,
26392624 };
26402625 _ = try self.allocateAtom(atom, match);
2641 self.dyld_info_dirty = true;
26422626}
26432627
26442628fn parseTextBlocks(self: *MachO) !void {
......@@ -2658,27 +2642,21 @@ fn addDataInCodeLC(self: *MachO) !void {
26582642 .datasize = 0,
26592643 },
26602644 });
2661 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
2662 const needed_size = 10 * @sizeOf(macho.data_in_code_entry);
2663 const dataoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.data_in_code_entry), null);
2664 log.debug("found data-in-code free space 0x{x} to 0x{x}", .{ dataoff, dataoff + needed_size });
2665 dice_cmd.dataoff = @intCast(u32, dataoff);
2666 dice_cmd.datasize = needed_size;
26672645 self.load_commands_dirty = true;
26682646}
26692647
26702648fn addCodeSignatureLC(self: *MachO) !void {
2671 if (self.code_signature_cmd_index == null and self.requires_adhoc_codesig) {
2672 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
2673 try self.load_commands.append(self.base.allocator, .{
2674 .LinkeditData = .{
2675 .cmd = macho.LC_CODE_SIGNATURE,
2676 .cmdsize = @sizeOf(macho.linkedit_data_command),
2677 .dataoff = 0,
2678 .datasize = 0,
2679 },
2680 });
2681 }
2649 if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;
2650 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
2651 try self.load_commands.append(self.base.allocator, .{
2652 .LinkeditData = .{
2653 .cmd = macho.LC_CODE_SIGNATURE,
2654 .cmdsize = @sizeOf(macho.linkedit_data_command),
2655 .dataoff = 0,
2656 .datasize = 0,
2657 },
2658 });
2659 self.load_commands_dirty = true;
26822660}
26832661
26842662fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {
......@@ -2697,6 +2675,7 @@ fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {
26972675 mem.set(u8, rpath_cmd.data, 0);
26982676 mem.copy(u8, rpath_cmd.data, rpath);
26992677 try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd });
2678 self.load_commands_dirty = true;
27002679 }
27012680}
27022681
......@@ -2713,6 +2692,7 @@ fn addLoadDylibLCs(self: *MachO) !void {
27132692 );
27142693 errdefer dylib_cmd.deinit(self.base.allocator);
27152694 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
2695 self.load_commands_dirty = true;
27162696 }
27172697}
27182698
......@@ -2937,7 +2917,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
29372917 };
29382918 const got_atom = try self.createGotAtom(key);
29392919 try self.got_entries_map.put(self.base.allocator, key, got_atom);
2940 self.dyld_info_dirty = true;
29412920}
29422921
29432922pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
......@@ -3138,10 +3117,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
31383117 symbol.n_type = macho.N_SECT;
31393118 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
31403119 symbol.n_desc = 0;
3141
3142 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
3143 if (self.d_sym) |*ds|
3144 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
31453120 } else {
31463121 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
31473122 defer self.base.allocator.free(decl_name);
......@@ -3168,10 +3143,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
31683143 .seg = self.data_const_segment_cmd_index.?,
31693144 .sect = self.got_section_index.?,
31703145 });
3171
3172 try self.writeLocalSymbol(decl.link.macho.local_sym_index);
3173 if (self.d_sym) |*ds|
3174 try ds.writeLocalSymbol(decl.link.macho.local_sym_index);
31753146 }
31763147
31773148 return symbol;
......@@ -3257,7 +3228,6 @@ pub fn updateDeclExports(
32573228 const name_str_index = try self.makeString(exp_name);
32583229 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
32593230 _ = self.globals.addOneAssumeCapacity();
3260 self.dyld_info_dirty = true;
32613231 break :blk @intCast(u32, self.globals.items.len - 1);
32623232 };
32633233 self.globals.items[i] = .{
......@@ -3347,7 +3317,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
33473317 const program_code_size_hint = self.base.options.program_code_size_hint;
33483318 // const program_code_size_hint = 10;
33493319 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
3350 const ideal_size = self.header_pad + program_code_size_hint + got_size_hint;
3320 const ideal_size = self.header_pad + (program_code_size_hint + got_size_hint) * 5;
33513321 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
33523322
33533323 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
......@@ -3441,7 +3411,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
34413411 if (self.data_const_segment_cmd_index == null) {
34423412 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
34433413 const address_and_offset = self.nextSegmentAddressAndOffset();
3444 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
3414 const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint * 1000;
34453415 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
34463416
34473417 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
......@@ -3482,7 +3452,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
34823452 if (self.data_segment_cmd_index == null) {
34833453 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
34843454 const address_and_offset = self.nextSegmentAddressAndOffset();
3485 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
3455 const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint * 1000;
34863456 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
34873457
34883458 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });
......@@ -3621,7 +3591,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
36213591
36223592 if (self.dyld_info_cmd_index == null) {
36233593 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
3624
36253594 try self.load_commands.append(self.base.allocator, .{
36263595 .DyldInfoOnly = .{
36273596 .cmd = macho.LC_DYLD_INFO_ONLY,
......@@ -3638,42 +3607,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
36383607 .export_size = 0,
36393608 },
36403609 });
3641
3642 // Preallocate rebase, binding, lazy binding info, and export info.
3643 const dyld = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
3644 const subsection_size = 128; // TODO this is totally random
3645 const needed_size = 4 * subsection_size;
3646 const offset = self.findFreeSpaceLinkedit(needed_size, 1, null);
3647
3648 const rebase_off = @intCast(u32, offset);
3649 log.debug("found rebase info free space 0x{x} to 0x{x}", .{ rebase_off, rebase_off + subsection_size });
3650 dyld.rebase_off = rebase_off;
3651 dyld.rebase_size = subsection_size;
3652
3653 const bind_off = rebase_off + subsection_size;
3654 log.debug("found binding info free space 0x{x} to 0x{x}", .{ bind_off, bind_off + subsection_size });
3655 dyld.bind_off = bind_off;
3656 dyld.bind_size = subsection_size;
3657
3658 const lazy_bind_off = bind_off + subsection_size;
3659 log.debug("found lazy binding info free space 0x{x} to 0x{x}", .{
3660 lazy_bind_off,
3661 lazy_bind_off + subsection_size,
3662 });
3663 dyld.lazy_bind_off = lazy_bind_off;
3664 dyld.lazy_bind_size = subsection_size;
3665
3666 const export_off = lazy_bind_off + subsection_size;
3667 log.debug("found export info free space 0x{x} to 0x{x}", .{ export_off, export_off + subsection_size });
3668 dyld.export_off = export_off;
3669 dyld.export_size = subsection_size;
3670
36713610 self.load_commands_dirty = true;
36723611 }
36733612
36743613 if (self.symtab_cmd_index == null) {
36753614 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
3676
36773615 try self.load_commands.append(self.base.allocator, .{
36783616 .Symtab = .{
36793617 .cmd = macho.LC_SYMTAB,
......@@ -3684,35 +3622,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
36843622 .strsize = 0,
36853623 },
36863624 });
3687
3688 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
3689
3690 const symtab_size = self.base.options.symbol_count_hint * @sizeOf(macho.nlist_64);
3691 const symtab_off = self.findFreeSpaceLinkedit(symtab_size, @sizeOf(macho.nlist_64), null);
3692 log.debug("found symbol table free space 0x{x} to 0x{x}", .{ symtab_off, symtab_off + symtab_size });
3693 symtab.symoff = @intCast(u32, symtab_off);
3694 symtab.nsyms = @intCast(u32, self.base.options.symbol_count_hint);
3695
3696 try self.strtab.append(self.base.allocator, 0);
3697 const strtab_size = self.strtab.items.len;
3698 const strtab_off = self.findFreeSpaceLinkedit(strtab_size, 1, symtab_off);
3699 log.debug("found string table free space 0x{x} to 0x{x}", .{ strtab_off, strtab_off + strtab_size });
3700 symtab.stroff = @intCast(u32, strtab_off);
3701 symtab.strsize = @intCast(u32, strtab_size);
3702
37033625 self.load_commands_dirty = true;
3704 self.strtab_dirty = true;
37053626 }
37063627
37073628 if (self.dysymtab_cmd_index == null) {
37083629 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);
3709
3710 // Preallocate space for indirect symbol table.
3711 const indsymtab_size = self.base.options.symbol_count_hint * @sizeOf(u64); // Each entry is just a u64.
3712 const indsymtab_off = self.findFreeSpaceLinkedit(indsymtab_size, @sizeOf(u64), null);
3713
3714 log.debug("found indirect symbol table free space 0x{x} to 0x{x}", .{ indsymtab_off, indsymtab_off + indsymtab_size });
3715
37163630 try self.load_commands.append(self.base.allocator, .{
37173631 .Dysymtab = .{
37183632 .cmd = macho.LC_DYSYMTAB,
......@@ -3729,8 +3643,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
37293643 .nmodtab = 0,
37303644 .extrefsymoff = 0,
37313645 .nextrefsyms = 0,
3732 .indirectsymoff = @intCast(u32, indsymtab_off),
3733 .nindirectsyms = @intCast(u32, self.base.options.symbol_count_hint),
3646 .indirectsymoff = 0,
3647 .nindirectsyms = 0,
37343648 .extreloff = 0,
37353649 .nextrel = 0,
37363650 .locreloff = 0,
......@@ -4084,387 +3998,7 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
40843998 };
40853999}
40864000
4087fn allocatedSizeLinkedit(self: *MachO, start: u64) u64 {
4088 assert(start > 0);
4089 var min_pos: u64 = std.math.maxInt(u64);
4090
4091 // __LINKEDIT is a weird segment where sections get their own load commands so we
4092 // special-case it.
4093 if (self.dyld_info_cmd_index) |idx| {
4094 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
4095 if (dyld_info.rebase_off > start and dyld_info.rebase_off < min_pos) min_pos = dyld_info.rebase_off;
4096 }
4097
4098 if (self.function_starts_cmd_index) |idx| {
4099 const fstart = self.load_commands.items[idx].LinkeditData;
4100 if (fstart.dataoff > start and fstart.dataoff < min_pos) min_pos = fstart.dataoff;
4101 }
4102
4103 if (self.data_in_code_cmd_index) |idx| {
4104 const dic = self.load_commands.items[idx].LinkeditData;
4105 if (dic.dataoff > start and dic.dataoff < min_pos) min_pos = dic.dataoff;
4106 }
4107
4108 if (self.dysymtab_cmd_index) |idx| {
4109 const dysymtab = self.load_commands.items[idx].Dysymtab;
4110 if (dysymtab.indirectsymoff > start and dysymtab.indirectsymoff < min_pos) min_pos = dysymtab.indirectsymoff;
4111 // TODO Handle more dynamic symbol table sections.
4112 }
4113
4114 if (self.symtab_cmd_index) |idx| {
4115 const symtab = self.load_commands.items[idx].Symtab;
4116 if (symtab.symoff > start and symtab.symoff < min_pos) min_pos = symtab.symoff;
4117 if (symtab.stroff > start and symtab.stroff < min_pos) min_pos = symtab.stroff;
4118 }
4119
4120 return min_pos - start;
4121}
4122inline fn checkForCollision(start: u64, end: u64, off: u64, size: u64) ?u64 {
4123 const increased_size = padToIdeal(size);
4124 const test_end = off + increased_size;
4125 if (end > off and start < test_end) {
4126 return test_end;
4127 }
4128 return null;
4129}
4130
4131fn detectAllocCollisionLinkedit(self: *MachO, start: u64, size: u64) ?u64 {
4132 const end = start + padToIdeal(size);
4133
4134 // __LINKEDIT is a weird segment where sections get their own load commands so we
4135 // special-case it.
4136 if (self.dyld_info_cmd_index) |idx| {
4137 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
4138 const offset = dyld_info.rebase_off;
4139 const actual_size = dyld_info.export_off + dyld_info.export_size - offset;
4140 const increased_size = padToIdeal(actual_size);
4141 const test_end = offset + increased_size;
4142 if (end > offset and start < test_end) {
4143 return test_end;
4144 }
4145 }
4146
4147 if (self.function_starts_cmd_index) |idx| outer: {
4148 if (self.load_commands.items.len == idx) break :outer;
4149 const fstart = self.load_commands.items[idx].LinkeditData;
4150 if (checkForCollision(start, end, fstart.dataoff, fstart.datasize)) |pos| {
4151 return pos;
4152 }
4153 }
4154
4155 if (self.data_in_code_cmd_index) |idx| outer: {
4156 if (self.load_commands.items.len == idx) break :outer;
4157 const dic = self.load_commands.items[idx].LinkeditData;
4158 if (checkForCollision(start, end, dic.dataoff, dic.datasize)) |pos| {
4159 return pos;
4160 }
4161 }
4162
4163 if (self.dysymtab_cmd_index) |idx| outer: {
4164 if (self.load_commands.items.len == idx) break :outer;
4165 const dysymtab = self.load_commands.items[idx].Dysymtab;
4166 // Indirect symbol table
4167 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
4168 if (checkForCollision(start, end, dysymtab.indirectsymoff, nindirectsize)) |pos| {
4169 return pos;
4170 }
4171 // TODO Handle more dynamic symbol table sections.
4172 }
4173
4174 if (self.symtab_cmd_index) |idx| outer: {
4175 if (self.load_commands.items.len == idx) break :outer;
4176 const symtab = self.load_commands.items[idx].Symtab;
4177 // Symbol table
4178 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
4179 if (checkForCollision(start, end, symtab.symoff, symsize)) |pos| {
4180 return pos;
4181 }
4182 // String table
4183 if (checkForCollision(start, end, symtab.stroff, symtab.strsize)) |pos| {
4184 return pos;
4185 }
4186 }
4187
4188 return null;
4189}
4190
4191fn findFreeSpaceLinkedit(self: *MachO, object_size: u64, min_alignment: u16, start: ?u64) u64 {
4192 const linkedit = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4193 var st: u64 = start orelse linkedit.inner.fileoff;
4194 while (self.detectAllocCollisionLinkedit(st, object_size)) |item_end| {
4195 st = mem.alignForwardGeneric(u64, item_end, min_alignment);
4196 }
4197 return st;
4198}
4199
4200fn relocateSymbolTable(self: *MachO) !void {
4201 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4202 const nlocals = self.locals.items.len;
4203 const nglobals = self.globals.items.len;
4204 const nundefs = self.undefs.items.len;
4205 const nsyms = nlocals + nglobals + nundefs;
4206
4207 if (symtab.nsyms < nsyms) {
4208 const needed_size = nsyms * @sizeOf(macho.nlist_64);
4209 if (needed_size > self.allocatedSizeLinkedit(symtab.symoff)) {
4210 // Move the entire symbol table to a new location
4211 const new_symoff = self.findFreeSpaceLinkedit(needed_size, @alignOf(macho.nlist_64), null);
4212 const existing_size = symtab.nsyms * @sizeOf(macho.nlist_64);
4213
4214 log.debug("relocating symbol table from 0x{x}-0x{x} to 0x{x}-0x{x}", .{
4215 symtab.symoff,
4216 symtab.symoff + existing_size,
4217 new_symoff,
4218 new_symoff + existing_size,
4219 });
4220
4221 // TODO copyRangeAll doesn't seem to extend the file beyond its allocated size
4222 try self.base.file.?.pwriteAll(&[_]u8{0}, new_symoff + existing_size - 1);
4223 const amt = try self.base.file.?.copyRangeAll(
4224 symtab.symoff,
4225 self.base.file.?,
4226 new_symoff,
4227 existing_size,
4228 );
4229 if (amt != existing_size) return error.InputOutput;
4230 symtab.symoff = @intCast(u32, new_symoff);
4231 self.strtab_needs_relocation = true;
4232 }
4233 symtab.nsyms = @intCast(u32, nsyms);
4234 self.load_commands_dirty = true;
4235 }
4236}
4237
4238fn writeLocalSymbol(self: *MachO, index: usize) !void {
4239 const tracy = trace(@src());
4240 defer tracy.end();
4241 try self.relocateSymbolTable();
4242 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4243 const off = symtab.symoff + @sizeOf(macho.nlist_64) * index;
4244 const sym = self.locals.items[index];
4245 log.debug("writing local symbol {s}: {} at 0x{x}", .{ self.getString(sym.n_strx), sym, off });
4246 try self.base.file.?.pwriteAll(mem.asBytes(&sym), off);
4247}
4248
4249fn writeAllGlobalAndUndefSymbols(self: *MachO) !void {
4250 const tracy = trace(@src());
4251 defer tracy.end();
4252
4253 try self.relocateSymbolTable();
4254 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4255 const nlocals = self.locals.items.len;
4256 const nglobals = self.globals.items.len;
4257 const nundefs = self.undefs.items.len;
4258
4259 const locals_off = symtab.symoff;
4260 const locals_size = nlocals * @sizeOf(macho.nlist_64);
4261
4262 const globals_off = locals_off + locals_size;
4263 const globals_size = nglobals * @sizeOf(macho.nlist_64);
4264 log.debug("writing global symbols from 0x{x} to 0x{x}", .{ globals_off, globals_size + globals_off });
4265 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), globals_off);
4266
4267 const undefs_off = globals_off + globals_size;
4268 const undefs_size = nundefs * @sizeOf(macho.nlist_64);
4269 log.debug("writing undef symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
4270 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off);
4271
4272 // Update dynamic symbol table.
4273 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
4274 dysymtab.nlocalsym = @intCast(u32, nlocals);
4275 dysymtab.iextdefsym = @intCast(u32, nlocals);
4276 dysymtab.nextdefsym = @intCast(u32, nglobals);
4277 dysymtab.iundefsym = @intCast(u32, nlocals + nglobals);
4278 dysymtab.nundefsym = @intCast(u32, nundefs);
4279 self.load_commands_dirty = true;
4280}
4281
4282fn writeIndirectSymbolTable(self: *MachO) !void {
4283 // TODO figure out a way not to rewrite the table every time if
4284 // no new undefs are not added.
4285 const tracy = trace(@src());
4286 defer tracy.end();
4287
4288 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4289 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
4290 const data_const_seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4291 const got = &data_const_seg.sections.items[self.got_section_index.?];
4292 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4293 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
4294 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
4295
4296 const nstubs = @intCast(u32, self.stubs_map.keys().len);
4297 const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
4298 const allocated_size = self.allocatedSizeLinkedit(dysymtab.indirectsymoff);
4299 const nindirectsyms = nstubs * 2 + ngot_entries;
4300 const needed_size = @intCast(u32, nindirectsyms * @sizeOf(u32));
4301
4302 if (needed_size > allocated_size) {
4303 dysymtab.nindirectsyms = 0;
4304 dysymtab.indirectsymoff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, @sizeOf(u32), null));
4305 }
4306 dysymtab.nindirectsyms = nindirectsyms;
4307 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
4308 dysymtab.indirectsymoff,
4309 dysymtab.indirectsymoff + needed_size,
4310 });
4311
4312 var buf = try self.base.allocator.alloc(u8, needed_size);
4313 defer self.base.allocator.free(buf);
4314 var stream = std.io.fixedBufferStream(buf);
4315 var writer = stream.writer();
4316
4317 stubs.reserved1 = 0;
4318 for (self.stubs_map.keys()) |key| {
4319 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
4320 }
4321
4322 got.reserved1 = nstubs;
4323 for (self.got_entries_map.keys()) |key| {
4324 switch (key.where) {
4325 .undef => {
4326 try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
4327 },
4328 .local => {
4329 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
4330 },
4331 }
4332 }
4333
4334 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
4335 for (self.stubs_map.keys()) |key| {
4336 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
4337 }
4338
4339 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
4340 self.load_commands_dirty = true;
4341}
4342
4343fn writeDices(self: *MachO) !void {
4344 if (!self.has_dices) return;
4345
4346 const tracy = trace(@src());
4347 defer tracy.end();
4348
4349 var buf = std.ArrayList(u8).init(self.base.allocator);
4350 defer buf.deinit();
4351
4352 var block: *TextBlock = self.blocks.get(.{
4353 .seg = self.text_segment_cmd_index orelse return,
4354 .sect = self.text_section_index orelse return,
4355 }) orelse return;
4356
4357 while (block.prev) |prev| {
4358 block = prev;
4359 }
4360
4361 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4362 const text_sect = text_seg.sections.items[self.text_section_index.?];
4363
4364 while (true) {
4365 if (block.dices.items.len > 0) {
4366 const sym = self.locals.items[block.local_sym_index];
4367 const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset);
4368
4369 try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
4370 for (block.dices.items) |dice| {
4371 const rebased_dice = macho.data_in_code_entry{
4372 .offset = base_off + dice.offset,
4373 .length = dice.length,
4374 .kind = dice.kind,
4375 };
4376 buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
4377 }
4378 }
4379
4380 if (block.next) |next| {
4381 block = next;
4382 } else break;
4383 }
4384
4385 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
4386 const allocated_size = self.allocatedSizeLinkedit(dice_cmd.dataoff);
4387 const needed_size = @intCast(u32, buf.items.len);
4388
4389 if (needed_size > allocated_size) {
4390 dice_cmd.datasize = 0;
4391 dice_cmd.dataoff = @intCast(u32, self.findFreeSpaceLinkedit(
4392 needed_size,
4393 @alignOf(macho.data_in_code_entry),
4394 dice_cmd.dataoff,
4395 ));
4396 }
4397 dice_cmd.datasize = needed_size;
4398 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
4399 dice_cmd.dataoff,
4400 dice_cmd.dataoff + dice_cmd.datasize,
4401 });
4402
4403 try self.base.file.?.pwriteAll(buf.items, dice_cmd.dataoff);
4404 self.load_commands_dirty = true;
4405}
4406
4407fn writeCodeSignaturePadding(self: *MachO) !void {
4408 // TODO figure out how not to rewrite padding every single time.
4409 const tracy = trace(@src());
4410 defer tracy.end();
4411
4412 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4413 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
4414 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
4415 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
4416 self.base.options.emit.?.sub_path,
4417 fileoff,
4418 self.page_size,
4419 );
4420 code_sig_cmd.dataoff = @intCast(u32, fileoff);
4421 code_sig_cmd.datasize = needed_size;
4422
4423 // Advance size of __LINKEDIT segment
4424 linkedit_segment.inner.filesize += needed_size;
4425 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
4426 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
4427 }
4428 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
4429 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
4430 // except for code signature data.
4431 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
4432 self.load_commands_dirty = true;
4433}
4434
4435fn writeCodeSignature(self: *MachO) !void {
4436 const tracy = trace(@src());
4437 defer tracy.end();
4438
4439 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4440 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
4441
4442 var code_sig: CodeSignature = .{};
4443 defer code_sig.deinit(self.base.allocator);
4444
4445 try code_sig.calcAdhocSignature(
4446 self.base.allocator,
4447 self.base.file.?,
4448 self.base.options.emit.?.sub_path,
4449 text_segment.inner,
4450 code_sig_cmd,
4451 self.base.options.output_mode,
4452 self.page_size,
4453 );
4454
4455 var buffer = try self.base.allocator.alloc(u8, code_sig.size());
4456 defer self.base.allocator.free(buffer);
4457 var stream = std.io.fixedBufferStream(buffer);
4458 try code_sig.write(stream.writer());
4459
4460 log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
4461
4462 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
4463}
4464
44654001fn writeDyldInfoData(self: *MachO) !void {
4466 if (!self.dyld_info_dirty) return;
4467
44684002 const tracy = trace(@src());
44694003 defer tracy.end();
44704004
......@@ -4528,7 +4062,7 @@ fn writeDyldInfoData(self: *MachO) !void {
45284062
45294063 {
45304064 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.
4531 log.debug("writing export trie", .{});
4065 log.debug("generating export trie", .{});
45324066 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
45334067 const base_address = text_segment.inner.vmaddr;
45344068
......@@ -4546,28 +4080,30 @@ fn writeDyldInfoData(self: *MachO) !void {
45464080 try trie.finalize(self.base.allocator);
45474081 }
45484082
4083 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
45494084 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
4550 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);
4551 const rebase_size = @intCast(u32, try bind.rebaseInfoSize(rebase_pointers.items));
4552 const bind_size = @intCast(u32, try bind.bindInfoSize(bind_pointers.items));
4553 const lazy_bind_size = @intCast(u32, try bind.lazyBindInfoSize(lazy_bind_pointers.items));
4554 const export_size = @intCast(u32, trie.size);
4555 const total_size = rebase_size + bind_size + lazy_bind_size + export_size;
4556 const needed_size = mem.alignForwardGeneric(u64, total_size, @alignOf(u64));
4085 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
4086 const bind_size = try bind.bindInfoSize(bind_pointers.items);
4087 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
4088 const export_size = trie.size;
45574089
4558 if (needed_size > allocated_size) {
4559 dyld_info.rebase_off = 0;
4560 dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));
4561 }
4090 dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
4091 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64)));
4092 seg.inner.filesize += dyld_info.rebase_size;
45624093
4563 dyld_info.rebase_size = rebase_size;
45644094 dyld_info.bind_off = dyld_info.rebase_off + dyld_info.rebase_size;
4565 dyld_info.bind_size = bind_size;
4095 dyld_info.bind_size = @intCast(u32, mem.alignForwardGeneric(u64, bind_size, @alignOf(u64)));
4096 seg.inner.filesize += dyld_info.bind_size;
4097
45664098 dyld_info.lazy_bind_off = dyld_info.bind_off + dyld_info.bind_size;
4567 dyld_info.lazy_bind_size = lazy_bind_size;
4099 dyld_info.lazy_bind_size = @intCast(u32, mem.alignForwardGeneric(u64, lazy_bind_size, @alignOf(u64)));
4100 seg.inner.filesize += dyld_info.lazy_bind_size;
4101
45684102 dyld_info.export_off = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size;
4569 dyld_info.export_size = export_size;
4103 dyld_info.export_size = @intCast(u32, mem.alignForwardGeneric(u64, export_size, @alignOf(u64)));
4104 seg.inner.filesize += dyld_info.export_size;
45704105
4106 const needed_size = dyld_info.rebase_size + dyld_info.bind_size + dyld_info.lazy_bind_size + dyld_info.export_size;
45714107 var buffer = try self.base.allocator.alloc(u8, needed_size);
45724108 defer self.base.allocator.free(buffer);
45734109 mem.set(u8, buffer, 0);
......@@ -4576,16 +4112,26 @@ fn writeDyldInfoData(self: *MachO) !void {
45764112 const writer = stream.writer();
45774113
45784114 try bind.writeRebaseInfo(rebase_pointers.items, writer);
4115 try stream.seekBy(@intCast(i64, dyld_info.rebase_size) - @intCast(i64, rebase_size));
4116
45794117 try bind.writeBindInfo(bind_pointers.items, writer);
4118 try stream.seekBy(@intCast(i64, dyld_info.bind_size) - @intCast(i64, bind_size));
4119
45804120 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);
4121 try stream.seekBy(@intCast(i64, dyld_info.lazy_bind_size) - @intCast(i64, lazy_bind_size));
4122
45814123 _ = try trie.write(writer);
45824124
4583 log.debug("writing dyld info from 0x{x} to 0x{x}", .{ dyld_info.rebase_off, dyld_info.rebase_off + needed_size });
4125 log.debug("writing dyld info from 0x{x} to 0x{x}", .{
4126 dyld_info.rebase_off,
4127 dyld_info.rebase_off + needed_size,
4128 });
45844129
45854130 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);
4586 try self.populateLazyBindOffsetsInStubHelper(buffer[rebase_size + bind_size ..][0..lazy_bind_size]);
4131 try self.populateLazyBindOffsetsInStubHelper(
4132 buffer[dyld_info.rebase_size + dyld_info.bind_size ..][0..dyld_info.lazy_bind_size],
4133 );
45874134 self.load_commands_dirty = true;
4588 self.dyld_info_dirty = false;
45894135}
45904136
45914137fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
......@@ -4661,7 +4207,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
46614207 const sym = self.locals.items[atom.local_sym_index];
46624208 const file_offset = sect.offset + sym.n_value - sect.addr + stub_offset;
46634209 mem.writeIntLittle(u32, &buf, bind_offset);
4664 log.debug("writing lazy binding offset in stub helper of 0x{x} for symbol {s} at offset 0x{x}", .{
4210 log.debug("writing lazy bind offset in stub helper of 0x{x} for symbol {s} at offset 0x{x}", .{
46654211 bind_offset,
46664212 self.getString(sym.n_strx),
46674213 file_offset,
......@@ -4674,79 +4220,307 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
46744220 }
46754221}
46764222
4677fn writeStringTable(self: *MachO) !void {
4678 if (!self.strtab_dirty) return;
4223fn writeDices(self: *MachO) !void {
4224 if (!self.has_dices) return;
46794225
46804226 const tracy = trace(@src());
46814227 defer tracy.end();
46824228
4229 var buf = std.ArrayList(u8).init(self.base.allocator);
4230 defer buf.deinit();
4231
4232 var block: *TextBlock = self.blocks.get(.{
4233 .seg = self.text_segment_cmd_index orelse return,
4234 .sect = self.text_section_index orelse return,
4235 }) orelse return;
4236
4237 while (block.prev) |prev| {
4238 block = prev;
4239 }
4240
4241 const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4242 const text_sect = text_seg.sections.items[self.text_section_index.?];
4243
4244 while (true) {
4245 if (block.dices.items.len > 0) {
4246 const sym = self.locals.items[block.local_sym_index];
4247 const base_off = try math.cast(u32, sym.n_value - text_sect.addr + text_sect.offset);
4248
4249 try buf.ensureUnusedCapacity(block.dices.items.len * @sizeOf(macho.data_in_code_entry));
4250 for (block.dices.items) |dice| {
4251 const rebased_dice = macho.data_in_code_entry{
4252 .offset = base_off + dice.offset,
4253 .length = dice.length,
4254 .kind = dice.kind,
4255 };
4256 buf.appendSliceAssumeCapacity(mem.asBytes(&rebased_dice));
4257 }
4258 }
4259
4260 if (block.next) |next| {
4261 block = next;
4262 } else break;
4263 }
4264
4265 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4266 const dice_cmd = &self.load_commands.items[self.data_in_code_cmd_index.?].LinkeditData;
4267 const needed_size = @intCast(u32, buf.items.len);
4268
4269 dice_cmd.dataoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
4270 dice_cmd.datasize = needed_size;
4271 seg.inner.filesize += needed_size;
4272
4273 log.debug("writing data-in-code from 0x{x} to 0x{x}", .{
4274 dice_cmd.dataoff,
4275 dice_cmd.dataoff + dice_cmd.datasize,
4276 });
4277
4278 try self.base.file.?.pwriteAll(buf.items, dice_cmd.dataoff);
4279 self.load_commands_dirty = true;
4280}
4281
4282fn writeSymbolTable(self: *MachO) !void {
4283 const tracy = trace(@src());
4284 defer tracy.end();
4285
4286 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
46834287 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4684 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);
4685 const needed_size = mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64));
4686
4687 if (needed_size > allocated_size or self.strtab_needs_relocation) {
4688 symtab.strsize = 0;
4689 symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, symtab.symoff));
4690 self.strtab_needs_relocation = false;
4691 }
4692 symtab.strsize = @intCast(u32, needed_size);
4693 log.debug("writing string table from 0x{x} to 0x{x}", .{
4694 symtab.stroff,
4695 symtab.stroff + symtab.strsize,
4288 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
4289
4290 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
4291 defer locals.deinit();
4292 try locals.appendSlice(self.locals.items);
4293
4294 if (self.has_stabs) {
4295 for (self.objects.items) |object| {
4296 if (object.debug_info == null) continue;
4297
4298 // Open scope
4299 try locals.ensureUnusedCapacity(3);
4300 locals.appendAssumeCapacity(.{
4301 .n_strx = try self.makeString(object.tu_comp_dir.?),
4302 .n_type = macho.N_SO,
4303 .n_sect = 0,
4304 .n_desc = 0,
4305 .n_value = 0,
4306 });
4307 locals.appendAssumeCapacity(.{
4308 .n_strx = try self.makeString(object.tu_name.?),
4309 .n_type = macho.N_SO,
4310 .n_sect = 0,
4311 .n_desc = 0,
4312 .n_value = 0,
4313 });
4314 locals.appendAssumeCapacity(.{
4315 .n_strx = try self.makeString(object.name),
4316 .n_type = macho.N_OSO,
4317 .n_sect = 0,
4318 .n_desc = 1,
4319 .n_value = object.mtime orelse 0,
4320 });
4321
4322 for (object.text_blocks.items) |block| {
4323 if (block.stab) |stab| {
4324 const nlists = try stab.asNlists(block.local_sym_index, self);
4325 defer self.base.allocator.free(nlists);
4326 try locals.appendSlice(nlists);
4327 } else {
4328 for (block.contained.items) |sym_at_off| {
4329 const stab = sym_at_off.stab orelse continue;
4330 const nlists = try stab.asNlists(sym_at_off.local_sym_index, self);
4331 defer self.base.allocator.free(nlists);
4332 try locals.appendSlice(nlists);
4333 }
4334 }
4335 }
4336
4337 // Close scope
4338 try locals.append(.{
4339 .n_strx = 0,
4340 .n_type = macho.N_SO,
4341 .n_sect = 0,
4342 .n_desc = 0,
4343 .n_value = 0,
4344 });
4345 }
4346 }
4347
4348 const nlocals = locals.items.len;
4349 const nexports = self.globals.items.len;
4350 const nundefs = self.undefs.items.len;
4351
4352 const locals_off = symtab.symoff;
4353 const locals_size = nlocals * @sizeOf(macho.nlist_64);
4354 log.debug("writing local symbols from 0x{x} to 0x{x}", .{ locals_off, locals_size + locals_off });
4355 try self.base.file.?.pwriteAll(mem.sliceAsBytes(locals.items), locals_off);
4356
4357 const exports_off = locals_off + locals_size;
4358 const exports_size = nexports * @sizeOf(macho.nlist_64);
4359 log.debug("writing exported symbols from 0x{x} to 0x{x}", .{ exports_off, exports_size + exports_off });
4360 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.globals.items), exports_off);
4361
4362 const undefs_off = exports_off + exports_size;
4363 const undefs_size = nundefs * @sizeOf(macho.nlist_64);
4364 log.debug("writing undefined symbols from 0x{x} to 0x{x}", .{ undefs_off, undefs_size + undefs_off });
4365 try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.undefs.items), undefs_off);
4366
4367 symtab.nsyms = @intCast(u32, nlocals + nexports + nundefs);
4368 seg.inner.filesize += locals_size + exports_size + undefs_size;
4369
4370 // Update dynamic symbol table.
4371 const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
4372 dysymtab.nlocalsym = @intCast(u32, nlocals);
4373 dysymtab.iextdefsym = dysymtab.nlocalsym;
4374 dysymtab.nextdefsym = @intCast(u32, nexports);
4375 dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym;
4376 dysymtab.nundefsym = @intCast(u32, nundefs);
4377
4378 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4379 const stubs = &text_segment.sections.items[self.stubs_section_index.?];
4380 const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].Segment;
4381 const got = &data_const_segment.sections.items[self.got_section_index.?];
4382 const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].Segment;
4383 const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?];
4384
4385 const nstubs = @intCast(u32, self.stubs_map.keys().len);
4386 const ngot_entries = @intCast(u32, self.got_entries_map.keys().len);
4387
4388 dysymtab.indirectsymoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
4389 dysymtab.nindirectsyms = nstubs * 2 + ngot_entries;
4390
4391 const needed_size = dysymtab.nindirectsyms * @sizeOf(u32);
4392 seg.inner.filesize += needed_size;
4393
4394 log.debug("writing indirect symbol table from 0x{x} to 0x{x}", .{
4395 dysymtab.indirectsymoff,
4396 dysymtab.indirectsymoff + needed_size,
46964397 });
46974398
4399 var buf = try self.base.allocator.alloc(u8, needed_size);
4400 defer self.base.allocator.free(buf);
4401
4402 var stream = std.io.fixedBufferStream(buf);
4403 var writer = stream.writer();
4404
4405 stubs.reserved1 = 0;
4406 for (self.stubs_map.keys()) |key| {
4407 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
4408 }
4409
4410 got.reserved1 = nstubs;
4411 for (self.got_entries_map.keys()) |key| {
4412 switch (key.where) {
4413 .undef => {
4414 try writer.writeIntLittle(u32, dysymtab.iundefsym + key.where_index);
4415 },
4416 .local => {
4417 try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL);
4418 },
4419 }
4420 }
4421
4422 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
4423 for (self.stubs_map.keys()) |key| {
4424 try writer.writeIntLittle(u32, dysymtab.iundefsym + key);
4425 }
4426
4427 try self.base.file.?.pwriteAll(buf, dysymtab.indirectsymoff);
4428 self.load_commands_dirty = true;
4429}
4430
4431fn writeStringTable(self: *MachO) !void {
4432 const tracy = trace(@src());
4433 defer tracy.end();
4434
4435 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4436 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4437 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
4438 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
4439 seg.inner.filesize += symtab.strsize;
4440
4441 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
4442
46984443 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);
4444
4445 if (symtab.strsize > self.strtab.items.len) {
4446 // This is potentially the last section, so we need to pad it out.
4447 try self.base.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
4448 }
46994449 self.load_commands_dirty = true;
4700 self.strtab_dirty = false;
47014450}
47024451
4703fn updateLinkeditSegmentSizes(self: *MachO) !void {
4704 if (!self.load_commands_dirty) return;
4452fn writeLinkeditSegment(self: *MachO) !void {
4453 const tracy = trace(@src());
4454 defer tracy.end();
4455
4456 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4457 seg.inner.filesize = 0;
4458
4459 try self.writeDyldInfoData();
4460 try self.writeDices();
4461 try self.writeSymbolTable();
4462 try self.writeStringTable();
4463
4464 seg.inner.vmsize = mem.alignForwardGeneric(u64, seg.inner.filesize, self.page_size);
4465}
47054466
4467fn writeCodeSignaturePadding(self: *MachO) !void {
47064468 const tracy = trace(@src());
47074469 defer tracy.end();
47084470
4709 // Now, we are in position to update __LINKEDIT segment sizes.
4710 // TODO Add checkpointing so that we don't have to do this every single time.
47114471 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4712 var final_offset = linkedit_segment.inner.fileoff;
4713
4714 if (self.dyld_info_cmd_index) |idx| {
4715 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;
4716 final_offset = std.math.max(final_offset, dyld_info.rebase_off + dyld_info.rebase_size);
4717 final_offset = std.math.max(final_offset, dyld_info.bind_off + dyld_info.bind_size);
4718 final_offset = std.math.max(final_offset, dyld_info.weak_bind_off + dyld_info.weak_bind_size);
4719 final_offset = std.math.max(final_offset, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size);
4720 final_offset = std.math.max(final_offset, dyld_info.export_off + dyld_info.export_size);
4721 }
4722 if (self.function_starts_cmd_index) |idx| {
4723 const fstart = self.load_commands.items[idx].LinkeditData;
4724 final_offset = std.math.max(final_offset, fstart.dataoff + fstart.datasize);
4725 }
4726 if (self.data_in_code_cmd_index) |idx| {
4727 const dic = self.load_commands.items[idx].LinkeditData;
4728 final_offset = std.math.max(final_offset, dic.dataoff + dic.datasize);
4729 }
4730 if (self.dysymtab_cmd_index) |idx| {
4731 const dysymtab = self.load_commands.items[idx].Dysymtab;
4732 const nindirectsize = dysymtab.nindirectsyms * @sizeOf(u32);
4733 final_offset = std.math.max(final_offset, dysymtab.indirectsymoff + nindirectsize);
4734 // TODO Handle more dynamic symbol table sections.
4735 }
4736 if (self.symtab_cmd_index) |idx| {
4737 const symtab = self.load_commands.items[idx].Symtab;
4738 const symsize = symtab.nsyms * @sizeOf(macho.nlist_64);
4739 final_offset = std.math.max(final_offset, symtab.symoff + symsize);
4740 final_offset = std.math.max(final_offset, symtab.stroff + symtab.strsize);
4741 }
4742
4743 const filesize = final_offset - linkedit_segment.inner.fileoff;
4744 linkedit_segment.inner.filesize = filesize;
4745 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, filesize, self.page_size);
4746 try self.base.file.?.pwriteAll(&[_]u8{0}, final_offset);
4472 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
4473 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
4474 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
4475 self.base.options.emit.?.sub_path,
4476 fileoff,
4477 self.page_size,
4478 );
4479 code_sig_cmd.dataoff = @intCast(u32, fileoff);
4480 code_sig_cmd.datasize = needed_size;
4481
4482 // Advance size of __LINKEDIT segment
4483 linkedit_segment.inner.filesize += needed_size;
4484 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
4485 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
4486 }
4487 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
4488 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
4489 // except for code signature data.
4490 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
47474491 self.load_commands_dirty = true;
47484492}
47494493
4494fn writeCodeSignature(self: *MachO) !void {
4495 const tracy = trace(@src());
4496 defer tracy.end();
4497
4498 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4499 const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
4500
4501 var code_sig: CodeSignature = .{};
4502 defer code_sig.deinit(self.base.allocator);
4503
4504 try code_sig.calcAdhocSignature(
4505 self.base.allocator,
4506 self.base.file.?,
4507 self.base.options.emit.?.sub_path,
4508 text_segment.inner,
4509 code_sig_cmd,
4510 self.base.options.output_mode,
4511 self.page_size,
4512 );
4513
4514 var buffer = try self.base.allocator.alloc(u8, code_sig.size());
4515 defer self.base.allocator.free(buffer);
4516 var stream = std.io.fixedBufferStream(buffer);
4517 try code_sig.write(stream.writer());
4518
4519 log.debug("writing code signature from 0x{x} to 0x{x}", .{ code_sig_cmd.dataoff, code_sig_cmd.dataoff + buffer.len });
4520
4521 try self.base.file.?.pwriteAll(buffer, code_sig_cmd.dataoff);
4522}
4523
47504524/// Writes all load commands and section headers.
47514525fn writeLoadCommands(self: *MachO) !void {
47524526 if (!self.load_commands_dirty) return;
src/link/MachO/TextBlock.zig-1
......@@ -844,7 +844,6 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
844844 .sect = context.macho_file.got_section_index.?,
845845 };
846846 _ = try context.macho_file.allocateAtom(atom, match);
847 context.macho_file.dyld_info_dirty = true;
848847 } else if (parsed_rel.payload == .unsigned) {
849848 switch (parsed_rel.where) {
850849 .undef => {