Commit 69f4281774

Jakub Konka <kubkon@jakubkonka.com>
2021-08-17 18:33:41
macho: memorize if dyld_stub_binder was already resolved
1 parent c6ea181
Changed files (1)
src
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);