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 {
207207 };
208208
209209 // Parse relocations
210 var relocs: ?[]*Relocation = if (sect.nreloc > 0) relocs: {
210 section.relocs = if (sect.nreloc > 0) relocs: {
211211 var raw_relocs = try self.allocator.alloc(u8, @sizeOf(macho.relocation_info) * sect.nreloc);
212212 defer self.allocator.free(raw_relocs);
213213
src/link/MachO/Zld.zig+134-4
......@@ -87,8 +87,14 @@ mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{},
8787unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{},
8888
8989const GotEntry = struct {
90 tag: enum {
91 local,
92 import,
93 },
9094 index: u32,
9195 target_addr: u64,
96 file: u16,
97 local_index: u32,
9298};
9399
94100const MappingKey = struct {
......@@ -273,7 +279,8 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
273279 try self.allocateDataSegment();
274280 self.allocateLinkeditSegment();
275281 try self.allocateSymbols();
276 self.printSymtab();
282 try self.allocateStubsAndGotEntries();
283 self.printDebug();
277284 // try self.writeStubHelperCommon();
278285 // try self.resolveRelocsAndWriteSections();
279286 // try self.flush();
......@@ -957,7 +964,7 @@ fn allocateSymbols(self: *Zld) !void {
957964 const target_addr = target_sect.addr + target_mapping.offset;
958965 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
962969 // TODO there might be a more generic way of doing this.
963970 var n_sect: u8 = 0;
......@@ -979,6 +986,41 @@ fn allocateSymbols(self: *Zld) !void {
979986 }
980987}
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
9821024fn writeStubHelperCommon(self: *Zld) !void {
9831025 const text_segment = &self.load_commands.items[self.text_segment_cmd_index.?].Segment;
9841026 const stub_helper = &text_segment.sections.items[self.stub_helper_section_index.?];
......@@ -1385,9 +1427,85 @@ fn resolveSymbols(self: *Zld) !void {
13851427 if (has_unresolved) {
13861428 return error.UndefinedSymbolReference;
13871429 }
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 });
13881444}
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
13921510fn resolveRelocsAndWriteSections(self: *Zld) !void {
13931511 for (self.objects.items) |object, object_id| {
......@@ -2871,9 +2989,21 @@ fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool {
28712989 return ((group_decode >> 2) == 4);
28722990}
28732991
2874fn printSymtab(self: Zld) void {
2992fn printDebug(self: Zld) void {
28752993 log.warn("symtab", .{});
28762994 for (self.symtab.items()) |entry| {
28772995 log.warn(" | {s} => {any}", .{ entry.key, entry.value });
28782996 }
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 }
28793009}
src/link/MachO/reloc.zig+14-14
......@@ -292,12 +292,12 @@ const RelocIterator = struct {
292292 self.index += 1;
293293 if (self.index < self.buffer.len) {
294294 const reloc = self.buffer[@intCast(u64, self.index)];
295 log.warn("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
296 log.warn(" | offset = {}", .{reloc.r_address});
297 log.warn(" | PC = {}", .{reloc.r_pcrel == 1});
298 log.warn(" | length = {}", .{reloc.r_length});
299 log.warn(" | symbolnum = {}", .{reloc.r_symbolnum});
300 log.warn(" | extern = {}", .{reloc.r_extern == 1});
295 log.debug("{s}", .{@intToEnum(macho.reloc_type_arm64, reloc.r_type)});
296 log.debug(" | offset = {}", .{reloc.r_address});
297 log.debug(" | PC = {}", .{reloc.r_pcrel == 1});
298 log.debug(" | length = {}", .{reloc.r_length});
299 log.debug(" | symbolnum = {}", .{reloc.r_symbolnum});
300 log.debug(" | extern = {}", .{reloc.r_extern == 1});
301301 return reloc;
302302 }
303303 return null;
......@@ -419,7 +419,7 @@ const Parser = struct {
419419 .inst = parsed_inst,
420420 };
421421
422 log.warn(" | emitting {}", .{branch});
422 log.debug(" | emitting {}", .{branch});
423423 try parser.parsed.append(&branch.base);
424424 }
425425
......@@ -458,7 +458,7 @@ const Parser = struct {
458458 .inst = parsed_inst,
459459 };
460460
461 log.warn(" | emitting {}", .{page});
461 log.debug(" | emitting {}", .{page});
462462
463463 break :ptr &page.base;
464464 },
......@@ -476,7 +476,7 @@ const Parser = struct {
476476 .inst = parsed_inst,
477477 };
478478
479 log.warn(" | emitting {}", .{page});
479 log.debug(" | emitting {}", .{page});
480480
481481 break :ptr &page.base;
482482 },
......@@ -494,7 +494,7 @@ const Parser = struct {
494494 .inst = parsed_inst,
495495 };
496496
497 log.warn(" | emitting {}", .{page});
497 log.debug(" | emitting {}", .{page});
498498
499499 break :ptr &page.base;
500500 },
......@@ -551,7 +551,7 @@ const Parser = struct {
551551 .addend = parser.addend,
552552 };
553553
554 log.warn(" | emitting {}", .{page_off});
554 log.debug(" | emitting {}", .{page_off});
555555 try parser.parsed.append(&page_off.base);
556556 }
557557
......@@ -588,7 +588,7 @@ const Parser = struct {
588588 },
589589 };
590590
591 log.warn(" | emitting {}", .{page_off});
591 log.debug(" | emitting {}", .{page_off});
592592 try parser.parsed.append(&page_off.base);
593593 }
594594
......@@ -655,7 +655,7 @@ const Parser = struct {
655655 },
656656 };
657657
658 log.warn(" | emitting {}", .{page_off});
658 log.debug(" | emitting {}", .{page_off});
659659 try parser.parsed.append(&page_off.base);
660660 }
661661
......@@ -716,7 +716,7 @@ const Parser = struct {
716716 .addend = addend,
717717 };
718718
719 log.warn(" | emitting {}", .{unsigned});
719 log.debug(" | emitting {}", .{unsigned});
720720 try parser.parsed.append(&unsigned.base);
721721 }
722722};