| ... | @@ -12,6 +12,7 @@ const aarch64 = @import("../codegen/aarch64.zig"); | ... | @@ -12,6 +12,7 @@ const aarch64 = @import("../codegen/aarch64.zig"); |
| 12 | const math = std.math; | 12 | const math = std.math; |
| 13 | const mem = std.mem; | 13 | const mem = std.mem; |
| 14 | | 14 | |
| | 15 | const bind = @import("MachO/bind.zig"); |
| 15 | const trace = @import("../tracy.zig").trace; | 16 | const trace = @import("../tracy.zig").trace; |
| 16 | const build_options = @import("build_options"); | 17 | const build_options = @import("build_options"); |
| 17 | const Module = @import("../Module.zig"); | 18 | const Module = @import("../Module.zig"); |
| ... | @@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig"); | ... | @@ -26,7 +27,6 @@ const Trie = @import("MachO/Trie.zig"); |
| 26 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 27 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 27 | | 28 | |
| 28 | usingnamespace @import("MachO/commands.zig"); | 29 | usingnamespace @import("MachO/commands.zig"); |
| 29 | usingnamespace @import("MachO/imports.zig"); | | |
| 30 | | 30 | |
| 31 | pub const base_tag: File.Tag = File.Tag.macho; | 31 | pub const base_tag: File.Tag = File.Tag.macho; |
| 32 | | 32 | |
| ... | @@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | ... | @@ -108,9 +108,9 @@ locals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 108 | /// Table of all global symbols | 108 | /// Table of all global symbols |
| 109 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, | 109 | globals: std.ArrayListUnmanaged(macho.nlist_64) = .{}, |
| 110 | /// Table of all extern nonlazy symbols, indexed by name. | 110 | /// Table of all extern nonlazy symbols, indexed by name. |
| 111 | nonlazy_imports: std.StringArrayHashMapUnmanaged(ExternSymbol) = .{}, | 111 | nonlazy_imports: std.StringArrayHashMapUnmanaged(Import) = .{}, |
| 112 | /// Table of all extern lazy symbols, indexed by name. | 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 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 115 | locals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| 116 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, | 116 | globals_free_list: std.ArrayListUnmanaged(u32) = .{}, |
| ... | @@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, | ... | @@ -169,6 +169,17 @@ pie_fixups: std.ArrayListUnmanaged(PieFixup) = .{}, |
| 169 | /// rather than sitting in the global scope. | 169 | /// rather than sitting in the global scope. |
| 170 | stub_fixups: std.ArrayListUnmanaged(StubFixup) = .{}, | 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 | pub const PieFixup = struct { | 183 | pub const PieFixup = struct { |
| 173 | /// Target address we wanted to address in absolute terms. | 184 | /// Target address we wanted to address in absolute terms. |
| 174 | address: u64, | 185 | address: u64, |
| ... | @@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { | ... | @@ -1285,9 +1296,6 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void { |
| 1285 | try self.writeStubInStubHelper(fixup.symbol); | 1296 | try self.writeStubInStubHelper(fixup.symbol); |
| 1286 | try self.writeLazySymbolPointer(fixup.symbol); | 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 | self.rebase_info_dirty = true; | 1299 | self.rebase_info_dirty = true; |
| 1292 | self.lazy_binding_info_dirty = true; | 1300 | self.lazy_binding_info_dirty = true; |
| 1293 | } | 1301 | } |
| ... | @@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2065,7 +2073,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2065 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); | 2073 | const name = try self.base.allocator.dupe(u8, "dyld_stub_binder"); |
| 2066 | const offset = try self.makeString("dyld_stub_binder"); | 2074 | const offset = try self.makeString("dyld_stub_binder"); |
| 2067 | try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{ | 2075 | try self.nonlazy_imports.putNoClobber(self.base.allocator, name, .{ |
| 2068 | .inner = .{ | 2076 | .symbol = .{ |
| 2069 | .n_strx = offset, | 2077 | .n_strx = offset, |
| 2070 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, | 2078 | .n_type = std.macho.N_UNDF | std.macho.N_EXT, |
| 2071 | .n_sect = 0, | 2079 | .n_sect = 0, |
| ... | @@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { | ... | @@ -2073,8 +2081,7 @@ pub fn populateMissingMetadata(self: *MachO) !void { |
| 2073 | .n_value = 0, | 2081 | .n_value = 0, |
| 2074 | }, | 2082 | }, |
| 2075 | .dylib_ordinal = 1, // TODO this is currently hardcoded. | 2083 | .dylib_ordinal = 1, // TODO this is currently hardcoded. |
| 2076 | .segment = self.data_const_segment_cmd_index.?, | 2084 | .index = index, |
| 2077 | .offset = index * @sizeOf(u64), | | |
| 2078 | }); | 2085 | }); |
| 2079 | self.binding_info_dirty = true; | 2086 | self.binding_info_dirty = true; |
| 2080 | } | 2087 | } |
| ... | @@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | ... | @@ -2238,7 +2245,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2238 | const sym_name = try self.base.allocator.dupe(u8, name); | 2245 | const sym_name = try self.base.allocator.dupe(u8, name); |
| 2239 | const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. | 2246 | const dylib_ordinal = 1; // TODO this is now hardcoded, since we only support libSystem. |
| 2240 | try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{ | 2247 | try self.lazy_imports.putNoClobber(self.base.allocator, sym_name, .{ |
| 2241 | .inner = .{ | 2248 | .symbol = .{ |
| 2242 | .n_strx = offset, | 2249 | .n_strx = offset, |
| 2243 | .n_type = macho.N_UNDF | macho.N_EXT, | 2250 | .n_type = macho.N_UNDF | macho.N_EXT, |
| 2244 | .n_sect = 0, | 2251 | .n_sect = 0, |
| ... | @@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { | ... | @@ -2246,6 +2253,7 @@ pub fn addExternSymbol(self: *MachO, name: []const u8) !u32 { |
| 2246 | .n_value = 0, | 2253 | .n_value = 0, |
| 2247 | }, | 2254 | }, |
| 2248 | .dylib_ordinal = dylib_ordinal, | 2255 | .dylib_ordinal = dylib_ordinal, |
| | 2256 | .index = index, |
| 2249 | }); | 2257 | }); |
| 2250 | log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); | 2258 | log.debug("adding new extern symbol '{s}' with dylib ordinal '{}'", .{ name, dylib_ordinal }); |
| 2251 | return index; | 2259 | return index; |
| ... | @@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { | ... | @@ -2767,10 +2775,10 @@ fn writeAllGlobalAndUndefSymbols(self: *MachO) !void { |
| 2767 | defer undefs.deinit(); | 2775 | defer undefs.deinit(); |
| 2768 | try undefs.ensureCapacity(nundefs); | 2776 | try undefs.ensureCapacity(nundefs); |
| 2769 | for (self.lazy_imports.items()) |entry| { | 2777 | for (self.lazy_imports.items()) |entry| { |
| 2770 | undefs.appendAssumeCapacity(entry.value.inner); | 2778 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2771 | } | 2779 | } |
| 2772 | for (self.nonlazy_imports.items()) |entry| { | 2780 | for (self.nonlazy_imports.items()) |entry| { |
| 2773 | undefs.appendAssumeCapacity(entry.value.inner); | 2781 | undefs.appendAssumeCapacity(entry.value.symbol); |
| 2774 | } | 2782 | } |
| 2775 | | 2783 | |
| 2776 | const locals_off = symtab.symoff; | 2784 | const locals_off = symtab.symoff; |
| ... | @@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void { | ... | @@ -2832,20 +2840,20 @@ fn writeIndirectSymbolTable(self: *MachO) !void { |
| 2832 | var writer = stream.writer(); | 2840 | var writer = stream.writer(); |
| 2833 | | 2841 | |
| 2834 | stubs.reserved1 = 0; | 2842 | stubs.reserved1 = 0; |
| 2835 | for (self.lazy_imports.items()) |_, i| { | 2843 | for (lazy) |_, i| { |
| 2836 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | 2844 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2837 | try writer.writeIntLittle(u32, symtab_idx); | 2845 | try writer.writeIntLittle(u32, symtab_idx); |
| 2838 | } | 2846 | } |
| 2839 | | 2847 | |
| 2840 | const base_id = @intCast(u32, lazy.len); | 2848 | const base_id = @intCast(u32, lazy.len); |
| 2841 | got.reserved1 = base_id; | 2849 | got.reserved1 = base_id; |
| 2842 | for (self.nonlazy_imports.items()) |_, i| { | 2850 | for (nonlazy) |_, i| { |
| 2843 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); | 2851 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i + base_id); |
| 2844 | try writer.writeIntLittle(u32, symtab_idx); | 2852 | try writer.writeIntLittle(u32, symtab_idx); |
| 2845 | } | 2853 | } |
| 2846 | | 2854 | |
| 2847 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); | 2855 | la_symbol_ptr.reserved1 = got.reserved1 + @intCast(u32, nonlazy.len); |
| 2848 | for (self.lazy_imports.items()) |_, i| { | 2856 | for (lazy) |_, i| { |
| 2849 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); | 2857 | const symtab_idx = @intCast(u32, dysymtab.iundefsym + i); |
| 2850 | try writer.writeIntLittle(u32, symtab_idx); | 2858 | try writer.writeIntLittle(u32, symtab_idx); |
| 2851 | } | 2859 | } |
| ... | @@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void { | ... | @@ -2962,14 +2970,33 @@ fn writeRebaseInfoTable(self: *MachO) !void { |
| 2962 | const tracy = trace(@src()); | 2970 | const tracy = trace(@src()); |
| 2963 | defer tracy.end(); | 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 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 2994 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2967 | defer self.base.allocator.free(buffer); | 2995 | defer self.base.allocator.free(buffer); |
| 2968 | | 2996 | |
| 2969 | var stream = std.io.fixedBufferStream(buffer); | 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 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3000 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 2974 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); | 3001 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.rebase_off); |
| 2975 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3002 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | @@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -2994,14 +3021,33 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 2994 | const tracy = trace(@src()); | 3021 | const tracy = trace(@src()); |
| 2995 | defer tracy.end(); | 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 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 3045 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 2999 | defer self.base.allocator.free(buffer); | 3046 | defer self.base.allocator.free(buffer); |
| 3000 | | 3047 | |
| 3001 | var stream = std.io.fixedBufferStream(buffer); | 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 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3051 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 3006 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); | 3052 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.bind_off); |
| 3007 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3053 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |
| ... | @@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void { | ... | @@ -3023,14 +3069,36 @@ fn writeBindingInfoTable(self: *MachO) !void { |
| 3023 | fn writeLazyBindingInfoTable(self: *MachO) !void { | 3069 | fn writeLazyBindingInfoTable(self: *MachO) !void { |
| 3024 | if (!self.lazy_binding_info_dirty) return; | 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 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); | 3096 | var buffer = try self.base.allocator.alloc(u8, @intCast(usize, size)); |
| 3028 | defer self.base.allocator.free(buffer); | 3097 | defer self.base.allocator.free(buffer); |
| 3029 | | 3098 | |
| 3030 | var stream = std.io.fixedBufferStream(buffer); | 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 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; | 3102 | const dyld_info = &self.load_commands.items[self.dyld_info_cmd_index.?].DyldInfoOnly; |
| 3035 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); | 3103 | const allocated_size = self.allocatedSizeLinkedit(dyld_info.lazy_bind_off); |
| 3036 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); | 3104 | const needed_size = mem.alignForwardGeneric(u64, buffer.len, @alignOf(u64)); |