authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-01 17:25:51+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-15 18:49:46+02:00
log2b3bda43e352152f0150bf2e795419cf1bcfcd90
treef6c550980ea30b8e3ded451b6145ebb203101b22
parent3622fe08dbdcaccb04204b48257e1d5fcbe0d164

zld: abstract Symbol creation logic


6 files changed, 231 insertions(+), 184 deletions(-)

src/link/MachO.zig+1-1
...@@ -724,7 +724,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -724,7 +724,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
724 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});724 try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
725 }725 }
726 } else {726 } else {
727 var zld = Zld.init(self.base.allocator);727 var zld = try Zld.init(self.base.allocator);
728 defer {728 defer {
729 zld.closeFiles();729 zld.closeFiles();
730 zld.deinit();730 zld.deinit();
src/link/MachO/Dylib.zig+8-14
...@@ -146,7 +146,12 @@ pub const CreateOpts = struct {...@@ -146,7 +146,12 @@ pub const CreateOpts = struct {
146 id: ?Id = null,146 id: ?Id = null,
147};147};
148148
149pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8, opts: CreateOpts) Error!?[]*Dylib {149pub fn createAndParseFromPath(
150 allocator: *Allocator,
151 arch: Arch,
152 path: []const u8,
153 opts: CreateOpts,
154) Error!?[]*Dylib {
150 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {155 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
151 error.FileNotFound => return null,156 error.FileNotFound => return null,
152 else => |e| return e,157 else => |e| return e,
...@@ -505,18 +510,7 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {...@@ -505,18 +510,7 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {
505510
506pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {511pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
507 if (!self.symbols.contains(sym_name)) return null;512 if (!self.symbols.contains(sym_name)) return null;
508513 return Symbol.Proxy.new(self.allocator, sym_name, .{
509 const name = try self.allocator.dupe(u8, sym_name);
510 const proxy = try self.allocator.create(Symbol.Proxy);
511 errdefer self.allocator.destroy(proxy);
512
513 proxy.* = .{
514 .base = .{
515 .@"type" = .proxy,
516 .name = name,
517 },
518 .file = self,514 .file = self,
519 };515 });
520
521 return &proxy.base;
522}516}
src/link/MachO/Object.zig+7-28
...@@ -9,12 +9,12 @@ const log = std.log.scoped(.object);...@@ -9,12 +9,12 @@ const log = std.log.scoped(.object);
9const macho = std.macho;9const macho = std.macho;
10const mem = std.mem;10const mem = std.mem;
11const reloc = @import("reloc.zig");11const reloc = @import("reloc.zig");
12const parseName = @import("Zld.zig").parseName;
1213
13const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
14const Arch = std.Target.Cpu.Arch;15const Arch = std.Target.Cpu.Arch;
15const Relocation = reloc.Relocation;16const Relocation = reloc.Relocation;
16const Symbol = @import("Symbol.zig");17const Symbol = @import("Symbol.zig");
17const parseName = @import("Zld.zig").parseName;
1818
19usingnamespace @import("commands.zig");19usingnamespace @import("commands.zig");
2020
...@@ -437,47 +437,26 @@ pub fn parseSymbols(self: *Object) !void {...@@ -437,47 +437,26 @@ pub fn parseSymbols(self: *Object) !void {
437 if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;437 if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;
438 break :linkage .global;438 break :linkage .global;
439 };439 };
440 const regular = try self.allocator.create(Symbol.Regular);440 break :symbol try Symbol.Regular.new(self.allocator, name, .{
441 errdefer self.allocator.destroy(regular);
442 regular.* = .{
443 .base = .{
444 .@"type" = .regular,
445 .name = name,
446 },
447 .linkage = linkage,441 .linkage = linkage,
448 .address = sym.n_value,442 .address = sym.n_value,
449 .section = sym.n_sect - 1,443 .section = sym.n_sect - 1,
450 .weak_ref = Symbol.isWeakRef(sym),444 .weak_ref = Symbol.isWeakRef(sym),
451 .file = self,445 .file = self,
452 };446 });
453 break :symbol &regular.base;
454 }447 }
455448
456 if (sym.n_value != 0) {449 if (sym.n_value != 0) {
457 const tentative = try self.allocator.create(Symbol.Tentative);450 break :symbol try Symbol.Tentative.new(self.allocator, name, .{
458 errdefer self.allocator.destroy(tentative);
459 tentative.* = .{
460 .base = .{
461 .@"type" = .tentative,
462 .name = name,
463 },
464 .size = sym.n_value,451 .size = sym.n_value,
465 .alignment = (sym.n_desc >> 8) & 0x0f,452 .alignment = (sym.n_desc >> 8) & 0x0f,
466 .file = self,453 .file = self,
467 };454 });
468 break :symbol &tentative.base;
469 }455 }
470456
471 const undef = try self.allocator.create(Symbol.Unresolved);457 break :symbol try Symbol.Unresolved.new(self.allocator, name, .{
472 errdefer self.allocator.destroy(undef);
473 undef.* = .{
474 .base = .{
475 .@"type" = .unresolved,
476 .name = name,
477 },
478 .file = self,458 .file = self,
479 };459 });
480 break :symbol &undef.base;
481 };460 };
482461
483 try self.symbols.append(self.allocator, symbol);462 try self.symbols.append(self.allocator, symbol);
src/link/MachO/StringTable.zig+7-27
...@@ -8,7 +8,6 @@ const Allocator = mem.Allocator;...@@ -8,7 +8,6 @@ const Allocator = mem.Allocator;
88
9allocator: *Allocator,9allocator: *Allocator,
10buffer: std.ArrayListUnmanaged(u8) = .{},10buffer: std.ArrayListUnmanaged(u8) = .{},
11used_offsets: std.ArrayListUnmanaged(u32) = .{},
12cache: std.StringHashMapUnmanaged(u32) = .{},11cache: std.StringHashMapUnmanaged(u32) = .{},
1312
14pub const Error = error{OutOfMemory};13pub const Error = error{OutOfMemory};
...@@ -22,8 +21,13 @@ pub fn init(allocator: *Allocator) Error!StringTable {...@@ -22,8 +21,13 @@ pub fn init(allocator: *Allocator) Error!StringTable {
22}21}
2322
24pub fn deinit(self: *StringTable) void {23pub fn deinit(self: *StringTable) void {
24 {
25 var it = self.cache.keyIterator();
26 while (it.next()) |key| {
27 self.allocator.free(key.*);
28 }
29 }
25 self.cache.deinit(self.allocator);30 self.cache.deinit(self.allocator);
26 self.used_offsets.deinit(self.allocator);
27 self.buffer.deinit(self.allocator);31 self.buffer.deinit(self.allocator);
28}32}
2933
...@@ -33,8 +37,6 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {...@@ -33,8 +37,6 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {
33 return off;37 return off;
34 }38 }
3539
36 const invalidate_cache = self.needsToGrow(string.len + 1);
37
38 try self.buffer.ensureUnusedCapacity(self.allocator, string.len + 1);40 try self.buffer.ensureUnusedCapacity(self.allocator, string.len + 1);
39 const new_off = @intCast(u32, self.buffer.items.len);41 const new_off = @intCast(u32, self.buffer.items.len);
4042
...@@ -43,25 +45,7 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {...@@ -43,25 +45,7 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {
43 self.buffer.appendSliceAssumeCapacity(string);45 self.buffer.appendSliceAssumeCapacity(string);
44 self.buffer.appendAssumeCapacity(0);46 self.buffer.appendAssumeCapacity(0);
4547
46 if (invalidate_cache) {48 try self.cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off);
47 log.debug("invalidating cache", .{});
48 // Re-create the cache.
49 self.cache.clearRetainingCapacity();
50 for (self.used_offsets.items) |off| {
51 try self.cache.putNoClobber(self.allocator, self.get(off).?, off);
52 }
53 }
54
55 {
56 log.debug("cache:", .{});
57 var it = self.cache.iterator();
58 while (it.next()) |entry| {
59 log.debug(" | {s} => {}", .{ entry.key_ptr.*, entry.value_ptr.* });
60 }
61 }
62
63 try self.cache.putNoClobber(self.allocator, self.get(new_off).?, new_off);
64 try self.used_offsets.append(self.allocator, new_off);
6549
66 return new_off;50 return new_off;
67}51}
...@@ -78,7 +62,3 @@ pub fn asSlice(self: StringTable) []const u8 {...@@ -78,7 +62,3 @@ pub fn asSlice(self: StringTable) []const u8 {
78pub fn size(self: StringTable) u64 {62pub fn size(self: StringTable) u64 {
79 return self.buffer.items.len;63 return self.buffer.items.len;
80}64}
81
82fn needsToGrow(self: StringTable, needed_space: u64) bool {
83 return self.buffer.capacity < needed_space + self.size();
84}
src/link/MachO/Symbol.zig+174-15
...@@ -7,6 +7,7 @@ const mem = std.mem;...@@ -7,6 +7,7 @@ const mem = std.mem;
7const Allocator = mem.Allocator;7const Allocator = mem.Allocator;
8const Dylib = @import("Dylib.zig");8const Dylib = @import("Dylib.zig");
9const Object = @import("Object.zig");9const Object = @import("Object.zig");
10const StringTable = @import("StringTable.zig");
1011
11pub const Type = enum {12pub const Type = enum {
12 regular,13 regular,
...@@ -19,7 +20,7 @@ pub const Type = enum {...@@ -19,7 +20,7 @@ pub const Type = enum {
19@"type": Type,20@"type": Type,
2021
21/// Symbol name. Owned slice.22/// Symbol name. Owned slice.
22name: []u8,23name: []const u8,
2324
24/// Alias of.25/// Alias of.
25alias: ?*Symbol = null,26alias: ?*Symbol = null,
...@@ -43,23 +44,14 @@ pub const Regular = struct {...@@ -43,23 +44,14 @@ pub const Regular = struct {
43 section: u8,44 section: u8,
4445
45 /// Whether the symbol is a weak ref.46 /// Whether the symbol is a weak ref.
46 weak_ref: bool,47 weak_ref: bool = false,
4748
48 /// Object file where to locate this symbol.49 /// Object file where to locate this symbol.
49 file: *Object,50 /// null means self-reference.
51 file: ?*Object = null,
5052
51 /// Debug stab if defined.53 /// Debug stab if defined.
52 stab: ?struct {54 stab: ?Stab = null,
53 /// Stab kind
54 kind: enum {
55 function,
56 global,
57 static,
58 },
59
60 /// Size of the stab.
61 size: u64,
62 } = null,
6355
64 /// True if symbol was already committed into the final56 /// True if symbol was already committed into the final
65 /// symbol table.57 /// symbol table.
...@@ -73,6 +65,68 @@ pub const Regular = struct {...@@ -73,6 +65,68 @@ pub const Regular = struct {
73 global,65 global,
74 };66 };
7567
68 pub const Stab = struct {
69 /// Stab kind
70 kind: enum {
71 function,
72 global,
73 static,
74 },
75
76 /// Size of the stab.
77 size: u64,
78 };
79
80 const Opts = struct {
81 linkage: Linkage = .translation_unit,
82 address: u64 = 0,
83 section: u8 = 0,
84 weak_ref: bool = false,
85 file: ?*Object = null,
86 stab: ?Stab = null,
87 };
88
89 pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
90 const reg = try allocator.create(Regular);
91 errdefer allocator.destroy(reg);
92
93 reg.* = .{
94 .base = .{
95 .@"type" = .regular,
96 .name = try allocator.dupe(u8, name),
97 },
98 .linkage = opts.linkage,
99 .address = opts.address,
100 .section = opts.section,
101 .weak_ref = opts.weak_ref,
102 .file = opts.file,
103 .stab = opts.stab,
104 };
105
106 return &reg.base;
107 }
108
109 pub fn asNlist(regular: *Regular, strtab: *StringTable) !macho.nlist_64 {
110 const n_strx = try strtab.getOrPut(regular.base.name);
111 var nlist = macho.nlist_64{
112 .n_strx = n_strx,
113 .n_type = macho.N_SECT,
114 .n_sect = regular.section,
115 .n_desc = 0,
116 .n_value = regular.address,
117 };
118
119 if (regular.linkage != .translation_unit) {
120 nlist.n_type |= macho.N_EXT;
121 }
122 if (regular.linkage == .linkage_unit) {
123 nlist.n_type |= macho.N_PEXT;
124 nlist.n_desc |= macho.N_WEAK_DEF;
125 }
126
127 return nlist;
128 }
129
76 pub fn isTemp(regular: *Regular) bool {130 pub fn isTemp(regular: *Regular) bool {
77 if (regular.linkage == .translation_unit) {131 if (regular.linkage == .translation_unit) {
78 return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");132 return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");
...@@ -97,6 +151,36 @@ pub const Proxy = struct {...@@ -97,6 +151,36 @@ pub const Proxy = struct {
97151
98 pub const base_type: Symbol.Type = .proxy;152 pub const base_type: Symbol.Type = .proxy;
99153
154 const Opts = struct {
155 file: ?*Dylib = null,
156 };
157
158 pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
159 const proxy = try allocator.create(Proxy);
160 errdefer allocator.destroy(proxy);
161
162 proxy.* = .{
163 .base = .{
164 .@"type" = .proxy,
165 .name = try allocator.dupe(u8, name),
166 },
167 .file = opts.file,
168 };
169
170 return &proxy.base;
171 }
172
173 pub fn asNlist(proxy: *Proxy, strtab: *StringTable) !macho.nlist_64 {
174 const n_strx = try strtab.getOrPut(proxy.base.name);
175 return macho.nlist_64{
176 .n_strx = n_strx,
177 .n_type = macho.N_UNDF | macho.N_EXT,
178 .n_sect = 0,
179 .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
180 .n_value = 0,
181 };
182 }
183
100 pub fn deinit(proxy: *Proxy, allocator: *Allocator) void {184 pub fn deinit(proxy: *Proxy, allocator: *Allocator) void {
101 proxy.bind_info.deinit(allocator);185 proxy.bind_info.deinit(allocator);
102 }186 }
...@@ -115,6 +199,36 @@ pub const Unresolved = struct {...@@ -115,6 +199,36 @@ pub const Unresolved = struct {
115 file: ?*Object = null,199 file: ?*Object = null,
116200
117 pub const base_type: Symbol.Type = .unresolved;201 pub const base_type: Symbol.Type = .unresolved;
202
203 const Opts = struct {
204 file: ?*Object = null,
205 };
206
207 pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
208 const undef = try allocator.create(Unresolved);
209 errdefer allocator.destroy(undef);
210
211 undef.* = .{
212 .base = .{
213 .@"type" = .unresolved,
214 .name = try allocator.dupe(u8, name),
215 },
216 .file = opts.file,
217 };
218
219 return &undef.base;
220 }
221
222 pub fn asNlist(undef: *Unresolved, strtab: *StringTable) !macho.nlist_64 {
223 const n_strx = try strtab.getOrPut(undef.base.name);
224 return macho.nlist_64{
225 .n_strx = n_strx,
226 .n_type = macho.N_UNDF,
227 .n_sect = 0,
228 .n_desc = 0,
229 .n_value = 0,
230 };
231 }
118};232};
119233
120pub const Tentative = struct {234pub const Tentative = struct {
...@@ -127,13 +241,49 @@ pub const Tentative = struct {...@@ -127,13 +241,49 @@ pub const Tentative = struct {
127 alignment: u16,241 alignment: u16,
128242
129 /// File where this symbol was referenced.243 /// File where this symbol was referenced.
130 file: *Object,244 file: ?*Object = null,
131245
132 pub const base_type: Symbol.Type = .tentative;246 pub const base_type: Symbol.Type = .tentative;
247
248 const Opts = struct {
249 size: u64 = 0,
250 alignment: u16 = 0,
251 file: ?*Object = null,
252 };
253
254 pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
255 const tent = try allocator.create(Tentative);
256 errdefer allocator.destroy(tent);
257
258 tent.* = .{
259 .base = .{
260 .@"type" = .tentative,
261 .name = try allocator.dupe(u8, name),
262 },
263 .size = opts.size,
264 .alignment = opts.alignment,
265 .file = opts.file,
266 };
267
268 return &tent.base;
269 }
270
271 pub fn asNlist(tent: *Tentative, strtab: *StringTable) !macho.nlist_64 {
272 // TODO
273 const n_strx = try strtab.getOrPut(tent.base.name);
274 return macho.nlist_64{
275 .n_strx = n_strx,
276 .n_type = macho.N_UNDF,
277 .n_sect = 0,
278 .n_desc = 0,
279 .n_value = 0,
280 };
281 }
133};282};
134283
135pub fn deinit(base: *Symbol, allocator: *Allocator) void {284pub fn deinit(base: *Symbol, allocator: *Allocator) void {
136 allocator.free(base.name);285 allocator.free(base.name);
286
137 switch (base.@"type") {287 switch (base.@"type") {
138 .proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator),288 .proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator),
139 else => {},289 else => {},
...@@ -154,6 +304,15 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol {...@@ -154,6 +304,15 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol {
154 return base;304 return base;
155}305}
156306
307pub fn asNlist(base: *Symbol, strtab: *StringTable) !macho.nlist_64 {
308 return switch (base.tag) {
309 .regular => @fieldParentPtr(Regular, "base", base).asNlist(strtab),
310 .proxy => @fieldParentPtr(Proxy, "base", base).asNlist(strtab),
311 .unresolved => @fieldParentPtr(Unresolved, "base", base).asNlist(strtab),
312 .tentative => @fieldParentPtr(Tentative, "base", base).asNlist(strtab),
313 };
314}
315
157pub fn isStab(sym: macho.nlist_64) bool {316pub fn isStab(sym: macho.nlist_64) bool {
158 return (macho.N_STAB & sym.n_type) != 0;317 return (macho.N_STAB & sym.n_type) != 0;
159}318}
src/link/MachO/Zld.zig+34-99
...@@ -17,6 +17,7 @@ const Archive = @import("Archive.zig");...@@ -17,6 +17,7 @@ const Archive = @import("Archive.zig");
17const CodeSignature = @import("CodeSignature.zig");17const CodeSignature = @import("CodeSignature.zig");
18const Dylib = @import("Dylib.zig");18const Dylib = @import("Dylib.zig");
19const Object = @import("Object.zig");19const Object = @import("Object.zig");
20const StringTable = @import("StringTable.zig");
20const Symbol = @import("Symbol.zig");21const Symbol = @import("Symbol.zig");
21const Trie = @import("Trie.zig");22const Trie = @import("Trie.zig");
2223
...@@ -24,6 +25,7 @@ usingnamespace @import("commands.zig");...@@ -24,6 +25,7 @@ usingnamespace @import("commands.zig");
24usingnamespace @import("bind.zig");25usingnamespace @import("bind.zig");
2526
26allocator: *Allocator,27allocator: *Allocator,
28strtab: StringTable,
2729
28target: ?std.Target = null,30target: ?std.Target = null,
29page_size: ?u16 = null,31page_size: ?u16 = null,
...@@ -109,9 +111,6 @@ tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{},...@@ -109,9 +111,6 @@ tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
109/// Set if the linker found tentative definitions in any of the objects.111/// Set if the linker found tentative definitions in any of the objects.
110tentative_defs_offset: u64 = 0,112tentative_defs_offset: u64 = 0,
111113
112strtab: std.ArrayListUnmanaged(u8) = .{},
113strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
114
115threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction114threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
116local_rebases: std.ArrayListUnmanaged(Pointer) = .{},115local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
117stubs: std.ArrayListUnmanaged(*Symbol) = .{},116stubs: std.ArrayListUnmanaged(*Symbol) = .{},
...@@ -138,8 +137,11 @@ const TlvOffset = struct {...@@ -138,8 +137,11 @@ const TlvOffset = struct {
138/// Default path to dyld137/// Default path to dyld
139const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";138const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
140139
141pub fn init(allocator: *Allocator) Zld {140pub fn init(allocator: *Allocator) !Zld {
142 return .{ .allocator = allocator };141 return Zld{
142 .allocator = allocator,
143 .strtab = try StringTable.init(allocator),
144 };
143}145}
144146
145pub fn deinit(self: *Zld) void {147pub fn deinit(self: *Zld) void {
...@@ -180,15 +182,7 @@ pub fn deinit(self: *Zld) void {...@@ -180,15 +182,7 @@ pub fn deinit(self: *Zld) void {
180 self.tentatives.deinit(self.allocator);182 self.tentatives.deinit(self.allocator);
181 self.globals.deinit(self.allocator);183 self.globals.deinit(self.allocator);
182 self.unresolved.deinit(self.allocator);184 self.unresolved.deinit(self.allocator);
183 self.strtab.deinit(self.allocator);185 self.strtab.deinit();
184
185 {
186 var it = self.strtab_dir.keyIterator();
187 while (it.next()) |key| {
188 self.allocator.free(key.*);
189 }
190 }
191 self.strtab_dir.deinit(self.allocator);
192}186}
193187
194pub fn closeFiles(self: Zld) void {188pub fn closeFiles(self: Zld) void {
...@@ -1137,16 +1131,7 @@ fn allocateTentativeSymbols(self: *Zld) !void {...@@ -1137,16 +1131,7 @@ fn allocateTentativeSymbols(self: *Zld) !void {
1137 // Convert tentative definitions into regular symbols.1131 // Convert tentative definitions into regular symbols.
1138 for (self.tentatives.values()) |sym| {1132 for (self.tentatives.values()) |sym| {
1139 const tent = sym.cast(Symbol.Tentative) orelse unreachable;1133 const tent = sym.cast(Symbol.Tentative) orelse unreachable;
1140 const reg = try self.allocator.create(Symbol.Regular);1134 const reg = try Symbol.Regular.new(self.allocator, tent.base.name, .{
1141 errdefer self.allocator.destroy(reg);
1142
1143 reg.* = .{
1144 .base = .{
1145 .@"type" = .regular,
1146 .name = try self.allocator.dupe(u8, tent.base.name),
1147 .got_index = tent.base.got_index,
1148 .stubs_index = tent.base.stubs_index,
1149 },
1150 .linkage = .global,1135 .linkage = .global,
1151 .address = base_address,1136 .address = base_address,
1152 .section = section,1137 .section = section,
...@@ -1156,16 +1141,18 @@ fn allocateTentativeSymbols(self: *Zld) !void {...@@ -1156,16 +1141,18 @@ fn allocateTentativeSymbols(self: *Zld) !void {
1156 .kind = .global,1141 .kind = .global,
1157 .size = 0,1142 .size = 0,
1158 },1143 },
1159 };1144 });
1145 reg.got_index = tent.base.got_index;
1146 reg.stubs_index = tent.base.stubs_index;
11601147
1161 try self.globals.putNoClobber(self.allocator, reg.base.name, &reg.base);1148 try self.globals.putNoClobber(self.allocator, reg.name, reg);
1162 tent.base.alias = &reg.base;1149 tent.base.alias = reg;
11631150
1164 if (tent.base.got_index) |idx| {1151 if (tent.base.got_index) |idx| {
1165 self.got_entries.items[idx] = &reg.base;1152 self.got_entries.items[idx] = reg;
1166 }1153 }
1167 if (tent.base.stubs_index) |idx| {1154 if (tent.base.stubs_index) |idx| {
1168 self.stubs.items[idx] = &reg.base;1155 self.stubs.items[idx] = reg;
1169 }1156 }
11701157
1171 const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);1158 const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);
...@@ -1615,15 +1602,8 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1615,15 +1602,8 @@ fn resolveSymbols(self: *Zld) !void {
1615 {1602 {
1616 const name = try self.allocator.dupe(u8, "dyld_stub_binder");1603 const name = try self.allocator.dupe(u8, "dyld_stub_binder");
1617 errdefer self.allocator.free(name);1604 errdefer self.allocator.free(name);
1618 const undef = try self.allocator.create(Symbol.Unresolved);1605 const undef = try Symbol.Unresolved.new(self.allocator, name, .{});
1619 errdefer self.allocator.destroy(undef);1606 try unresolved.append(undef);
1620 undef.* = .{
1621 .base = .{
1622 .@"type" = .unresolved,
1623 .name = name,
1624 },
1625 };
1626 try unresolved.append(&undef.base);
1627 }1607 }
16281608
1629 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);1609 var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
...@@ -1641,16 +1621,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1641,16 +1621,7 @@ fn resolveSymbols(self: *Zld) !void {
1641 // TODO this is just a temp patch until I work out what to actually1621 // TODO this is just a temp patch until I work out what to actually
1642 // do with ___dso_handle and __mh_execute_header symbols which are1622 // do with ___dso_handle and __mh_execute_header symbols which are
1643 // synthetically created by the linker on macOS.1623 // synthetically created by the linker on macOS.
1644 const name = try self.allocator.dupe(u8, undef.name);1624 break :inner try Symbol.Proxy.new(self.allocator, undef.name, .{});
1645 const proxy = try self.allocator.create(Symbol.Proxy);
1646 errdefer self.allocator.destroy(proxy);
1647 proxy.* = .{
1648 .base = .{
1649 .@"type" = .proxy,
1650 .name = name,
1651 },
1652 };
1653 break :inner &proxy.base;
1654 }1625 }
16551626
1656 self.unresolved.putAssumeCapacityNoClobber(undef.name, undef);1627 self.unresolved.putAssumeCapacityNoClobber(undef.name, undef);
...@@ -2126,7 +2097,6 @@ fn populateMetadata(self: *Zld) !void {...@@ -2126,7 +2097,6 @@ fn populateMetadata(self: *Zld) !void {
2126 .strsize = 0,2097 .strsize = 0,
2127 },2098 },
2128 });2099 });
2129 try self.strtab.append(self.allocator, 0);
2130 }2100 }
21312101
2132 if (self.dysymtab_cmd_index == null) {2102 if (self.dysymtab_cmd_index == null) {
...@@ -2752,7 +2722,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2752,7 +2722,7 @@ fn writeDebugInfo(self: *Zld) !void {
2752 const dirname = std.fs.path.dirname(tu_path) orelse "./";2722 const dirname = std.fs.path.dirname(tu_path) orelse "./";
2753 // Current dir2723 // Current dir
2754 try stabs.append(.{2724 try stabs.append(.{
2755 .n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]),2725 .n_strx = try self.strtab.getOrPut(tu_path[0 .. dirname.len + 1]),
2756 .n_type = macho.N_SO,2726 .n_type = macho.N_SO,
2757 .n_sect = 0,2727 .n_sect = 0,
2758 .n_desc = 0,2728 .n_desc = 0,
...@@ -2760,7 +2730,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2760,7 +2730,7 @@ fn writeDebugInfo(self: *Zld) !void {
2760 });2730 });
2761 // Artifact name2731 // Artifact name
2762 try stabs.append(.{2732 try stabs.append(.{
2763 .n_strx = try self.makeString(tu_path[dirname.len + 1 ..]),2733 .n_strx = try self.strtab.getOrPut(tu_path[dirname.len + 1 ..]),
2764 .n_type = macho.N_SO,2734 .n_type = macho.N_SO,
2765 .n_sect = 0,2735 .n_sect = 0,
2766 .n_desc = 0,2736 .n_desc = 0,
...@@ -2768,7 +2738,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2768,7 +2738,7 @@ fn writeDebugInfo(self: *Zld) !void {
2768 });2738 });
2769 // Path to object file with debug info2739 // Path to object file with debug info
2770 try stabs.append(.{2740 try stabs.append(.{
2771 .n_strx = try self.makeString(object.name.?),2741 .n_strx = try self.strtab.getOrPut(object.name.?),
2772 .n_type = macho.N_OSO,2742 .n_type = macho.N_OSO,
2773 .n_sect = 0,2743 .n_sect = 0,
2774 .n_desc = 1,2744 .n_desc = 1,
...@@ -2801,7 +2771,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2801,7 +2771,7 @@ fn writeDebugInfo(self: *Zld) !void {
2801 .n_value = reg.address,2771 .n_value = reg.address,
2802 });2772 });
2803 try stabs.append(.{2773 try stabs.append(.{
2804 .n_strx = try self.makeString(sym.name),2774 .n_strx = try self.strtab.getOrPut(sym.name),
2805 .n_type = macho.N_FUN,2775 .n_type = macho.N_FUN,
2806 .n_sect = reg.section,2776 .n_sect = reg.section,
2807 .n_desc = 0,2777 .n_desc = 0,
...@@ -2824,7 +2794,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2824,7 +2794,7 @@ fn writeDebugInfo(self: *Zld) !void {
2824 },2794 },
2825 .global => {2795 .global => {
2826 try stabs.append(.{2796 try stabs.append(.{
2827 .n_strx = try self.makeString(sym.name),2797 .n_strx = try self.strtab.getOrPut(sym.name),
2828 .n_type = macho.N_GSYM,2798 .n_type = macho.N_GSYM,
2829 .n_sect = 0,2799 .n_sect = 0,
2830 .n_desc = 0,2800 .n_desc = 0,
...@@ -2833,7 +2803,7 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2833,7 +2803,7 @@ fn writeDebugInfo(self: *Zld) !void {
2833 },2803 },
2834 .static => {2804 .static => {
2835 try stabs.append(.{2805 try stabs.append(.{
2836 .n_strx = try self.makeString(sym.name),2806 .n_strx = try self.strtab.getOrPut(sym.name),
2837 .n_type = macho.N_STSYM,2807 .n_type = macho.N_STSYM,
2838 .n_sect = reg.section,2808 .n_sect = reg.section,
2839 .n_desc = 0,2809 .n_desc = 0,
...@@ -2892,24 +2862,14 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2892,24 +2862,14 @@ fn writeSymbolTable(self: *Zld) !void {
2892 if (reg.isTemp()) continue;2862 if (reg.isTemp()) continue;
2893 if (reg.visited) continue;2863 if (reg.visited) continue;
28942864
2865 const nlist = try reg.asNlist(&self.strtab);
2866
2895 switch (reg.linkage) {2867 switch (reg.linkage) {
2896 .translation_unit => {2868 .translation_unit => {
2897 try locals.append(.{2869 try locals.append(nlist);
2898 .n_strx = try self.makeString(sym.name),
2899 .n_type = macho.N_SECT,
2900 .n_sect = reg.section,
2901 .n_desc = 0,
2902 .n_value = reg.address,
2903 });
2904 },2870 },
2905 else => {2871 else => {
2906 try exports.append(.{2872 try exports.append(nlist);
2907 .n_strx = try self.makeString(sym.name),
2908 .n_type = macho.N_SECT | macho.N_EXT,
2909 .n_sect = reg.section,
2910 .n_desc = 0,
2911 .n_value = reg.address,
2912 });
2913 },2873 },
2914 }2874 }
29152875
...@@ -2922,13 +2882,8 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2922,13 +2882,8 @@ fn writeSymbolTable(self: *Zld) !void {
29222882
2923 for (self.imports.values()) |sym| {2883 for (self.imports.values()) |sym| {
2924 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;2884 const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
2925 try undefs.append(.{2885 const nlist = try proxy.asNlist(&self.strtab);
2926 .n_strx = try self.makeString(sym.name),2886 try undefs.append(nlist);
2927 .n_type = macho.N_UNDF | macho.N_EXT,
2928 .n_sect = 0,
2929 .n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
2930 .n_value = 0,
2931 });
2932 }2887 }
29332888
2934 const nlocals = locals.items.len;2889 const nlocals = locals.items.len;
...@@ -3017,14 +2972,14 @@ fn writeStringTable(self: *Zld) !void {...@@ -3017,14 +2972,14 @@ fn writeStringTable(self: *Zld) !void {
3017 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2972 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
3018 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2973 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
3019 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);2974 symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
3020 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));2975 symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.size(), @alignOf(u64)));
3021 seg.inner.filesize += symtab.strsize;2976 seg.inner.filesize += symtab.strsize;
30222977
3023 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });2978 log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
30242979
3025 try self.file.?.pwriteAll(self.strtab.items, symtab.stroff);2980 try self.file.?.pwriteAll(self.strtab.asSlice(), symtab.stroff);
30262981
3027 if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) {2982 if (symtab.strsize > self.strtab.size() and self.target.?.cpu.arch == .x86_64) {
3028 // This is the last section, so we need to pad it out.2983 // This is the last section, so we need to pad it out.
3029 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);2984 try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
3030 }2985 }
...@@ -3173,26 +3128,6 @@ fn writeHeader(self: *Zld) !void {...@@ -3173,26 +3128,6 @@ fn writeHeader(self: *Zld) !void {
3173 try self.file.?.pwriteAll(mem.asBytes(&header), 0);3128 try self.file.?.pwriteAll(mem.asBytes(&header), 0);
3174}3129}
31753130
3176fn makeString(self: *Zld, bytes: []const u8) !u32 {
3177 if (self.strtab_dir.get(bytes)) |offset| {
3178 log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });
3179 return offset;
3180 }
3181
3182 try self.strtab.ensureCapacity(self.allocator, self.strtab.items.len + bytes.len + 1);
3183 const offset = @intCast(u32, self.strtab.items.len);
3184 log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset });
3185 self.strtab.appendSliceAssumeCapacity(bytes);
3186 self.strtab.appendAssumeCapacity(0);
3187 try self.strtab_dir.putNoClobber(self.allocator, try self.allocator.dupe(u8, bytes), offset);
3188 return offset;
3189}
3190
3191fn getString(self: *const Zld, str_off: u32) []const u8 {
3192 assert(str_off < self.strtab.items.len);
3193 return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
3194}
3195
3196pub fn parseName(name: *const [16]u8) []const u8 {3131pub fn parseName(name: *const [16]u8) []const u8 {
3197 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;3132 const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
3198 return name[0..len];3133 return name[0..len];