authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-17 18:33:41+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-17 18:33:41+02:00
log69f42817745a13fc3cc69896cb628a7028696a88
tree2db265ec8dd270631a281f3358fd5e487c02cd40
parentc6ea181e75cc6822edbaceccb11bc3a39484d116

macho: memorize if dyld_stub_binder was already resolved


1 files changed, 62 insertions(+), 50 deletions(-)

src/link/MachO.zig+62-50
...@@ -145,6 +145,8 @@ symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{},...@@ -145,6 +145,8 @@ symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{},
145locals_free_list: std.ArrayListUnmanaged(u32) = .{},145locals_free_list: std.ArrayListUnmanaged(u32) = .{},
146globals_free_list: std.ArrayListUnmanaged(u32) = .{},146globals_free_list: std.ArrayListUnmanaged(u32) = .{},
147147
148dyld_stub_binder_index: ?u32 = null,
149
148stub_helper_stubs_start_off: ?u64 = null,150stub_helper_stubs_start_off: ?u64 = null,
149151
150strtab: std.ArrayListUnmanaged(u8) = .{},152strtab: std.ArrayListUnmanaged(u8) = .{},
...@@ -386,10 +388,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -386,10 +388,8 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
386 try self.populateMissingMetadata();388 try self.populateMissingMetadata();
387 try self.writeLocalSymbol(0);389 try self.writeLocalSymbol(0);
388390
389 if (!self.strtab_dir.containsAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{391 if (self.dyld_stub_binder_index == null) {
390 .strtab = &self.strtab,392 self.dyld_stub_binder_index = @intCast(u32, self.undefs.items.len);
391 })) {
392 const import_sym_index = @intCast(u32, self.undefs.items.len);
393 const n_strx = try self.makeString("dyld_stub_binder");393 const n_strx = try self.makeString("dyld_stub_binder");
394 try self.undefs.append(self.base.allocator, .{394 try self.undefs.append(self.base.allocator, .{
395 .n_strx = n_strx,395 .n_strx = n_strx,
...@@ -400,11 +400,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -400,11 +400,11 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
400 });400 });
401 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{401 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
402 .where = .undef,402 .where = .undef,
403 .where_index = import_sym_index,403 .where_index = self.dyld_stub_binder_index.?,
404 });404 });
405 const got_key = GotIndirectionKey{405 const got_key = GotIndirectionKey{
406 .where = .undef,406 .where = .undef,
407 .where_index = import_sym_index,407 .where_index = self.dyld_stub_binder_index.?,
408 };408 };
409 const got_index = @intCast(u32, self.got_entries.items.len);409 const got_index = @intCast(u32, self.got_entries.items.len);
410 try self.got_entries.append(self.base.allocator, got_key);410 try self.got_entries.append(self.base.allocator, got_key);
...@@ -799,26 +799,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -799,26 +799,11 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
799 try self.parseInputFiles(positionals.items, self.base.options.sysroot);799 try self.parseInputFiles(positionals.items, self.base.options.sysroot);
800 try self.parseLibs(libs.items, self.base.options.sysroot);800 try self.parseLibs(libs.items, self.base.options.sysroot);
801 try self.resolveSymbols();801 try self.resolveSymbols();
802 try self.resolveDyldStubBinder();
802 try self.parseTextBlocks();803 try self.parseTextBlocks();
803 try self.addLoadDylibLCs();804 try self.addLoadDylibLCs();
804 try self.addDataInCodeLC();805 try self.addDataInCodeLC();
805 try self.addCodeSignatureLC();806 try self.addCodeSignatureLC();
806
807 {
808 // Add dyld_stub_binder as the final GOT entry.
809 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
810 .strtab = &self.strtab,
811 }) orelse unreachable;
812 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
813 const got_index = @intCast(u32, self.got_entries.items.len);
814 const got_entry = GotIndirectionKey{
815 .where = .undef,
816 .where_index = resolv.where_index,
817 };
818 try self.got_entries.append(self.base.allocator, got_entry);
819 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
820 }
821
822 try self.sortSections();807 try self.sortSections();
823 try self.allocateTextSegment();808 try self.allocateTextSegment();
824 try self.allocateDataConstSegment();809 try self.allocateDataConstSegment();
...@@ -1982,13 +1967,9 @@ fn writeStubHelperCommon(self: *MachO) !void {...@@ -1982,13 +1967,9 @@ fn writeStubHelperCommon(self: *MachO) !void {
1982 code[9] = 0xff;1967 code[9] = 0xff;
1983 code[10] = 0x25;1968 code[10] = 0x25;
1984 {1969 {
1985 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
1986 .strtab = &self.strtab,
1987 }) orelse unreachable;
1988 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
1989 const got_index = self.got_entries_map.get(.{1970 const got_index = self.got_entries_map.get(.{
1990 .where = .undef,1971 .where = .undef,
1991 .where_index = resolv.where_index,1972 .where_index = self.dyld_stub_binder_index.?,
1992 }) orelse unreachable;1973 }) orelse unreachable;
1993 const addr = got.addr + got_index * @sizeOf(u64);1974 const addr = got.addr + got_index * @sizeOf(u64);
1994 const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);1975 const displacement = try math.cast(u32, addr - stub_helper.addr - code_size);
...@@ -2033,13 +2014,9 @@ fn writeStubHelperCommon(self: *MachO) !void {...@@ -2033,13 +2014,9 @@ fn writeStubHelperCommon(self: *MachO) !void {
2033 code[10] = 0xbf;2014 code[10] = 0xbf;
2034 code[11] = 0xa9;2015 code[11] = 0xa9;
2035 binder_blk_outer: {2016 binder_blk_outer: {
2036 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
2037 .strtab = &self.strtab,
2038 }) orelse unreachable;
2039 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
2040 const got_index = self.got_entries_map.get(.{2017 const got_index = self.got_entries_map.get(.{
2041 .where = .undef,2018 .where = .undef,
2042 .where_index = resolv.where_index,2019 .where_index = self.dyld_stub_binder_index.?,
2043 }) orelse unreachable;2020 }) orelse unreachable;
2044 const this_addr = stub_helper.addr + 3 * @sizeOf(u32);2021 const this_addr = stub_helper.addr + 3 * @sizeOf(u32);
2045 const target_addr = got.addr + got_index * @sizeOf(u64);2022 const target_addr = got.addr + got_index * @sizeOf(u64);
...@@ -2405,24 +2382,6 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2405,24 +2382,6 @@ fn resolveSymbols(self: *MachO) !void {
2405 }2382 }
24062383
2407 // Third pass, resolve symbols in dynamic libraries.2384 // Third pass, resolve symbols in dynamic libraries.
2408 {
2409 // Put dyld_stub_binder as an undefined special symbol.
2410 const n_strx = try self.makeString("dyld_stub_binder");
2411 const undef_sym_index = @intCast(u32, self.undefs.items.len);
2412 try self.undefs.append(self.base.allocator, .{
2413 .n_strx = n_strx,
2414 .n_type = macho.N_UNDF,
2415 .n_sect = 0,
2416 .n_desc = 0,
2417 .n_value = 0,
2418 });
2419 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2420 .where = .undef,
2421 .where_index = undef_sym_index,
2422 });
2423 _ = try unresolved.getOrPut(undef_sym_index);
2424 }
2425
2426 next_sym = 0;2385 next_sym = 0;
2427 loop: while (next_sym < unresolved.count()) {2386 loop: while (next_sym < unresolved.count()) {
2428 const sym = self.undefs.items[unresolved.keys()[next_sym]];2387 const sym = self.undefs.items[unresolved.keys()[next_sym]];
...@@ -2523,6 +2482,59 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2523,6 +2482,59 @@ fn resolveSymbols(self: *MachO) !void {
2523 return error.UndefinedSymbolReference;2482 return error.UndefinedSymbolReference;
2524}2483}
25252484
2485fn resolveDyldStubBinder(self: *MachO) !void {
2486 if (self.dyld_stub_binder_index != null) return;
2487
2488 const n_strx = try self.makeString("dyld_stub_binder");
2489 const sym_index = @intCast(u32, self.undefs.items.len);
2490 try self.undefs.append(self.base.allocator, .{
2491 .n_strx = n_strx,
2492 .n_type = macho.N_UNDF,
2493 .n_sect = 0,
2494 .n_desc = 0,
2495 .n_value = 0,
2496 });
2497 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2498 .where = .undef,
2499 .where_index = sym_index,
2500 });
2501 const sym = &self.undefs.items[sym_index];
2502 const sym_name = self.getString(n_strx);
2503
2504 for (self.dylibs.items) |dylib, id| {
2505 if (!dylib.symbols.contains(sym_name)) continue;
2506
2507 const dylib_id = @intCast(u16, id);
2508 if (!self.referenced_dylibs.contains(dylib_id)) {
2509 try self.referenced_dylibs.putNoClobber(self.base.allocator, dylib_id, {});
2510 }
2511
2512 const ordinal = self.referenced_dylibs.getIndex(dylib_id) orelse unreachable;
2513 sym.n_type |= macho.N_EXT;
2514 sym.n_desc = @intCast(u16, ordinal + 1) * macho.N_SYMBOL_RESOLVER;
2515 self.dyld_stub_binder_index = sym_index;
2516
2517 break;
2518 }
2519
2520 if (self.dyld_stub_binder_index == null) {
2521 log.err("undefined reference to symbol '{s}'", .{sym_name});
2522 return error.UndefinedSymbolReference;
2523 }
2524
2525 // Add dyld_stub_binder as the final GOT entry.
2526 const got_index = @intCast(u32, self.got_entries.items.len);
2527 const got_entry = GotIndirectionKey{
2528 .where = .undef,
2529 .where_index = self.dyld_stub_binder_index.?,
2530 };
2531 try self.got_entries.append(self.base.allocator, got_entry);
2532 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
2533
2534 self.binding_info_dirty = true;
2535 self.got_entries_count_dirty = true;
2536}
2537
2526fn parseTextBlocks(self: *MachO) !void {2538fn parseTextBlocks(self: *MachO) !void {
2527 for (self.objects.items) |*object, object_id| {2539 for (self.objects.items) |*object, object_id| {
2528 try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);2540 try object.parseTextBlocks(self.base.allocator, @intCast(u16, object_id), self);