| ... | ... | @@ -12,6 +12,7 @@ const aarch64 = @import("../codegen/aarch64.zig"); |
| 12 | 12 | const math = std.math; |
| 13 | 13 | const mem = std.mem; |
| 14 | 14 | |
| 15 | const bind = @import("MachO/bind.zig"); |
| 15 | 16 | const trace = @import("../tracy.zig").trace; |
| 16 | 17 | const build_options = @import("build_options"); |
| 17 | 18 | const Module = @import("../Module.zig"); |
| ... | ... | @@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig"); |
| 26 | 27 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 27 | 28 | |
| 28 | 29 | usingnamespace @import("MachO/commands.zig"); |
| 29 | | usingnamespace @import("MachO/imports.zig"); |
| 30 | 30 | |
| 31 | 31 | pub const base_tag: File.Tag = File.Tag.macho; |
| 32 | 32 | |
| ... | ... | @@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | 108 | /// Table of all global symbols |
| 109 | 109 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | 110 | /// Table of all extern nonlazy symbols, indexed by name. |
| 111 | | nonlazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, |
| 111 | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 112 | 112 | /// Table of all extern lazy symbols, indexed by name. |
| 113 | | lazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, |
| 113 | lazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 114 | 114 | |
| 115 | 115 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | 116 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | ... | @@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 169 | 169 | /// rather than sitting in the global scope. |
| 170 | 170 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, |
| 171 | 171 | |
| 172 | pub const Import = struct { |
| 173 | /// MachO symbol table entry. |
| 174 | symbol: macho.nlist_64, |
| 175 | |
| 176 | /// Id of the dynamic library where the specified entries can be found. |
| 177 | dylib_ordinal: i64, |
| 178 | |
| 179 | /// Index of this import within the import list. |
| 180 | index: u32, |
| 181 | }; |
| 182 | |
| 172 | 183 | pub const PieFixup = struct { |
| 173 | 184 | /// Target address we wanted to address in absolute terms. |
| 174 | 185 | address: u64, |
| ... | ... | @@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1285 | 1296 | try self.writeStubInStubHelper(fixup.symbol); |
| 1286 | 1297 | try self.writeLazySymbolPointer(fixup.symbol); |
| 1287 | 1298 | |
| 1288 | | const extern_sym = &self.lazy_imports.items()[fixup.symbol].value; |
| 1289 | | extern_sym.segment = self.data_segment_cmd_index.?; |
| 1290 | | extern_sym.offset = fixup.symbol * @sizeOf(u64); |
| 1291 | 1299 | self.rebase_info_dirty = true; |
| 1292 | 1300 | self.lazy_binding_info_dirty = true; |
| 1293 | 1301 | } |
| ... | ... | @@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2065 | 2073 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); |
| 2066 | 2074 | const offset = try self.makeString("dyld_stub_binder"); |
| 2067 | 2075 | try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{ |
| 2068 | | .inner = .{ |
| 2076 | .symbol = .{ |
| 2069 | 2077 | .n_strx = offset, |
| 2070 | 2078 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| 2071 | 2079 | .n_sect = 0, |
| ... | ... | @@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2073 | 2081 | .n_value = 0, |
| 2074 | 2082 | }, |
| 2075 | 2083 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2076 | | .segment = self.data_const_segment_cmd_index.?, |
| 2077 | | .offset = index * @sizeOf(u64), |
| 2084 | .index = index, |
| 2078 | 2085 | }); |
| 2079 | 2086 | self.binding_info_dirty = true; |
| 2080 | 2087 | } |
| ... | ... | @@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2238 | 2245 | const sym_name = try self.base.allocator.dupe(u8, name); |
| 2239 | 2246 | const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. |
| 2240 | 2247 | try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{ |
| 2241 | | .inner = .{ |
| 2248 | .symbol = .{ |
| 2242 | 2249 | .n_strx = offset, |
| 2243 | 2250 | .n_type = macho.N_UNDF | macho.N_EXT, |
| 2244 | 2251 | .n_sect = 0, |
| ... | ... | @@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2246 | 2253 | .n_value = 0, |
| 2247 | 2254 | }, |
| 2248 | 2255 | .dylib_ordinal = dylib_ordinal, |
| 2256 | .index = index, |
| 2249 | 2257 | }); |
| 2250 | 2258 | log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); |
| 2251 | 2259 | return index; |
| ... | ... | @@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2767 | 2775 | defer undefs.deinit(); |
| 2768 | 2776 | try undefs.ensureCapacity(nundefs); |
| 2769 | 2777 | for (self.lazy_imports.items()) |entry| { |
| 2770 | | undefs.appendAssumeCapacity(entry.value.inner); |
| 2778 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2771 | 2779 | } |
| 2772 | 2780 | for (self.nonlazy_imports.items()) |entry| { |
| 2773 | | undefs.appendAssumeCapacity(entry.value.inner); |
| 2781 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2774 | 2782 | } |
| 2775 | 2783 | |
| 2776 | 2784 | const locals_off = symtab.symoff; |
| ... | ... | @@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2832 | 2840 | var writer = stream.writer(); |
| 2833 | 2841 | |
| 2834 | 2842 | stubs.reserved1 = 0; |
| 2835 | | for (self.lazy_imports.items()) |_, i| { |
| 2843 | for (lazy) |_, i| { |
| 2836 | 2844 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2837 | 2845 | try writer.writeIntLittle(u32, symtab_idx); |
| 2838 | 2846 | } |
| 2839 | 2847 | |
| 2840 | 2848 | const base_id = @intCast(u32, lazy.len); |
| 2841 | 2849 | got.reserved1 = base_id; |
| 2842 | | for (self.nonlazy_imports.items()) |_, i| { |
| 2850 | for (nonlazy) |_, i| { |
| 2843 | 2851 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); |
| 2844 | 2852 | try writer.writeIntLittle(u32, symtab_idx); |
| 2845 | 2853 | } |
| 2846 | 2854 | |
| 2847 | 2855 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); |
| 2848 | | for (self.lazy_imports.items()) |_, i| { |
| 2856 | for (lazy) |_, i| { |
| 2849 | 2857 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2850 | 2858 | try writer.writeIntLittle(u32, symtab_idx); |
| 2851 | 2859 | } |
| ... | ... | @@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2962 | 2970 | const tracy = trace(@src()); |
| 2963 | 2971 | defer tracy.end(); |
| 2964 | 2972 | |
| 2965 | | const size = try rebaseInfoSize(self.lazy_imports.items()); |
| 2973 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 2974 | defer pointers.deinit(); |
| 2975 | |
| 2976 | if (self.la_symbol_ptr_section_index) |idx| { |
| 2977 | try pointers.ensureCapacity(pointers.items.len + self.lazy_imports.items().len); |
| 2978 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 2979 | const sect = seg.sections.items[idx]; |
| 2980 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 2981 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 2982 | |
| 2983 | for (self.lazy_imports.items()) |entry| { |
| 2984 | pointers.appendAssumeCapacity(.{ |
| 2985 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 2986 | .segment_id = segment_id, |
| 2987 | }); |
| 2988 | } |
| 2989 | } |
| 2990 | |
| 2991 | std.sort.sort(bind.Pointer, pointers.items, {}, bind.pointerCmp); |
| 2992 | |
| 2993 | const size = try bind.rebaseInfoSize(pointers.items); |
| 2966 | 2994 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2967 | 2995 | defer self.base.allocator.free(buffer); |
| 2968 | 2996 | |
| 2969 | 2997 | var stream = std.io.fixedBufferStream(buffer); |
| 2970 | | try writeRebaseInfo(self.lazy_imports.items(), stream.writer()); |
| 2998 | try bind.writeRebaseInfo(pointers.items, stream.writer()); |
| 2971 | 2999 | |
| 2972 | | const linkedit_segment = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2973 | 3000 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2974 | 3001 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); |
| 2975 | 3002 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | ... | @@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2994 | 3021 | const tracy = trace(@src()); |
| 2995 | 3022 | defer tracy.end(); |
| 2996 | 3023 | |
| 2997 | | const size = try bindInfoSize(self.nonlazy_imports.items()); |
| 3024 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 3025 | defer pointers.deinit(); |
| 3026 | |
| 3027 | if (self.data_got_section_index) |idx| { |
| 3028 | try pointers.ensureCapacity(pointers.items.len + self.nonlazy_imports.items().len); |
| 3029 | const seg = self.load_commands.items[self.data_const_segment_cmd_index.?].Segment; |
| 3030 | const sect = seg.sections.items[idx]; |
| 3031 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 3032 | const segment_id = @intCast(u16, self.data_const_segment_cmd_index.?); |
| 3033 | |
| 3034 | for (self.nonlazy_imports.items()) |entry| { |
| 3035 | pointers.appendAssumeCapacity(.{ |
| 3036 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 3037 | .segment_id = segment_id, |
| 3038 | .dylib_ordinal = entry.value.dylib_ordinal, |
| 3039 | .name = entry.key, |
| 3040 | }); |
| 3041 | } |
| 3042 | } |
| 3043 | |
| 3044 | const size = try bind.bindInfoSize(pointers.items); |
| 2998 | 3045 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2999 | 3046 | defer self.base.allocator.free(buffer); |
| 3000 | 3047 | |
| 3001 | 3048 | var stream = std.io.fixedBufferStream(buffer); |
| 3002 | | try writeBindInfo(self.nonlazy_imports.items(), stream.writer()); |
| 3049 | try bind.writeBindInfo(pointers.items, stream.writer()); |
| 3003 | 3050 | |
| 3004 | | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 3005 | 3051 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 3006 | 3052 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); |
| 3007 | 3053 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | ... | @@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 3023 | 3069 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 3024 | 3070 | if (!self.lazy_binding_info_dirty) return; |
| 3025 | 3071 | |
| 3026 | | const size = try lazyBindInfoSize(self.lazy_imports.items()); |
| 3072 | const tracy = trace(@src()); |
| 3073 | defer tracy.end(); |
| 3074 | |
| 3075 | var pointers = std.ArrayList(bind.Pointer).init(self.base.allocator); |
| 3076 | defer pointers.deinit(); |
| 3077 | |
| 3078 | if (self.la_symbol_ptr_section_index) |idx| { |
| 3079 | try pointers.ensureCapacity(self.lazy_imports.items().len); |
| 3080 | const seg = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 3081 | const sect = seg.sections.items[idx]; |
| 3082 | const base_offset = sect.addr - seg.inner.vmaddr; |
| 3083 | const segment_id = @intCast(u16, self.data_segment_cmd_index.?); |
| 3084 | |
| 3085 | for (self.lazy_imports.items()) |entry| { |
| 3086 | pointers.appendAssumeCapacity(.{ |
| 3087 | .offset = base_offset + entry.value.index * @sizeOf(u64), |
| 3088 | .segment_id = segment_id, |
| 3089 | .dylib_ordinal = entry.value.dylib_ordinal, |
| 3090 | .name = entry.key, |
| 3091 | }); |
| 3092 | } |
| 3093 | } |
| 3094 | |
| 3095 | const size = try bind.lazyBindInfoSize(pointers.items); |
| 3027 | 3096 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 3028 | 3097 | defer self.base.allocator.free(buffer); |
| 3029 | 3098 | |
| 3030 | 3099 | var stream = std.io.fixedBufferStream(buffer); |
| 3031 | | try writeLazyBindInfo(self.lazy_imports.items(), stream.writer()); |
| 3100 | try bind.writeLazyBindInfo(pointers.items, stream.writer()); |
| 3032 | 3101 | |
| 3033 | | const linkedit_segment = self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 3034 | 3102 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 3035 | 3103 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); |
| 3036 | 3104 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |