| ... | ... | @@ -164,11 +164,13 @@ tentatives: std.AutoArrayHashMapUnmanaged(u32, void) = .{}, |
| 164 | 164 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 165 | 165 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 166 | 166 | |
| 167 | | mh_execute_header_index: ?u32 = null, |
| 168 | 167 | dyld_stub_binder_index: ?u32 = null, |
| 169 | 168 | dyld_private_atom: ?*Atom = null, |
| 170 | 169 | stub_helper_preamble_atom: ?*Atom = null, |
| 171 | 170 | |
| 171 | mh_execute_header_sym_index: ?u32 = null, |
| 172 | dso_handle_sym_index: ?u32 = null, |
| 173 | |
| 172 | 174 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 173 | 175 | strtab_dir: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.default_max_load_percentage) = .{}, |
| 174 | 176 | |
| ... | ... | @@ -856,7 +858,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 856 | 858 | // re-exports every single symbol definition. |
| 857 | 859 | for (lib_dirs.items) |dir| { |
| 858 | 860 | if (try resolveLib(arena, dir, "System", ".tbd")) |full_path| { |
| 859 | | try libs.put(full_path, .{ .needed = false }); |
| 861 | try libs.put(full_path, .{ .needed = true }); |
| 860 | 862 | libsystem_available = true; |
| 861 | 863 | break :blk; |
| 862 | 864 | } |
| ... | ... | @@ -866,8 +868,8 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 866 | 868 | for (lib_dirs.items) |dir| { |
| 867 | 869 | if (try resolveLib(arena, dir, "System", ".dylib")) |libsystem_path| { |
| 868 | 870 | if (try resolveLib(arena, dir, "c", ".dylib")) |libc_path| { |
| 869 | | try libs.put(libsystem_path, .{ .needed = false }); |
| 870 | | try libs.put(libc_path, .{ .needed = false }); |
| 871 | try libs.put(libsystem_path, .{ .needed = true }); |
| 872 | try libs.put(libc_path, .{ .needed = true }); |
| 871 | 873 | libsystem_available = true; |
| 872 | 874 | break :blk; |
| 873 | 875 | } |
| ... | ... | @@ -881,7 +883,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 881 | 883 | const full_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ |
| 882 | 884 | "libc", "darwin", libsystem_name, |
| 883 | 885 | }); |
| 884 | | try libs.put(full_path, .{ .needed = false }); |
| 886 | try libs.put(full_path, .{ .needed = true }); |
| 885 | 887 | } |
| 886 | 888 | |
| 887 | 889 | // frameworks |
| ... | ... | @@ -1090,7 +1092,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1090 | 1092 | try self.parseDependentLibs(self.base.options.sysroot, &dependent_libs); |
| 1091 | 1093 | } |
| 1092 | 1094 | |
| 1093 | | try self.createMhExecuteHeaderAtom(); |
| 1095 | try self.createMhExecuteHeaderSymbol(); |
| 1094 | 1096 | for (self.objects.items) |*object, object_id| { |
| 1095 | 1097 | if (object.analyzed) continue; |
| 1096 | 1098 | try self.resolveSymbolsInObject(@intCast(u16, object_id)); |
| ... | ... | @@ -1101,7 +1103,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1101 | 1103 | try self.createDyldPrivateAtom(); |
| 1102 | 1104 | try self.createStubHelperPreambleAtom(); |
| 1103 | 1105 | try self.resolveSymbolsInDylibs(); |
| 1104 | | try self.createDsoHandleAtom(); |
| 1106 | try self.createDsoHandleSymbol(); |
| 1105 | 1107 | try self.addCodeSignatureLC(); |
| 1106 | 1108 | |
| 1107 | 1109 | { |
| ... | ... | @@ -1156,14 +1158,12 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 1156 | 1158 | |
| 1157 | 1159 | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; |
| 1158 | 1160 | if (use_llvm or use_stage1) { |
| 1159 | | try self.sortSections(); |
| 1160 | | try self.allocateTextSegment(); |
| 1161 | | try self.allocateDataConstSegment(); |
| 1162 | | try self.allocateDataSegment(); |
| 1163 | | self.allocateLinkeditSegment(); |
| 1161 | try self.pruneAndSortSections(); |
| 1162 | try self.allocateSegments(); |
| 1164 | 1163 | try self.allocateLocals(); |
| 1165 | 1164 | } |
| 1166 | 1165 | |
| 1166 | try self.allocateSpecialSymbols(); |
| 1167 | 1167 | try self.allocateGlobals(); |
| 1168 | 1168 | |
| 1169 | 1169 | if (build_options.enable_logging) { |
| ... | ... | @@ -2261,6 +2261,27 @@ fn shiftLocalsByOffset(self: *MachO, match: MatchingSection, offset: i64) !void |
| 2261 | 2261 | } |
| 2262 | 2262 | } |
| 2263 | 2263 | |
| 2264 | fn allocateSpecialSymbols(self: *MachO) !void { |
| 2265 | for (&[_]?u32{ |
| 2266 | self.mh_execute_header_sym_index, |
| 2267 | self.dso_handle_sym_index, |
| 2268 | }) |maybe_sym_index| { |
| 2269 | const sym_index = maybe_sym_index orelse continue; |
| 2270 | const sym = &self.locals.items[sym_index]; |
| 2271 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 2272 | sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(.{ |
| 2273 | .seg = self.text_segment_cmd_index.?, |
| 2274 | .sect = 0, |
| 2275 | }).? + 1); |
| 2276 | sym.n_value = seg.inner.vmaddr; |
| 2277 | |
| 2278 | log.debug("allocating {s} at the start of {s}", .{ |
| 2279 | self.getString(sym.n_strx), |
| 2280 | seg.inner.segName(), |
| 2281 | }); |
| 2282 | } |
| 2283 | } |
| 2284 | |
| 2264 | 2285 | fn allocateGlobals(self: *MachO) !void { |
| 2265 | 2286 | log.debug("allocating global symbols", .{}); |
| 2266 | 2287 | |
| ... | ... | @@ -2442,7 +2463,9 @@ pub fn createTlvPtrAtom(self: *MachO, target: Atom.Relocation.Target) !*Atom { |
| 2442 | 2463 | } |
| 2443 | 2464 | |
| 2444 | 2465 | fn createDyldPrivateAtom(self: *MachO) !void { |
| 2466 | if (self.dyld_stub_binder_index == null) return; |
| 2445 | 2467 | if (self.dyld_private_atom != null) return; |
| 2468 | |
| 2446 | 2469 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2447 | 2470 | const sym = try self.locals.addOne(self.base.allocator); |
| 2448 | 2471 | sym.* = .{ |
| ... | ... | @@ -2468,7 +2491,9 @@ fn createDyldPrivateAtom(self: *MachO) !void { |
| 2468 | 2491 | } |
| 2469 | 2492 | |
| 2470 | 2493 | fn createStubHelperPreambleAtom(self: *MachO) !void { |
| 2494 | if (self.dyld_stub_binder_index == null) return; |
| 2471 | 2495 | if (self.stub_helper_preamble_atom != null) return; |
| 2496 | |
| 2472 | 2497 | const arch = self.base.options.target.cpu.arch; |
| 2473 | 2498 | const size: u64 = switch (arch) { |
| 2474 | 2499 | .x86_64 => 15, |
| ... | ... | @@ -2816,57 +2841,46 @@ fn createTentativeDefAtoms(self: *MachO) !void { |
| 2816 | 2841 | } |
| 2817 | 2842 | } |
| 2818 | 2843 | |
| 2819 | | fn createDsoHandleAtom(self: *MachO) !void { |
| 2820 | | if (self.strtab_dir.getKeyAdapted(@as([]const u8, "___dso_handle"), StringIndexAdapter{ |
| 2844 | fn createDsoHandleSymbol(self: *MachO) !void { |
| 2845 | if (self.dso_handle_sym_index != null) return; |
| 2846 | |
| 2847 | const n_strx = self.strtab_dir.getKeyAdapted(@as([]const u8, "___dso_handle"), StringIndexAdapter{ |
| 2821 | 2848 | .bytes = &self.strtab, |
| 2822 | | })) |n_strx| blk: { |
| 2823 | | const resolv = self.symbol_resolver.getPtr(n_strx) orelse break :blk; |
| 2824 | | if (resolv.where != .undef) break :blk; |
| 2849 | }) orelse return; |
| 2825 | 2850 | |
| 2826 | | const undef = &self.undefs.items[resolv.where_index]; |
| 2827 | | const match: MatchingSection = .{ |
| 2828 | | .seg = self.text_segment_cmd_index.?, |
| 2829 | | .sect = self.text_section_index.?, |
| 2830 | | }; |
| 2831 | | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2832 | | var nlist = macho.nlist_64{ |
| 2833 | | .n_strx = undef.n_strx, |
| 2834 | | .n_type = macho.N_SECT, |
| 2835 | | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1), |
| 2836 | | .n_desc = 0, |
| 2837 | | .n_value = 0, |
| 2838 | | }; |
| 2839 | | try self.locals.append(self.base.allocator, nlist); |
| 2840 | | const global_sym_index = @intCast(u32, self.globals.items.len); |
| 2841 | | nlist.n_type |= macho.N_EXT; |
| 2842 | | nlist.n_desc = macho.N_WEAK_DEF; |
| 2843 | | try self.globals.append(self.base.allocator, nlist); |
| 2851 | const resolv = self.symbol_resolver.getPtr(n_strx) orelse return; |
| 2852 | if (resolv.where != .undef) return; |
| 2844 | 2853 | |
| 2845 | | assert(self.unresolved.swapRemove(resolv.where_index)); |
| 2854 | const undef = &self.undefs.items[resolv.where_index]; |
| 2855 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 2856 | var nlist = macho.nlist_64{ |
| 2857 | .n_strx = undef.n_strx, |
| 2858 | .n_type = macho.N_SECT, |
| 2859 | .n_sect = 0, |
| 2860 | .n_desc = 0, |
| 2861 | .n_value = 0, |
| 2862 | }; |
| 2863 | try self.locals.append(self.base.allocator, nlist); |
| 2864 | const global_sym_index = @intCast(u32, self.globals.items.len); |
| 2865 | nlist.n_type |= macho.N_EXT; |
| 2866 | nlist.n_desc = macho.N_WEAK_DEF; |
| 2867 | try self.globals.append(self.base.allocator, nlist); |
| 2868 | self.dso_handle_sym_index = local_sym_index; |
| 2846 | 2869 | |
| 2847 | | undef.* = .{ |
| 2848 | | .n_strx = 0, |
| 2849 | | .n_type = macho.N_UNDF, |
| 2850 | | .n_sect = 0, |
| 2851 | | .n_desc = 0, |
| 2852 | | .n_value = 0, |
| 2853 | | }; |
| 2854 | | resolv.* = .{ |
| 2855 | | .where = .global, |
| 2856 | | .where_index = global_sym_index, |
| 2857 | | .local_sym_index = local_sym_index, |
| 2858 | | }; |
| 2870 | assert(self.unresolved.swapRemove(resolv.where_index)); |
| 2859 | 2871 | |
| 2860 | | // We create an empty atom for this symbol. |
| 2861 | | // TODO perhaps we should special-case special symbols? Create a separate |
| 2862 | | // linked list of atoms? |
| 2863 | | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); |
| 2864 | | if (self.needs_prealloc) { |
| 2865 | | const sym = &self.locals.items[local_sym_index]; |
| 2866 | | const vaddr = try self.allocateAtom(atom, 0, 1, match); |
| 2867 | | sym.n_value = vaddr; |
| 2868 | | } else try self.addAtomToSection(atom, match); |
| 2869 | | } |
| 2872 | undef.* = .{ |
| 2873 | .n_strx = 0, |
| 2874 | .n_type = macho.N_UNDF, |
| 2875 | .n_sect = 0, |
| 2876 | .n_desc = 0, |
| 2877 | .n_value = 0, |
| 2878 | }; |
| 2879 | resolv.* = .{ |
| 2880 | .where = .global, |
| 2881 | .where_index = global_sym_index, |
| 2882 | .local_sym_index = local_sym_index, |
| 2883 | }; |
| 2870 | 2884 | } |
| 2871 | 2885 | |
| 2872 | 2886 | fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void { |
| ... | ... | @@ -3183,27 +3197,21 @@ fn resolveSymbolsInDylibs(self: *MachO) !void { |
| 3183 | 3197 | } |
| 3184 | 3198 | } |
| 3185 | 3199 | |
| 3186 | | fn createMhExecuteHeaderAtom(self: *MachO) !void { |
| 3187 | | if (self.mh_execute_header_index != null) return; |
| 3188 | | |
| 3189 | | const match: MatchingSection = .{ |
| 3190 | | .seg = self.text_segment_cmd_index.?, |
| 3191 | | .sect = self.text_section_index.?, |
| 3192 | | }; |
| 3193 | | const seg = self.load_commands.items[match.seg].segment; |
| 3194 | | const sect = seg.sections.items[match.sect]; |
| 3200 | fn createMhExecuteHeaderSymbol(self: *MachO) !void { |
| 3201 | if (self.base.options.output_mode != .Exe) return; |
| 3202 | if (self.mh_execute_header_sym_index != null) return; |
| 3195 | 3203 | |
| 3196 | 3204 | const n_strx = try self.makeString("__mh_execute_header"); |
| 3197 | 3205 | const local_sym_index = @intCast(u32, self.locals.items.len); |
| 3198 | 3206 | var nlist = macho.nlist_64{ |
| 3199 | 3207 | .n_strx = n_strx, |
| 3200 | 3208 | .n_type = macho.N_SECT, |
| 3201 | | .n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1), |
| 3209 | .n_sect = 0, |
| 3202 | 3210 | .n_desc = 0, |
| 3203 | | .n_value = sect.addr, |
| 3211 | .n_value = 0, |
| 3204 | 3212 | }; |
| 3205 | 3213 | try self.locals.append(self.base.allocator, nlist); |
| 3206 | | self.mh_execute_header_index = local_sym_index; |
| 3214 | self.mh_execute_header_sym_index = local_sym_index; |
| 3207 | 3215 | |
| 3208 | 3216 | if (self.symbol_resolver.getPtr(n_strx)) |resolv| { |
| 3209 | 3217 | const global = &self.globals.items[resolv.where_index]; |
| ... | ... | @@ -3223,23 +3231,11 @@ fn createMhExecuteHeaderAtom(self: *MachO) !void { |
| 3223 | 3231 | .file = null, |
| 3224 | 3232 | }); |
| 3225 | 3233 | } |
| 3226 | | |
| 3227 | | // We always set the __mh_execute_header to point to the beginning of the __TEXT,__text section |
| 3228 | | const atom = try self.createEmptyAtom(local_sym_index, 0, 0); |
| 3229 | | if (self.atoms.get(match)) |last| { |
| 3230 | | var first = last; |
| 3231 | | while (first.prev) |prev| { |
| 3232 | | first = prev; |
| 3233 | | } |
| 3234 | | atom.next = first; |
| 3235 | | first.prev = atom; |
| 3236 | | } else { |
| 3237 | | try self.atoms.putNoClobber(self.base.allocator, match, atom); |
| 3238 | | } |
| 3239 | 3234 | } |
| 3240 | 3235 | |
| 3241 | 3236 | fn resolveDyldStubBinder(self: *MachO) !void { |
| 3242 | 3237 | if (self.dyld_stub_binder_index != null) return; |
| 3238 | if (self.unresolved.count() == 0) return; // no need for a stub binder if we don't have any imports |
| 3243 | 3239 | |
| 3244 | 3240 | const n_strx = try self.makeString("dyld_stub_binder"); |
| 3245 | 3241 | const sym_index = @intCast(u32, self.undefs.items.len); |
| ... | ... | @@ -3295,7 +3291,12 @@ fn resolveDyldStubBinder(self: *MachO) !void { |
| 3295 | 3291 | const vaddr = try self.allocateAtom(atom, @sizeOf(u64), 8, match); |
| 3296 | 3292 | log.debug("allocated {s} atom at 0x{x}", .{ self.getString(sym.n_strx), vaddr }); |
| 3297 | 3293 | atom_sym.n_value = vaddr; |
| 3298 | | } else try self.addAtomToSection(atom, match); |
| 3294 | } else { |
| 3295 | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 3296 | const sect = &seg.sections.items[self.got_section_index.?]; |
| 3297 | sect.size += atom.size; |
| 3298 | try self.addAtomToSection(atom, match); |
| 3299 | } |
| 3299 | 3300 | |
| 3300 | 3301 | atom_sym.n_sect = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| 3301 | 3302 | } |
| ... | ... | @@ -4512,6 +4513,7 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4512 | 4513 | const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size); |
| 4513 | 4514 | |
| 4514 | 4515 | if (self.pagezero_segment_cmd_index == null) blk: { |
| 4516 | if (self.base.options.output_mode == .Lib) break :blk; |
| 4515 | 4517 | if (aligned_pagezero_vmsize == 0) break :blk; |
| 4516 | 4518 | if (aligned_pagezero_vmsize != pagezero_vmsize) { |
| 4517 | 4519 | log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize}); |
| ... | ... | @@ -4636,9 +4638,9 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4636 | 4638 | var fileoff: u64 = 0; |
| 4637 | 4639 | var needed_size: u64 = 0; |
| 4638 | 4640 | if (self.needs_prealloc) { |
| 4639 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 4640 | | vmaddr = address_and_offset.address; |
| 4641 | | fileoff = address_and_offset.offset; |
| 4641 | const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?}); |
| 4642 | vmaddr = base.vmaddr; |
| 4643 | fileoff = base.fileoff; |
| 4642 | 4644 | const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 4643 | 4645 | needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 4644 | 4646 | log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{ |
| ... | ... | @@ -4686,9 +4688,9 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4686 | 4688 | var fileoff: u64 = 0; |
| 4687 | 4689 | var needed_size: u64 = 0; |
| 4688 | 4690 | if (self.needs_prealloc) { |
| 4689 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 4690 | | vmaddr = address_and_offset.address; |
| 4691 | | fileoff = address_and_offset.offset; |
| 4691 | const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?}); |
| 4692 | vmaddr = base.vmaddr; |
| 4693 | fileoff = base.fileoff; |
| 4692 | 4694 | const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint; |
| 4693 | 4695 | needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size); |
| 4694 | 4696 | log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{ |
| ... | ... | @@ -4803,9 +4805,9 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 4803 | 4805 | var vmaddr: u64 = 0; |
| 4804 | 4806 | var fileoff: u64 = 0; |
| 4805 | 4807 | if (self.needs_prealloc) { |
| 4806 | | const address_and_offset = self.nextSegmentAddressAndOffset(); |
| 4807 | | vmaddr = address_and_offset.address; |
| 4808 | | fileoff = address_and_offset.offset; |
| 4808 | const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?}); |
| 4809 | vmaddr = base.vmaddr; |
| 4810 | fileoff = base.fileoff; |
| 4809 | 4811 | log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff}); |
| 4810 | 4812 | } |
| 4811 | 4813 | try self.load_commands.append(self.base.allocator, .{ |
| ... | ... | @@ -5030,17 +5032,10 @@ fn populateMissingMetadata(self: *MachO) !void { |
| 5030 | 5032 | self.cold_start = true; |
| 5031 | 5033 | } |
| 5032 | 5034 | |
| 5033 | | fn allocateTextSegment(self: *MachO) !void { |
| 5034 | | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5035 | | const base_vmaddr = if (self.pagezero_segment_cmd_index) |index| |
| 5036 | | self.load_commands.items[index].segment.inner.vmsize |
| 5037 | | else |
| 5038 | | 0; |
| 5039 | | seg.inner.fileoff = 0; |
| 5040 | | seg.inner.vmaddr = base_vmaddr; |
| 5041 | | |
| 5035 | fn calcMinHeaderpad(self: *MachO) u64 { |
| 5042 | 5036 | var sizeofcmds: u32 = 0; |
| 5043 | 5037 | for (self.load_commands.items) |lc| { |
| 5038 | if (lc.cmd() == .NONE) continue; |
| 5044 | 5039 | sizeofcmds += lc.cmdsize(); |
| 5045 | 5040 | } |
| 5046 | 5041 | |
| ... | ... | @@ -5067,60 +5062,74 @@ fn allocateTextSegment(self: *MachO) !void { |
| 5067 | 5062 | } |
| 5068 | 5063 | const offset = @sizeOf(macho.mach_header_64) + padding; |
| 5069 | 5064 | log.debug("actual headerpad size 0x{x}", .{offset}); |
| 5070 | | try self.allocateSegment(self.text_segment_cmd_index.?, offset); |
| 5071 | 5065 | |
| 5072 | | // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments. |
| 5073 | | var min_alignment: u32 = 0; |
| 5074 | | for (seg.sections.items) |sect| { |
| 5075 | | const alignment = try math.powi(u32, 2, sect.@"align"); |
| 5076 | | min_alignment = math.max(min_alignment, alignment); |
| 5077 | | } |
| 5066 | return offset; |
| 5067 | } |
| 5078 | 5068 | |
| 5079 | | assert(min_alignment > 0); |
| 5080 | | const last_sect_idx = seg.sections.items.len - 1; |
| 5081 | | const last_sect = seg.sections.items[last_sect_idx]; |
| 5082 | | const shift: u32 = blk: { |
| 5083 | | const diff = seg.inner.filesize - last_sect.offset - last_sect.size; |
| 5084 | | const factor = @divTrunc(diff, min_alignment); |
| 5085 | | break :blk @intCast(u32, factor * min_alignment); |
| 5086 | | }; |
| 5069 | fn allocateSegments(self: *MachO) !void { |
| 5070 | try self.allocateSegment(self.text_segment_cmd_index, &.{ |
| 5071 | self.pagezero_segment_cmd_index, |
| 5072 | }, self.calcMinHeaderpad()); |
| 5073 | |
| 5074 | if (self.text_segment_cmd_index) |index| blk: { |
| 5075 | const seg = &self.load_commands.items[index].segment; |
| 5076 | if (seg.sections.items.len == 0) break :blk; |
| 5087 | 5077 | |
| 5088 | | if (shift > 0) { |
| 5089 | | for (seg.sections.items) |*sect| { |
| 5090 | | sect.offset += shift; |
| 5091 | | sect.addr += shift; |
| 5078 | // Shift all sections to the back to minimize jump size between __TEXT and __DATA segments. |
| 5079 | var min_alignment: u32 = 0; |
| 5080 | for (seg.sections.items) |sect| { |
| 5081 | const alignment = try math.powi(u32, 2, sect.@"align"); |
| 5082 | min_alignment = math.max(min_alignment, alignment); |
| 5083 | } |
| 5084 | |
| 5085 | assert(min_alignment > 0); |
| 5086 | const last_sect_idx = seg.sections.items.len - 1; |
| 5087 | const last_sect = seg.sections.items[last_sect_idx]; |
| 5088 | const shift: u32 = shift: { |
| 5089 | const diff = seg.inner.filesize - last_sect.offset - last_sect.size; |
| 5090 | const factor = @divTrunc(diff, min_alignment); |
| 5091 | break :shift @intCast(u32, factor * min_alignment); |
| 5092 | }; |
| 5093 | |
| 5094 | if (shift > 0) { |
| 5095 | for (seg.sections.items) |*sect| { |
| 5096 | sect.offset += shift; |
| 5097 | sect.addr += shift; |
| 5098 | } |
| 5092 | 5099 | } |
| 5093 | 5100 | } |
| 5094 | | } |
| 5095 | 5101 | |
| 5096 | | fn allocateDataConstSegment(self: *MachO) !void { |
| 5097 | | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5098 | | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5099 | | seg.inner.fileoff = text_seg.inner.fileoff + text_seg.inner.filesize; |
| 5100 | | seg.inner.vmaddr = text_seg.inner.vmaddr + text_seg.inner.vmsize; |
| 5101 | | try self.allocateSegment(self.data_const_segment_cmd_index.?, 0); |
| 5102 | | } |
| 5102 | try self.allocateSegment(self.data_const_segment_cmd_index, &.{ |
| 5103 | self.text_segment_cmd_index, |
| 5104 | self.pagezero_segment_cmd_index, |
| 5105 | }, 0); |
| 5103 | 5106 | |
| 5104 | | fn allocateDataSegment(self: *MachO) !void { |
| 5105 | | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5106 | | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5107 | | seg.inner.fileoff = data_const_seg.inner.fileoff + data_const_seg.inner.filesize; |
| 5108 | | seg.inner.vmaddr = data_const_seg.inner.vmaddr + data_const_seg.inner.vmsize; |
| 5109 | | try self.allocateSegment(self.data_segment_cmd_index.?, 0); |
| 5110 | | } |
| 5107 | try self.allocateSegment(self.data_segment_cmd_index, &.{ |
| 5108 | self.data_const_segment_cmd_index, |
| 5109 | self.text_segment_cmd_index, |
| 5110 | self.pagezero_segment_cmd_index, |
| 5111 | }, 0); |
| 5111 | 5112 | |
| 5112 | | fn allocateLinkeditSegment(self: *MachO) void { |
| 5113 | | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].segment; |
| 5114 | | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5115 | | seg.inner.fileoff = data_seg.inner.fileoff + data_seg.inner.filesize; |
| 5116 | | seg.inner.vmaddr = data_seg.inner.vmaddr + data_seg.inner.vmsize; |
| 5113 | try self.allocateSegment(self.linkedit_segment_cmd_index, &.{ |
| 5114 | self.data_segment_cmd_index, |
| 5115 | self.data_const_segment_cmd_index, |
| 5116 | self.text_segment_cmd_index, |
| 5117 | self.pagezero_segment_cmd_index, |
| 5118 | }, 0); |
| 5117 | 5119 | } |
| 5118 | 5120 | |
| 5119 | | fn allocateSegment(self: *MachO, index: u16, offset: u64) !void { |
| 5121 | fn allocateSegment(self: *MachO, maybe_index: ?u16, indices: []const ?u16, init_size: u64) !void { |
| 5122 | const index = maybe_index orelse return; |
| 5120 | 5123 | const seg = &self.load_commands.items[index].segment; |
| 5121 | 5124 | |
| 5125 | const base = self.getSegmentAllocBase(indices); |
| 5126 | seg.inner.vmaddr = base.vmaddr; |
| 5127 | seg.inner.fileoff = base.fileoff; |
| 5128 | seg.inner.filesize = init_size; |
| 5129 | seg.inner.vmsize = init_size; |
| 5130 | |
| 5122 | 5131 | // Allocate the sections according to their alignment at the beginning of the segment. |
| 5123 | | var start: u64 = offset; |
| 5132 | var start = init_size; |
| 5124 | 5133 | for (seg.sections.items) |*sect, sect_id| { |
| 5125 | 5134 | const is_zerofill = sect.flags == macho.S_ZEROFILL or sect.flags == macho.S_THREAD_LOCAL_ZEROFILL; |
| 5126 | 5135 | const use_llvm = build_options.have_llvm and self.base.options.use_llvm; |
| ... | ... | @@ -5524,6 +5533,9 @@ fn addAtomToSection(self: *MachO, atom: *Atom, match: MatchingSection) !void { |
| 5524 | 5533 | } else { |
| 5525 | 5534 | try self.atoms.putNoClobber(self.base.allocator, match, atom); |
| 5526 | 5535 | } |
| 5536 | const seg = &self.load_commands.items[match.seg].segment; |
| 5537 | const sect = &seg.sections.items[match.sect]; |
| 5538 | sect.size += atom.size; |
| 5527 | 5539 | } |
| 5528 | 5540 | |
| 5529 | 5541 | pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 { |
| ... | ... | @@ -5551,180 +5563,145 @@ pub fn getGlobalSymbol(self: *MachO, name: []const u8) !u32 { |
| 5551 | 5563 | return n_strx; |
| 5552 | 5564 | } |
| 5553 | 5565 | |
| 5554 | | const NextSegmentAddressAndOffset = struct { |
| 5555 | | address: u64, |
| 5556 | | offset: u64, |
| 5557 | | }; |
| 5558 | | |
| 5559 | | fn nextSegmentAddressAndOffset(self: *MachO) NextSegmentAddressAndOffset { |
| 5560 | | var prev_segment_idx: ?usize = null; // We use optional here for safety. |
| 5561 | | for (self.load_commands.items) |cmd, i| { |
| 5562 | | if (cmd == .segment) { |
| 5563 | | prev_segment_idx = i; |
| 5564 | | } |
| 5566 | fn getSegmentAllocBase(self: MachO, indices: []const ?u16) struct { vmaddr: u64, fileoff: u64 } { |
| 5567 | for (indices) |maybe_prev_id| { |
| 5568 | const prev_id = maybe_prev_id orelse continue; |
| 5569 | const prev = self.load_commands.items[prev_id].segment; |
| 5570 | return .{ |
| 5571 | .vmaddr = prev.inner.vmaddr + prev.inner.vmsize, |
| 5572 | .fileoff = prev.inner.fileoff + prev.inner.filesize, |
| 5573 | }; |
| 5565 | 5574 | } |
| 5566 | | const prev_segment = self.load_commands.items[prev_segment_idx.?].segment; |
| 5567 | | const address = prev_segment.inner.vmaddr + prev_segment.inner.vmsize; |
| 5568 | | const offset = prev_segment.inner.fileoff + prev_segment.inner.filesize; |
| 5569 | | return .{ |
| 5570 | | .address = address, |
| 5571 | | .offset = offset, |
| 5572 | | }; |
| 5575 | return .{ .vmaddr = 0, .fileoff = 0 }; |
| 5573 | 5576 | } |
| 5574 | 5577 | |
| 5575 | | fn sortSections(self: *MachO) !void { |
| 5576 | | var text_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator); |
| 5577 | | defer text_index_mapping.deinit(); |
| 5578 | | var data_const_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator); |
| 5579 | | defer data_const_index_mapping.deinit(); |
| 5580 | | var data_index_mapping = std.AutoHashMap(u16, u16).init(self.base.allocator); |
| 5581 | | defer data_index_mapping.deinit(); |
| 5578 | fn pruneAndSortSectionsInSegment(self: *MachO, maybe_seg_id: *?u16, indices: []*?u16) !void { |
| 5579 | const seg_id = maybe_seg_id.* orelse return; |
| 5582 | 5580 | |
| 5583 | | { |
| 5584 | | // __TEXT segment |
| 5585 | | const seg = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5586 | | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 5587 | | defer self.base.allocator.free(sections); |
| 5588 | | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| 5589 | | |
| 5590 | | const indices = &[_]*?u16{ |
| 5591 | | &self.text_section_index, |
| 5592 | | &self.stubs_section_index, |
| 5593 | | &self.stub_helper_section_index, |
| 5594 | | &self.gcc_except_tab_section_index, |
| 5595 | | &self.cstring_section_index, |
| 5596 | | &self.ustring_section_index, |
| 5597 | | &self.text_const_section_index, |
| 5598 | | &self.objc_methlist_section_index, |
| 5599 | | &self.objc_methname_section_index, |
| 5600 | | &self.objc_methtype_section_index, |
| 5601 | | &self.objc_classname_section_index, |
| 5602 | | &self.eh_frame_section_index, |
| 5603 | | }; |
| 5604 | | for (indices) |maybe_index| { |
| 5605 | | const new_index: u16 = if (maybe_index.*) |index| blk: { |
| 5606 | | const idx = @intCast(u16, seg.sections.items.len); |
| 5607 | | seg.sections.appendAssumeCapacity(sections[index]); |
| 5608 | | try text_index_mapping.putNoClobber(index, idx); |
| 5609 | | break :blk idx; |
| 5610 | | } else continue; |
| 5611 | | maybe_index.* = new_index; |
| 5581 | var mapping = std.AutoArrayHashMap(u16, ?u16).init(self.base.allocator); |
| 5582 | defer mapping.deinit(); |
| 5583 | |
| 5584 | const seg = &self.load_commands.items[seg_id].segment; |
| 5585 | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 5586 | defer self.base.allocator.free(sections); |
| 5587 | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| 5588 | |
| 5589 | for (indices) |maybe_index| { |
| 5590 | const old_idx = maybe_index.* orelse continue; |
| 5591 | const sect = sections[old_idx]; |
| 5592 | if (sect.size == 0) { |
| 5593 | log.debug("pruning section {s},{s}", .{ sect.segName(), sect.sectName() }); |
| 5594 | maybe_index.* = null; |
| 5595 | seg.inner.cmdsize -= @sizeOf(macho.section_64); |
| 5596 | seg.inner.nsects -= 1; |
| 5597 | } else { |
| 5598 | maybe_index.* = @intCast(u16, seg.sections.items.len); |
| 5599 | seg.sections.appendAssumeCapacity(sect); |
| 5612 | 5600 | } |
| 5601 | try mapping.putNoClobber(old_idx, maybe_index.*); |
| 5613 | 5602 | } |
| 5614 | 5603 | |
| 5615 | | { |
| 5616 | | // __DATA_CONST segment |
| 5617 | | const seg = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5618 | | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 5619 | | defer self.base.allocator.free(sections); |
| 5620 | | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| 5621 | | |
| 5622 | | const indices = &[_]*?u16{ |
| 5623 | | &self.got_section_index, |
| 5624 | | &self.mod_init_func_section_index, |
| 5625 | | &self.mod_term_func_section_index, |
| 5626 | | &self.data_const_section_index, |
| 5627 | | &self.objc_cfstring_section_index, |
| 5628 | | &self.objc_classlist_section_index, |
| 5629 | | &self.objc_imageinfo_section_index, |
| 5604 | var atoms = std.ArrayList(struct { match: MatchingSection, atom: *Atom }).init(self.base.allocator); |
| 5605 | defer atoms.deinit(); |
| 5606 | try atoms.ensureTotalCapacity(mapping.count()); |
| 5607 | |
| 5608 | for (mapping.keys()) |old_sect| { |
| 5609 | const new_sect = mapping.get(old_sect).? orelse { |
| 5610 | _ = self.atoms.remove(.{ .seg = seg_id, .sect = old_sect }); |
| 5611 | continue; |
| 5630 | 5612 | }; |
| 5631 | | for (indices) |maybe_index| { |
| 5632 | | const new_index: u16 = if (maybe_index.*) |index| blk: { |
| 5633 | | const idx = @intCast(u16, seg.sections.items.len); |
| 5634 | | seg.sections.appendAssumeCapacity(sections[index]); |
| 5635 | | try data_const_index_mapping.putNoClobber(index, idx); |
| 5636 | | break :blk idx; |
| 5637 | | } else continue; |
| 5638 | | maybe_index.* = new_index; |
| 5639 | | } |
| 5613 | const kv = self.atoms.fetchRemove(.{ .seg = seg_id, .sect = old_sect }).?; |
| 5614 | atoms.appendAssumeCapacity(.{ |
| 5615 | .match = .{ .seg = seg_id, .sect = new_sect }, |
| 5616 | .atom = kv.value, |
| 5617 | }); |
| 5640 | 5618 | } |
| 5641 | 5619 | |
| 5642 | | { |
| 5643 | | // __DATA segment |
| 5644 | | const seg = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5645 | | var sections = seg.sections.toOwnedSlice(self.base.allocator); |
| 5646 | | defer self.base.allocator.free(sections); |
| 5647 | | try seg.sections.ensureTotalCapacity(self.base.allocator, sections.len); |
| 5648 | | |
| 5649 | | // __DATA segment |
| 5650 | | const indices = &[_]*?u16{ |
| 5651 | | &self.rustc_section_index, |
| 5652 | | &self.la_symbol_ptr_section_index, |
| 5653 | | &self.objc_const_section_index, |
| 5654 | | &self.objc_selrefs_section_index, |
| 5655 | | &self.objc_classrefs_section_index, |
| 5656 | | &self.objc_data_section_index, |
| 5657 | | &self.data_section_index, |
| 5658 | | &self.tlv_section_index, |
| 5659 | | &self.tlv_ptrs_section_index, |
| 5660 | | &self.tlv_data_section_index, |
| 5661 | | &self.tlv_bss_section_index, |
| 5662 | | &self.bss_section_index, |
| 5663 | | }; |
| 5664 | | for (indices) |maybe_index| { |
| 5665 | | const new_index: u16 = if (maybe_index.*) |index| blk: { |
| 5666 | | const idx = @intCast(u16, seg.sections.items.len); |
| 5667 | | seg.sections.appendAssumeCapacity(sections[index]); |
| 5668 | | try data_index_mapping.putNoClobber(index, idx); |
| 5669 | | break :blk idx; |
| 5670 | | } else continue; |
| 5671 | | maybe_index.* = new_index; |
| 5672 | | } |
| 5620 | while (atoms.popOrNull()) |next| { |
| 5621 | try self.atoms.putNoClobber(self.base.allocator, next.match, next.atom); |
| 5673 | 5622 | } |
| 5674 | 5623 | |
| 5675 | | { |
| 5676 | | var transient: std.AutoHashMapUnmanaged(MatchingSection, *Atom) = .{}; |
| 5677 | | try transient.ensureTotalCapacity(self.base.allocator, self.atoms.count()); |
| 5624 | if (seg.inner.nsects == 0 and !mem.eql(u8, "__TEXT", seg.inner.segName())) { |
| 5625 | // Segment has now become empty, so mark it as such |
| 5626 | log.debug("marking segment {s} as dead", .{seg.inner.segName()}); |
| 5627 | seg.inner.cmd = @intToEnum(macho.LC, 0); |
| 5628 | maybe_seg_id.* = null; |
| 5629 | } |
| 5630 | } |
| 5678 | 5631 | |
| 5679 | | var it = self.atoms.iterator(); |
| 5680 | | while (it.next()) |entry| { |
| 5681 | | const old = entry.key_ptr.*; |
| 5682 | | const sect = if (old.seg == self.text_segment_cmd_index.?) |
| 5683 | | text_index_mapping.get(old.sect).? |
| 5684 | | else if (old.seg == self.data_const_segment_cmd_index.?) |
| 5685 | | data_const_index_mapping.get(old.sect).? |
| 5686 | | else |
| 5687 | | data_index_mapping.get(old.sect).?; |
| 5688 | | transient.putAssumeCapacityNoClobber(.{ |
| 5689 | | .seg = old.seg, |
| 5690 | | .sect = sect, |
| 5691 | | }, entry.value_ptr.*); |
| 5692 | | } |
| 5632 | fn pruneAndSortSections(self: *MachO) !void { |
| 5633 | try self.pruneAndSortSectionsInSegment(&self.text_segment_cmd_index, &.{ |
| 5634 | &self.text_section_index, |
| 5635 | &self.stubs_section_index, |
| 5636 | &self.stub_helper_section_index, |
| 5637 | &self.gcc_except_tab_section_index, |
| 5638 | &self.cstring_section_index, |
| 5639 | &self.ustring_section_index, |
| 5640 | &self.text_const_section_index, |
| 5641 | &self.objc_methlist_section_index, |
| 5642 | &self.objc_methname_section_index, |
| 5643 | &self.objc_methtype_section_index, |
| 5644 | &self.objc_classname_section_index, |
| 5645 | &self.eh_frame_section_index, |
| 5646 | }); |
| 5693 | 5647 | |
| 5694 | | self.atoms.clearAndFree(self.base.allocator); |
| 5695 | | self.atoms.deinit(self.base.allocator); |
| 5696 | | self.atoms = transient; |
| 5697 | | } |
| 5648 | try self.pruneAndSortSectionsInSegment(&self.data_const_segment_cmd_index, &.{ |
| 5649 | &self.got_section_index, |
| 5650 | &self.mod_init_func_section_index, |
| 5651 | &self.mod_term_func_section_index, |
| 5652 | &self.data_const_section_index, |
| 5653 | &self.objc_cfstring_section_index, |
| 5654 | &self.objc_classlist_section_index, |
| 5655 | &self.objc_imageinfo_section_index, |
| 5656 | }); |
| 5698 | 5657 | |
| 5699 | | { |
| 5700 | | // Create new section ordinals. |
| 5701 | | self.section_ordinals.clearRetainingCapacity(); |
| 5702 | | const text_seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5703 | | for (text_seg.sections.items) |_, sect_id| { |
| 5658 | try self.pruneAndSortSectionsInSegment(&self.data_segment_cmd_index, &.{ |
| 5659 | &self.rustc_section_index, |
| 5660 | &self.la_symbol_ptr_section_index, |
| 5661 | &self.objc_const_section_index, |
| 5662 | &self.objc_selrefs_section_index, |
| 5663 | &self.objc_classrefs_section_index, |
| 5664 | &self.objc_data_section_index, |
| 5665 | &self.data_section_index, |
| 5666 | &self.tlv_section_index, |
| 5667 | &self.tlv_ptrs_section_index, |
| 5668 | &self.tlv_data_section_index, |
| 5669 | &self.tlv_bss_section_index, |
| 5670 | &self.bss_section_index, |
| 5671 | }); |
| 5672 | |
| 5673 | // Create new section ordinals. |
| 5674 | self.section_ordinals.clearRetainingCapacity(); |
| 5675 | if (self.text_segment_cmd_index) |seg_id| { |
| 5676 | const seg = self.load_commands.items[seg_id].segment; |
| 5677 | for (seg.sections.items) |_, sect_id| { |
| 5704 | 5678 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5705 | | .seg = self.text_segment_cmd_index.?, |
| 5679 | .seg = seg_id, |
| 5706 | 5680 | .sect = @intCast(u16, sect_id), |
| 5707 | 5681 | }); |
| 5708 | 5682 | assert(!res.found_existing); |
| 5709 | 5683 | } |
| 5710 | | const data_const_seg = self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 5711 | | for (data_const_seg.sections.items) |_, sect_id| { |
| 5684 | } |
| 5685 | if (self.data_const_segment_cmd_index) |seg_id| { |
| 5686 | const seg = self.load_commands.items[seg_id].segment; |
| 5687 | for (seg.sections.items) |_, sect_id| { |
| 5712 | 5688 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5713 | | .seg = self.data_const_segment_cmd_index.?, |
| 5689 | .seg = seg_id, |
| 5714 | 5690 | .sect = @intCast(u16, sect_id), |
| 5715 | 5691 | }); |
| 5716 | 5692 | assert(!res.found_existing); |
| 5717 | 5693 | } |
| 5718 | | const data_seg = self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 5719 | | for (data_seg.sections.items) |_, sect_id| { |
| 5694 | } |
| 5695 | if (self.data_segment_cmd_index) |seg_id| { |
| 5696 | const seg = self.load_commands.items[seg_id].segment; |
| 5697 | for (seg.sections.items) |_, sect_id| { |
| 5720 | 5698 | const res = self.section_ordinals.getOrPutAssumeCapacity(.{ |
| 5721 | | .seg = self.data_segment_cmd_index.?, |
| 5699 | .seg = seg_id, |
| 5722 | 5700 | .sect = @intCast(u16, sect_id), |
| 5723 | 5701 | }); |
| 5724 | 5702 | assert(!res.found_existing); |
| 5725 | 5703 | } |
| 5726 | 5704 | } |
| 5727 | | |
| 5728 | 5705 | self.sections_order_dirty = false; |
| 5729 | 5706 | } |
| 5730 | 5707 | |
| ... | ... | @@ -5739,12 +5716,16 @@ fn updateSectionOrdinals(self: *MachO) !void { |
| 5739 | 5716 | var ordinals: std.AutoArrayHashMapUnmanaged(MatchingSection, void) = .{}; |
| 5740 | 5717 | |
| 5741 | 5718 | var new_ordinal: u8 = 0; |
| 5742 | | for (self.load_commands.items) |lc, lc_id| { |
| 5743 | | if (lc != .segment) break; |
| 5744 | | |
| 5745 | | for (lc.segment.sections.items) |_, sect_id| { |
| 5719 | for (&[_]?u16{ |
| 5720 | self.text_segment_cmd_index, |
| 5721 | self.data_const_segment_cmd_index, |
| 5722 | self.data_segment_cmd_index, |
| 5723 | }) |maybe_index| { |
| 5724 | const index = maybe_index orelse continue; |
| 5725 | const seg = self.load_commands.items[index].segment; |
| 5726 | for (seg.sections.items) |_, sect_id| { |
| 5746 | 5727 | const match = MatchingSection{ |
| 5747 | | .seg = @intCast(u16, lc_id), |
| 5728 | .seg = @intCast(u16, index), |
| 5748 | 5729 | .sect = @intCast(u16, sect_id), |
| 5749 | 5730 | }; |
| 5750 | 5731 | const old_ordinal = @intCast(u8, self.section_ordinals.getIndex(match).? + 1); |
| ... | ... | @@ -5783,7 +5764,9 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5783 | 5764 | const match = entry.key_ptr.*; |
| 5784 | 5765 | var atom: *Atom = entry.value_ptr.*; |
| 5785 | 5766 | |
| 5786 | | if (match.seg == self.text_segment_cmd_index.?) continue; // __TEXT is non-writable |
| 5767 | if (self.text_segment_cmd_index) |seg| { |
| 5768 | if (match.seg == seg) continue; // __TEXT is non-writable |
| 5769 | } |
| 5787 | 5770 | |
| 5788 | 5771 | const seg = self.load_commands.items[match.seg].segment; |
| 5789 | 5772 | |
| ... | ... | @@ -5865,6 +5848,7 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5865 | 5848 | { |
| 5866 | 5849 | // TODO handle macho.EXPORT_SYMBOL_FLAGS_REEXPORT and macho.EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER. |
| 5867 | 5850 | log.debug("generating export trie", .{}); |
| 5851 | |
| 5868 | 5852 | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 5869 | 5853 | const base_address = text_segment.inner.vmaddr; |
| 5870 | 5854 | |
| ... | ... | @@ -5957,10 +5941,13 @@ fn writeDyldInfoData(self: *MachO) !void { |
| 5957 | 5941 | } |
| 5958 | 5942 | |
| 5959 | 5943 | fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 5944 | const text_segment_cmd_index = self.text_segment_cmd_index orelse return; |
| 5945 | const stub_helper_section_index = self.stub_helper_section_index orelse return; |
| 5960 | 5946 | const last_atom = self.atoms.get(.{ |
| 5961 | | .seg = self.text_segment_cmd_index.?, |
| 5962 | | .sect = self.stub_helper_section_index.?, |
| 5947 | .seg = text_segment_cmd_index, |
| 5948 | .sect = stub_helper_section_index, |
| 5963 | 5949 | }) orelse return; |
| 5950 | if (self.stub_helper_preamble_atom == null) return; |
| 5964 | 5951 | if (last_atom == self.stub_helper_preamble_atom.?) return; |
| 5965 | 5952 | |
| 5966 | 5953 | var table = std.AutoHashMap(i64, *Atom).init(self.base.allocator); |
| ... | ... | @@ -6036,8 +6023,8 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, buffer: []const u8) !void { |
| 6036 | 6023 | } |
| 6037 | 6024 | |
| 6038 | 6025 | const sect = blk: { |
| 6039 | | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 6040 | | break :blk seg.sections.items[self.stub_helper_section_index.?]; |
| 6026 | const seg = self.load_commands.items[text_segment_cmd_index].segment; |
| 6027 | break :blk seg.sections.items[stub_helper_section_index]; |
| 6041 | 6028 | }; |
| 6042 | 6029 | const stub_offset: u4 = switch (self.base.options.target.cpu.arch) { |
| 6043 | 6030 | .x86_64 => 1, |
| ... | ... | @@ -6326,15 +6313,8 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6326 | 6313 | dysymtab.iundefsym = dysymtab.nlocalsym + dysymtab.nextdefsym; |
| 6327 | 6314 | dysymtab.nundefsym = @intCast(u32, nundefs); |
| 6328 | 6315 | |
| 6329 | | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 6330 | | const stubs = &text_segment.sections.items[self.stubs_section_index.?]; |
| 6331 | | const data_const_segment = &self.load_commands.items[self.data_const_segment_cmd_index.?].segment; |
| 6332 | | const got = &data_const_segment.sections.items[self.got_section_index.?]; |
| 6333 | | const data_segment = &self.load_commands.items[self.data_segment_cmd_index.?].segment; |
| 6334 | | const la_symbol_ptr = &data_segment.sections.items[self.la_symbol_ptr_section_index.?]; |
| 6335 | | |
| 6336 | | const nstubs = @intCast(u32, self.stubs_table.keys().len); |
| 6337 | | const ngot_entries = @intCast(u32, self.got_entries_table.keys().len); |
| 6316 | const nstubs = @intCast(u32, self.stubs_table.count()); |
| 6317 | const ngot_entries = @intCast(u32, self.got_entries_table.count()); |
| 6338 | 6318 | |
| 6339 | 6319 | const indirectsymoff = mem.alignForwardGeneric(u64, seg.inner.fileoff + seg.inner.filesize, @alignOf(u64)); |
| 6340 | 6320 | dysymtab.indirectsymoff = @intCast(u32, indirectsymoff); |
| ... | ... | @@ -6352,35 +6332,50 @@ fn writeSymbolTable(self: *MachO) !void { |
| 6352 | 6332 | try buf.ensureTotalCapacity(dysymtab.nindirectsyms * @sizeOf(u32)); |
| 6353 | 6333 | const writer = buf.writer(); |
| 6354 | 6334 | |
| 6355 | | stubs.reserved1 = 0; |
| 6356 | | for (self.stubs_table.keys()) |key| { |
| 6357 | | const resolv = self.symbol_resolver.get(key).?; |
| 6358 | | switch (resolv.where) { |
| 6359 | | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6360 | | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6335 | if (self.text_segment_cmd_index) |text_segment_cmd_index| blk: { |
| 6336 | const stubs_section_index = self.stubs_section_index orelse break :blk; |
| 6337 | const text_segment = &self.load_commands.items[text_segment_cmd_index].segment; |
| 6338 | const stubs = &text_segment.sections.items[stubs_section_index]; |
| 6339 | stubs.reserved1 = 0; |
| 6340 | for (self.stubs_table.keys()) |key| { |
| 6341 | const resolv = self.symbol_resolver.get(key).?; |
| 6342 | switch (resolv.where) { |
| 6343 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6344 | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6345 | } |
| 6361 | 6346 | } |
| 6362 | 6347 | } |
| 6363 | 6348 | |
| 6364 | | got.reserved1 = nstubs; |
| 6365 | | for (self.got_entries_table.keys()) |key| { |
| 6366 | | switch (key) { |
| 6367 | | .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6368 | | .global => |n_strx| { |
| 6369 | | const resolv = self.symbol_resolver.get(n_strx).?; |
| 6370 | | switch (resolv.where) { |
| 6371 | | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6372 | | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6373 | | } |
| 6374 | | }, |
| 6349 | if (self.data_const_segment_cmd_index) |data_const_segment_cmd_index| blk: { |
| 6350 | const got_section_index = self.got_section_index orelse break :blk; |
| 6351 | const data_const_segment = &self.load_commands.items[data_const_segment_cmd_index].segment; |
| 6352 | const got = &data_const_segment.sections.items[got_section_index]; |
| 6353 | got.reserved1 = nstubs; |
| 6354 | for (self.got_entries_table.keys()) |key| { |
| 6355 | switch (key) { |
| 6356 | .local => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6357 | .global => |n_strx| { |
| 6358 | const resolv = self.symbol_resolver.get(n_strx).?; |
| 6359 | switch (resolv.where) { |
| 6360 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6361 | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6362 | } |
| 6363 | }, |
| 6364 | } |
| 6375 | 6365 | } |
| 6376 | 6366 | } |
| 6377 | 6367 | |
| 6378 | | la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries; |
| 6379 | | for (self.stubs_table.keys()) |key| { |
| 6380 | | const resolv = self.symbol_resolver.get(key).?; |
| 6381 | | switch (resolv.where) { |
| 6382 | | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6383 | | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6368 | if (self.data_segment_cmd_index) |data_segment_cmd_index| blk: { |
| 6369 | const la_symbol_ptr_section_index = self.la_symbol_ptr_section_index orelse break :blk; |
| 6370 | const data_segment = &self.load_commands.items[data_segment_cmd_index].segment; |
| 6371 | const la_symbol_ptr = &data_segment.sections.items[la_symbol_ptr_section_index]; |
| 6372 | la_symbol_ptr.reserved1 = nstubs + ngot_entries; |
| 6373 | for (self.stubs_table.keys()) |key| { |
| 6374 | const resolv = self.symbol_resolver.get(key).?; |
| 6375 | switch (resolv.where) { |
| 6376 | .global => try writer.writeIntLittle(u32, macho.INDIRECT_SYMBOL_LOCAL), |
| 6377 | .undef => try writer.writeIntLittle(u32, dysymtab.iundefsym + undefs_table.get(resolv.where_index).?), |
| 6378 | } |
| 6384 | 6379 | } |
| 6385 | 6380 | } |
| 6386 | 6381 | |
| ... | ... | @@ -6452,15 +6447,16 @@ fn writeCodeSignature(self: *MachO, code_sig: *CodeSignature) !void { |
| 6452 | 6447 | const tracy = trace(@src()); |
| 6453 | 6448 | defer tracy.end(); |
| 6454 | 6449 | |
| 6455 | | const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 6456 | 6450 | const code_sig_cmd = self.load_commands.items[self.code_signature_cmd_index.?].linkedit_data; |
| 6451 | const seg = self.load_commands.items[self.text_segment_cmd_index.?].segment; |
| 6457 | 6452 | |
| 6458 | 6453 | var buffer = std.ArrayList(u8).init(self.base.allocator); |
| 6459 | 6454 | defer buffer.deinit(); |
| 6460 | 6455 | try buffer.ensureTotalCapacityPrecise(code_sig.size()); |
| 6461 | 6456 | try code_sig.writeAdhocSignature(self.base.allocator, .{ |
| 6462 | 6457 | .file = self.base.file.?, |
| 6463 | | .text_segment = text_segment.inner, |
| 6458 | .exec_seg_base = seg.inner.fileoff, |
| 6459 | .exec_seg_limit = seg.inner.filesize, |
| 6464 | 6460 | .code_sig_cmd = code_sig_cmd, |
| 6465 | 6461 | .output_mode = self.base.options.output_mode, |
| 6466 | 6462 | }, buffer.writer()); |
| ... | ... | @@ -6480,6 +6476,7 @@ fn writeLoadCommands(self: *MachO) !void { |
| 6480 | 6476 | |
| 6481 | 6477 | var sizeofcmds: u32 = 0; |
| 6482 | 6478 | for (self.load_commands.items) |lc| { |
| 6479 | if (lc.cmd() == .NONE) continue; |
| 6483 | 6480 | sizeofcmds += lc.cmdsize(); |
| 6484 | 6481 | } |
| 6485 | 6482 | |
| ... | ... | @@ -6488,12 +6485,13 @@ fn writeLoadCommands(self: *MachO) !void { |
| 6488 | 6485 | var fib = std.io.fixedBufferStream(buffer); |
| 6489 | 6486 | const writer = fib.writer(); |
| 6490 | 6487 | for (self.load_commands.items) |lc| { |
| 6488 | if (lc.cmd() == .NONE) continue; |
| 6491 | 6489 | try lc.write(writer); |
| 6492 | 6490 | } |
| 6493 | 6491 | |
| 6494 | 6492 | const off = @sizeOf(macho.mach_header_64); |
| 6495 | 6493 | |
| 6496 | | log.debug("writing {} load commands from 0x{x} to 0x{x}", .{ self.load_commands.items.len, off, off + sizeofcmds }); |
| 6494 | log.debug("writing load commands from 0x{x} to 0x{x}", .{ off, off + sizeofcmds }); |
| 6497 | 6495 | |
| 6498 | 6496 | try self.base.file.?.pwriteAll(buffer, off); |
| 6499 | 6497 | self.load_commands_dirty = false; |
| ... | ... | @@ -6532,11 +6530,13 @@ fn writeHeader(self: *MachO) !void { |
| 6532 | 6530 | header.flags |= macho.MH_HAS_TLV_DESCRIPTORS; |
| 6533 | 6531 | } |
| 6534 | 6532 | |
| 6535 | | header.ncmds = @intCast(u32, self.load_commands.items.len); |
| 6533 | header.ncmds = 0; |
| 6536 | 6534 | header.sizeofcmds = 0; |
| 6537 | 6535 | |
| 6538 | 6536 | for (self.load_commands.items) |cmd| { |
| 6537 | if (cmd.cmd() == .NONE) continue; |
| 6539 | 6538 | header.sizeofcmds += cmd.cmdsize(); |
| 6539 | header.ncmds += 1; |
| 6540 | 6540 | } |
| 6541 | 6541 | |
| 6542 | 6542 | log.debug("writing Mach-O header {}", .{header}); |