| ... | ... | @@ -162,10 +162,6 @@ stubs_map: std.AutoArrayHashMapUnmanaged(u32, *TextBlock) = .{}, |
| 162 | 162 | error_flags: File.ErrorFlags = File.ErrorFlags{}, |
| 163 | 163 | |
| 164 | 164 | load_commands_dirty: bool = false, |
| 165 | | dyld_info_dirty: bool = false, |
| 166 | | |
| 167 | | strtab_dirty: bool = false, |
| 168 | | strtab_needs_relocation: bool = false, |
| 169 | 165 | |
| 170 | 166 | has_dices: bool = false, |
| 171 | 167 | has_stabs: bool = false, |
| ... | ... | @@ -368,13 +364,12 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 368 | 364 | .n_desc = 0, |
| 369 | 365 | .n_value = 0, |
| 370 | 366 | }); |
| 367 | try self.strtab.append(allocator, 0); |
| 371 | 368 | |
| 372 | 369 | try self.populateMissingMetadata(); |
| 373 | | try self.writeLocalSymbol(0); |
| 374 | 370 | |
| 375 | 371 | if (self.d_sym) |*ds| { |
| 376 | 372 | try ds.populateMissingMetadata(allocator); |
| 377 | | try ds.writeLocalSymbol(0); |
| 378 | 373 | } |
| 379 | 374 | |
| 380 | 375 | return self; |
| ... | ... | @@ -553,6 +548,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 553 | 548 | .n_desc = 0, |
| 554 | 549 | .n_value = 0, |
| 555 | 550 | }); |
| 551 | try self.strtab.append(self.base.allocator, 0); |
| 556 | 552 | } |
| 557 | 553 | |
| 558 | 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 | 780 | } |
| 785 | 781 | } |
| 786 | 782 | try self.writeAtoms(); |
| 787 | | try self.writeDices(); |
| 788 | 783 | try self.flushModule(comp); |
| 789 | 784 | } |
| 790 | 785 | |
| ... | ... | @@ -792,11 +787,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 792 | 787 | // Update the file with the digest. If it fails we can continue; it only |
| 793 | 788 | // means that the next invocation will have an unnecessary cache miss. |
| 794 | 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 | 792 | // Again failure here only means an unnecessary cache miss. |
| 798 | 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 | 796 | // We hang on to this lock so that the output file path can be used without |
| 802 | 797 | // other processes clobbering it. |
| ... | ... | @@ -811,11 +806,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 811 | 806 | defer tracy.end(); |
| 812 | 807 | |
| 813 | 808 | 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(); |
| 819 | 810 | |
| 820 | 811 | if (self.d_sym) |*ds| { |
| 821 | 812 | // Flush debug symbols bundle. |
| ... | ... | @@ -843,9 +834,6 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 843 | 834 | } |
| 844 | 835 | |
| 845 | 836 | assert(!self.load_commands_dirty); |
| 846 | | assert(!self.dyld_info_dirty); |
| 847 | | assert(!self.strtab_dirty); |
| 848 | | assert(!self.strtab_needs_relocation); |
| 849 | 837 | |
| 850 | 838 | if (self.requires_adhoc_codesig) { |
| 851 | 839 | try self.writeCodeSignature(); // code signing always comes last |
| ... | ... | @@ -1769,7 +1757,6 @@ pub fn writeAtom(self: *MachO, atom: *TextBlock, match: MatchingSection) !void { |
| 1769 | 1757 | try atom.resolveRelocs(self); |
| 1770 | 1758 | log.debug("writing atom for symbol {s} at file offset 0x{x}", .{ self.getString(sym.n_strx), file_offset }); |
| 1771 | 1759 | try self.base.file.?.pwriteAll(atom.code.items, file_offset); |
| 1772 | | try self.writeLocalSymbol(atom.local_sym_index); |
| 1773 | 1760 | } |
| 1774 | 1761 | |
| 1775 | 1762 | fn allocateLocalSymbols(self: *MachO, match: MatchingSection, old_base_addr: u64) !void { |
| ... | ... | @@ -1830,7 +1817,7 @@ fn writeAtoms(self: *MachO) !void { |
| 1830 | 1817 | pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock { |
| 1831 | 1818 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1832 | 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 | 1821 | .n_type = macho.N_SECT, |
| 1835 | 1822 | .n_sect = 0, |
| 1836 | 1823 | .n_desc = 0, |
| ... | ... | @@ -1866,7 +1853,7 @@ pub fn createGotAtom(self: *MachO, key: GotIndirectionKey) !*TextBlock { |
| 1866 | 1853 | fn createDyldPrivateAtom(self: *MachO) !*TextBlock { |
| 1867 | 1854 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1868 | 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 | 1857 | .n_type = macho.N_SECT, |
| 1871 | 1858 | .n_sect = 0, |
| 1872 | 1859 | .n_desc = 0, |
| ... | ... | @@ -1890,7 +1877,7 @@ fn createStubHelperPreambleAtom(self: *MachO) !*TextBlock { |
| 1890 | 1877 | }; |
| 1891 | 1878 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 1892 | 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 | 1881 | .n_type = macho.N_SECT, |
| 1895 | 1882 | .n_sect = 0, |
| 1896 | 1883 | .n_desc = 0, |
| ... | ... | @@ -2023,7 +2010,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 2023 | 2010 | }; |
| 2024 | 2011 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2025 | 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 | 2014 | .n_type = macho.N_SECT, |
| 2028 | 2015 | .n_sect = 0, |
| 2029 | 2016 | .n_desc = 0, |
| ... | ... | @@ -2078,7 +2065,7 @@ pub fn createStubHelperAtom(self: *MachO) !*TextBlock { |
| 2078 | 2065 | pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym_index: u32) !*TextBlock { |
| 2079 | 2066 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2080 | 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 | 2069 | .n_type = macho.N_SECT, |
| 2083 | 2070 | .n_sect = 0, |
| 2084 | 2071 | .n_desc = 0, |
| ... | ... | @@ -2102,7 +2089,6 @@ pub fn createLazyPointerAtom(self: *MachO, stub_sym_index: u32, lazy_binding_sym |
| 2102 | 2089 | .local_sym_index = lazy_binding_sym_index, |
| 2103 | 2090 | .offset = 0, |
| 2104 | 2091 | }); |
| 2105 | | self.dyld_info_dirty = true; |
| 2106 | 2092 | return atom; |
| 2107 | 2093 | } |
| 2108 | 2094 | |
| ... | ... | @@ -2120,7 +2106,7 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*TextBlock { |
| 2120 | 2106 | }; |
| 2121 | 2107 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2122 | 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 | 2110 | .n_type = macho.N_SECT, |
| 2125 | 2111 | .n_sect = 0, |
| 2126 | 2112 | .n_desc = 0, |
| ... | ... | @@ -2303,7 +2289,6 @@ fn resolveSymbolsInObject( |
| 2303 | 2289 | .local_sym_index = local_sym_index, |
| 2304 | 2290 | .file = object_id, |
| 2305 | 2291 | }; |
| 2306 | | self.dyld_info_dirty = true; |
| 2307 | 2292 | } else if (symbolIsTentative(sym)) { |
| 2308 | 2293 | // Symbol is a tentative definition. |
| 2309 | 2294 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse { |
| ... | ... | @@ -2638,7 +2623,6 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 2638 | 2623 | .sect = self.got_section_index.?, |
| 2639 | 2624 | }; |
| 2640 | 2625 | _ = try self.allocateAtom(atom, match); |
| 2641 | | self.dyld_info_dirty = true; |
| 2642 | 2626 | } |
| 2643 | 2627 | |
| 2644 | 2628 | fn parseTextBlocks(self: *MachO) !void { |
| ... | ... | @@ -2658,27 +2642,21 @@ fn addDataInCodeLC(self: *MachO) !void { |
| 2658 | 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 | 2645 | self.load_commands_dirty = true; |
| 2668 | 2646 | } |
| 2669 | 2647 | |
| 2670 | 2648 | fn 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; |
| 2682 | 2660 | } |
| 2683 | 2661 | |
| 2684 | 2662 | fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void { |
| ... | ... | @@ -2697,6 +2675,7 @@ fn addRpathLCs(self: *MachO, rpaths: []const []const u8) !void { |
| 2697 | 2675 | mem.set(u8, rpath_cmd.data, 0); |
| 2698 | 2676 | mem.copy(u8, rpath_cmd.data, rpath); |
| 2699 | 2677 | try self.load_commands.append(self.base.allocator, .{ .Rpath = rpath_cmd }); |
| 2678 | self.load_commands_dirty = true; |
| 2700 | 2679 | } |
| 2701 | 2680 | } |
| 2702 | 2681 | |
| ... | ... | @@ -2713,6 +2692,7 @@ fn addLoadDylibLCs(self: *MachO) !void { |
| 2713 | 2692 | ); |
| 2714 | 2693 | errdefer dylib_cmd.deinit(self.base.allocator); |
| 2715 | 2694 | try self.load_commands.append(self.base.allocator, .{ .Dylib = dylib_cmd }); |
| 2695 | self.load_commands_dirty = true; |
| 2716 | 2696 | } |
| 2717 | 2697 | } |
| 2718 | 2698 | |
| ... | ... | @@ -2937,7 +2917,6 @@ pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| 2937 | 2917 | }; |
| 2938 | 2918 | const got_atom = try self.createGotAtom(key); |
| 2939 | 2919 | try self.got_entries_map.put(self.base.allocator, key, got_atom); |
| 2940 | | self.dyld_info_dirty = true; |
| 2941 | 2920 | } |
| 2942 | 2921 | |
| 2943 | 2922 | pub 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 | 3117 | symbol.n_type = macho.N_SECT; |
| 3139 | 3118 | symbol.n_sect = @intCast(u8, self.text_section_index.?) + 1; |
| 3140 | 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 | 3120 | } else { |
| 3146 | 3121 | const decl_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{mem.spanZ(decl.name)}); |
| 3147 | 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 | 3143 | .seg = self.data_const_segment_cmd_index.?, |
| 3169 | 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 | } |
| 3176 | 3147 | |
| 3177 | 3148 | return symbol; |
| ... | ... | @@ -3257,7 +3228,6 @@ pub fn updateDeclExports( |
| 3257 | 3228 | const name_str_index = try self.makeString(exp_name); |
| 3258 | 3229 | const i = if (self.globals_free_list.popOrNull()) |i| i else blk: { |
| 3259 | 3230 | _ = self.globals.addOneAssumeCapacity(); |
| 3260 | | self.dyld_info_dirty = true; |
| 3261 | 3231 | break :blk @intCast(u32, self.globals.items.len - 1); |
| 3262 | 3232 | }; |
| 3263 | 3233 | self.globals.items[i] = .{ |
| ... | ... | @@ -3347,7 +3317,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3347 | 3317 | const program_code_size_hint = self.base.options.program_code_size_hint; |
| 3348 | 3318 | // const program_code_size_hint = 10; |
| 3349 | 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 | 3321 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3352 | 3322 | |
| 3353 | 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 | 3411 | if (self.data_const_segment_cmd_index == null) { |
| 3442 | 3412 | self.data_const_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3443 | 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 | 3415 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3446 | 3416 | |
| 3447 | 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 | 3452 | if (self.data_segment_cmd_index == null) { |
| 3483 | 3453 | self.data_segment_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3484 | 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 | 3456 | const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 3487 | 3457 | |
| 3488 | 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 | 3591 | |
| 3622 | 3592 | if (self.dyld_info_cmd_index == null) { |
| 3623 | 3593 | self.dyld_info_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3624 | | |
| 3625 | 3594 | try self.load_commands.append(self.base.allocator, .{ |
| 3626 | 3595 | .DyldInfoOnly = .{ |
| 3627 | 3596 | .cmd = macho.LC_DYLD_INFO_ONLY, |
| ... | ... | @@ -3638,42 +3607,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3638 | 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 | 3610 | self.load_commands_dirty = true; |
| 3672 | 3611 | } |
| 3673 | 3612 | |
| 3674 | 3613 | if (self.symtab_cmd_index == null) { |
| 3675 | 3614 | self.symtab_cmd_index = @intCast(u16, self.load_commands.items.len); |
| 3676 | | |
| 3677 | 3615 | try self.load_commands.append(self.base.allocator, .{ |
| 3678 | 3616 | .Symtab = .{ |
| 3679 | 3617 | .cmd = macho.LC_SYMTAB, |
| ... | ... | @@ -3684,35 +3622,11 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3684 | 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 | 3625 | self.load_commands_dirty = true; |
| 3704 | | self.strtab_dirty = true; |
| 3705 | 3626 | } |
| 3706 | 3627 | |
| 3707 | 3628 | if (self.dysymtab_cmd_index == null) { |
| 3708 | 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 | 3630 | try self.load_commands.append(self.base.allocator, .{ |
| 3717 | 3631 | .Dysymtab = .{ |
| 3718 | 3632 | .cmd = macho.LC_DYSYMTAB, |
| ... | ... | @@ -3729,8 +3643,8 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 3729 | 3643 | .nmodtab = 0, |
| 3730 | 3644 | .extrefsymoff = 0, |
| 3731 | 3645 | .nextrefsyms = 0, |
| 3732 | | .indirectsymoff = @intCast(u32, indsymtab_off), |
| 3733 | | .nindirectsyms = @intCast(u32, self.base.options.symbol_count_hint), |
| 3646 | .indirectsymoff = 0, |
| 3647 | .nindirectsyms = 0, |
| 3734 | 3648 | .extreloff = 0, |
| 3735 | 3649 | .nextrel = 0, |
| 3736 | 3650 | .locreloff = 0, |
| ... | ... | @@ -4084,387 +3998,7 @@ fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 4084 | 3998 | }; |
| 4085 | 3999 | } |
| 4086 | 4000 | |
| 4087 | | fn 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 | | } |
| 4122 | | inline 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 | | |
| 4131 | | fn 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 | | |
| 4191 | | fn 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 | | |
| 4200 | | fn 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 | | |
| 4238 | | fn 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 | | |
| 4249 | | fn 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 | | |
| 4282 | | fn 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 | | |
| 4343 | | fn 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 | | |
| 4407 | | fn 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 | | |
| 4435 | | fn 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 | | |
| 4465 | 4001 | fn writeDyldInfoData(self: *MachO) !void { |
| 4466 | | if (!self.dyld_info_dirty) return; |
| 4467 | | |
| 4468 | 4002 | const tracy = trace(@src()); |
| 4469 | 4003 | defer tracy.end(); |
| 4470 | 4004 | |
| ... | ... | @@ -4528,7 +4062,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4528 | 4062 | |
| 4529 | 4063 | { |
| 4530 | 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 | 4066 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 4533 | 4067 | const base_address = text_segment.inner.vmaddr; |
| 4534 | 4068 | |
| ... | ... | @@ -4546,28 +4080,30 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4546 | 4080 | try trie.finalize(self.base.allocator); |
| 4547 | 4081 | } |
| 4548 | 4082 | |
| 4083 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 4549 | 4084 | 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; |
| 4557 | 4089 | |
| 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; |
| 4562 | 4093 | |
| 4563 | | dyld_info.rebase_size = rebase_size; |
| 4564 | 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 | 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 | 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; |
| 4570 | 4105 | |
| 4106 | const needed_size = dyld_info.rebase_size + dyld_info.bind_size + dyld_info.lazy_bind_size + dyld_info.export_size; |
| 4571 | 4107 | var buffer = try self.base.allocator.alloc(u8, needed_size); |
| 4572 | 4108 | defer self.base.allocator.free(buffer); |
| 4573 | 4109 | mem.set(u8, buffer, 0); |
| ... | ... | @@ -4576,16 +4112,26 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 4576 | 4112 | const writer = stream.writer(); |
| 4577 | 4113 | |
| 4578 | 4114 | try bind.writeRebaseInfo(rebase_pointers.items, writer); |
| 4115 | try stream.seekBy(@intCast(i64, dyld_info.rebase_size) - @intCast(i64, rebase_size)); |
| 4116 | |
| 4579 | 4117 | try bind.writeBindInfo(bind_pointers.items, writer); |
| 4118 | try stream.seekBy(@intCast(i64, dyld_info.bind_size) - @intCast(i64, bind_size)); |
| 4119 | |
| 4580 | 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 | 4123 | _ = try trie.write(writer); |
| 4582 | 4124 | |
| 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 | }); |
| 4584 | 4129 | |
| 4585 | 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 | 4134 | self.load_commands_dirty = true; |
| 4588 | | self.dyld_info_dirty = false; |
| 4589 | 4135 | } |
| 4590 | 4136 | |
| 4591 | 4137 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| ... | ... | @@ -4661,7 +4207,7 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4661 | 4207 | const sym = self.locals.items[atom.local_sym_index]; |
| 4662 | 4208 | const file_offset = sect.offset + sym.n_value - sect.addr + stub_offset; |
| 4663 | 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 | 4211 | bind_offset, |
| 4666 | 4212 | self.getString(sym.n_strx), |
| 4667 | 4213 | file_offset, |
| ... | ... | @@ -4674,79 +4220,307 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 4674 | 4220 | } |
| 4675 | 4221 | } |
| 4676 | 4222 | |
| 4677 | | fn writeStringTable(self: *MachO) !void { |
| 4678 | | if (!self.strtab_dirty) return; |
| 4223 | fn writeDices(self: *MachO) !void { |
| 4224 | if (!self.has_dices) return; |
| 4679 | 4225 | |
| 4680 | 4226 | const tracy = trace(@src()); |
| 4681 | 4227 | defer tracy.end(); |
| 4682 | 4228 | |
| 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 | |
| 4282 | fn 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 | 4287 | 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, |
| 4696 | 4397 | }); |
| 4697 | 4398 | |
| 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 | |
| 4431 | fn 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 | 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 | 4449 | self.load_commands_dirty = true; |
| 4700 | | self.strtab_dirty = false; |
| 4701 | 4450 | } |
| 4702 | 4451 | |
| 4703 | | fn updateLinkeditSegmentSizes(self: *MachO) !void { |
| 4704 | | if (!self.load_commands_dirty) return; |
| 4452 | fn 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 | } |
| 4705 | 4466 | |
| 4467 | fn writeCodeSignaturePadding(self: *MachO) !void { |
| 4706 | 4468 | const tracy = trace(@src()); |
| 4707 | 4469 | defer tracy.end(); |
| 4708 | 4470 | |
| 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 | 4471 | 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); |
| 4747 | 4491 | self.load_commands_dirty = true; |
| 4748 | 4492 | } |
| 4749 | 4493 | |
| 4494 | fn 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 | 4524 | /// Writes all load commands and section headers. |
| 4751 | 4525 | fn writeLoadCommands(self: *MachO) !void { |
| 4752 | 4526 | if (!self.load_commands_dirty) return; |