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