authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-07 13:58:12+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
logb667fe2c62044ec56e05edd74f8ab3f080f813b1
treefa77cc5acc88f84a783f88c0285cbab506c6eb13
parent46cc214f2d6a9219b7b80ba3e1b0b9f54761d8f7

zld: resolve stubs and GOT entries


3 files changed, 149 insertions(+), 19 deletions(-)

src/link/MachO/Object.zig+1-1
...@@ -207,7 +207,7 @@ pub fn parseSections(self: *Object) !void {...@@ -207,7 +207,7 @@ pub fn parseSections(self: *Object) !void {
207 };207 };
208208
209 // Parse relocations209 // Parse relocations
210 var relocs: ?[]*Relocation = if (sect.nreloc > 0) relocs: {210 section.relocs = if (sect.nreloc > 0) relocs: {
211 var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);211 var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
212 defer self.allocator.free(raw_relocs);212 defer self.allocator.free(raw_relocs);
213213
src/link/MachO/Zld.zig+134-4
...@@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},...@@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
87unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},87unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
8888
89const GotEntry = struct {89const 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};
9399
94const MappingKey = struct {100const 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;
959966
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 });
961968
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}
981988
989fn 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
982fn writeStubHelperCommon(self: *Zld) !void {1024fn 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}
13891445
1390fn resolveStubsAndGotEntries(self: *Zld) !void {}1446fn 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}
13911509
1392fn resolveRelocsAndWriteSections(self: *Zld) !void {1510fn 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}
28732991
2874fn printSymtab(self: Zld) void {2992fn 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}
src/link/MachO/reloc.zig+14-14
...@@ -292,12 +292,12 @@ const RelocIterator = struct {...@@ -292,12 +292,12 @@ const RelocIterator = struct {
292 self.index += 1;292 self.index += 1;
293 if (self.index < self.buffer.len) {293 if (self.index < self.buffer.len) {
294 const reloc = self.buffer[@intCast(u64, self.index)];294 const reloc = self.buffer[@intCast(u64, self.index)];
295 log.warn("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});295 log.debug("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
296 log.warn(" | offset = {}", .{reloc.r_address});296 log.debug(" | offset = {}", .{reloc.r_address});
297 log.warn(" | PC = {}", .{reloc.r_pcrel == 1});297 log.debug(" | PC = {}", .{reloc.r_pcrel == 1});
298 log.warn(" | length = {}", .{reloc.r_length});298 log.debug(" | length = {}", .{reloc.r_length});
299 log.warn(" | symbolnum = {}", .{reloc.r_symbolnum});299 log.debug(" | symbolnum = {}", .{reloc.r_symbolnum});
300 log.warn(" | extern = {}", .{reloc.r_extern == 1});300 log.debug(" | extern = {}", .{reloc.r_extern == 1});
301 return reloc;301 return reloc;
302 }302 }
303 return null;303 return null;
...@@ -419,7 +419,7 @@ const Parser = struct {...@@ -419,7 +419,7 @@ const Parser = struct {
419 .inst = parsed_inst,419 .inst = parsed_inst,
420 };420 };
421421
422 log.warn(" | emitting {}", .{branch});422 log.debug(" | emitting {}", .{branch});
423 try parser.parsed.append(&branch.base);423 try parser.parsed.append(&branch.base);
424 }424 }
425425
...@@ -458,7 +458,7 @@ const Parser = struct {...@@ -458,7 +458,7 @@ const Parser = struct {
458 .inst = parsed_inst,458 .inst = parsed_inst,
459 };459 };
460460
461 log.warn(" | emitting {}", .{page});461 log.debug(" | emitting {}", .{page});
462462
463 break :ptr &page.base;463 break :ptr &page.base;
464 },464 },
...@@ -476,7 +476,7 @@ const Parser = struct {...@@ -476,7 +476,7 @@ const Parser = struct {
476 .inst = parsed_inst,476 .inst = parsed_inst,
477 };477 };
478478
479 log.warn(" | emitting {}", .{page});479 log.debug(" | emitting {}", .{page});
480480
481 break :ptr &page.base;481 break :ptr &page.base;
482 },482 },
...@@ -494,7 +494,7 @@ const Parser = struct {...@@ -494,7 +494,7 @@ const Parser = struct {
494 .inst = parsed_inst,494 .inst = parsed_inst,
495 };495 };
496496
497 log.warn(" | emitting {}", .{page});497 log.debug(" | emitting {}", .{page});
498498
499 break :ptr &page.base;499 break :ptr &page.base;
500 },500 },
...@@ -551,7 +551,7 @@ const Parser = struct {...@@ -551,7 +551,7 @@ const Parser = struct {
551 .addend = parser.addend,551 .addend = parser.addend,
552 };552 };
553553
554 log.warn(" | emitting {}", .{page_off});554 log.debug(" | emitting {}", .{page_off});
555 try parser.parsed.append(&page_off.base);555 try parser.parsed.append(&page_off.base);
556 }556 }
557557
...@@ -588,7 +588,7 @@ const Parser = struct {...@@ -588,7 +588,7 @@ const Parser = struct {
588 },588 },
589 };589 };
590590
591 log.warn(" | emitting {}", .{page_off});591 log.debug(" | emitting {}", .{page_off});
592 try parser.parsed.append(&page_off.base);592 try parser.parsed.append(&page_off.base);
593 }593 }
594594
...@@ -655,7 +655,7 @@ const Parser = struct {...@@ -655,7 +655,7 @@ const Parser = struct {
655 },655 },
656 };656 };
657657
658 log.warn(" | emitting {}", .{page_off});658 log.debug(" | emitting {}", .{page_off});
659 try parser.parsed.append(&page_off.base);659 try parser.parsed.append(&page_off.base);
660 }660 }
661661
...@@ -716,7 +716,7 @@ const Parser = struct {...@@ -716,7 +716,7 @@ const Parser = struct {
716 .addend = addend,716 .addend = addend,
717 };717 };
718718
719 log.warn(" | emitting {}", .{unsigned});719 log.debug(" | emitting {}", .{unsigned});
720 try parser.parsed.append(&unsigned.base);720 try parser.parsed.append(&unsigned.base);
721 }721 }
722};722};