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) = .{},...@@ -162,10 +162,6 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{},
162error_flags: File.ErrorFlags = File.ErrorFlags{},162error_flags: File.ErrorFlags = File.ErrorFlags{},
163163
164load_commands_dirty: bool = false,164load_commands_dirty: bool = false,
165dyld_info_dirty: bool = false,
166
167strtab_dirty: bool = false,
168strtab_needs_relocation: bool = false,
169165
170has_dices: bool = false,166has_dices: bool = false,
171has_stabs: bool = false,167has_stabs: bool = false,
...@@ -368,13 +364,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -368,13 +364,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
368 .n_desc = 0,364 .n_desc = 0,
369 .n_value = 0,365 .n_value = 0,
370 });366 });
367 try self.strtab.append(allocator, 0);
371368
372 try self.populateMissingMetadata();369 try self.populateMissingMetadata();
373 try self.writeLocalSymbol(0);
374370
375 if (self.d_sym) |*ds| {371 if (self.d_sym) |*ds| {
376 try ds.populateMissingMetadata(allocator);372 try ds.populateMissingMetadata(allocator);
377 try ds.writeLocalSymbol(0);
378 }373 }
379374
380 return self;375 return self;
...@@ -553,6 +548,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -553,6 +548,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
553 .n_desc = 0,548 .n_desc = 0,
554 .n_value = 0,549 .n_value = 0,
555 });550 });
551 try self.strtab.append(self.base.allocator, 0);
556 }552 }
557553
558 // Positional arguments to the linker such as object files and static archives.554 // Positional arguments to the linker such as object files and static archives.
...@@ -784,7 +780,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -784,7 +780,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
784 }780 }
785 }781 }
786 try self.writeAtoms();782 try self.writeAtoms();
787 try self.writeDices();
788 try self.flushModule(comp);783 try self.flushModule(comp);
789 }784 }
790785
...@@ -792,11 +787,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -792,11 +787,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
792 // Update the file with the digest. If it fails we can continue; it only787 // Update the file with the digest. If it fails we can continue; it only
793 // means that the next invocation will have an unnecessary cache miss.788 // means that the next invocation will have an unnecessary cache miss.
794 Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {789 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)});
796 };791 };
797 // Again failure here only means an unnecessary cache miss.792 // Again failure here only means an unnecessary cache miss.
798 man.writeManifest() catch |err| {793 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)});
800 };795 };
801 // We hang on to this lock so that the output file path can be used without796 // We hang on to this lock so that the output file path can be used without
802 // other processes clobbering it.797 // other processes clobbering it.
...@@ -811,11 +806,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -811,11 +806,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
811 defer tracy.end();806 defer tracy.end();
812807
813 try self.setEntryPoint();808 try self.setEntryPoint();
814 try self.writeDyldInfoData();809 try self.writeLinkeditSegment();
815 try self.writeAllGlobalAndUndefSymbols();
816 try self.writeIndirectSymbolTable();
817 try self.writeStringTable();
818 try self.updateLinkeditSegmentSizes();
819810
820 if (self.d_sym) |*ds| {811 if (self.d_sym) |*ds| {
821 // Flush debug symbols bundle.812 // Flush debug symbols bundle.
...@@ -843,9 +834,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -843,9 +834,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
843 }834 }
844835
845 assert(!self.load_commands_dirty);836 assert(!self.load_commands_dirty);
846 assert(!self.dyld_info_dirty);
847 assert(!self.strtab_dirty);
848 assert(!self.strtab_needs_relocation);
849837
850 if (self.requires_adhoc_codesig) {838 if (self.requires_adhoc_codesig) {
851 try self.writeCodeSignature(); // code signing always comes last839 try self.writeCodeSignature(); // code signing always comes last
...@@ -1769,7 +1757,6 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {...@@ -1769,7 +1757,6 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void {
1769 try atom.resolveRelocs(self);1757 try atom.resolveRelocs(self);
1770 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset });1758 log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset });
1771 try self.base.file.?.pwriteAll(atom.code.items, file_offset);1759 try self.base.file.?.pwriteAll(atom.code.items, file_offset);
1772 try self.writeLocalSymbol(atom.local_sym_index);
1773}1760}
17741761
1775fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void {1762fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void {
...@@ -1830,7 +1817,7 @@ fn writeAtoms(self: *MachO) !void {...@@ -1830,7 +1817,7 @@ fn writeAtoms(self: *MachO) !void {
1830pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {1817pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
1831 const local_sym_index = @intCast(u32, self.locals.items.len);1818 const local_sym_index = @intCast(u32, self.locals.items.len);
1832 try self.locals.append(self.base.allocator, .{1819 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"),
1834 .n_type = macho.N_SECT,1821 .n_type = macho.N_SECT,
1835 .n_sect = 0,1822 .n_sect = 0,
1836 .n_desc = 0,1823 .n_desc = 0,
...@@ -1866,7 +1853,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {...@@ -1866,7 +1853,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock {
1866fn createDyldPrivateAtom(self: *MachO) !*TextBlock {1853fn createDyldPrivateAtom(self: *MachO) !*TextBlock {
1867 const local_sym_index = @intCast(u32, self.locals.items.len);1854 const local_sym_index = @intCast(u32, self.locals.items.len);
1868 try self.locals.append(self.base.allocator, .{1855 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"),
1870 .n_type = macho.N_SECT,1857 .n_type = macho.N_SECT,
1871 .n_sect = 0,1858 .n_sect = 0,
1872 .n_desc = 0,1859 .n_desc = 0,
...@@ -1890,7 +1877,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {...@@ -1890,7 +1877,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock {
1890 };1877 };
1891 const local_sym_index = @intCast(u32, self.locals.items.len);1878 const local_sym_index = @intCast(u32, self.locals.items.len);
1892 try self.locals.append(self.base.allocator, .{1879 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"),
1894 .n_type = macho.N_SECT,1881 .n_type = macho.N_SECT,
1895 .n_sect = 0,1882 .n_sect = 0,
1896 .n_desc = 0,1883 .n_desc = 0,
...@@ -2023,7 +2010,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {...@@ -2023,7 +2010,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
2023 };2010 };
2024 const local_sym_index = @intCast(u32, self.locals.items.len);2011 const local_sym_index = @intCast(u32, self.locals.items.len);
2025 try self.locals.append(self.base.allocator, .{2012 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"),
2027 .n_type = macho.N_SECT,2014 .n_type = macho.N_SECT,
2028 .n_sect = 0,2015 .n_sect = 0,
2029 .n_desc = 0,2016 .n_desc = 0,
...@@ -2078,7 +2065,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {...@@ -2078,7 +2065,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock {
2078pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {2065pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock {
2079 const local_sym_index = @intCast(u32, self.locals.items.len);2066 const local_sym_index = @intCast(u32, self.locals.items.len);
2080 try self.locals.append(self.base.allocator, .{2067 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"),
2082 .n_type = macho.N_SECT,2069 .n_type = macho.N_SECT,
2083 .n_sect = 0,2070 .n_sect = 0,
2084 .n_desc = 0,2071 .n_desc = 0,
...@@ -2102,7 +2089,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym...@@ -2102,7 +2089,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym
2102 .local_sym_index = lazy_binding_sym_index,2089 .local_sym_index = lazy_binding_sym_index,
2103 .offset = 0,2090 .offset = 0,
2104 });2091 });
2105 self.dyld_info_dirty = true;
2106 return atom;2092 return atom;
2107}2093}
21082094
...@@ -2120,7 +2106,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {...@@ -2120,7 +2106,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock {
2120 };2106 };
2121 const local_sym_index = @intCast(u32, self.locals.items.len);2107 const local_sym_index = @intCast(u32, self.locals.items.len);
2122 try self.locals.append(self.base.allocator, .{2108 try self.locals.append(self.base.allocator, .{
2123 .n_strx = try self.makeString("stub"),2109 .n_strx = try self.makeString("l_zld_stub"),
2124 .n_type = macho.N_SECT,2110 .n_type = macho.N_SECT,
2125 .n_sect = 0,2111 .n_sect = 0,
2126 .n_desc = 0,2112 .n_desc = 0,
...@@ -2303,7 +2289,6 @@ fn resolveSymbolsInObject(...@@ -2303,7 +2289,6 @@ fn resolveSymbolsInObject(
2303 .local_sym_index = local_sym_index,2289 .local_sym_index = local_sym_index,
2304 .file = object_id,2290 .file = object_id,
2305 };2291 };
2306 self.dyld_info_dirty = true;
2307 } else if (symbolIsTentative(sym)) {2292 } else if (symbolIsTentative(sym)) {
2308 // Symbol is a tentative definition.2293 // Symbol is a tentative definition.
2309 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {2294 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
...@@ -2638,7 +2623,6 @@ fn resolveDyldStubBinder(self: *MachO) !void {...@@ -2638,7 +2623,6 @@ fn resolveDyldStubBinder(self: *MachO) !void {
2638 .sect = self.got_section_index.?,2623 .sect = self.got_section_index.?,
2639 };2624 };
2640 _ = try self.allocateAtom(atom, match);2625 _ = try self.allocateAtom(atom, match);
2641 self.dyld_info_dirty = true;
2642}2626}
26432627
2644fn parseTextBlocks(self: *MachO) !void {2628fn parseTextBlocks(self: *MachO) !void {
...@@ -2658,27 +2642,21 @@ fn addDataInCodeLC(self: *MachO) !void {...@@ -2658,27 +2642,21 @@ fn addDataInCodeLC(self: *MachO) !void {
2658 .datasize = 0,2642 .datasize = 0,
2659 },2643 },
2660 });2644 });
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;
2667 self.load_commands_dirty = true;2645 self.load_commands_dirty = true;
2668}2646}
26692647
2670fn addCodeSignatureLC(self: *MachO) !void {2648fn addCodeSignatureLC(self: *MachO) !void {
2671 if (self.code_signature_cmd_index == null and self.requires_adhoc_codesig) {2649 if (self.code_signature_cmd_index != null or !self.requires_adhoc_codesig) return;
2672 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);2650 self.code_signature_cmd_index = @intCast(u16, self.load_commands.items.len);
2673 try self.load_commands.append(self.base.allocator, .{2651 try self.load_commands.append(self.base.allocator, .{
2674 .LinkeditData = .{2652 .LinkeditData = .{
2675 .cmd = macho.LC_CODE_SIGNATURE,2653 .cmd = macho.LC_CODE_SIGNATURE,
2676 .cmdsize = @sizeOf(macho.linkedit_data_command),2654 .cmdsize = @sizeOf(macho.linkedit_data_command),
2677 .dataoff = 0,2655 .dataoff = 0,
2678 .datasize = 0,2656 .datasize = 0,
2679 },2657 },
2680 });2658 });
2681 }2659 self.load_commands_dirty = true;
2682}2660}
26832661
2684fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {2662fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {
...@@ -2697,6 +2675,7 @@ fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {...@@ -2697,6 +2675,7 @@ fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void {
2697 mem.set(u8, rpath_cmd.data, 0);2675 mem.set(u8, rpath_cmd.data, 0);
2698 mem.copy(u8, rpath_cmd.data, rpath);2676 mem.copy(u8, rpath_cmd.data, rpath);
2699 try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd });2677 try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd });
2678 self.load_commands_dirty = true;
2700 }2679 }
2701}2680}
27022681
...@@ -2713,6 +2692,7 @@ fn addLoadDylibLCs(self: *MachO) !void {...@@ -2713,6 +2692,7 @@ fn addLoadDylibLCs(self: *MachO) !void {
2713 );2692 );
2714 errdefer dylib_cmd.deinit(self.base.allocator);2693 errdefer dylib_cmd.deinit(self.base.allocator);
2715 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });2694 try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd });
2695 self.load_commands_dirty = true;
2716 }2696 }
2717}2697}
27182698
...@@ -2937,7 +2917,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {...@@ -2937,7 +2917,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void {
2937 };2917 };
2938 const got_atom = try self.createGotAtom(key);2918 const got_atom = try self.createGotAtom(key);
2939 try self.got_entries_map.put(self.base.allocator, key, got_atom);2919 try self.got_entries_map.put(self.base.allocator, key, got_atom);
2940 self.dyld_info_dirty = true;
2941}2920}
29422921
2943pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {2922pub 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...@@ -3138,10 +3117,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3138 symbol.n_type = macho.N_SECT;3117 symbol.n_type = macho.N_SECT;
3139 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;3118 symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1;
3140 symbol.n_desc = 0;3119 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);
3145 } else {3120 } else {
3146 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});3121 const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)});
3147 defer self.base.allocator.free(decl_name);3122 defer self.base.allocator.free(decl_name);
...@@ -3168,10 +3143,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64...@@ -3168,10 +3143,6 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
3168 .seg = self.data_const_segment_cmd_index.?,3143 .seg = self.data_const_segment_cmd_index.?,
3169 .sect = self.got_section_index.?,3144 .sect = self.got_section_index.?,
3170 });3145 });
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);
3175 }3146 }
31763147
3177 return symbol;3148 return symbol;
...@@ -3257,7 +3228,6 @@ pub fn updateDeclExports(...@@ -3257,7 +3228,6 @@ pub fn updateDeclExports(
3257 const name_str_index = try self.makeString(exp_name);3228 const name_str_index = try self.makeString(exp_name);
3258 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {3229 const i = if (self.globals_free_list.popOrNull()) |i| i else blk: {
3259 _ = self.globals.addOneAssumeCapacity();3230 _ = self.globals.addOneAssumeCapacity();
3260 self.dyld_info_dirty = true;
3261 break :blk @intCast(u32, self.globals.items.len - 1);3231 break :blk @intCast(u32, self.globals.items.len - 1);
3262 };3232 };
3263 self.globals.items[i] = .{3233 self.globals.items[i] = .{
...@@ -3347,7 +3317,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3347,7 +3317,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3347 const program_code_size_hint = self.base.options.program_code_size_hint;3317 const program_code_size_hint = self.base.options.program_code_size_hint;
3348 // const program_code_size_hint = 10;3318 // const program_code_size_hint = 10;
3349 const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;3319 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;
3351 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);3321 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
33523322
3353 log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });3323 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 {...@@ -3441,7 +3411,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3441 if (self.data_const_segment_cmd_index == null) {3411 if (self.data_const_segment_cmd_index == null) {
3442 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3412 self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3443 const address_and_offset = self.nextSegmentAddressAndOffset();3413 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;
3445 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);3415 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
34463416
3447 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{3417 log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
...@@ -3482,7 +3452,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3482,7 +3452,7 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3482 if (self.data_segment_cmd_index == null) {3452 if (self.data_segment_cmd_index == null) {
3483 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);3453 self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len);
3484 const address_and_offset = self.nextSegmentAddressAndOffset();3454 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;
3486 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);3456 const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
34873457
3488 log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ address_and_offset.offset, address_and_offset.offset + needed_size });3458 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 {...@@ -3621,7 +3591,6 @@ pub fn populateMissingMetadata(self: *MachO) !void {
36213591
3622 if (self.dyld_info_cmd_index == null) {3592 if (self.dyld_info_cmd_index == null) {
3623 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);3593 self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len);
3624
3625 try self.load_commands.append(self.base.allocator, .{3594 try self.load_commands.append(self.base.allocator, .{
3626 .DyldInfoOnly = .{3595 .DyldInfoOnly = .{
3627 .cmd = macho.LC_DYLD_INFO_ONLY,3596 .cmd = macho.LC_DYLD_INFO_ONLY,
...@@ -3638,42 +3607,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3638,42 +3607,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3638 .export_size = 0,3607 .export_size = 0,
3639 },3608 },
3640 });3609 });
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
3671 self.load_commands_dirty = true;3610 self.load_commands_dirty = true;
3672 }3611 }
36733612
3674 if (self.symtab_cmd_index == null) {3613 if (self.symtab_cmd_index == null) {
3675 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);3614 self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len);
3676
3677 try self.load_commands.append(self.base.allocator, .{3615 try self.load_commands.append(self.base.allocator, .{
3678 .Symtab = .{3616 .Symtab = .{
3679 .cmd = macho.LC_SYMTAB,3617 .cmd = macho.LC_SYMTAB,
...@@ -3684,35 +3622,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3684,35 +3622,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3684 .strsize = 0,3622 .strsize = 0,
3685 },3623 },
3686 });3624 });
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
3703 self.load_commands_dirty = true;3625 self.load_commands_dirty = true;
3704 self.strtab_dirty = true;
3705 }3626 }
37063627
3707 if (self.dysymtab_cmd_index == null) {3628 if (self.dysymtab_cmd_index == null) {
3708 self.dysymtab_cmd_index = @intCast(u16, self.load_commands.items.len);3629 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
3716 try self.load_commands.append(self.base.allocator, .{3630 try self.load_commands.append(self.base.allocator, .{
3717 .Dysymtab = .{3631 .Dysymtab = .{
3718 .cmd = macho.LC_DYSYMTAB,3632 .cmd = macho.LC_DYSYMTAB,
...@@ -3729,8 +3643,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -3729,8 +3643,8 @@ pub fn populateMissingMetadata(self: *MachO) !void {
3729 .nmodtab = 0,3643 .nmodtab = 0,
3730 .extrefsymoff = 0,3644 .extrefsymoff = 0,
3731 .nextrefsyms = 0,3645 .nextrefsyms = 0,
3732 .indirectsymoff = @intCast(u32, indsymtab_off),3646 .indirectsymoff = 0,
3733 .nindirectsyms = @intCast(u32, self.base.options.symbol_count_hint),3647 .nindirectsyms = 0,
3734 .extreloff = 0,3648 .extreloff = 0,
3735 .nextrel = 0,3649 .nextrel = 0,
3736 .locreloff = 0,3650 .locreloff = 0,
...@@ -4084,387 +3998,7 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {...@@ -4084,387 +3998,7 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset {
4084 };3998 };
4085}3999}
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
4465fn writeDyldInfoData(self: *MachO) !void {4001fn writeDyldInfoData(self: *MachO) !void {
4466 if (!self.dyld_info_dirty) return;
4467
4468 const tracy = trace(@src());4002 const tracy = trace(@src());
4469 defer tracy.end();4003 defer tracy.end();
44704004
...@@ -4528,7 +4062,7 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -4528,7 +4062,7 @@ fn writeDyldInfoData(self: *MachO) !void {
45284062
4529 {4063 {
4530 // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER.4064 // 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", .{});
4532 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;4066 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
4533 const base_address = text_segment.inner.vmaddr;4067 const base_address = text_segment.inner.vmaddr;
45344068
...@@ -4546,28 +4080,30 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -4546,28 +4080,30 @@ fn writeDyldInfoData(self: *MachO) !void {
4546 try trie.finalize(self.base.allocator);4080 try trie.finalize(self.base.allocator);
4547 }4081 }
45484082
4083 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4549 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;4084 const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly;
4550 const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off);4085 const rebase_size = try bind.rebaseInfoSize(rebase_pointers.items);
4551 const rebase_size = @intCast(u32, try bind.rebaseInfoSize(rebase_pointers.items));4086 const bind_size = try bind.bindInfoSize(bind_pointers.items);
4552 const bind_size = @intCast(u32, try bind.bindInfoSize(bind_pointers.items));4087 const lazy_bind_size = try bind.lazyBindInfoSize(lazy_bind_pointers.items);
4553 const lazy_bind_size = @intCast(u32, try bind.lazyBindInfoSize(lazy_bind_pointers.items));4088 const export_size = trie.size;
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));
45574089
4558 if (needed_size > allocated_size) {4090 dyld_info.rebase_off = @intCast(u32, seg.inner.fileoff);
4559 dyld_info.rebase_off = 0;4091 dyld_info.rebase_size = @intCast(u32, mem.alignForwardGeneric(u64, rebase_size, @alignOf(u64)));
4560 dyld_info.rebase_off = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, null));4092 seg.inner.filesize += dyld_info.rebase_size;
4561 }
45624093
4563 dyld_info.rebase_size = rebase_size;
4564 dyld_info.bind_off = dyld_info.rebase_off + dyld_info.rebase_size;4094 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
4566 dyld_info.lazy_bind_off = dyld_info.bind_off + dyld_info.bind_size;4098 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
4568 dyld_info.export_off = dyld_info.lazy_bind_off + dyld_info.lazy_bind_size;4102 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;
4571 var buffer = try self.base.allocator.alloc(u8, needed_size);4107 var buffer = try self.base.allocator.alloc(u8, needed_size);
4572 defer self.base.allocator.free(buffer);4108 defer self.base.allocator.free(buffer);
4573 mem.set(u8, buffer, 0);4109 mem.set(u8, buffer, 0);
...@@ -4576,16 +4112,26 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -4576,16 +4112,26 @@ fn writeDyldInfoData(self: *MachO) !void {
4576 const writer = stream.writer();4112 const writer = stream.writer();
45774113
4578 try bind.writeRebaseInfo(rebase_pointers.items, writer);4114 try bind.writeRebaseInfo(rebase_pointers.items, writer);
4115 try stream.seekBy(@intCast(i64, dyld_info.rebase_size) - @intCast(i64, rebase_size));
4116
4579 try bind.writeBindInfo(bind_pointers.items, writer);4117 try bind.writeBindInfo(bind_pointers.items, writer);
4118 try stream.seekBy(@intCast(i64, dyld_info.bind_size) - @intCast(i64, bind_size));
4119
4580 try bind.writeLazyBindInfo(lazy_bind_pointers.items, writer);4120 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
4581 _ = try trie.write(writer);4123 _ = 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
4585 try self.base.file.?.pwriteAll(buffer, dyld_info.rebase_off);4130 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 );
4587 self.load_commands_dirty = true;4134 self.load_commands_dirty = true;
4588 self.dyld_info_dirty = false;
4589}4135}
45904136
4591fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {4137fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
...@@ -4661,7 +4207,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -4661,7 +4207,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
4661 const sym = self.locals.items[atom.local_sym_index];4207 const sym = self.locals.items[atom.local_sym_index];
4662 const file_offset = sect.offset + sym.n_value - sect.addr + stub_offset;4208 const file_offset = sect.offset + sym.n_value - sect.addr + stub_offset;
4663 mem.writeIntLittle(u32, &buf, bind_offset);4209 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}", .{
4665 bind_offset,4211 bind_offset,
4666 self.getString(sym.n_strx),4212 self.getString(sym.n_strx),
4667 file_offset,4213 file_offset,
...@@ -4674,79 +4220,307 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {...@@ -4674,79 +4220,307 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void {
4674 }4220 }
4675}4221}
46764222
4677fn writeStringTable(self: *MachO) !void {4223fn writeDices(self: *MachO) !void {
4678 if (!self.strtab_dirty) return;4224 if (!self.has_dices) return;
46794225
4680 const tracy = trace(@src());4226 const tracy = trace(@src());
4681 defer tracy.end();4227 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;
4683 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;4287 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
4684 const allocated_size = self.allocatedSizeLinkedit(symtab.stroff);4288 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
4685 const needed_size = mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64));4289
46864290 var locals = std.ArrayList(macho.nlist_64).init(self.base.allocator);
4687 if (needed_size > allocated_size or self.strtab_needs_relocation) {4291 defer locals.deinit();
4688 symtab.strsize = 0;4292 try locals.appendSlice(self.locals.items);
4689 symtab.stroff = @intCast(u32, self.findFreeSpaceLinkedit(needed_size, 1, symtab.symoff));4293
4690 self.strtab_needs_relocation = false;4294 if (self.has_stabs) {
4691 }4295 for (self.objects.items) |object| {
4692 symtab.strsize = @intCast(u32, needed_size);4296 if (object.debug_info == null) continue;
4693 log.debug("writing string table from 0x{x} to 0x{x}", .{4297
4694 symtab.stroff,4298 // Open scope
4695 symtab.stroff + symtab.strsize,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,
4696 });4397 });
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
4698 try self.base.file.?.pwriteAll(self.strtab.items, symtab.stroff);4443 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 }
4699 self.load_commands_dirty = true;4449 self.load_commands_dirty = true;
4700 self.strtab_dirty = false;
4701}4450}
47024451
4703fn updateLinkeditSegmentSizes(self: *MachO) !void {4452fn writeLinkeditSegment(self: *MachO) !void {
4704 if (!self.load_commands_dirty) return;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 {
4706 const tracy = trace(@src());4468 const tracy = trace(@src());
4707 defer tracy.end();4469 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.
4711 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;4471 const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
4712 var final_offset = linkedit_segment.inner.fileoff;4472 const code_sig_cmd = &self.load_commands.items[self.code_signature_cmd_index.?].LinkeditData;
47134473 const fileoff = linkedit_segment.inner.fileoff + linkedit_segment.inner.filesize;
4714 if (self.dyld_info_cmd_index) |idx| {4474 const needed_size = CodeSignature.calcCodeSignaturePaddingSize(
4715 const dyld_info = self.load_commands.items[idx].DyldInfoOnly;4475 self.base.options.emit.?.sub_path,
4716 final_offset = std.math.max(final_offset, dyld_info.rebase_off + dyld_info.rebase_size);4476 fileoff,
4717 final_offset = std.math.max(final_offset, dyld_info.bind_off + dyld_info.bind_size);4477 self.page_size,
4718 final_offset = std.math.max(final_offset, dyld_info.weak_bind_off + dyld_info.weak_bind_size);4478 );
4719 final_offset = std.math.max(final_offset, dyld_info.lazy_bind_off + dyld_info.lazy_bind_size);4479 code_sig_cmd.dataoff = @intCast(u32, fileoff);
4720 final_offset = std.math.max(final_offset, dyld_info.export_off + dyld_info.export_size);4480 code_sig_cmd.datasize = needed_size;
4721 }4481
4722 if (self.function_starts_cmd_index) |idx| {4482 // Advance size of __LINKEDIT segment
4723 const fstart = self.load_commands.items[idx].LinkeditData;4483 linkedit_segment.inner.filesize += needed_size;
4724 final_offset = std.math.max(final_offset, fstart.dataoff + fstart.datasize);4484 if (linkedit_segment.inner.vmsize < linkedit_segment.inner.filesize) {
4725 }4485 linkedit_segment.inner.vmsize = mem.alignForwardGeneric(u64, linkedit_segment.inner.filesize, self.page_size);
4726 if (self.data_in_code_cmd_index) |idx| {4486 }
4727 const dic = self.load_commands.items[idx].LinkeditData;4487 log.debug("writing code signature padding from 0x{x} to 0x{x}", .{ fileoff, fileoff + needed_size });
4728 final_offset = std.math.max(final_offset, dic.dataoff + dic.datasize);4488 // Pad out the space. We need to do this to calculate valid hashes for everything in the file
4729 }4489 // except for code signature data.
4730 if (self.dysymtab_cmd_index) |idx| {4490 try self.base.file.?.pwriteAll(&[_]u8{0}, fileoff + needed_size - 1);
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);
4747 self.load_commands_dirty = true;4491 self.load_commands_dirty = true;
4748}4492}
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
4750/// Writes all load commands and section headers.4524/// Writes all load commands and section headers.
4751fn writeLoadCommands(self: *MachO) !void {4525fn writeLoadCommands(self: *MachO) !void {
4752 if (!self.load_commands_dirty) return;4526 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...@@ -844,7 +844,6 @@ pub fn parseRelocs(self: *TextBlock, relocs: []macho.relocation_info, context: R
844 .sect = context.macho_file.got_section_index.?,844 .sect = context.macho_file.got_section_index.?,
845 };845 };
846 _ = try context.macho_file.allocateAtom(atom, match);846 _ = try context.macho_file.allocateAtom(atom, match);
847 context.macho_file.dyld_info_dirty = true;
848 } else if (parsed_rel.payload == .unsigned) {847 } else if (parsed_rel.payload == .unsigned) {
849 switch (parsed_rel.where) {848 switch (parsed_rel.where) {
850 .undef => {849 .undef => {