From 69f42817745a13fc3cc69896cb628a7028696a88 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 17 Aug 2021 18:33:41 +0200 Subject: [PATCH] macho: memorize if dyld_stub_binder was already resolved --- src/link/MachO.zig | 112 +++++++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 50 deletions(-) diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 2074dc6b5d..73b7b93d11 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -145,6 +145,8 @@ symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{}, locals_free_list: std.ArrayListUnmanaged(u32) = .{}, globals_free_list: std.ArrayListUnmanaged(u32) = .{}, +dyld_stub_binder_index: ?u32 = null, + stub_helper_stubs_start_off: ?u64 = null, strtab: std.ArrayListUnmanaged(u8) = .{}, @@ -386,10 +388,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio try self.populateMissingMetadata(); try self.writeLocalSymbol(0); - if (!self.strtab_dir.containsAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{ - .strtab = &self.strtab, - })) { - const import_sym_index = @intCast(u32, self.undefs.items.len); + if (self.dyld_stub_binder_index == null) { + self.dyld_stub_binder_index = @intCast(u32, self.undefs.items.len); const n_strx = try self.makeString("dyld_stub_binder"); try self.undefs.append(self.base.allocator, .{ .n_strx = n_strx, @@ -400,11 +400,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio }); try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ .where = .undef, - .where_index = import_sym_index, + .where_index = self.dyld_stub_binder_index.?, }); const got_key = GotIndirectionKey{ .where = .undef, - .where_index = import_sym_index, + .where_index = self.dyld_stub_binder_index.?, }; const got_index = @intCast(u32, self.got_entries.items.len); try self.got_entries.append(self.base.allocator, got_key); @@ -799,26 +799,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { try self.parseInputFiles(positionals.items, self.base.options.sysroot); try self.parseLibs(libs.items, self.base.options.sysroot); try self.resolveSymbols(); + try self.resolveDyldStubBinder(); try self.parseTextBlocks(); try self.addLoadDylibLCs(); try self.addDataInCodeLC(); try self.addCodeSignatureLC(); - - { - // Add dyld_stub_binder as the final GOT entry. - const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{ - .strtab = &self.strtab, - }) orelse unreachable; - const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; - const got_index = @intCast(u32, self.got_entries.items.len); - const got_entry = GotIndirectionKey{ - .where = .undef, - .where_index = resolv.where_index, - }; - try self.got_entries.append(self.base.allocator, got_entry); - try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index); - } - try self.sortSections(); try self.allocateTextSegment(); try self.allocateDataConstSegment(); @@ -1982,13 +1967,9 @@ fn writeStubHelperCommon(self: *MachO) !void { code[9] = 0xff; code[10] = 0x25; { - const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{ - .strtab = &self.strtab, - }) orelse unreachable; - const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; const got_index = self.got_entries_map.get(.{ .where = .undef, - .where_index = resolv.where_index, + .where_index = self.dyld_stub_binder_index.?, }) orelse unreachable; const addr = got.addr + got_index * @sizeOf(u64); const displacement = try math.cast(u32, addr - stub_helper.addr - code_size); @@ -2033,13 +2014,9 @@ fn writeStubHelperCommon(self: *MachO) !void { code[10] = 0xbf; code[11] = 0xa9; binder_blk_outer: { - const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{ - .strtab = &self.strtab, - }) orelse unreachable; - const resolv = self.symbol_resolver.get(n_strx) orelse unreachable; const got_index = self.got_entries_map.get(.{ .where = .undef, - .where_index = resolv.where_index, + .where_index = self.dyld_stub_binder_index.?, }) orelse unreachable; const this_addr = stub_helper.addr + 3 * @sizeOf(u32); const target_addr = got.addr + got_index * @sizeOf(u64); @@ -2405,24 +2382,6 @@ fn resolveSymbols(self: *MachO) !void { } // Third pass, resolve symbols in dynamic libraries. - { - // Put dyld_stub_binder as an undefined special symbol. - const n_strx = try self.makeString("dyld_stub_binder"); - const undef_sym_index = @intCast(u32, self.undefs.items.len); - try self.undefs.append(self.base.allocator, .{ - .n_strx = n_strx, - .n_type = macho.N_UNDF, - .n_sect = 0, - .n_desc = 0, - .n_value = 0, - }); - try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ - .where = .undef, - .where_index = undef_sym_index, - }); - _ = try unresolved.getOrPut(undef_sym_index); - } - next_sym = 0; loop: while (next_sym < unresolved.count()) { const sym = self.undefs.items[unresolved.keys()[next_sym]]; @@ -2523,6 +2482,59 @@ fn resolveSymbols(self: *MachO) !void { return error.UndefinedSymbolReference; } +fn resolveDyldStubBinder(self: *MachO) !void { + if (self.dyld_stub_binder_index != null) return; + + const n_strx = try self.makeString("dyld_stub_binder"); + const sym_index = @intCast(u32, self.undefs.items.len); + try self.undefs.append(self.base.allocator, .{ + .n_strx = n_strx, + .n_type = macho.N_UNDF, + .n_sect = 0, + .n_desc = 0, + .n_value = 0, + }); + try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{ + .where = .undef, + .where_index = sym_index, + }); + const sym = &self.undefs.items[sym_index]; + const sym_name = self.getString(n_strx); + + for (self.dylibs.items) |dylib, id| { + if (!dylib.symbols.contains(sym_name)) continue; + + const dylib_id = @intCast(u16, id); + if (!self.referenced_dylibs.contains(dylib_id)) { + try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {}); + } + + const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable; + sym.n_type |= macho.N_EXT; + sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER; + self.dyld_stub_binder_index = sym_index; + + break; + } + + if (self.dyld_stub_binder_index == null) { + log.err("undefined reference to symbol '{s}'", .{sym_name}); + return error.UndefinedSymbolReference; + } + + // Add dyld_stub_binder as the final GOT entry. + const got_index = @intCast(u32, self.got_entries.items.len); + const got_entry = GotIndirectionKey{ + .where = .undef, + .where_index = self.dyld_stub_binder_index.?, + }; + try self.got_entries.append(self.base.allocator, got_entry); + try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index); + + self.binding_info_dirty = true; + self.got_entries_count_dirty = true; +} + fn parseTextBlocks(self: *MachO) !void { for (self.objects.items) |*object, object_id| { try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);