authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-20 23:37:22+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-20 23:37:22+02:00
log5276ce8e638d3d295c443d8bc33e5c51538ae540
tree27f3a465a4a5f95d39d857c29c7ba7a6be617873
parenta442b165f1e219b429e497e1de26780612762871

macho: use adapters to directly reference strtab

Thanks to this, we no longer need to do allocs per symbol name landing in the symbol resolver, plus we do not need to actively track if the string was already inserted into the string table.

2 files changed, 106 insertions(+), 55 deletions(-)

src/link/MachO.zig+98-53
...@@ -127,7 +127,7 @@ globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},...@@ -127,7 +127,7 @@ globals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
127imports: std.ArrayListUnmanaged(macho.nlist_64) = .{},127imports: std.ArrayListUnmanaged(macho.nlist_64) = .{},
128undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},128undefs: std.ArrayListUnmanaged(macho.nlist_64) = .{},
129tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{},129tentatives: std.ArrayListUnmanaged(macho.nlist_64) = .{},
130symbol_resolver: std.StringArrayHashMapUnmanaged(SymbolWithLoc) = .{},130symbol_resolver: std.AutoHashMapUnmanaged(u32, SymbolWithLoc) = .{},
131131
132locals_free_list: std.ArrayListUnmanaged(u32) = .{},132locals_free_list: std.ArrayListUnmanaged(u32) = .{},
133globals_free_list: std.ArrayListUnmanaged(u32) = .{},133globals_free_list: std.ArrayListUnmanaged(u32) = .{},
...@@ -135,6 +135,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},...@@ -135,6 +135,7 @@ globals_free_list: std.ArrayListUnmanaged(u32) = .{},
135stub_helper_stubs_start_off: ?u64 = null,135stub_helper_stubs_start_off: ?u64 = null,
136136
137strtab: std.ArrayListUnmanaged(u8) = .{},137strtab: std.ArrayListUnmanaged(u8) = .{},
138strtab_dir: std.HashMapUnmanaged(u32, u32, StringIndexContext, std.hash_map.default_max_load_percentage) = .{},
138139
139got_entries: std.ArrayListUnmanaged(GotIndirectionKey) = .{},140got_entries: std.ArrayListUnmanaged(GotIndirectionKey) = .{},
140got_entries_map: std.AutoHashMapUnmanaged(GotIndirectionKey, u32) = .{},141got_entries_map: std.AutoHashMapUnmanaged(GotIndirectionKey, u32) = .{},
...@@ -199,6 +200,33 @@ blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},...@@ -199,6 +200,33 @@ blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
199/// backends.200/// backends.
200pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},201pie_fixups: std.ArrayListUnmanaged(PIEFixup) = .{},
201202
203const StringIndexContext = struct {
204 strtab: *std.ArrayListUnmanaged(u8),
205
206 pub fn eql(self: StringIndexContext, a: u32, b: u32) bool {
207 return a == b;
208 }
209
210 pub fn hash(self: StringIndexContext, x: u32) u64 {
211 const x_slice = mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr) + x);
212 return std.hash_map.hashString(x_slice);
213 }
214};
215
216pub const StringSliceAdapter = struct {
217 strtab: *std.ArrayListUnmanaged(u8),
218
219 pub fn eql(self: StringSliceAdapter, a_slice: []const u8, b: u32) bool {
220 const b_slice = mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr) + b);
221 return mem.eql(u8, a_slice, b_slice);
222 }
223
224 pub fn hash(self: StringSliceAdapter, adapted_key: []const u8) u64 {
225 _ = self;
226 return std.hash_map.hashString(adapted_key);
227 }
228};
229
202const SymbolWithLoc = struct {230const SymbolWithLoc = struct {
203 // Table where the symbol can be found.231 // Table where the symbol can be found.
204 where: enum {232 where: enum {
...@@ -882,7 +910,10 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -882,7 +910,10 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
882910
883 {911 {
884 // Add dyld_stub_binder as the final GOT entry.912 // Add dyld_stub_binder as the final GOT entry.
885 const resolv = self.symbol_resolver.get("dyld_stub_binder") orelse unreachable;913 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
914 .strtab = &self.strtab,
915 }) orelse unreachable;
916 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
886 const got_index = @intCast(u32, self.got_entries.items.len);917 const got_index = @intCast(u32, self.got_entries.items.len);
887 const got_entry = GotIndirectionKey{918 const got_entry = GotIndirectionKey{
888 .where = .import,919 .where = .import,
...@@ -1722,14 +1753,17 @@ fn allocateTextBlocks(self: *MachO) !void {...@@ -1722,14 +1753,17 @@ fn allocateTextBlocks(self: *MachO) !void {
1722 }1753 }
17231754
1724 // Update globals1755 // Update globals
1725 for (self.symbol_resolver.values()) |resolv| {1756 {
1726 if (resolv.where != .global) continue;1757 var sym_it = self.symbol_resolver.valueIterator();
17271758 while (sym_it.next()) |resolv| {
1728 assert(resolv.local_sym_index != 0);1759 if (resolv.where != .global) continue;
1729 const local_sym = self.locals.items[resolv.local_sym_index];1760
1730 const sym = &self.globals.items[resolv.where_index];1761 assert(resolv.local_sym_index != 0);
1731 sym.n_value = local_sym.n_value;1762 const local_sym = self.locals.items[resolv.local_sym_index];
1732 sym.n_sect = local_sym.n_sect;1763 const sym = &self.globals.items[resolv.where_index];
1764 sym.n_value = local_sym.n_value;
1765 sym.n_sect = local_sym.n_sect;
1766 }
1733 }1767 }
1734}1768}
17351769
...@@ -1821,7 +1855,10 @@ fn writeStubHelperCommon(self: *MachO) !void {...@@ -1821,7 +1855,10 @@ fn writeStubHelperCommon(self: *MachO) !void {
1821 code[9] = 0xff;1855 code[9] = 0xff;
1822 code[10] = 0x25;1856 code[10] = 0x25;
1823 {1857 {
1824 const resolv = self.symbol_resolver.get("dyld_stub_binder") orelse unreachable;1858 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
1859 .strtab = &self.strtab,
1860 }) orelse unreachable;
1861 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
1825 const got_index = self.got_entries_map.get(.{1862 const got_index = self.got_entries_map.get(.{
1826 .where = .import,1863 .where = .import,
1827 .where_index = resolv.where_index,1864 .where_index = resolv.where_index,
...@@ -1869,7 +1906,10 @@ fn writeStubHelperCommon(self: *MachO) !void {...@@ -1869,7 +1906,10 @@ fn writeStubHelperCommon(self: *MachO) !void {
1869 code[10] = 0xbf;1906 code[10] = 0xbf;
1870 code[11] = 0xa9;1907 code[11] = 0xa9;
1871 binder_blk_outer: {1908 binder_blk_outer: {
1872 const resolv = self.symbol_resolver.get("dyld_stub_binder") orelse unreachable;1909 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
1910 .strtab = &self.strtab,
1911 }) orelse unreachable;
1912 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
1873 const got_index = self.got_entries_map.get(.{1913 const got_index = self.got_entries_map.get(.{
1874 .where = .import,1914 .where = .import,
1875 .where_index = resolv.where_index,1915 .where_index = resolv.where_index,
...@@ -1965,19 +2005,9 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -1965,19 +2005,9 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
1965 return error.UnhandledSymbolType;2005 return error.UnhandledSymbolType;
1966 }2006 }
19672007
2008 const n_strx = try self.makeString(sym_name);
1968 if (symbolIsSect(sym)) {2009 if (symbolIsSect(sym)) {
1969 // Defined symbol regardless of scope lands in the locals symbol table.2010 // Defined symbol regardless of scope lands in the locals symbol table.
1970 const n_strx = blk: {
1971 if (self.symbol_resolver.get(sym_name)) |resolv| {
1972 switch (resolv.where) {
1973 .global => break :blk self.globals.items[resolv.where_index].n_strx,
1974 .tentative => break :blk self.tentatives.items[resolv.where_index].n_strx,
1975 .undef => break :blk self.undefs.items[resolv.where_index].n_strx,
1976 .import => unreachable,
1977 }
1978 }
1979 break :blk try self.makeString(sym_name);
1980 };
1981 const local_sym_index = @intCast(u32, self.locals.items.len);2011 const local_sym_index = @intCast(u32, self.locals.items.len);
1982 try self.locals.append(self.base.allocator, .{2012 try self.locals.append(self.base.allocator, .{
1983 .n_strx = n_strx,2013 .n_strx = n_strx,
...@@ -1993,7 +2023,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -1993,7 +2023,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
1993 if (!symbolIsExt(sym)) continue;2023 if (!symbolIsExt(sym)) continue;
19942024
1995 const local = self.locals.items[local_sym_index];2025 const local = self.locals.items[local_sym_index];
1996 const resolv = self.symbol_resolver.getPtr(sym_name) orelse {2026 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
1997 const global_sym_index = @intCast(u32, self.globals.items.len);2027 const global_sym_index = @intCast(u32, self.globals.items.len);
1998 try self.globals.append(self.base.allocator, .{2028 try self.globals.append(self.base.allocator, .{
1999 .n_strx = n_strx,2029 .n_strx = n_strx,
...@@ -2002,7 +2032,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2002,7 +2032,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2002 .n_desc = sym.n_desc,2032 .n_desc = sym.n_desc,
2003 .n_value = sym.n_value,2033 .n_value = sym.n_value,
2004 });2034 });
2005 try self.symbol_resolver.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, sym_name), .{2035 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2006 .where = .global,2036 .where = .global,
2007 .where_index = global_sym_index,2037 .where_index = global_sym_index,
2008 .local_sym_index = local_sym_index,2038 .local_sym_index = local_sym_index,
...@@ -2072,7 +2102,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2072,7 +2102,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2072 };2102 };
2073 } else if (symbolIsTentative(sym)) {2103 } else if (symbolIsTentative(sym)) {
2074 // Symbol is a tentative definition.2104 // Symbol is a tentative definition.
2075 const resolv = self.symbol_resolver.getPtr(sym_name) orelse {2105 const resolv = self.symbol_resolver.getPtr(n_strx) orelse {
2076 const tent_sym_index = @intCast(u32, self.tentatives.items.len);2106 const tent_sym_index = @intCast(u32, self.tentatives.items.len);
2077 try self.tentatives.append(self.base.allocator, .{2107 try self.tentatives.append(self.base.allocator, .{
2078 .n_strx = try self.makeString(sym_name),2108 .n_strx = try self.makeString(sym_name),
...@@ -2081,7 +2111,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2081,7 +2111,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2081 .n_desc = sym.n_desc,2111 .n_desc = sym.n_desc,
2082 .n_value = sym.n_value,2112 .n_value = sym.n_value,
2083 });2113 });
2084 try self.symbol_resolver.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, sym_name), .{2114 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2085 .where = .tentative,2115 .where = .tentative,
2086 .where_index = tent_sym_index,2116 .where_index = tent_sym_index,
2087 .file = object_id,2117 .file = object_id,
...@@ -2126,7 +2156,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2126,7 +2156,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2126 }2156 }
2127 } else {2157 } else {
2128 // Symbol is undefined.2158 // Symbol is undefined.
2129 if (self.symbol_resolver.contains(sym_name)) continue;2159 if (self.symbol_resolver.contains(n_strx)) continue;
21302160
2131 const undef_sym_index = @intCast(u32, self.undefs.items.len);2161 const undef_sym_index = @intCast(u32, self.undefs.items.len);
2132 try self.undefs.append(self.base.allocator, .{2162 try self.undefs.append(self.base.allocator, .{
...@@ -2136,7 +2166,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {...@@ -2136,7 +2166,7 @@ fn resolveSymbolsInObject(self: *MachO, object_id: u16) !void {
2136 .n_desc = 0,2166 .n_desc = 0,
2137 .n_value = 0,2167 .n_value = 0,
2138 });2168 });
2139 try self.symbol_resolver.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, sym_name), .{2169 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2140 .where = .undef,2170 .where = .undef,
2141 .where_index = undef_sym_index,2171 .where_index = undef_sym_index,
2142 .file = object_id,2172 .file = object_id,
...@@ -2214,7 +2244,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2214,7 +2244,7 @@ fn resolveSymbols(self: *MachO) !void {
2214 mem.set(u8, code, 0);2244 mem.set(u8, code, 0);
2215 const alignment = (sym.n_desc >> 8) & 0x0f;2245 const alignment = (sym.n_desc >> 8) & 0x0f;
22162246
2217 const resolv = self.symbol_resolver.getPtr(sym_name) orelse unreachable;2247 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
2218 const local_sym_index = @intCast(u32, self.locals.items.len);2248 const local_sym_index = @intCast(u32, self.locals.items.len);
2219 var nlist = macho.nlist_64{2249 var nlist = macho.nlist_64{
2220 .n_strx = sym.n_strx,2250 .n_strx = sym.n_strx,
...@@ -2263,15 +2293,16 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2263,15 +2293,16 @@ fn resolveSymbols(self: *MachO) !void {
2263 // Third pass, resolve symbols in dynamic libraries.2293 // Third pass, resolve symbols in dynamic libraries.
2264 {2294 {
2265 // Put dyld_stub_binder as an undefined special symbol.2295 // Put dyld_stub_binder as an undefined special symbol.
2296 const n_strx = try self.makeString("dyld_stub_binder");
2266 const undef_sym_index = @intCast(u32, self.undefs.items.len);2297 const undef_sym_index = @intCast(u32, self.undefs.items.len);
2267 try self.undefs.append(self.base.allocator, .{2298 try self.undefs.append(self.base.allocator, .{
2268 .n_strx = try self.makeString("dyld_stub_binder"),2299 .n_strx = n_strx,
2269 .n_type = macho.N_UNDF,2300 .n_type = macho.N_UNDF,
2270 .n_sect = 0,2301 .n_sect = 0,
2271 .n_desc = 0,2302 .n_desc = 0,
2272 .n_value = 0,2303 .n_value = 0,
2273 });2304 });
2274 try self.symbol_resolver.putNoClobber(self.base.allocator, try self.base.allocator.dupe(u8, "dyld_stub_binder"), .{2305 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
2275 .where = .undef,2306 .where = .undef,
2276 .where_index = undef_sym_index,2307 .where_index = undef_sym_index,
2277 });2308 });
...@@ -2304,7 +2335,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2304,7 +2335,7 @@ fn resolveSymbols(self: *MachO) !void {
2304 try referenced.putNoClobber(dylib, {});2335 try referenced.putNoClobber(dylib, {});
2305 }2336 }
23062337
2307 const resolv = self.symbol_resolver.getPtr(sym_name) orelse unreachable;2338 const resolv = self.symbol_resolver.getPtr(sym.n_strx) orelse unreachable;
2308 const undef = &self.undefs.items[resolv.where_index];2339 const undef = &self.undefs.items[resolv.where_index];
2309 const import_sym_index = @intCast(u32, self.imports.items.len);2340 const import_sym_index = @intCast(u32, self.imports.items.len);
2310 try self.imports.append(self.base.allocator, .{2341 try self.imports.append(self.base.allocator, .{
...@@ -2331,7 +2362,10 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2331,7 +2362,10 @@ fn resolveSymbols(self: *MachO) !void {
2331 }2362 }
23322363
2333 // Fourth pass, handle synthetic symbols and flag any undefined references.2364 // Fourth pass, handle synthetic symbols and flag any undefined references.
2334 if (self.symbol_resolver.getPtr("___dso_handle")) |resolv| blk: {2365 if (self.strtab_dir.getAdapted(@as([]const u8, "___dso_handle"), StringSliceAdapter{
2366 .strtab = &self.strtab,
2367 })) |n_strx| blk: {
2368 const resolv = self.symbol_resolver.getPtr(n_strx) orelse break :blk;
2335 if (resolv.where != .undef) break :blk;2369 if (resolv.where != .undef) break :blk;
23362370
2337 const undef = &self.undefs.items[resolv.where_index];2371 const undef = &self.undefs.items[resolv.where_index];
...@@ -2390,7 +2424,7 @@ fn resolveSymbols(self: *MachO) !void {...@@ -2390,7 +2424,7 @@ fn resolveSymbols(self: *MachO) !void {
2390 if (symbolIsNull(sym)) continue;2424 if (symbolIsNull(sym)) continue;
23912425
2392 const sym_name = self.getString(sym.n_strx);2426 const sym_name = self.getString(sym.n_strx);
2393 const resolv = self.symbol_resolver.get(sym_name) orelse unreachable;2427 const resolv = self.symbol_resolver.get(sym.n_strx) orelse unreachable;
23942428
2395 log.err("undefined reference to symbol '{s}'", .{sym_name});2429 log.err("undefined reference to symbol '{s}'", .{sym_name});
2396 log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name.?});2430 log.err(" first referenced in '{s}'", .{self.objects.items[resolv.file].name.?});
...@@ -2830,10 +2864,13 @@ fn setEntryPoint(self: *MachO) !void {...@@ -2830,10 +2864,13 @@ fn setEntryPoint(self: *MachO) !void {
2830 // TODO we should respect the -entry flag passed in by the user to set a custom2864 // TODO we should respect the -entry flag passed in by the user to set a custom
2831 // entrypoint. For now, assume default of `_main`.2865 // entrypoint. For now, assume default of `_main`.
2832 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;2866 const seg = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
2833 const resolv = self.symbol_resolver.get("_main") orelse {2867 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "_main"), StringSliceAdapter{
2868 .strtab = &self.strtab,
2869 }) orelse {
2834 log.err("'_main' export not found", .{});2870 log.err("'_main' export not found", .{});
2835 return error.MissingMainEntrypoint;2871 return error.MissingMainEntrypoint;
2836 };2872 };
2873 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
2837 assert(resolv.where == .global);2874 assert(resolv.where == .global);
2838 const sym = self.globals.items[resolv.where_index];2875 const sym = self.globals.items[resolv.where_index];
2839 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;2876 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
...@@ -3235,6 +3272,7 @@ pub fn deinit(self: *MachO) void {...@@ -3235,6 +3272,7 @@ pub fn deinit(self: *MachO) void {
3235 self.got_entries_free_list.deinit(self.base.allocator);3272 self.got_entries_free_list.deinit(self.base.allocator);
3236 self.stubs.deinit(self.base.allocator);3273 self.stubs.deinit(self.base.allocator);
3237 self.stubs_map.deinit(self.base.allocator);3274 self.stubs_map.deinit(self.base.allocator);
3275 self.strtab_dir.deinit(self.base.allocator);
3238 self.strtab.deinit(self.base.allocator);3276 self.strtab.deinit(self.base.allocator);
3239 self.undefs.deinit(self.base.allocator);3277 self.undefs.deinit(self.base.allocator);
3240 self.tentatives.deinit(self.base.allocator);3278 self.tentatives.deinit(self.base.allocator);
...@@ -3243,10 +3281,6 @@ pub fn deinit(self: *MachO) void {...@@ -3243,10 +3281,6 @@ pub fn deinit(self: *MachO) void {
3243 self.globals_free_list.deinit(self.base.allocator);3281 self.globals_free_list.deinit(self.base.allocator);
3244 self.locals.deinit(self.base.allocator);3282 self.locals.deinit(self.base.allocator);
3245 self.locals_free_list.deinit(self.base.allocator);3283 self.locals_free_list.deinit(self.base.allocator);
3246
3247 for (self.symbol_resolver.keys()) |key| {
3248 self.base.allocator.free(key);
3249 }
3250 self.symbol_resolver.deinit(self.base.allocator);3284 self.symbol_resolver.deinit(self.base.allocator);
32513285
3252 for (self.objects.items) |object| {3286 for (self.objects.items) |object| {
...@@ -3715,9 +3749,7 @@ pub fn updateDeclExports(...@@ -3715,9 +3749,7 @@ pub fn updateDeclExports(
3715 .n_desc = n_desc,3749 .n_desc = n_desc,
3716 .n_value = decl_sym.n_value,3750 .n_value = decl_sym.n_value,
3717 };3751 };
3718 const resolv_name = try self.base.allocator.dupe(u8, exp_name);3752 const resolv = try self.symbol_resolver.getOrPut(self.base.allocator, name_str_index);
3719 const resolv = try self.symbol_resolver.getOrPut(self.base.allocator, resolv_name);
3720 defer if (resolv.found_existing) self.base.allocator.free(resolv_name);
3721 resolv.value_ptr.* = .{3753 resolv.value_ptr.* = .{
3722 .where = .global,3754 .where = .global,
3723 .where_index = i,3755 .where_index = i,
...@@ -4233,17 +4265,19 @@ pub fn populateMissingMetadata(self: *MachO) !void {...@@ -4233,17 +4265,19 @@ pub fn populateMissingMetadata(self: *MachO) !void {
4233 });4265 });
4234 self.load_commands_dirty = true;4266 self.load_commands_dirty = true;
4235 }4267 }
4236 if (!self.symbol_resolver.contains("dyld_stub_binder")) {4268 if (!self.strtab_dir.containsAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
4269 .strtab = &self.strtab,
4270 })) {
4237 const import_sym_index = @intCast(u32, self.imports.items.len);4271 const import_sym_index = @intCast(u32, self.imports.items.len);
4272 const n_strx = try self.makeString("dyld_stub_binder");
4238 try self.imports.append(self.base.allocator, .{4273 try self.imports.append(self.base.allocator, .{
4239 .n_strx = try self.makeString("dyld_stub_binder"),4274 .n_strx = n_strx,
4240 .n_type = macho.N_UNDF | macho.N_EXT,4275 .n_type = macho.N_UNDF | macho.N_EXT,
4241 .n_sect = 0,4276 .n_sect = 0,
4242 .n_desc = packDylibOrdinal(1),4277 .n_desc = packDylibOrdinal(1),
4243 .n_value = 0,4278 .n_value = 0,
4244 });4279 });
4245 const name = try self.base.allocator.dupe(u8, "dyld_stub_binder");4280 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
4246 try self.symbol_resolver.putNoClobber(self.base.allocator, name, .{
4247 .where = .import,4281 .where = .import,
4248 .where_index = import_sym_index,4282 .where_index = import_sym_index,
4249 });4283 });
...@@ -4370,24 +4404,26 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,...@@ -4370,24 +4404,26 @@ fn allocateTextBlock(self: *MachO, text_block: *TextBlock, new_block_size: u64,
43704404
4371pub fn addExternFn(self: *MachO, name: []const u8) !u32 {4405pub fn addExternFn(self: *MachO, name: []const u8) !u32 {
4372 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});4406 const sym_name = try std.fmt.allocPrint(self.base.allocator, "_{s}", .{name});
4373 const already_defined = self.symbol_resolver.contains(sym_name);4407 defer self.base.allocator.free(sym_name);
43744408
4375 if (already_defined) {4409 if (self.strtab_dir.getAdapted(@as([]const u8, sym_name), StringSliceAdapter{
4376 const resolv = self.symbol_resolver.get(sym_name) orelse unreachable;4410 .strtab = &self.strtab,
4377 self.base.allocator.free(sym_name);4411 })) |n_strx| {
4412 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
4378 return resolv.where_index;4413 return resolv.where_index;
4379 }4414 }
43804415
4381 log.debug("adding new extern function '{s}' with dylib ordinal 1", .{sym_name});4416 log.debug("adding new extern function '{s}' with dylib ordinal 1", .{sym_name});
4382 const import_sym_index = @intCast(u32, self.imports.items.len);4417 const import_sym_index = @intCast(u32, self.imports.items.len);
4418 const n_strx = try self.makeString(sym_name);
4383 try self.imports.append(self.base.allocator, .{4419 try self.imports.append(self.base.allocator, .{
4384 .n_strx = try self.makeString(sym_name),4420 .n_strx = n_strx,
4385 .n_type = macho.N_UNDF | macho.N_EXT,4421 .n_type = macho.N_UNDF | macho.N_EXT,
4386 .n_sect = 0,4422 .n_sect = 0,
4387 .n_desc = packDylibOrdinal(1),4423 .n_desc = packDylibOrdinal(1),
4388 .n_value = 0,4424 .n_value = 0,
4389 });4425 });
4390 try self.symbol_resolver.putNoClobber(self.base.allocator, sym_name, .{4426 try self.symbol_resolver.putNoClobber(self.base.allocator, n_strx, .{
4391 .where = .import,4427 .where = .import,
4392 .where_index = import_sym_index,4428 .where_index = import_sym_index,
4393 });4429 });
...@@ -5609,6 +5645,11 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {...@@ -5609,6 +5645,11 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
5609}5645}
56105646
5611pub fn makeString(self: *MachO, string: []const u8) !u32 {5647pub fn makeString(self: *MachO, string: []const u8) !u32 {
5648 if (self.strtab_dir.getAdapted(@as([]const u8, string), StringSliceAdapter{ .strtab = &self.strtab })) |off| {
5649 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
5650 return off;
5651 }
5652
5612 try self.strtab.ensureUnusedCapacity(self.base.allocator, string.len + 1);5653 try self.strtab.ensureUnusedCapacity(self.base.allocator, string.len + 1);
5613 const new_off = @intCast(u32, self.strtab.items.len);5654 const new_off = @intCast(u32, self.strtab.items.len);
56145655
...@@ -5617,6 +5658,10 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {...@@ -5617,6 +5658,10 @@ pub fn makeString(self: *MachO, string: []const u8) !u32 {
5617 self.strtab.appendSliceAssumeCapacity(string);5658 self.strtab.appendSliceAssumeCapacity(string);
5618 self.strtab.appendAssumeCapacity(0);5659 self.strtab.appendAssumeCapacity(0);
56195660
5661 try self.strtab_dir.putContext(self.base.allocator, new_off, new_off, StringIndexContext{
5662 .strtab = &self.strtab,
5663 });
5664
5620 return new_off;5665 return new_off;
5621}5666}
56225667
src/link/MachO/TextBlock.zig+8-2
...@@ -640,7 +640,10 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo...@@ -640,7 +640,10 @@ fn initRelocFromObject(rel: macho.relocation_info, object: *Object, ctx: RelocCo
640 parsed_rel.where = .local;640 parsed_rel.where = .local;
641 parsed_rel.where_index = where_index;641 parsed_rel.where_index = where_index;
642 } else {642 } else {
643 const resolv = ctx.macho_file.symbol_resolver.get(sym_name) orelse unreachable;643 const n_strx = ctx.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{
644 .strtab = &ctx.macho_file.strtab,
645 }) orelse unreachable;
646 const resolv = ctx.macho_file.symbol_resolver.get(n_strx) orelse unreachable;
644 switch (resolv.where) {647 switch (resolv.where) {
645 .global => {648 .global => {
646 parsed_rel.where = .local;649 parsed_rel.where = .local;
...@@ -704,7 +707,10 @@ pub fn parseRelocsFromObject(...@@ -704,7 +707,10 @@ pub fn parseRelocsFromObject(
704 const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;707 const where_index = object.symbol_mapping.get(rel.r_symbolnum) orelse unreachable;
705 subtractor = where_index;708 subtractor = where_index;
706 } else {709 } else {
707 const resolv = ctx.macho_file.symbol_resolver.get(sym_name) orelse unreachable;710 const n_strx = ctx.macho_file.strtab_dir.getAdapted(@as([]const u8, sym_name), MachO.StringSliceAdapter{
711 .strtab = &ctx.macho_file.strtab,
712 }) orelse unreachable;
713 const resolv = ctx.macho_file.symbol_resolver.get(n_strx) orelse unreachable;
708 assert(resolv.where == .global);714 assert(resolv.where == .global);
709 subtractor = resolv.local_sym_index;715 subtractor = resolv.local_sym_index;
710 }716 }