| ... | @@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | ... | @@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 87 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | 87 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 88 | | 88 | |
| 89 | const GotEntry = struct { | 89 | const GotEntry = struct { |
| | 90 | tag: enum { |
| | 91 | local, |
| | 92 | import, |
| | 93 | }, |
| 90 | index: u32, | 94 | index: u32, |
| 91 | target_addr: u64, | 95 | target_addr: u64, |
| | 96 | file: u16, |
| | 97 | local_index: u32, |
| 92 | }; | 98 | }; |
| 93 | | 99 | |
| 94 | const MappingKey = struct { | 100 | const MappingKey = struct { |
| ... | @@ -273,7 +279,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { | ... | @@ -273,7 +279,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void { |
| 273 | try self.allocateDataSegment(); | 279 | try self.allocateDataSegment(); |
| 274 | self.allocateLinkeditSegment(); | 280 | self.allocateLinkeditSegment(); |
| 275 | try self.allocateSymbols(); | 281 | try self.allocateSymbols(); |
| 276 | self.printSymtab(); | 282 | try self.allocateStubsAndGotEntries(); |
| | 283 | self.printDebug(); |
| 277 | // try self.writeStubHelperCommon(); | 284 | // try self.writeStubHelperCommon(); |
| 278 | // try self.resolveRelocsAndWriteSections(); | 285 | // try self.resolveRelocsAndWriteSections(); |
| 279 | // try self.flush(); | 286 | // try self.flush(); |
| ... | @@ -957,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void { | ... | @@ -957,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void { |
| 957 | const target_addr = target_sect.addr + target_mapping.offset; | 964 | const target_addr = target_sect.addr + target_mapping.offset; |
| 958 | const n_value = source_sym.inner.n_value - source_sect.addr + target_addr; | 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 | // TODO there might be a more generic way of doing this. | 969 | // TODO there might be a more generic way of doing this. |
| 963 | var n_sect: u8 = 0; | 970 | var n_sect: u8 = 0; |
| ... | @@ -979,6 +986,41 @@ fn allocateSymbols(self: *Zld) !void { | ... | @@ -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 | fn writeStubHelperCommon(self: *Zld) !void { | 1024 | fn writeStubHelperCommon(self: *Zld) !void { |
| 983 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; | 1025 | const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 984 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; | 1026 | const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?]; |
| ... | @@ -1385,9 +1427,85 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1385,9 +1427,85 @@ fn resolveSymbols(self: *Zld) !void { |
| 1385 | if (has_unresolved) { | 1427 | if (has_unresolved) { |
| 1386 | return error.UndefinedSymbolReference; | 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 | fn resolveRelocsAndWriteSections(self: *Zld) !void { | 1510 | fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1393 | for (self.objects.items) |object, object_id| { | 1511 | for (self.objects.items) |object, object_id| { |
| ... | @@ -2871,9 +2989,21 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { | ... | @@ -2871,9 +2989,21 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool { |
| 2871 | return ((group_decode >> 2) == 4); | 2989 | return ((group_decode >> 2) == 4); |
| 2872 | } | 2990 | } |
| 2873 | | 2991 | |
| 2874 | fn printSymtab(self: Zld) void { | 2992 | fn printDebug(self: Zld) void { |
| 2875 | log.warn("symtab", .{}); | 2993 | log.warn("symtab", .{}); |
| 2876 | for (self.symtab.items()) |entry| { | 2994 | for (self.symtab.items()) |entry| { |
| 2877 | log.warn(" | {s} => {any}", .{ entry.key, entry.value }); | 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 | } |