| ... | @@ -29,8 +29,8 @@ page_size: ?u16 = null, | ... | @@ -29,8 +29,8 @@ page_size: ?u16 = null, |
| 29 | file: ?fs.File = null, | 29 | file: ?fs.File = null, |
| 30 | out_path: ?[]const u8 = null, | 30 | out_path: ?[]const u8 = null, |
| 31 | | 31 | |
| 32 | objects: std.ArrayListUnmanaged(Object) = .{}, | 32 | objects: std.ArrayListUnmanaged(*Object) = .{}, |
| 33 | archives: std.ArrayListUnmanaged(Archive) = .{}, | 33 | archives: std.ArrayListUnmanaged(*Archive) = .{}, |
| 34 | | 34 | |
| 35 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 35 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 36 | | 36 | |
| ... | @@ -74,30 +74,23 @@ data_section_index: ?u16 = null, | ... | @@ -74,30 +74,23 @@ data_section_index: ?u16 = null, |
| 74 | bss_section_index: ?u16 = null, | 74 | bss_section_index: ?u16 = null, |
| 75 | common_section_index: ?u16 = null, | 75 | common_section_index: ?u16 = null, |
| 76 | | 76 | |
| 77 | symtab: std.StringArrayHashMapUnmanaged(Symbol) = .{}, | 77 | globals: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| | 78 | imports: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| | 79 | unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| | 80 | |
| 78 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 81 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 79 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, | 82 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, |
| 80 | | 83 | |
| 81 | threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, | 84 | threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, |
| 82 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | 85 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 83 | stubs: std.StringArrayHashMapUnmanaged(u32) = .{}, | 86 | stubs: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 84 | got_entries: std.StringArrayHashMapUnmanaged(GotEntry) = .{}, | 87 | got_entries: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 85 | | 88 | |
| 86 | stub_helper_stubs_start_off: ?u64 = null, | 89 | stub_helper_stubs_start_off: ?u64 = null, |
| 87 | | 90 | |
| 88 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | 91 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 89 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | 92 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 90 | | 93 | |
| 91 | const GotEntry = struct { | | |
| 92 | tag: enum { | | |
| 93 | local, | | |
| 94 | import, | | |
| 95 | }, | | |
| 96 | index: u32, | | |
| 97 | target_addr: u64, | | |
| 98 | file: u16, | | |
| 99 | }; | | |
| 100 | | | |
| 101 | const MappingKey = struct { | 94 | const MappingKey = struct { |
| 102 | object_id: u16, | 95 | object_id: u16, |
| 103 | source_sect_id: u16, | 96 | source_sect_id: u16, |
| ... | @@ -124,15 +117,7 @@ pub fn init(allocator: *Allocator) Zld { | ... | @@ -124,15 +117,7 @@ pub fn init(allocator: *Allocator) Zld { |
| 124 | pub fn deinit(self: *Zld) void { | 117 | pub fn deinit(self: *Zld) void { |
| 125 | self.threadlocal_offsets.deinit(self.allocator); | 118 | self.threadlocal_offsets.deinit(self.allocator); |
| 126 | self.local_rebases.deinit(self.allocator); | 119 | self.local_rebases.deinit(self.allocator); |
| 127 | | | |
| 128 | for (self.stubs.items()) |entry| { | | |
| 129 | self.allocator.free(entry.key); | | |
| 130 | } | | |
| 131 | self.stubs.deinit(self.allocator); | 120 | self.stubs.deinit(self.allocator); |
| 132 | | | |
| 133 | for (self.got_entries.items()) |entry| { | | |
| 134 | self.allocator.free(entry.key); | | |
| 135 | } | | |
| 136 | self.got_entries.deinit(self.allocator); | 121 | self.got_entries.deinit(self.allocator); |
| 137 | | 122 | |
| 138 | for (self.load_commands.items) |*lc| { | 123 | for (self.load_commands.items) |*lc| { |
| ... | @@ -140,23 +125,22 @@ pub fn deinit(self: *Zld) void { | ... | @@ -140,23 +125,22 @@ pub fn deinit(self: *Zld) void { |
| 140 | } | 125 | } |
| 141 | self.load_commands.deinit(self.allocator); | 126 | self.load_commands.deinit(self.allocator); |
| 142 | | 127 | |
| 143 | for (self.objects.items) |*object| { | 128 | for (self.objects.items) |object| { |
| 144 | object.deinit(); | 129 | object.deinit(); |
| | 130 | self.allocator.destroy(object); |
| 145 | } | 131 | } |
| 146 | self.objects.deinit(self.allocator); | 132 | self.objects.deinit(self.allocator); |
| 147 | | 133 | |
| 148 | for (self.archives.items) |*archive| { | 134 | for (self.archives.items) |archive| { |
| 149 | archive.deinit(); | 135 | archive.deinit(); |
| | 136 | self.allocator.destroy(archive); |
| 150 | } | 137 | } |
| 151 | self.archives.deinit(self.allocator); | 138 | self.archives.deinit(self.allocator); |
| 152 | | 139 | |
| 153 | self.mappings.deinit(self.allocator); | 140 | self.mappings.deinit(self.allocator); |
| 154 | self.unhandled_sections.deinit(self.allocator); | 141 | self.unhandled_sections.deinit(self.allocator); |
| 155 | | 142 | |
| 156 | for (self.symtab.items()) |*entry| { | 143 | self.globals.deinit(self.allocator); |
| 157 | entry.value.deinit(self.allocator); | | |
| 158 | } | | |
| 159 | self.symtab.deinit(self.allocator); | | |
| 160 | self.strtab.deinit(self.allocator); | 144 | self.strtab.deinit(self.allocator); |
| 161 | | 145 | |
| 162 | { | 146 | { |
| ... | @@ -216,19 +200,21 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { | ... | @@ -216,19 +200,21 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 216 | try self.populateMetadata(); | 200 | try self.populateMetadata(); |
| 217 | try self.parseInputFiles(files); | 201 | try self.parseInputFiles(files); |
| 218 | try self.resolveSymbols(); | 202 | try self.resolveSymbols(); |
| 219 | try self.resolveStubsAndGotEntries(); | 203 | self.printSymbols(); |
| 220 | try self.updateMetadata(); | 204 | return error.Unfinished; |
| 221 | try self.sortSections(); | 205 | // try self.resolveStubsAndGotEntries(); |
| 222 | try self.allocateTextSegment(); | 206 | // try self.updateMetadata(); |
| 223 | try self.allocateDataConstSegment(); | 207 | // try self.sortSections(); |
| 224 | try self.allocateDataSegment(); | 208 | // try self.allocateTextSegment(); |
| 225 | self.allocateLinkeditSegment(); | 209 | // try self.allocateDataConstSegment(); |
| 226 | try self.allocateSymbols(); | 210 | // try self.allocateDataSegment(); |
| 227 | try self.allocateStubsAndGotEntries(); | 211 | // self.allocateLinkeditSegment(); |
| 228 | try self.allocateCppStatics(); | 212 | // try self.allocateSymbols(); |
| 229 | try self.writeStubHelperCommon(); | 213 | // try self.allocateStubsAndGotEntries(); |
| 230 | try self.resolveRelocsAndWriteSections(); | 214 | // try self.allocateCppStatics(); |
| 231 | try self.flush(); | 215 | // try self.writeStubHelperCommon(); |
| | 216 | // try self.resolveRelocsAndWriteSections(); |
| | 217 | // try self.flush(); |
| 232 | } | 218 | } |
| 233 | | 219 | |
| 234 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | 220 | fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| ... | @@ -291,7 +277,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -291,7 +277,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 291 | for (classified.items) |input| { | 277 | for (classified.items) |input| { |
| 292 | switch (input.kind) { | 278 | switch (input.kind) { |
| 293 | .object => { | 279 | .object => { |
| 294 | var object = Object.init(self.allocator); | 280 | const object = try self.allocator.create(Object); |
| | 281 | errdefer self.allocator.destroy(object); |
| | 282 | |
| | 283 | object.* = Object.init(self.allocator); |
| 295 | object.arch = self.arch.?; | 284 | object.arch = self.arch.?; |
| 296 | object.name = try self.allocator.dupe(u8, input.name); | 285 | object.name = try self.allocator.dupe(u8, input.name); |
| 297 | object.file = input.file; | 286 | object.file = input.file; |
| ... | @@ -299,7 +288,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -299,7 +288,10 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 299 | try self.objects.append(self.allocator, object); | 288 | try self.objects.append(self.allocator, object); |
| 300 | }, | 289 | }, |
| 301 | .archive => { | 290 | .archive => { |
| 302 | var archive = Archive.init(self.allocator); | 291 | const archive = try self.allocator.create(Archive); |
| | 292 | errdefer self.allocator.destroy(archive); |
| | 293 | |
| | 294 | archive.* = Archive.init(self.allocator); |
| 303 | archive.arch = self.arch.?; | 295 | archive.arch = self.arch.?; |
| 304 | archive.name = try self.allocator.dupe(u8, input.name); | 296 | archive.name = try self.allocator.dupe(u8, input.name); |
| 305 | archive.file = input.file; | 297 | archive.file = input.file; |
| ... | @@ -1274,141 +1266,150 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { | ... | @@ -1274,141 +1266,150 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void { |
| 1274 | try self.file.?.pwriteAll(code, stub_off); | 1266 | try self.file.?.pwriteAll(code, stub_off); |
| 1275 | } | 1267 | } |
| 1276 | | 1268 | |
| 1277 | fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { | 1269 | fn resolveSymbolsInObject(self: *Zld, object: *Object) !void { |
| 1278 | const object = self.objects.items[object_id]; | 1270 | log.warn("resolving symbols in '{s}'", .{object.name}); |
| 1279 | log.debug("resolving symbols in '{s}'", .{object.name}); | | |
| 1280 | | 1271 | |
| 1281 | for (object.symtab.items) |sym, sym_id| { | 1272 | for (object.symbols.items) |sym| { |
| 1282 | if (Symbol.isLocal(sym)) { | 1273 | if (sym.cast(Symbol.Regular)) |reg| { |
| 1283 | // If symbol is local to CU, we don't put it in the global symbol table. | 1274 | if (reg.linkage == .translation_unit) continue; // Symbol local to TU. |
| 1284 | continue; | 1275 | |
| 1285 | } else if (Symbol.isGlobal(sym)) { | 1276 | if (self.unresolved.swapRemove(sym.name)) |entry| { |
| 1286 | const sym_name = object.getString(sym.n_strx); | 1277 | // Create link to the global. |
| 1287 | const is_weak = Symbol.isWeakDef(sym) or Symbol.isPext(sym); | 1278 | entry.value.alias = sym; |
| 1288 | const global = self.symtab.getEntry(sym_name) orelse { | 1279 | } |
| | 1280 | const entry = self.globals.getEntry(sym.name) orelse { |
| 1289 | // Put new global symbol into the symbol table. | 1281 | // Put new global symbol into the symbol table. |
| 1290 | const name = try self.allocator.dupe(u8, sym_name); | 1282 | try self.globals.putNoClobber(self.allocator, sym.name, sym); |
| 1291 | try self.symtab.putNoClobber(self.allocator, name, .{ | | |
| 1292 | .tag = if (is_weak) .weak else .strong, | | |
| 1293 | .name = name, | | |
| 1294 | .address = 0, | | |
| 1295 | .section = 0, | | |
| 1296 | .file = object_id, | | |
| 1297 | .index = @intCast(u32, sym_id), | | |
| 1298 | }); | | |
| 1299 | continue; | 1283 | continue; |
| 1300 | }; | 1284 | }; |
| 1301 | | 1285 | const g_sym = entry.value; |
| 1302 | switch (global.value.tag) { | 1286 | const g_reg = g_sym.cast(Symbol.Regular) orelse unreachable; |
| 1303 | .weak => { | 1287 | |
| 1304 | if (is_weak) continue; // Nothing to do for weak symbol. | 1288 | switch (g_reg.linkage) { |
| | 1289 | .translation_unit => unreachable, |
| | 1290 | .linkage_unit => { |
| | 1291 | if (reg.linkage == .linkage_unit) { |
| | 1292 | // Create link to the first encountered linkage_unit symbol. |
| | 1293 | sym.alias = g_sym; |
| | 1294 | continue; |
| | 1295 | } |
| 1305 | }, | 1296 | }, |
| 1306 | .strong => { | 1297 | .global => { |
| 1307 | if (!is_weak) { | 1298 | if (reg.linkage == .global) { |
| 1308 | log.debug("strong symbol '{s}' defined multiple times", .{sym_name}); | 1299 | log.warn("symbol '{s}' defined multiple times", .{reg.base.name}); |
| 1309 | return error.MultipleSymbolDefinitions; | 1300 | return error.MultipleSymbolDefinitions; |
| 1310 | } | 1301 | } |
| | 1302 | sym.alias = g_sym; |
| 1311 | continue; | 1303 | continue; |
| 1312 | }, | 1304 | }, |
| 1313 | else => {}, | | |
| 1314 | } | 1305 | } |
| 1315 | | 1306 | |
| 1316 | global.value.tag = if (is_weak) .weak else .strong; | 1307 | g_sym.alias = sym; |
| 1317 | global.value.file = object_id; | 1308 | entry.value = sym; |
| 1318 | global.value.index = @intCast(u32, sym_id); | 1309 | } else if (sym.cast(Symbol.Unresolved)) |und| { |
| 1319 | } else if (Symbol.isUndef(sym)) { | 1310 | if (self.globals.get(sym.name)) |g_sym| { |
| 1320 | const sym_name = object.getString(sym.n_strx); | 1311 | sym.alias = g_sym; |
| 1321 | if (self.symtab.contains(sym_name)) continue; // Nothing to do if we already found a definition. | 1312 | continue; |
| 1322 | | 1313 | } |
| 1323 | const name = try self.allocator.dupe(u8, sym_name); | 1314 | if (self.unresolved.get(sym.name)) |u_sym| { |
| 1324 | try self.symtab.putNoClobber(self.allocator, name, .{ | 1315 | sym.alias = u_sym; |
| 1325 | .tag = .undef, | 1316 | continue; |
| 1326 | .name = name, | 1317 | } |
| 1327 | .address = 0, | 1318 | try self.unresolved.putNoClobber(self.allocator, sym.name, sym); |
| 1328 | .section = 0, | | |
| 1329 | }); | | |
| 1330 | } else unreachable; | 1319 | } else unreachable; |
| 1331 | } | 1320 | } |
| 1332 | } | 1321 | } |
| 1333 | | 1322 | |
| 1334 | fn resolveSymbols(self: *Zld) !void { | 1323 | fn resolveSymbols(self: *Zld) !void { |
| 1335 | // First pass, resolve symbols in provided objects. | 1324 | // First pass, resolve symbols in provided objects. |
| 1336 | for (self.objects.items) |object, object_id| { | 1325 | for (self.objects.items) |object| { |
| 1337 | try self.resolveSymbolsInObject(@intCast(u16, object_id)); | 1326 | try self.resolveSymbolsInObject(object); |
| 1338 | } | 1327 | } |
| 1339 | | 1328 | |
| 1340 | // Second pass, resolve symbols in static libraries. | 1329 | // Second pass, resolve symbols in static libraries. |
| 1341 | var next_sym: usize = 0; | 1330 | var next_sym: usize = 0; |
| 1342 | var nsyms: usize = self.symtab.items().len; | 1331 | while (true) { |
| 1343 | while (next_sym < nsyms) : (next_sym += 1) { | 1332 | if (next_sym == self.unresolved.count()) break; |
| 1344 | const sym = self.symtab.items()[next_sym]; | 1333 | |
| 1345 | if (sym.value.tag != .undef) continue; | 1334 | const entry = self.unresolved.items()[next_sym]; |
| | 1335 | const sym = entry.value; |
| 1346 | | 1336 | |
| 1347 | const sym_name = sym.value.name; | 1337 | var reset: bool = false; |
| 1348 | for (self.archives.items) |archive| { | 1338 | for (self.archives.items) |archive| { |
| 1349 | // Check if the entry exists in a static archive. | 1339 | // Check if the entry exists in a static archive. |
| 1350 | const offsets = archive.toc.get(sym_name) orelse { | 1340 | const offsets = archive.toc.get(sym.name) orelse { |
| 1351 | // No hit. | 1341 | // No hit. |
| 1352 | continue; | 1342 | continue; |
| 1353 | }; | 1343 | }; |
| 1354 | assert(offsets.items.len > 0); | 1344 | assert(offsets.items.len > 0); |
| 1355 | | 1345 | |
| 1356 | const object = try archive.parseObject(offsets.items[0]); | 1346 | const object = try self.allocator.create(Object); |
| 1357 | const object_id = @intCast(u16, self.objects.items.len); | 1347 | errdefer self.allocator.destroy(object); |
| | 1348 | |
| | 1349 | object.* = try archive.parseObject(offsets.items[0]); |
| 1358 | try self.objects.append(self.allocator, object); | 1350 | try self.objects.append(self.allocator, object); |
| 1359 | try self.resolveSymbolsInObject(object_id); | 1351 | try self.resolveSymbolsInObject(object); |
| 1360 | | 1352 | |
| 1361 | nsyms = self.symtab.items().len; | 1353 | reset = true; |
| 1362 | break; | 1354 | break; |
| 1363 | } | 1355 | } |
| | 1356 | |
| | 1357 | if (reset) { |
| | 1358 | next_sym = 0; |
| | 1359 | } else { |
| | 1360 | next_sym += 1; |
| | 1361 | } |
| 1364 | } | 1362 | } |
| 1365 | | 1363 | |
| 1366 | // Third pass, resolve symbols in dynamic libraries. | 1364 | // Third pass, resolve symbols in dynamic libraries. |
| 1367 | // TODO Implement libSystem as a hard-coded library, or ship with | 1365 | // TODO Implement libSystem as a hard-coded library, or ship with |
| 1368 | // a libSystem.B.tbd definition file? | 1366 | // a libSystem.B.tbd definition file? |
| 1369 | for (self.symtab.items()) |*entry| { | 1367 | try self.imports.ensureCapacity(self.allocator, self.unresolved.count()); |
| 1370 | if (entry.value.tag != .undef) continue; | 1368 | for (self.unresolved.items()) |entry| { |
| | 1369 | const proxy = try self.allocator.create(Symbol.Proxy); |
| | 1370 | errdefer self.allocator.destroy(proxy); |
| | 1371 | |
| | 1372 | proxy.* = .{ |
| | 1373 | .base = .{ |
| | 1374 | .@"type" = .proxy, |
| | 1375 | .name = try self.allocator.dupe(u8, entry.key), |
| | 1376 | }, |
| | 1377 | .dylib = 0, |
| | 1378 | }; |
| 1371 | | 1379 | |
| 1372 | entry.value.tag = .import; | 1380 | self.imports.putAssumeCapacityNoClobber(proxy.base.name, &proxy.base); |
| 1373 | entry.value.file = 0; | 1381 | entry.value.alias = &proxy.base; |
| 1374 | } | 1382 | } |
| | 1383 | self.unresolved.clearAndFree(self.allocator); |
| 1375 | | 1384 | |
| 1376 | // If there are any undefs left, flag an error. | 1385 | // If there are any undefs left, flag an error. |
| 1377 | var has_unresolved = false; | 1386 | if (self.unresolved.count() > 0) { |
| 1378 | for (self.symtab.items()) |entry| { | 1387 | for (self.unresolved.items()) |entry| { |
| 1379 | if (entry.value.tag != .undef) continue; | 1388 | log.err("undefined reference to symbol '{s}'", .{entry.key}); |
| 1380 | | 1389 | log.err(" | referenced in {s}", .{ |
| 1381 | has_unresolved = true; | 1390 | entry.value.cast(Symbol.Unresolved).?.file.name.?, |
| 1382 | log.err("undefined reference to symbol '{s}'", .{entry.value.name}); | 1391 | }); |
| 1383 | } | 1392 | } |
| 1384 | if (has_unresolved) { | | |
| 1385 | return error.UndefinedSymbolReference; | 1393 | return error.UndefinedSymbolReference; |
| 1386 | } | 1394 | } |
| 1387 | | 1395 | |
| 1388 | // Finally put dyld_stub_binder as an Import | 1396 | // Finally put dyld_stub_binder as an Import |
| 1389 | var name = try self.allocator.dupe(u8, "dyld_stub_binder"); | 1397 | const dyld_stub_binder = try self.allocator.create(Symbol.Proxy); |
| 1390 | try self.symtab.putNoClobber(self.allocator, name, .{ | 1398 | errdefer self.allocator.destroy(dyld_stub_binder); |
| 1391 | .tag = .import, | | |
| 1392 | .name = name, | | |
| 1393 | .address = 0, | | |
| 1394 | .section = 0, | | |
| 1395 | .file = 0, | | |
| 1396 | }); | | |
| 1397 | | 1399 | |
| 1398 | { | 1400 | dyld_stub_binder.* = .{ |
| 1399 | log.debug("symtab", .{}); | 1401 | .base = .{ |
| 1400 | for (self.symtab.items()) |sym| { | 1402 | .@"type" = .proxy, |
| 1401 | switch (sym.value.tag) { | 1403 | .name = try self.allocator.dupe(u8, "dyld_stub_binder"), |
| 1402 | .weak, .strong => { | 1404 | }, |
| 1403 | log.debug(" | {s} => {s}", .{ sym.key, self.objects.items[sym.value.file.?].name.? }); | 1405 | .dylib = 0, |
| 1404 | }, | 1406 | }; |
| 1405 | .import => { | 1407 | |
| 1406 | log.debug(" | {s} => libSystem.B.dylib", .{sym.key}); | 1408 | try self.imports.putNoClobber( |
| 1407 | }, | 1409 | self.allocator, |
| 1408 | else => unreachable, | 1410 | dyld_stub_binder.base.name, |
| 1409 | } | 1411 | &dyld_stub_binder.base, |
| 1410 | } | 1412 | ); |
| 1411 | } | | |
| 1412 | } | 1413 | } |
| 1413 | | 1414 | |
| 1414 | fn resolveStubsAndGotEntries(self: *Zld) !void { | 1415 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| ... | @@ -2979,3 +2980,33 @@ pub fn parseName(name: *const [16]u8) []const u8 { | ... | @@ -2979,3 +2980,33 @@ pub fn parseName(name: *const [16]u8) []const u8 { |
| 2979 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; | 2980 | const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len; |
| 2980 | return name[0..len]; | 2981 | return name[0..len]; |
| 2981 | } | 2982 | } |
| | 2983 | |
| | 2984 | fn printSymbols(self: *Zld) void { |
| | 2985 | log.warn("globals", .{}); |
| | 2986 | for (self.globals.items()) |entry| { |
| | 2987 | const sym = entry.value.cast(Symbol.Regular) orelse unreachable; |
| | 2988 | log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); |
| | 2989 | log.warn(" => alias of {*}", .{sym.base.alias}); |
| | 2990 | log.warn(" => linkage {s}", .{sym.linkage}); |
| | 2991 | log.warn(" => defined in {s}", .{sym.file.name.?}); |
| | 2992 | } |
| | 2993 | for (self.objects.items) |object| { |
| | 2994 | log.warn("locals in {s}", .{object.name.?}); |
| | 2995 | for (object.symbols.items) |sym| { |
| | 2996 | log.warn(" | {s} @ {*}", .{ sym.name, sym }); |
| | 2997 | log.warn(" => alias of {*}", .{sym.alias}); |
| | 2998 | if (sym.cast(Symbol.Regular)) |reg| { |
| | 2999 | log.warn(" => linkage {s}", .{reg.linkage}); |
| | 3000 | } else { |
| | 3001 | log.warn(" => unresolved", .{}); |
| | 3002 | } |
| | 3003 | } |
| | 3004 | } |
| | 3005 | log.warn("proxies", .{}); |
| | 3006 | for (self.imports.items()) |entry| { |
| | 3007 | const sym = entry.value.cast(Symbol.Proxy) orelse unreachable; |
| | 3008 | log.warn(" | {s} @ {*}", .{ sym.base.name, entry.value }); |
| | 3009 | log.warn(" => alias of {*}", .{sym.base.alias}); |
| | 3010 | log.warn(" => defined in libSystem.B.dylib", .{}); |
| | 3011 | } |
| | 3012 | } |