| ... | ... | @@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 87 | 87 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 88 | 88 | |
| 89 | 89 | const GotEntry = struct { |
| 90 | tag: enum { |
| 91 | local, |
| 92 | import, |
| 93 | }, |
| 90 | 94 | index: u32, |
| 91 | 95 | target_addr: u64, |
| 96 | file: u16, |
| 97 | local_index: u32, |
| 92 | 98 | }; |
| 93 | 99 | |
| 94 | 100 | const MappingKey = struct { |
| ... | ... | @@ -273,7 +279,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 273 | 279 | try self.allocateDataSegment(); |
| 274 | 280 | self.allocateLinkeditSegment(); |
| 275 | 281 | try self.allocateSymbols(); |
| 276 | | self.printSymtab(); |
| 282 | try self.allocateStubsAndGotEntries(); |
| 283 | self.printDebug(); |
| 277 | 284 | // try self.writeStubHelperCommon(); |
| 278 | 285 | // try self.resolveRelocsAndWriteSections(); |
| 279 | 286 | // try self.flush(); |
| ... | ... | @@ -957,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void { |
| 957 | 964 | const target_addr = target_sect.addr + target_mapping.offset; |
| 958 | 965 | const n_value = source_sym.inner.n_value - source_sect.addr + target_addr; |
| 959 | 966 | |
| 960 | | log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 967 | log.debug("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 961 | 968 | |
| 962 | 969 | // TODO there might be a more generic way of doing this. |
| 963 | 970 | var n_sect: u8 = 0; |
| ... | ... | @@ -979,6 +986,41 @@ fn allocateSymbols(self: *Zld) !void { |
| 979 | 986 | } |
| 980 | 987 | } |
| 981 | 988 | |
| 989 | fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 990 | for (self.got_entries.items()) |*entry| { |
| 991 | if (entry.value.tag == .import) continue; |
| 992 | |
| 993 | const object = self.objects.items[entry.value.file]; |
| 994 | const sym = object.symtab.items[entry.value.local_index]; |
| 995 | const sym_name = object.getString(sym.inner.n_strx); |
| 996 | assert(mem.eql(u8, sym_name, entry.key)); |
| 997 | |
| 998 | // TODO clean this up |
| 999 | entry.value.target_addr = target_addr: { |
| 1000 | if (sym.tag != .Local) { |
| 1001 | const glob = self.symtab.get(sym_name) orelse unreachable; |
| 1002 | break :target_addr glob.inner.n_value; |
| 1003 | } |
| 1004 | |
| 1005 | const target_mapping = self.mappings.get(.{ |
| 1006 | .object_id = entry.value.file, |
| 1007 | .source_sect_id = sym.inner.n_sect - 1, |
| 1008 | }) orelse unreachable; |
| 1009 | const source_sect = object.sections.items[target_mapping.source_sect_id]; |
| 1010 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; |
| 1011 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; |
| 1012 | const target_sect_addr = target_sect.addr + target_mapping.offset; |
| 1013 | |
| 1014 | break :target_addr target_sect_addr + sym.inner.n_value - source_sect.inner.addr; |
| 1015 | }; |
| 1016 | |
| 1017 | log.warn("resolving GOT entry '{s}' at 0x{x}", .{ |
| 1018 | entry.key, |
| 1019 | entry.value.target_addr, |
| 1020 | }); |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 982 | 1024 | fn writeStubHelperCommon(self: *Zld) !void { |
| 983 | 1025 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 984 | 1026 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | ... | @@ -1385,9 +1427,85 @@ fn resolveSymbols(self: *Zld) !void { |
| 1385 | 1427 | if (has_unresolved) { |
| 1386 | 1428 | return error.UndefinedSymbolReference; |
| 1387 | 1429 | } |
| 1430 | |
| 1431 | // Finally put dyld_stub_binder as an Import |
| 1432 | var name = try self.allocator.dupe(u8, "dyld_stub_binder"); |
| 1433 | try self.symtab.putNoClobber(self.allocator, name, .{ |
| 1434 | .tag = .Import, |
| 1435 | .inner = .{ |
| 1436 | .n_strx = 0, // This will be populated once we write the string table. |
| 1437 | .n_type = macho.N_UNDF | macho.N_EXT, |
| 1438 | .n_sect = 0, |
| 1439 | .n_desc = macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY | macho.N_SYMBOL_RESOLVER, |
| 1440 | .n_value = 0, |
| 1441 | }, |
| 1442 | .file = 0, |
| 1443 | }); |
| 1388 | 1444 | } |
| 1389 | 1445 | |
| 1390 | | fn resolveStubsAndGotEntries(self: *Zld) !void {} |
| 1446 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1447 | for (self.objects.items) |object, object_id| { |
| 1448 | log.debug("\nresolving stubs and got entries from {s}", .{object.name}); |
| 1449 | |
| 1450 | for (object.sections.items) |sect| { |
| 1451 | const relocs = sect.relocs orelse continue; |
| 1452 | for (relocs) |reloc| { |
| 1453 | switch (reloc.@"type") { |
| 1454 | .unsigned => continue, |
| 1455 | .got_page, .got_page_off => { |
| 1456 | const sym = object.symtab.items[reloc.target.symbol]; |
| 1457 | const sym_name = object.getString(sym.inner.n_strx); |
| 1458 | |
| 1459 | if (self.got_entries.contains(sym_name)) continue; |
| 1460 | |
| 1461 | const is_import = self.symtab.get(sym_name).?.tag == .Import; |
| 1462 | var name = try self.allocator.dupe(u8, sym_name); |
| 1463 | const index = @intCast(u32, self.got_entries.items().len); |
| 1464 | try self.got_entries.putNoClobber(self.allocator, name, .{ |
| 1465 | .tag = if (is_import) .import else .local, |
| 1466 | .index = index, |
| 1467 | .target_addr = 0, |
| 1468 | .file = if (is_import) 0 else @intCast(u16, object_id), |
| 1469 | .local_index = if (is_import) 0 else reloc.target.symbol, |
| 1470 | }); |
| 1471 | |
| 1472 | log.debug(" | found GOT entry {s}: {}", .{ sym_name, self.got_entries.get(sym_name) }); |
| 1473 | }, |
| 1474 | else => { |
| 1475 | const sym = object.symtab.items[reloc.target.symbol]; |
| 1476 | const sym_name = object.getString(sym.inner.n_strx); |
| 1477 | |
| 1478 | if (sym.tag != .Undef) continue; |
| 1479 | |
| 1480 | const in_globals = self.symtab.get(sym_name) orelse unreachable; |
| 1481 | |
| 1482 | if (in_globals.tag != .Import) continue; |
| 1483 | if (self.stubs.contains(sym_name)) continue; |
| 1484 | |
| 1485 | var name = try self.allocator.dupe(u8, sym_name); |
| 1486 | const index = @intCast(u32, self.stubs.items().len); |
| 1487 | try self.stubs.putNoClobber(self.allocator, name, index); |
| 1488 | |
| 1489 | log.debug(" | found stub {s}: {}", .{ sym_name, self.stubs.get(sym_name) }); |
| 1490 | }, |
| 1491 | } |
| 1492 | } |
| 1493 | } |
| 1494 | } |
| 1495 | |
| 1496 | // Finally, put dyld_stub_binder as the final GOT entry |
| 1497 | var name = try self.allocator.dupe(u8, "dyld_stub_binder"); |
| 1498 | const index = @intCast(u32, self.got_entries.items().len); |
| 1499 | try self.got_entries.putNoClobber(self.allocator, name, .{ |
| 1500 | .tag = .import, |
| 1501 | .index = index, |
| 1502 | .target_addr = 0, |
| 1503 | .file = 0, |
| 1504 | .local_index = 0, |
| 1505 | }); |
| 1506 | |
| 1507 | log.debug(" | found GOT entry dyld_stub_binder: {}", .{self.got_entries.get("dyld_stub_binder")}); |
| 1508 | } |
| 1391 | 1509 | |
| 1392 | 1510 | fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1393 | 1511 | for (self.objects.items) |object, object_id| { |
| ... | ... | @@ -2871,9 +2989,21 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { |
| 2871 | 2989 | return ((group_decode >> 2) == 4); |
| 2872 | 2990 | } |
| 2873 | 2991 | |
| 2874 | | fn printSymtab(self: Zld) void { |
| 2992 | fn printDebug(self: Zld) void { |
| 2875 | 2993 | log.warn("symtab", .{}); |
| 2876 | 2994 | for (self.symtab.items()) |entry| { |
| 2877 | 2995 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); |
| 2878 | 2996 | } |
| 2997 | |
| 2998 | log.warn("\n", .{}); |
| 2999 | log.warn("GOT entries", .{}); |
| 3000 | for (self.got_entries.items()) |entry| { |
| 3001 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); |
| 3002 | } |
| 3003 | |
| 3004 | log.warn("\n", .{}); |
| 3005 | log.warn("stubs", .{}); |
| 3006 | for (self.stubs.items()) |entry| { |
| 3007 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); |
| 3008 | } |
| 2879 | 3009 | } |