authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 07:41:59+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:47+02:00
logf8678c48ff43879d043b626031f7a5c92303fdea
treebc6955440f013026f692a35345f7ab5ac8492653
parentec874a9b2bf24bb37f1e90558153bbf04ac5f22a

zld: reuse string table for symbol names

rather than manage allocs separately per symbol.

4 files changed, 107 insertions(+), 116 deletions(-)

src/link/MachO/Object.zig+25-14
...@@ -389,7 +389,7 @@ const TextBlockParser = struct {...@@ -389,7 +389,7 @@ const TextBlockParser = struct {
389 return switch (rreg.linkage) {389 return switch (rreg.linkage) {
390 .global => true,390 .global => true,
391 .linkage_unit => lreg.linkage == .translation_unit,391 .linkage_unit => lreg.linkage == .translation_unit,
392 else => lsym.isTemp(),392 else => lsym.isTemp(context.zld),
393 };393 };
394 }394 }
395395
...@@ -417,7 +417,7 @@ const TextBlockParser = struct {...@@ -417,7 +417,7 @@ const TextBlockParser = struct {
417 const sym = self.object.symbols.items[nlist_with_index.index];417 const sym = self.object.symbols.items[nlist_with_index.index];
418 if (sym.payload != .regular) {418 if (sym.payload != .regular) {
419 log.err("expected a regular symbol, found {s}", .{sym.payload});419 log.err("expected a regular symbol, found {s}", .{sym.payload});
420 log.err(" when remapping {s}", .{sym.name});420 log.err(" when remapping {s}", .{self.zld.getString(sym.strx)});
421 return error.SymbolIsNotRegular;421 return error.SymbolIsNotRegular;
422 }422 }
423 assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.423 assert(sym.payload.regular.local_sym_index != 0); // This means the symbol has not been properly resolved.
...@@ -463,7 +463,7 @@ const TextBlockParser = struct {...@@ -463,7 +463,7 @@ const TextBlockParser = struct {
463 }463 }
464 }464 }
465 }465 }
466 if (self.zld.globals.contains(senior_sym.name)) break :blk .global;466 if (self.zld.globals.contains(self.zld.getString(senior_sym.strx))) break :blk .global;
467 break :blk .static;467 break :blk .static;
468 } else null;468 } else null;
469469
...@@ -598,7 +598,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -598,7 +598,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
598 sectionName(sect),598 sectionName(sect),
599 });599 });
600 defer self.allocator.free(name);600 defer self.allocator.free(name);
601 const symbol = try Symbol.new(self.allocator, name);601 const symbol = try zld.allocator.create(Symbol);
602 symbol.* = .{
603 .strx = try zld.makeString(name),
604 .payload = .{ .undef = .{} },
605 };
602 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);606 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
603 break :symbol symbol;607 break :symbol symbol;
604 };608 };
...@@ -684,7 +688,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -684,7 +688,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
684 const reg = &sym.payload.regular;688 const reg = &sym.payload.regular;
685 if (reg.file) |file| {689 if (reg.file) |file| {
686 if (file != self) {690 if (file != self) {
687 log.debug("deduping definition of {s} in {s}", .{ sym.name, self.name.? });691 log.debug("deduping definition of {s} in {s}", .{ zld.getString(sym.strx), self.name.? });
688 block.deinit();692 block.deinit();
689 self.allocator.destroy(block);693 self.allocator.destroy(block);
690 continue;694 continue;
...@@ -739,7 +743,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -739,7 +743,11 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
739 sectionName(sect),743 sectionName(sect),
740 });744 });
741 defer self.allocator.free(name);745 defer self.allocator.free(name);
742 const symbol = try Symbol.new(self.allocator, name);746 const symbol = try zld.allocator.create(Symbol);
747 symbol.* = .{
748 .strx = try zld.makeString(name),
749 .payload = .{ .undef = .{} },
750 };
743 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);751 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
744 break :symbol symbol;752 break :symbol symbol;
745 };753 };
...@@ -812,7 +820,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {...@@ -812,7 +820,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
812 }820 }
813 }821 }
814 }822 }
815 if (zld.globals.contains(sym.name)) break :blk .global;823 if (zld.globals.contains(zld.getString(sym.strx))) break :blk .global;
816 break :blk .static;824 break :blk .static;
817 } else null;825 } else null;
818826
...@@ -870,7 +878,7 @@ fn parseRelocs(...@@ -870,7 +878,7 @@ fn parseRelocs(
870 try parser.parse();878 try parser.parse();
871}879}
872880
873pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {881pub fn symbolFromReloc(self: *Object, zld: *Zld, rel: macho.relocation_info) !*Symbol {
874 const symbol = blk: {882 const symbol = blk: {
875 if (rel.r_extern == 1) {883 if (rel.r_extern == 1) {
876 break :blk self.symbols.items[rel.r_symbolnum];884 break :blk self.symbols.items[rel.r_symbolnum];
...@@ -888,12 +896,15 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {...@@ -888,12 +896,15 @@ pub fn symbolFromReloc(self: *Object, rel: macho.relocation_info) !*Symbol {
888 sectionName(sect),896 sectionName(sect),
889 });897 });
890 defer self.allocator.free(name);898 defer self.allocator.free(name);
891 const symbol = try Symbol.new(self.allocator, name);899 const symbol = try zld.allocator.create(Symbol);
892 symbol.payload = .{900 symbol.* = .{
893 .regular = .{901 .strx = try zld.makeString(name),
894 .linkage = .translation_unit,902 .payload = .{
895 .address = sect.addr,903 .regular = .{
896 .file = self,904 .linkage = .translation_unit,
905 .address = sect.addr,
906 .file = self,
907 },
897 },908 },
898 };909 };
899 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);910 try self.sections_as_symbols.putNoClobber(self.allocator, sect_id, symbol);
src/link/MachO/Symbol.zig+10-40
...@@ -11,8 +11,8 @@ const Dylib = @import("Dylib.zig");...@@ -11,8 +11,8 @@ const Dylib = @import("Dylib.zig");
11const Object = @import("Object.zig");11const Object = @import("Object.zig");
12const Zld = @import("Zld.zig");12const Zld = @import("Zld.zig");
1313
14/// Symbol name. Owned slice.14/// Offset into the string table.
15name: []const u8,15strx: u32,
1616
17/// Index in GOT table for indirection.17/// Index in GOT table for indirection.
18got_index: ?u32 = null,18got_index: ?u32 = null,
...@@ -160,26 +160,11 @@ pub const Undefined = struct {...@@ -160,26 +160,11 @@ pub const Undefined = struct {
160 }160 }
161};161};
162162
163/// Create new undefined symbol.
164pub fn new(allocator: *Allocator, name: []const u8) !*Symbol {
165 const new_sym = try allocator.create(Symbol);
166 errdefer allocator.destroy(new_sym);
167
168 new_sym.* = .{
169 .name = try allocator.dupe(u8, name),
170 .payload = .{
171 .undef = .{},
172 },
173 };
174
175 return new_sym;
176}
177
178pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {163pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
179 _ = fmt;164 _ = fmt;
180 _ = options;165 _ = options;
181 try std.fmt.format(writer, "Symbol {{", .{});166 try std.fmt.format(writer, "Symbol {{", .{});
182 try std.fmt.format(writer, ".name = {s}, ", .{self.name});167 try std.fmt.format(writer, ".strx = {d}, ", .{self.strx});
183 if (self.got_index) |got_index| {168 if (self.got_index) |got_index| {
184 try std.fmt.format(writer, ".got_index = {}, ", .{got_index});169 try std.fmt.format(writer, ".got_index = {}, ", .{got_index});
185 }170 }
...@@ -190,11 +175,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt...@@ -190,11 +175,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt
190 try std.fmt.format(writer, "}}", .{});175 try std.fmt.format(writer, "}}", .{});
191}176}
192177
193pub fn isTemp(symbol: Symbol) bool {178pub fn isTemp(symbol: Symbol, zld: *Zld) bool {
179 const sym_name = zld.getString(symbol.strx);
194 switch (symbol.payload) {180 switch (symbol.payload) {
195 .regular => |regular| {181 .regular => |regular| {
196 if (regular.linkage == .translation_unit) {182 if (regular.linkage == .translation_unit) {
197 return mem.startsWith(u8, symbol.name, "l") or mem.startsWith(u8, symbol.name, "L");183 return mem.startsWith(u8, sym_name, "l") or mem.startsWith(u8, sym_name, "L");
198 }184 }
199 },185 },
200 else => {},186 else => {},
...@@ -202,24 +188,12 @@ pub fn isTemp(symbol: Symbol) bool {...@@ -202,24 +188,12 @@ pub fn isTemp(symbol: Symbol) bool {
202 return false;188 return false;
203}189}
204190
205pub fn needsTlvOffset(self: Symbol, zld: *Zld) bool {
206 if (self.payload != .regular) return false;
207
208 const reg = self.payload.regular;
209 const seg = zld.load_command.items[reg.segment_id].Segment;
210 const sect = seg.sections.items[reg.section_id];
211 const sect_type = commands.sectionType(sect);
212
213 return sect_type == macho.S_THREAD_LOCAL_VARIABLES;
214}
215
216pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {191pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
217 const n_strx = try zld.makeString(symbol.name);
218 const nlist = nlist: {192 const nlist = nlist: {
219 switch (symbol.payload) {193 switch (symbol.payload) {
220 .regular => |regular| {194 .regular => |regular| {
221 var nlist = macho.nlist_64{195 var nlist = macho.nlist_64{
222 .n_strx = n_strx,196 .n_strx = symbol.strx,
223 .n_type = macho.N_SECT,197 .n_type = macho.N_SECT,
224 .n_sect = regular.sectionId(zld),198 .n_sect = regular.sectionId(zld),
225 .n_desc = 0,199 .n_desc = 0,
...@@ -239,7 +213,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {...@@ -239,7 +213,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
239 .tentative => {213 .tentative => {
240 // TODO214 // TODO
241 break :nlist macho.nlist_64{215 break :nlist macho.nlist_64{
242 .n_strx = n_strx,216 .n_strx = symbol.strx,
243 .n_type = macho.N_UNDF,217 .n_type = macho.N_UNDF,
244 .n_sect = 0,218 .n_sect = 0,
245 .n_desc = 0,219 .n_desc = 0,
...@@ -248,7 +222,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {...@@ -248,7 +222,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
248 },222 },
249 .proxy => |proxy| {223 .proxy => |proxy| {
250 break :nlist macho.nlist_64{224 break :nlist macho.nlist_64{
251 .n_strx = n_strx,225 .n_strx = symbol.strx,
252 .n_type = macho.N_UNDF | macho.N_EXT,226 .n_type = macho.N_UNDF | macho.N_EXT,
253 .n_sect = 0,227 .n_sect = 0,
254 .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,228 .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
...@@ -258,7 +232,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {...@@ -258,7 +232,7 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
258 .undef => {232 .undef => {
259 // TODO233 // TODO
260 break :nlist macho.nlist_64{234 break :nlist macho.nlist_64{
261 .n_strx = n_strx,235 .n_strx = symbol.strx,
262 .n_type = macho.N_UNDF,236 .n_type = macho.N_UNDF,
263 .n_sect = 0,237 .n_sect = 0,
264 .n_desc = 0,238 .n_desc = 0,
...@@ -270,10 +244,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {...@@ -270,10 +244,6 @@ pub fn asNlist(symbol: *Symbol, zld: *Zld) !macho.nlist_64 {
270 return nlist;244 return nlist;
271}245}
272246
273pub fn deinit(symbol: *Symbol, allocator: *Allocator) void {
274 allocator.free(symbol.name);
275}
276
277pub fn isStab(sym: macho.nlist_64) bool {247pub fn isStab(sym: macho.nlist_64) bool {
278 return (macho.N_STAB & sym.n_type) != 0;248 return (macho.N_STAB & sym.n_type) != 0;
279}249}
src/link/MachO/Zld.zig+59-54
...@@ -113,7 +113,6 @@ stub_helper_stubs_start_off: ?u64 = null,...@@ -113,7 +113,6 @@ stub_helper_stubs_start_off: ?u64 = null,
113blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},113blocks: std.AutoHashMapUnmanaged(MatchingSection, *TextBlock) = .{},
114114
115strtab: std.ArrayListUnmanaged(u8) = .{},115strtab: std.ArrayListUnmanaged(u8) = .{},
116strtab_cache: std.StringHashMapUnmanaged(u32) = .{},
117116
118has_dices: bool = false,117has_dices: bool = false,
119has_stabs: bool = false,118has_stabs: bool = false,
...@@ -171,7 +170,7 @@ pub const TextBlock = struct {...@@ -171,7 +170,7 @@ pub const TextBlock = struct {
171 .n_value = reg.address,170 .n_value = reg.address,
172 });171 });
173 nlists.appendAssumeCapacity(.{172 nlists.appendAssumeCapacity(.{
174 .n_strx = try zld.makeString(sym.name),173 .n_strx = sym.strx,
175 .n_type = macho.N_FUN,174 .n_type = macho.N_FUN,
176 .n_sect = section_id,175 .n_sect = section_id,
177 .n_desc = 0,176 .n_desc = 0,
...@@ -194,7 +193,7 @@ pub const TextBlock = struct {...@@ -194,7 +193,7 @@ pub const TextBlock = struct {
194 },193 },
195 .global => {194 .global => {
196 try nlists.append(.{195 try nlists.append(.{
197 .n_strx = try zld.makeString(sym.name),196 .n_strx = sym.strx,
198 .n_type = macho.N_GSYM,197 .n_type = macho.N_GSYM,
199 .n_sect = 0,198 .n_sect = 0,
200 .n_desc = 0,199 .n_desc = 0,
...@@ -203,7 +202,7 @@ pub const TextBlock = struct {...@@ -203,7 +202,7 @@ pub const TextBlock = struct {
203 },202 },
204 .static => {203 .static => {
205 try nlists.append(.{204 try nlists.append(.{
206 .n_strx = try zld.makeString(sym.name),205 .n_strx = sym.strx,
207 .n_type = macho.N_STSYM,206 .n_type = macho.N_STSYM,
208 .n_sect = reg.sectionId(zld),207 .n_sect = reg.sectionId(zld),
209 .n_desc = 0,208 .n_desc = 0,
...@@ -349,26 +348,20 @@ pub fn deinit(self: *Zld) void {...@@ -349,26 +348,20 @@ pub fn deinit(self: *Zld) void {
349 self.dylibs.deinit(self.allocator);348 self.dylibs.deinit(self.allocator);
350349
351 for (self.imports.items) |sym| {350 for (self.imports.items) |sym| {
352 sym.deinit(self.allocator);
353 self.allocator.destroy(sym);351 self.allocator.destroy(sym);
354 }352 }
355 self.imports.deinit(self.allocator);353 self.imports.deinit(self.allocator);
356354
357 for (self.locals.items) |sym| {355 for (self.locals.items) |sym| {
358 sym.deinit(self.allocator);
359 self.allocator.destroy(sym);356 self.allocator.destroy(sym);
360 }357 }
361 self.locals.deinit(self.allocator);358 self.locals.deinit(self.allocator);
362359
360 for (self.globals.keys()) |key| {
361 self.allocator.free(key);
362 }
363 self.globals.deinit(self.allocator);363 self.globals.deinit(self.allocator);
364364
365 {
366 var it = self.strtab_cache.keyIterator();
367 while (it.next()) |key| {
368 self.allocator.free(key.*);
369 }
370 }
371 self.strtab_cache.deinit(self.allocator);
372 self.strtab.deinit(self.allocator);365 self.strtab.deinit(self.allocator);
373366
374 // TODO dealloc all blocks367 // TODO dealloc all blocks
...@@ -1168,7 +1161,7 @@ fn allocateTextBlocks(self: *Zld) !void {...@@ -1168,7 +1161,7 @@ fn allocateTextBlocks(self: *Zld) !void {
1168 sym.payload.regular.address = base_addr;1161 sym.payload.regular.address = base_addr;
11691162
1170 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{1163 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
1171 sym.name,1164 self.getString(sym.strx),
1172 base_addr,1165 base_addr,
1173 base_addr + block.size,1166 base_addr + block.size,
1174 block.size,1167 block.size,
...@@ -1231,7 +1224,7 @@ fn writeTextBlocks(self: *Zld) !void {...@@ -1231,7 +1224,7 @@ fn writeTextBlocks(self: *Zld) !void {
12311224
1232 const sym = self.locals.items[block.local_sym_index];1225 const sym = self.locals.items[block.local_sym_index];
1233 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{1226 log.debug(" {s}: start=0x{x}, end=0x{x}, size={}, align={}", .{
1234 sym.name,1227 self.getString(sym.strx),
1235 aligned_base_off,1228 aligned_base_off,
1236 aligned_base_off + block.size,1229 aligned_base_off + block.size,
1237 block.size,1230 block.size,
...@@ -1552,14 +1545,17 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {...@@ -1552,14 +1545,17 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
15521545
1553 if (Symbol.isSect(sym) and !Symbol.isExt(sym)) {1546 if (Symbol.isSect(sym) and !Symbol.isExt(sym)) {
1554 // Regular symbol local to translation unit1547 // Regular symbol local to translation unit
1555 const symbol = try Symbol.new(self.allocator, sym_name);1548 const symbol = try self.allocator.create(Symbol);
1556 symbol.payload = .{1549 symbol.* = .{
1557 .regular = .{1550 .strx = try self.makeString(sym_name),
1558 .linkage = .translation_unit,1551 .payload = .{
1559 .address = sym.n_value,1552 .regular = .{
1560 .weak_ref = Symbol.isWeakRef(sym),1553 .linkage = .translation_unit,
1561 .file = object,1554 .address = sym.n_value,
1562 .local_sym_index = @intCast(u32, self.locals.items.len),1555 .weak_ref = Symbol.isWeakRef(sym),
1556 .file = object,
1557 .local_sym_index = @intCast(u32, self.locals.items.len),
1558 },
1563 },1559 },
1564 };1560 };
1565 try self.locals.append(self.allocator, symbol);1561 try self.locals.append(self.allocator, symbol);
...@@ -1569,9 +1565,13 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {...@@ -1569,9 +1565,13 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
15691565
1570 const symbol = self.globals.get(sym_name) orelse symbol: {1566 const symbol = self.globals.get(sym_name) orelse symbol: {
1571 // Insert new global symbol.1567 // Insert new global symbol.
1572 const symbol = try Symbol.new(self.allocator, sym_name);1568 const symbol = try self.allocator.create(Symbol);
1573 symbol.payload.undef.file = object;1569 symbol.* = .{
1574 try self.globals.putNoClobber(self.allocator, symbol.name, symbol);1570 .strx = try self.makeString(sym_name),
1571 .payload = .{ .undef = .{ .file = object } },
1572 };
1573 const alloc_name = try self.allocator.dupe(u8, sym_name);
1574 try self.globals.putNoClobber(self.allocator, alloc_name, symbol);
1575 break :symbol symbol;1575 break :symbol symbol;
1576 };1576 };
15771577
...@@ -1628,7 +1628,8 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {...@@ -1628,7 +1628,8 @@ fn resolveSymbolsInObject(self: *Zld, object: *Object) !void {
1628fn resolveSymbols(self: *Zld) !void {1628fn resolveSymbols(self: *Zld) !void {
1629 // TODO mimicking insertion of null symbol from incremental linker.1629 // TODO mimicking insertion of null symbol from incremental linker.
1630 // This will need to moved.1630 // This will need to moved.
1631 const null_sym = try Symbol.new(self.allocator, "");1631 const null_sym = try self.allocator.create(Symbol);
1632 null_sym.* = .{ .strx = 0, .payload = .{ .undef = .{} } };
1632 try self.locals.append(self.allocator, null_sym);1633 try self.locals.append(self.allocator, null_sym);
16331634
1634 // First pass, resolve symbols in provided objects.1635 // First pass, resolve symbols in provided objects.
...@@ -1639,12 +1640,13 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1639,12 +1640,13 @@ fn resolveSymbols(self: *Zld) !void {
1639 // Second pass, resolve symbols in static libraries.1640 // Second pass, resolve symbols in static libraries.
1640 var sym_it = self.globals.iterator();1641 var sym_it = self.globals.iterator();
1641 while (sym_it.next()) |entry| {1642 while (sym_it.next()) |entry| {
1643 const sym_name = entry.key_ptr.*;
1642 const symbol = entry.value_ptr.*;1644 const symbol = entry.value_ptr.*;
1643 if (symbol.payload != .undef) continue;1645 if (symbol.payload != .undef) continue;
16441646
1645 for (self.archives.items) |archive| {1647 for (self.archives.items) |archive| {
1646 // Check if the entry exists in a static archive.1648 // Check if the entry exists in a static archive.
1647 const offsets = archive.toc.get(symbol.name) orelse {1649 const offsets = archive.toc.get(sym_name) orelse {
1648 // No hit.1650 // No hit.
1649 continue;1651 continue;
1650 };1652 };
...@@ -1734,21 +1736,27 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1734,21 +1736,27 @@ fn resolveSymbols(self: *Zld) !void {
1734 // Third pass, resolve symbols in dynamic libraries.1736 // Third pass, resolve symbols in dynamic libraries.
1735 {1737 {
1736 // Put dyld_stub_binder as an undefined special symbol.1738 // Put dyld_stub_binder as an undefined special symbol.
1737 const symbol = try Symbol.new(self.allocator, "dyld_stub_binder");1739 const symbol = try self.allocator.create(Symbol);
1740 symbol.* = .{
1741 .strx = try self.makeString("dyld_stub_binder"),
1742 .payload = .{ .undef = .{} },
1743 };
1738 const index = @intCast(u32, self.got_entries.items.len);1744 const index = @intCast(u32, self.got_entries.items.len);
1739 symbol.got_index = index;1745 symbol.got_index = index;
1740 try self.got_entries.append(self.allocator, symbol);1746 try self.got_entries.append(self.allocator, symbol);
1741 try self.globals.putNoClobber(self.allocator, symbol.name, symbol);1747 const alloc_name = try self.allocator.dupe(u8, "dyld_stub_binder");
1748 try self.globals.putNoClobber(self.allocator, alloc_name, symbol);
1742 }1749 }
17431750
1744 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);1751 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
1745 defer referenced.deinit();1752 defer referenced.deinit();
17461753
1747 loop: for (self.globals.values()) |symbol| {1754 loop: for (self.globals.keys()) |sym_name| {
1755 const symbol = self.globals.get(sym_name).?;
1748 if (symbol.payload != .undef) continue;1756 if (symbol.payload != .undef) continue;
17491757
1750 for (self.dylibs.items) |dylib| {1758 for (self.dylibs.items) |dylib| {
1751 if (!dylib.symbols.contains(symbol.name)) continue;1759 if (!dylib.symbols.contains(sym_name)) continue;
17521760
1753 try referenced.put(dylib, {});1761 try referenced.put(dylib, {});
1754 const index = @intCast(u32, self.imports.items.len);1762 const index = @intCast(u32, self.imports.items.len);
...@@ -1798,10 +1806,11 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1798,10 +1806,11 @@ fn resolveSymbols(self: *Zld) !void {
1798 }1806 }
17991807
1800 var has_undefined = false;1808 var has_undefined = false;
1801 for (self.globals.values()) |symbol| {1809 for (self.globals.keys()) |sym_name| {
1810 const symbol = self.globals.get(sym_name).?;
1802 if (symbol.payload != .undef) continue;1811 if (symbol.payload != .undef) continue;
18031812
1804 log.err("undefined reference to symbol '{s}'", .{symbol.name});1813 log.err("undefined reference to symbol '{s}'", .{sym_name});
1805 if (symbol.payload.undef.file) |file| {1814 if (symbol.payload.undef.file) |file| {
1806 log.err(" | referenced in {s}", .{file.name.?});1815 log.err(" | referenced in {s}", .{file.name.?});
1807 }1816 }
...@@ -2344,7 +2353,7 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2344,7 +2353,7 @@ fn writeBindInfoTable(self: *Zld) !void {
2344 .offset = base_offset + sym.got_index.? * @sizeOf(u64),2353 .offset = base_offset + sym.got_index.? * @sizeOf(u64),
2345 .segment_id = segment_id,2354 .segment_id = segment_id,
2346 .dylib_ordinal = proxy.dylibOrdinal(),2355 .dylib_ordinal = proxy.dylibOrdinal(),
2347 .name = sym.name,2356 .name = self.getString(sym.strx),
2348 });2357 });
2349 }2358 }
2350 }2359 }
...@@ -2372,7 +2381,7 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2372,7 +2381,7 @@ fn writeBindInfoTable(self: *Zld) !void {
2372 .offset = binding.offset + base_offset,2381 .offset = binding.offset + base_offset,
2373 .segment_id = match.seg,2382 .segment_id = match.seg,
2374 .dylib_ordinal = proxy.dylibOrdinal(),2383 .dylib_ordinal = proxy.dylibOrdinal(),
2375 .name = bind_sym.name,2384 .name = self.getString(bind_sym.strx),
2376 });2385 });
2377 }2386 }
23782387
...@@ -2395,7 +2404,7 @@ fn writeBindInfoTable(self: *Zld) !void {...@@ -2395,7 +2404,7 @@ fn writeBindInfoTable(self: *Zld) !void {
2395 .offset = base_offset,2404 .offset = base_offset,
2396 .segment_id = segment_id,2405 .segment_id = segment_id,
2397 .dylib_ordinal = proxy.dylibOrdinal(),2406 .dylib_ordinal = proxy.dylibOrdinal(),
2398 .name = sym.name,2407 .name = self.getString(sym.strx),
2399 });2408 });
2400 }2409 }
24012410
...@@ -2435,7 +2444,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void {...@@ -2435,7 +2444,7 @@ fn writeLazyBindInfoTable(self: *Zld) !void {
2435 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),2444 .offset = base_offset + sym.stubs_index.? * @sizeOf(u64),
2436 .segment_id = segment_id,2445 .segment_id = segment_id,
2437 .dylib_ordinal = proxy.dylibOrdinal(),2446 .dylib_ordinal = proxy.dylibOrdinal(),
2438 .name = sym.name,2447 .name = self.getString(sym.strx),
2439 });2448 });
2440 }2449 }
2441 }2450 }
...@@ -2547,7 +2556,7 @@ fn writeExportInfo(self: *Zld) !void {...@@ -2547,7 +2556,7 @@ fn writeExportInfo(self: *Zld) !void {
2547 if (sym.payload != .regular) continue;2556 if (sym.payload != .regular) continue;
2548 const reg = sym.payload.regular;2557 const reg = sym.payload.regular;
2549 if (reg.linkage != .global) continue;2558 if (reg.linkage != .global) continue;
2550 try sorted_globals.append(sym.name);2559 try sorted_globals.append(self.getString(sym.strx));
2551 }2560 }
25522561
2553 std.sort.sort([]const u8, sorted_globals.items, {}, Sorter.lessThan);2562 std.sort.sort([]const u8, sorted_globals.items, {}, Sorter.lessThan);
...@@ -2556,10 +2565,10 @@ fn writeExportInfo(self: *Zld) !void {...@@ -2556,10 +2565,10 @@ fn writeExportInfo(self: *Zld) !void {
2556 const sym = self.globals.get(sym_name) orelse unreachable;2565 const sym = self.globals.get(sym_name) orelse unreachable;
2557 const reg = sym.payload.regular;2566 const reg = sym.payload.regular;
25582567
2559 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym.name, reg.address });2568 log.debug(" | putting '{s}' defined at 0x{x}", .{ sym_name, reg.address });
25602569
2561 try trie.put(.{2570 try trie.put(.{
2562 .name = sym.name,2571 .name = sym_name,
2563 .vmaddr_offset = reg.address - base_address,2572 .vmaddr_offset = reg.address - base_address,
2564 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,2573 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2565 });2574 });
...@@ -2597,7 +2606,7 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2597,7 +2606,7 @@ fn writeSymbolTable(self: *Zld) !void {
25972606
2598 for (self.locals.items) |symbol, i| {2607 for (self.locals.items) |symbol, i| {
2599 if (i == 0) continue; // skip null symbol2608 if (i == 0) continue; // skip null symbol
2600 if (symbol.isTemp()) continue; // TODO when merging codepaths, this should go into freelist2609 if (symbol.isTemp(self)) continue; // TODO when merging codepaths, this should go into freelist
26012610
2602 const reg = symbol.payload.regular;2611 const reg = symbol.payload.regular;
2603 const nlist = try symbol.asNlist(self);2612 const nlist = try symbol.asNlist(self);
...@@ -2673,7 +2682,7 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2673,7 +2682,7 @@ fn writeSymbolTable(self: *Zld) !void {
2673 const nlist = try sym.asNlist(self);2682 const nlist = try sym.asNlist(self);
2674 const id = @intCast(u32, undefs.items.len);2683 const id = @intCast(u32, undefs.items.len);
2675 try undefs.append(nlist);2684 try undefs.append(nlist);
2676 try undef_dir.putNoClobber(sym.name, id);2685 try undef_dir.putNoClobber(self.getString(sym.strx), id);
2677 }2686 }
26782687
2679 const nlocals = locals.items.len;2688 const nlocals = locals.items.len;
...@@ -2735,7 +2744,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2735,7 +2744,8 @@ fn writeSymbolTable(self: *Zld) !void {
27352744
2736 stubs.reserved1 = 0;2745 stubs.reserved1 = 0;
2737 for (self.stubs.items) |sym| {2746 for (self.stubs.items) |sym| {
2738 const id = undef_dir.get(sym.name) orelse unreachable;2747 const sym_name = self.getString(sym.strx);
2748 const id = undef_dir.get(sym_name) orelse unreachable;
2739 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2749 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
2740 }2750 }
27412751
...@@ -2743,7 +2753,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2743,7 +2753,8 @@ fn writeSymbolTable(self: *Zld) !void {
2743 for (self.got_entries.items) |sym| {2753 for (self.got_entries.items) |sym| {
2744 switch (sym.payload) {2754 switch (sym.payload) {
2745 .proxy => {2755 .proxy => {
2746 const id = undef_dir.get(sym.name) orelse unreachable;2756 const sym_name = self.getString(sym.strx);
2757 const id = undef_dir.get(sym_name) orelse unreachable;
2747 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2758 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
2748 },2759 },
2749 else => {2760 else => {
...@@ -2754,7 +2765,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2754,7 +2765,8 @@ fn writeSymbolTable(self: *Zld) !void {
27542765
2755 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;2766 la_symbol_ptr.reserved1 = got.reserved1 + ngot_entries;
2756 for (self.stubs.items) |sym| {2767 for (self.stubs.items) |sym| {
2757 const id = undef_dir.get(sym.name) orelse unreachable;2768 const sym_name = self.getString(sym.strx);
2769 const id = undef_dir.get(sym_name) orelse unreachable;
2758 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);2770 try writer.writeIntLittle(u32, dysymtab.iundefsym + id);
2759 }2771 }
27602772
...@@ -2940,11 +2952,6 @@ fn writeHeader(self: *Zld) !void {...@@ -2940,11 +2952,6 @@ fn writeHeader(self: *Zld) !void {
2940}2952}
29412953
2942pub fn makeString(self: *Zld, string: []const u8) !u32 {2954pub fn makeString(self: *Zld, string: []const u8) !u32 {
2943 if (self.strtab_cache.get(string)) |off| {
2944 log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
2945 return off;
2946 }
2947
2948 try self.strtab.ensureUnusedCapacity(self.allocator, string.len + 1);2955 try self.strtab.ensureUnusedCapacity(self.allocator, string.len + 1);
2949 const new_off = @intCast(u32, self.strtab.items.len);2956 const new_off = @intCast(u32, self.strtab.items.len);
29502957
...@@ -2953,12 +2960,10 @@ pub fn makeString(self: *Zld, string: []const u8) !u32 {...@@ -2953,12 +2960,10 @@ pub fn makeString(self: *Zld, string: []const u8) !u32 {
2953 self.strtab.appendSliceAssumeCapacity(string);2960 self.strtab.appendSliceAssumeCapacity(string);
2954 self.strtab.appendAssumeCapacity(0);2961 self.strtab.appendAssumeCapacity(0);
29552962
2956 try self.strtab_cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off);
2957
2958 return new_off;2963 return new_off;
2959}2964}
29602965
2961pub fn getString(self: *Zld, off: u32) ?[]const u8 {2966pub fn getString(self: *Zld, off: u32) []const u8 {
2962 assert(off < self.strtab.items.len);2967 assert(off < self.strtab.items.len);
2963 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));2968 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + off));
2964}2969}
src/link/MachO/reloc.zig+13-8
...@@ -407,7 +407,7 @@ pub const Relocation = struct {...@@ -407,7 +407,7 @@ pub const Relocation = struct {
407 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;407 const dc_seg = zld.load_commands.items[zld.data_const_segment_cmd_index.?].Segment;
408 const got = dc_seg.sections.items[zld.got_section_index.?];408 const got = dc_seg.sections.items[zld.got_section_index.?];
409 const got_index = self.target.got_index orelse {409 const got_index = self.target.got_index orelse {
410 log.err("expected GOT entry for symbol '{s}'", .{self.target.name});410 log.err("expected GOT entry for symbol '{s}'", .{zld.getString(self.target.strx)});
411 log.err(" this is an internal linker error", .{});411 log.err(" this is an internal linker error", .{});
412 return error.FailedToResolveRelocationTarget;412 return error.FailedToResolveRelocationTarget;
413 };413 };
...@@ -446,8 +446,8 @@ pub const Relocation = struct {...@@ -446,8 +446,8 @@ pub const Relocation = struct {
446446
447 break :blk reg.address;447 break :blk reg.address;
448 },448 },
449 .proxy => |proxy| {449 .proxy => {
450 if (mem.eql(u8, self.target.name, "__tlv_bootstrap")) {450 if (mem.eql(u8, zld.getString(self.target.strx), "__tlv_bootstrap")) {
451 break :blk 0; // Dynamically bound by dyld.451 break :blk 0; // Dynamically bound by dyld.
452 }452 }
453453
...@@ -460,7 +460,9 @@ pub const Relocation = struct {...@@ -460,7 +460,9 @@ pub const Relocation = struct {
460 break :blk stubs.addr + stubs_index * stubs.reserved2;460 break :blk stubs.addr + stubs_index * stubs.reserved2;
461 },461 },
462 else => {462 else => {
463 log.err("failed to resolve symbol '{s}' as a relocation target", .{self.target.name});463 log.err("failed to resolve symbol '{s}' as a relocation target", .{
464 zld.getString(self.target.strx),
465 });
464 log.err(" this is an internal linker error", .{});466 log.err(" this is an internal linker error", .{});
465 return error.FailedToResolveRelocationTarget;467 return error.FailedToResolveRelocationTarget;
466 },468 },
...@@ -634,7 +636,10 @@ pub const Parser = struct {...@@ -634,7 +636,10 @@ pub const Parser = struct {
634 out_rel.target.got_index = index;636 out_rel.target.got_index = index;
635 try self.zld.got_entries.append(self.zld.allocator, out_rel.target);637 try self.zld.got_entries.append(self.zld.allocator, out_rel.target);
636638
637 log.debug("adding GOT entry for symbol {s} at index {}", .{ out_rel.target.name, index });639 log.debug("adding GOT entry for symbol {s} at index {}", .{
640 self.zld.getString(out_rel.target.strx),
641 index,
642 });
638 } else if (out_rel.payload == .unsigned) {643 } else if (out_rel.payload == .unsigned) {
639 const sym = out_rel.target;644 const sym = out_rel.target;
640 switch (sym.payload) {645 switch (sym.payload) {
...@@ -697,14 +702,14 @@ pub const Parser = struct {...@@ -697,14 +702,14 @@ pub const Parser = struct {
697 sym.stubs_index = index;702 sym.stubs_index = index;
698 try self.zld.stubs.append(self.zld.allocator, sym);703 try self.zld.stubs.append(self.zld.allocator, sym);
699704
700 log.debug("adding stub entry for symbol {s} at index {}", .{ sym.name, index });705 log.debug("adding stub entry for symbol {s} at index {}", .{ self.zld.getString(sym.strx), index });
701 }706 }
702 }707 }
703 }708 }
704709
705 fn parseBaseRelInfo(self: *Parser, rel: macho.relocation_info) !Relocation {710 fn parseBaseRelInfo(self: *Parser, rel: macho.relocation_info) !Relocation {
706 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);711 const offset = @intCast(u32, @intCast(u64, rel.r_address) - self.base_addr);
707 const target = try self.object.symbolFromReloc(rel);712 const target = try self.object.symbolFromReloc(self.zld, rel);
708 return Relocation{713 return Relocation{
709 .offset = offset,714 .offset = offset,
710 .target = target,715 .target = target,
...@@ -888,7 +893,7 @@ pub const Parser = struct {...@@ -888,7 +893,7 @@ pub const Parser = struct {
888 assert(rel.r_pcrel == 0);893 assert(rel.r_pcrel == 0);
889 assert(self.subtractor == null);894 assert(self.subtractor == null);
890895
891 self.subtractor = try self.object.symbolFromReloc(rel);896 self.subtractor = try self.object.symbolFromReloc(self.zld, rel);
892 }897 }
893898
894 fn parseLoad(self: *Parser, rel: macho.relocation_info) !Relocation {899 fn parseLoad(self: *Parser, rel: macho.relocation_info) !Relocation {