authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-02 07:45:11+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
logd5c2f8ed322d8246992202197851bd4d46ec0b3b
treea783ec75bc42df0f3d5a761c802917d5f30b28ba
parent1b5bceec910778ced3c03b885bddd31f1aac3842

zld: store a single global symtab


3 files changed, 125 insertions(+), 110 deletions(-)

src/link/MachO/Object.zig+16
...@@ -237,7 +237,23 @@ pub fn parseSymtab(self: *Object) !void {...@@ -237,7 +237,23 @@ pub fn parseSymtab(self: *Object) !void {
237 error.EndOfStream => break,237 error.EndOfStream => break,
238 else => |e| return e,238 else => |e| return e,
239 };239 };
240 const tag: Symbol.Tag = tag: {
241 if (Symbol.isLocal(symbol)) {
242 if (Symbol.isStab(symbol))
243 break :tag .Stab
244 else
245 break :tag .Local;
246 } else if (Symbol.isGlobal(symbol)) {
247 if (Symbol.isWeakDef(symbol))
248 break :tag .Weak
249 else
250 break :tag .Strong;
251 } else {
252 break :tag .Undef;
253 }
254 };
240 self.symtab.appendAssumeCapacity(.{255 self.symtab.appendAssumeCapacity(.{
256 .tag = tag,
241 .inner = symbol,257 .inner = symbol,
242 });258 });
243 }259 }
src/link/MachO/Symbol.zig+29-18
...@@ -3,6 +3,17 @@ const Symbol = @This();...@@ -3,6 +3,17 @@ const Symbol = @This();
3const std = @import("std");3const std = @import("std");
4const macho = std.macho;4const macho = std.macho;
55
6pub const Tag = enum {
7 Stab,
8 Local,
9 Weak,
10 Strong,
11 Import,
12 Undef,
13};
14
15tag: Tag,
16
6/// MachO representation of this symbol.17/// MachO representation of this symbol.
7inner: macho.nlist_64,18inner: macho.nlist_64,
819
...@@ -13,43 +24,43 @@ file: ?u16 = null,...@@ -13,43 +24,43 @@ file: ?u16 = null,
13/// Index of this symbol within the file's symbol table.24/// Index of this symbol within the file's symbol table.
14index: ?u32 = null,25index: ?u32 = null,
1526
16pub fn isStab(self: Symbol) bool {27pub fn isStab(sym: macho.nlist_64) bool {
17 return (macho.N_STAB & self.inner.n_type) != 0;28 return (macho.N_STAB & sym.n_type) != 0;
18}29}
1930
20pub fn isPext(self: Symbol) bool {31pub fn isPext(sym: macho.nlist_64) bool {
21 return (macho.N_PEXT & self.inner.n_type) != 0;32 return (macho.N_PEXT & sym.n_type) != 0;
22}33}
2334
24pub fn isExt(self: Symbol) bool {35pub fn isExt(sym: macho.nlist_64) bool {
25 return (macho.N_EXT & self.inner.n_type) != 0;36 return (macho.N_EXT & sym.n_type) != 0;
26}37}
2738
28pub fn isSect(self: Symbol) bool {39pub fn isSect(sym: macho.nlist_64) bool {
29 const type_ = macho.N_TYPE & self.inner.n_type;40 const type_ = macho.N_TYPE & sym.n_type;
30 return type_ == macho.N_SECT;41 return type_ == macho.N_SECT;
31}42}
3243
33pub fn isUndf(self: Symbol) bool {44pub fn isUndf(sym: macho.nlist_64) bool {
34 const type_ = macho.N_TYPE & self.inner.n_type;45 const type_ = macho.N_TYPE & sym.n_type;
35 return type_ == macho.N_UNDF;46 return type_ == macho.N_UNDF;
36}47}
3748
38pub fn isWeakDef(self: Symbol) bool {49pub fn isWeakDef(sym: macho.nlist_64) bool {
39 return self.inner.n_desc == macho.N_WEAK_DEF;50 return sym.n_desc == macho.N_WEAK_DEF;
40}51}
4152
42/// Symbol is local if it is either a stab or it is defined and not an extern.53/// Symbol is local if it is either a stab or it is defined and not an extern.
43pub fn isLocal(self: Symbol) bool {54pub fn isLocal(sym: macho.nlist_64) bool {
44 return self.isStab() or (self.isSect() and !self.isExt());55 return isStab(sym) or (isSect(sym) and !isExt(sym));
45}56}
4657
47/// Symbol is global if it is defined and an extern.58/// Symbol is global if it is defined and an extern.
48pub fn isGlobal(self: Symbol) bool {59pub fn isGlobal(sym: macho.nlist_64) bool {
49 return self.isSect() and self.isExt();60 return isSect(sym) and isExt(sym);
50}61}
5162
52/// Symbol is undefined if it is not defined and an extern.63/// Symbol is undefined if it is not defined and an extern.
53pub fn isUndef(self: Symbol) bool {64pub fn isUndef(sym: macho.nlist_64) bool {
54 return self.isUndf() and self.isExt();65 return isUndf(sym) and isExt(sym);
55}66}
src/link/MachO/Zld.zig+80-92
...@@ -73,9 +73,7 @@ la_symbol_ptr_section_index: ?u16 = null,...@@ -73,9 +73,7 @@ la_symbol_ptr_section_index: ?u16 = null,
73data_section_index: ?u16 = null,73data_section_index: ?u16 = null,
74bss_section_index: ?u16 = null,74bss_section_index: ?u16 = null,
7575
76globals: std.StringArrayHashMapUnmanaged(Symbol) = .{},76symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{},
77undefs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
78externs: std.StringArrayHashMapUnmanaged(Symbol) = .{},
79strtab: std.ArrayListUnmanaged(u8) = .{},77strtab: std.ArrayListUnmanaged(u8) = .{},
8078
81threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},79threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{},
...@@ -210,20 +208,11 @@ pub fn deinit(self: *Zld) void {...@@ -210,20 +208,11 @@ pub fn deinit(self: *Zld) void {
210 self.mappings.deinit(self.allocator);208 self.mappings.deinit(self.allocator);
211 self.unhandled_sections.deinit(self.allocator);209 self.unhandled_sections.deinit(self.allocator);
212210
213 for (self.globals.items()) |*entry| {211 for (self.symtab.items()) |*entry| {
214 self.allocator.free(entry.key);212 self.allocator.free(entry.key);
215 }213 }
216 self.globals.deinit(self.allocator);214 self.symtab.deinit(self.allocator);
217215 self.strtab.deinit(self.allocator);
218 for (self.undefs.items()) |*entry| {
219 self.allocator.free(entry.key);
220 }
221 self.undefs.deinit(self.allocator);
222
223 for (self.externs.items()) |*entry| {
224 self.allocator.free(entry.key);
225 }
226 self.externs.deinit(self.allocator);
227}216}
228217
229pub fn closeFiles(self: Zld) void {218pub fn closeFiles(self: Zld) void {
...@@ -276,10 +265,11 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {...@@ -276,10 +265,11 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
276 try self.resolveSymbols();265 try self.resolveSymbols();
277 try self.updateMetadata();266 try self.updateMetadata();
278 try self.sortSections();267 try self.sortSections();
279 try self.allocateTextSegment();268 self.printSymtab();
280 try self.allocateDataConstSegment();269 // try self.allocateTextSegment();
281 try self.allocateDataSegment();270 // try self.allocateDataConstSegment();
282 self.allocateLinkeditSegment();271 // try self.allocateDataSegment();
272 // self.allocateLinkeditSegment();
283 // try self.writeStubHelperCommon();273 // try self.writeStubHelperCommon();
284 // try self.doRelocs();274 // try self.doRelocs();
285 // try self.flush();275 // try self.flush();
...@@ -1216,48 +1206,64 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {...@@ -1216,48 +1206,64 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
1216 log.warn("resolving symbols in '{s}'", .{object.name});1206 log.warn("resolving symbols in '{s}'", .{object.name});
12171207
1218 for (object.symtab.items) |sym, sym_id| {1208 for (object.symtab.items) |sym, sym_id| {
1219 if (sym.isLocal()) continue; // If symbol is local to CU, we don't put it in the global symbol table.1209 switch (sym.tag) {
12201210 .Local, .Stab => continue, // If symbol is local to CU, we don't put it in the global symbol table.
1221 const sym_name = object.getString(sym.inner.n_strx);1211 .Weak, .Strong => {
1222 if (sym.isGlobal()) {1212 const sym_name = object.getString(sym.inner.n_strx);
1223 const global = self.globals.getEntry(sym_name) orelse {1213 const global = self.symtab.getEntry(sym_name) orelse {
1224 const name = try self.allocator.dupe(u8, sym_name);1214 // Put new global symbol into the symbol table.
1225 try self.globals.putNoClobber(self.allocator, name, .{1215 const name = try self.allocator.dupe(u8, sym_name);
1226 .inner = sym.inner,1216 try self.symtab.putNoClobber(self.allocator, name, .{
1227 .file = object_id,1217 .tag = sym.tag,
1228 .index = @intCast(u32, sym_id),1218 .inner = .{
1229 });1219 .n_strx = 0, // This will be populated later.
1220 .n_value = 0, // This will be populated later,
1221 .n_type = macho.N_SECT | macho.N_EXT,
1222 .n_desc = 0,
1223 .n_sect = 0, // This will be populated later.
1224 },
1225 .file = object_id,
1226 .index = @intCast(u32, sym_id),
1227 });
1228 continue;
1229 };
12301230
1231 if (self.undefs.swapRemove(sym_name)) |undef| {1231 if (sym.tag == .Weak) continue; // If symbol is weak, nothing to do.
1232 self.allocator.free(undef.key);1232 if (global.value.tag == .Strong) { // If both symbols are strong, we have a collision.
1233 log.err("symbol '{s}' defined multiple times", .{sym_name});
1234 return error.MultipleSymbolDefinitions;
1233 }1235 }
12341236
1235 continue;1237 global.value = .{
1236 };1238 .tag = .Strong,
12371239 .inner = .{
1238 if (sym.isWeakDef()) continue; // If symbol is weak, nothing to do.1240 .n_strx = 0, // This will be populated later.
1239 if (!global.value.isWeakDef()) { // If both symbols are strong, we have a collision.1241 .n_value = 0, // This will be populated later,
1240 log.err("symbol '{s}' defined multiple times", .{sym_name});1242 .n_type = macho.N_SECT | macho.N_EXT,
1241 return error.MultipleSymbolDefinitions;1243 .n_desc = 0,
1242 }1244 .n_sect = 0, // This will be populated later.
12431245 },
1244 global.value = .{1246 .file = object_id,
1245 .inner = sym.inner,1247 .index = @intCast(u32, sym_id),
1246 .file = object_id,1248 };
1247 .index = @intCast(u32, sym_id),1249 },
1248 };1250 .Undef => {
1249 } else if (sym.isUndef()) {1251 const sym_name = object.getString(sym.inner.n_strx);
1250 if (self.globals.contains(sym_name)) continue; // Nothing to do if we already found a definition.1252 if (self.symtab.contains(sym_name)) continue; // Nothing to do if we already found a definition.
1251 if (self.undefs.contains(sym_name)) continue; // No need to reinsert the undef ref.
12521253
1253 const name = try self.allocator.dupe(u8, sym_name);1254 const name = try self.allocator.dupe(u8, sym_name);
1254 try self.undefs.putNoClobber(self.allocator, name, .{1255 try self.symtab.putNoClobber(self.allocator, name, .{
1255 .inner = sym.inner,1256 .tag = .Undef,
1256 });1257 .inner = .{
1257 } else {1258 .n_strx = 0,
1258 // Oh no, unhandled symbol type, report back to the user.1259 .n_value = 0,
1259 log.err("unhandled symbol type for symbol {any}", .{sym});1260 .n_type = 0,
1260 return error.UnhandledSymbolType;1261 .n_desc = 0,
1262 .n_sect = 0,
1263 },
1264 });
1265 },
1266 .Import => unreachable, // We don't expect any imports just yet.
1261 }1267 }
1262 }1268 }
1263}1269}
...@@ -1274,7 +1280,9 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1274,7 +1280,9 @@ fn resolveSymbols(self: *Zld) !void {
1274 var archive = &self.archives.items[next];1280 var archive = &self.archives.items[next];
1275 var hit: bool = false;1281 var hit: bool = false;
12761282
1277 for (self.undefs.items()) |entry| {1283 for (self.symtab.items()) |entry| {
1284 if (entry.value.tag != .Undef) continue;
1285
1278 const sym_name = entry.key;1286 const sym_name = entry.key;
12791287
1280 // Check if the entry exists in a static archive.1288 // Check if the entry exists in a static archive.
...@@ -1306,9 +1314,10 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1306,9 +1314,10 @@ fn resolveSymbols(self: *Zld) !void {
1306 // Third pass, resolve symbols in dynamic libraries.1314 // Third pass, resolve symbols in dynamic libraries.
1307 // TODO Implement libSystem as a hard-coded library, or ship with1315 // TODO Implement libSystem as a hard-coded library, or ship with
1308 // a libSystem.B.tbd definition file?1316 // a libSystem.B.tbd definition file?
1309 while (self.undefs.items().len > 0) {1317 for (self.symtab.items()) |*entry| {
1310 const entry = self.undefs.pop();1318 if (entry.value.tag != .Undef) continue;
1311 try self.externs.putNoClobber(self.allocator, entry.key, .{1319 entry.value = .{
1320 .tag = .Import,
1312 .inner = .{1321 .inner = .{
1313 .n_strx = 0, // This will be populated once we write the string table.1322 .n_strx = 0, // This will be populated once we write the string table.
1314 .n_type = macho.N_UNDF | macho.N_EXT,1323 .n_type = macho.N_UNDF | macho.N_EXT,
...@@ -1317,30 +1326,19 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1317,30 +1326,19 @@ fn resolveSymbols(self: *Zld) !void {
1317 .n_value = 0,1326 .n_value = 0,
1318 },1327 },
1319 .file = 0,1328 .file = 0,
1320 });1329 };
1321 }1330 }
13221331
1323 // If there are any undefs left, flag an error.1332 // If there are any undefs left, flag an error.
1324 if (self.undefs.items().len > 0) {1333 var has_unresolved = false;
1325 for (self.undefs.items()) |entry| {1334 for (self.symtab.items()) |entry| {
1326 log.err("undefined reference to symbol '{s}'", .{entry.key});1335 if (entry.value.tag != .Undef) continue;
1327 }1336 has_unresolved = true;
13281337 log.err("undefined reference to symbol '{s}'", .{entry.key});
1338 }
1339 if (has_unresolved) {
1329 return error.UndefinedSymbolReference;1340 return error.UndefinedSymbolReference;
1330 }1341 }
1331
1332 // Finally, put in a reference to 'dyld_stub_binder'.
1333 const name = try self.allocator.dupe(u8, "dyld_stub_binder");
1334 try self.externs.putNoClobber(self.allocator, name, .{
1335 .inner = .{
1336 .n_strx = 0, // This will be populated once we write the string table.
1337 .n_type = std.macho.N_UNDF | std.macho.N_EXT,
1338 .n_sect = 0,
1339 .n_desc = std.macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | std.macho.N_SYMBOL_RESOLVER,
1340 .n_value = 0,
1341 },
1342 .file = 0,
1343 });
1344}1342}
13451343
1346fn doRelocs(self: *Zld) !void {1344fn doRelocs(self: *Zld) !void {
...@@ -3261,18 +3259,8 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool {...@@ -3261,18 +3259,8 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool {
3261}3259}
32623260
3263fn printSymtab(self: Zld) void {3261fn printSymtab(self: Zld) void {
3264 log.warn("globals", .{});3262 log.warn("symtab", .{});
3265 for (self.globals.items()) |entry| {3263 for (self.symtab.items()) |entry| {
3266 log.warn(" | {s} => {any}", .{ entry.key, entry.value });
3267 }
3268
3269 log.warn("externs", .{});
3270 for (self.externs.items()) |entry| {
3271 log.warn(" | {s} => {any}", .{ entry.key, entry.value });
3272 }
3273
3274 log.warn("undefs", .{});
3275 for (self.undefs.items()) |entry| {
3276 log.warn(" | {s} => {any}", .{ entry.key, entry.value });3264 log.warn(" | {s} => {any}", .{ entry.key, entry.value });
3277 }3265 }
3278}3266}