authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-08 12:37:10+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-04-13 10:56:03+02:00
logdc7cff8ebc5f00c784647c0bd1b40dec70a5008f
treed463c69ad6b5aaf9c2e922f4938cbd44f9f52fa7
parent23bb6fa9f45d99f97e64bea7011702db19718914

zld: add prelim support for locals


2 files changed, 109 insertions(+), 107 deletions(-)

src/link/MachO/Archive.zig+3-1
...@@ -207,12 +207,14 @@ pub fn parseObject(self: Archive, offset: u32) !Object {...@@ -207,12 +207,14 @@ pub fn parseObject(self: Archive, offset: u32) !Object {
207 }207 }
208208
209 const object_name = try parseName(self.allocator, object_header, reader);209 const object_name = try parseName(self.allocator, object_header, reader);
210 defer self.allocator.free(object_name);
211
210 log.warn("extracting object '{s}' from archive '{s}'", .{ object_name, self.name.? });212 log.warn("extracting object '{s}' from archive '{s}'", .{ object_name, self.name.? });
211213
212 var object = Object.init(self.allocator);214 var object = Object.init(self.allocator);
213 object.arch = self.arch.?;215 object.arch = self.arch.?;
214 object.file = try fs.cwd().openFile(self.name.?, .{});216 object.file = try fs.cwd().openFile(self.name.?, .{});
215 object.name = object_name;217 object.name = try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ self.name.?, object_name });
216 object.file_offset = @intCast(u32, try reader.context.getPos());218 object.file_offset = @intCast(u32, try reader.context.getPos());
217 try object.parse();219 try object.parse();
218220
src/link/MachO/Zld.zig+106-106
...@@ -933,56 +933,69 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {...@@ -933,56 +933,69 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void {
933}933}
934934
935fn allocateSymbols(self: *Zld) !void {935fn allocateSymbols(self: *Zld) !void {
936 for (self.symtab.items()) |*entry| {936 for (self.objects.items) |*object, object_id| {
937 if (entry.value.tag == .Import) continue;937 for (object.symtab.items) |*sym| {
938938 switch (sym.tag) {
939 const object_id = entry.value.file orelse unreachable;939 .Import => unreachable,
940 const index = entry.value.index orelse unreachable;940 .Undef => continue,
941 else => {},
942 }
941943
942 const object = self.objects.items[object_id];944 const sym_name = object.getString(sym.inner.n_strx);
943 const source_sym = object.symtab.items[index];945 const source_sect_id = sym.inner.n_sect - 1;
944 const source_sect_id = source_sym.inner.n_sect - 1;
945946
946 // TODO I am more and more convinced we should store the mapping as part of the Object struct.947 // TODO I am more and more convinced we should store the mapping as part of the Object struct.
947 const target_mapping = self.mappings.get(.{948 const target_mapping = self.mappings.get(.{
948 .object_id = object_id,949 .object_id = @intCast(u16, object_id),
949 .source_sect_id = source_sect_id,
950 }) orelse {
951 if (self.unhandled_sections.get(.{
952 .object_id = object_id,
953 .source_sect_id = source_sect_id,950 .source_sect_id = source_sect_id,
954 }) != null) continue;951 }) orelse {
952 if (self.unhandled_sections.get(.{
953 .object_id = @intCast(u16, object_id),
954 .source_sect_id = source_sect_id,
955 }) != null) continue;
955956
956 log.err("section not mapped for symbol '{s}': {}", .{ entry.key, source_sym });957 log.err("section not mapped for symbol '{s}': {}", .{ sym_name, sym });
957 return error.SectionNotMappedForSymbol;958 return error.SectionNotMappedForSymbol;
958 };959 };
959960
960 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;961 const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment;
961 const source_sect = source_seg.sections.items[source_sect_id];962 const source_sect = source_seg.sections.items[source_sect_id];
962 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;963 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
963 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];964 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
964 const target_addr = target_sect.addr + target_mapping.offset;965 const target_addr = target_sect.addr + target_mapping.offset;
965 const n_value = source_sym.inner.n_value - source_sect.addr + target_addr;966 const n_value = sym.inner.n_value - source_sect.addr + target_addr;
966967
967 log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value });968 log.warn("resolving local symbol '{s}' at 0x{x}", .{ sym_name, n_value });
968969
969 // TODO there might be a more generic way of doing this.970 // TODO there might be a more generic way of doing this.
970 var n_sect: u8 = 0;971 var n_sect: u8 = 0;
971 for (self.load_commands.items) |cmd, cmd_id| {972 for (self.load_commands.items) |cmd, cmd_id| {
972 if (cmd != .Segment) break;973 if (cmd != .Segment) break;
973 if (cmd_id == target_mapping.target_seg_id) {974 if (cmd_id == target_mapping.target_seg_id) {
974 n_sect += @intCast(u8, target_mapping.target_sect_id) + 1;975 n_sect += @intCast(u8, target_mapping.target_sect_id) + 1;
975 break;976 break;
977 }
978 n_sect += @intCast(u8, cmd.Segment.sections.items.len);
976 }979 }
977 n_sect += @intCast(u8, cmd.Segment.sections.items.len);980
981 sym.inner.n_value = n_value;
982 sym.inner.n_sect = n_sect;
978 }983 }
984 }
985
986 for (self.symtab.items()) |*entry| {
987 if (entry.value.tag == .Import) continue;
988
989 const object_id = entry.value.file orelse unreachable;
990 const index = entry.value.index orelse unreachable;
991
992 const object = self.objects.items[object_id];
993 const sym = object.symtab.items[index];
979994
980 entry.value.inner.n_value = n_value;995 log.warn("resolving {} symbol '{s}' at 0x{x}", .{ entry.value.tag, entry.key, sym.inner.n_value });
981 entry.value.inner.n_sect = n_sect;
982996
983 // TODO This will need to be redone for any CU locals that end up in the final symbol table.997 entry.value.inner.n_value = sym.inner.n_value;
984 // This could be part of writing debug info since this is the only valid reason (is it?) for998 entry.value.inner.n_sect = sym.inner.n_sect;
985 // including CU locals in the final MachO symbol table.
986 }999 }
987}1000}
9881001
...@@ -995,23 +1008,12 @@ fn allocateStubsAndGotEntries(self: *Zld) !void {...@@ -995,23 +1008,12 @@ fn allocateStubsAndGotEntries(self: *Zld) !void {
995 const sym_name = object.getString(sym.inner.n_strx);1008 const sym_name = object.getString(sym.inner.n_strx);
996 assert(mem.eql(u8, sym_name, entry.key));1009 assert(mem.eql(u8, sym_name, entry.key));
9971010
998 // TODO clean this up
999 entry.value.target_addr = target_addr: {1011 entry.value.target_addr = target_addr: {
1000 if (sym.tag != .Local) {1012 if (sym.tag == .Undef) {
1001 const glob = self.symtab.get(sym_name) orelse unreachable;1013 const glob = self.symtab.get(sym_name) orelse unreachable;
1002 break :target_addr glob.inner.n_value;1014 break :target_addr glob.inner.n_value;
1003 }1015 }
10041016 break :target_addr sym.inner.n_value;
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 };1017 };
10161018
1017 log.warn("resolving GOT entry '{s}' at 0x{x}", .{1019 log.warn("resolving GOT entry '{s}' at 0x{x}", .{
...@@ -1315,7 +1317,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {...@@ -1315,7 +1317,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void {
1315 continue;1317 continue;
1316 };1318 };
13171319
1318 if (sym.tag == .Weak) continue; // If symbol is weak, nothing to do.1320 if (global.value.tag == .Weak) continue; // If symbol is weak, nothing to do.
1319 if (global.value.tag == .Strong) { // If both symbols are strong, we have a collision.1321 if (global.value.tag == .Strong) { // If both symbols are strong, we have a collision.
1320 log.err("symbol '{s}' defined multiple times", .{sym_name});1322 log.err("symbol '{s}' defined multiple times", .{sym_name});
1321 return error.MultipleSymbolDefinitions;1323 return error.MultipleSymbolDefinitions;
...@@ -1363,9 +1365,10 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1363,9 +1365,10 @@ fn resolveSymbols(self: *Zld) !void {
13631365
1364 // Second pass, resolve symbols in static libraries.1366 // Second pass, resolve symbols in static libraries.
1365 var next: usize = 0;1367 var next: usize = 0;
1368 var hit: bool = undefined;
1366 while (true) {1369 while (true) {
1367 var archive = &self.archives.items[next];1370 var archive = &self.archives.items[next];
1368 var hit: bool = false;1371 hit = false;
13691372
1370 for (self.symtab.items()) |entry| {1373 for (self.symtab.items()) |entry| {
1371 if (entry.value.tag != .Undef) continue;1374 if (entry.value.tag != .Undef) continue;
...@@ -1444,7 +1447,7 @@ fn resolveSymbols(self: *Zld) !void {...@@ -1444,7 +1447,7 @@ fn resolveSymbols(self: *Zld) !void {
14441447
1445fn resolveStubsAndGotEntries(self: *Zld) !void {1448fn resolveStubsAndGotEntries(self: *Zld) !void {
1446 for (self.objects.items) |object, object_id| {1449 for (self.objects.items) |object, object_id| {
1447 log.warn("\nresolving stubs and got entries from {s}", .{object.name});1450 log.warn("resolving stubs and got entries from {s}", .{object.name});
14481451
1449 for (object.sections.items) |sect| {1452 for (object.sections.items) |sect| {
1450 const relocs = sect.relocs orelse continue;1453 const relocs = sect.relocs orelse continue;
...@@ -1574,7 +1577,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1574,7 +1577,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1574 const sym_name = object.getString(sym.inner.n_strx);1577 const sym_name = object.getString(sym.inner.n_strx);
15751578
1576 // TODO we don't want to save offset to tlv_bootstrap1579 // TODO we don't want to save offset to tlv_bootstrap
1577 if (mem.eql(u8, sym_name, "__tlv_boostrap")) break :tlv;1580 if (mem.eql(u8, sym_name, "__tlv_bootstrap")) break :tlv;
15781581
1579 const base_addr = blk: {1582 const base_addr = blk: {
1580 if (self.tlv_data_section_index) |index| {1583 if (self.tlv_data_section_index) |index| {
...@@ -1646,27 +1649,18 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 {...@@ -1646,27 +1649,18 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 {
1646 const sym_name = object.getString(sym.inner.n_strx);1649 const sym_name = object.getString(sym.inner.n_strx);
16471650
1648 switch (sym.tag) {1651 switch (sym.tag) {
1649 .Stab => unreachable, // TODO is this even allowed to happen?1652 .Stab, .Local, .Weak, .Strong => {
1650 .Local, .Weak, .Strong => {1653 log.warn(" | local symbol '{s}'", .{sym_name});
1651 // Relocate using section offsets only.1654 break :blk sym.inner.n_value;
1652 const target_mapping = self.mappings.get(.{
1653 .object_id = object_id,
1654 .source_sect_id = sym.inner.n_sect - 1,
1655 }) orelse unreachable;
1656 const source_sect = object.sections.items[target_mapping.source_sect_id];
1657 const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment;
1658 const target_sect = target_seg.sections.items[target_mapping.target_sect_id];
1659 const target_sect_addr = target_sect.addr + target_mapping.offset;
1660 log.warn(" | symbol local to object", .{});
1661 break :blk target_sect_addr + sym.inner.n_value - source_sect.inner.addr;
1662 },1655 },
1663 else => {1656 else => {
1664 if (self.stubs.get(sym_name)) |index| {1657 if (self.stubs.get(sym_name)) |index| {
1665 log.warn(" | symbol stub {s}", .{sym_name});1658 log.warn(" | symbol stub '{s}'", .{sym_name});
1666 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;1659 const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
1667 const stubs = segment.sections.items[self.stubs_section_index.?];1660 const stubs = segment.sections.items[self.stubs_section_index.?];
1668 break :blk stubs.addr + index * stubs.reserved2;1661 break :blk stubs.addr + index * stubs.reserved2;
1669 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {1662 } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) {
1663 log.warn(" | symbol '__tlv_bootstrap'", .{});
1670 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;1664 const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment;
1671 const tlv = segment.sections.items[self.tlv_section_index.?];1665 const tlv = segment.sections.items[self.tlv_section_index.?];
1672 break :blk tlv.addr;1666 break :blk tlv.addr;
...@@ -1675,6 +1669,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 {...@@ -1675,6 +1669,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 {
1675 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});1669 log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name});
1676 return error.FailedToResolveRelocationTarget;1670 return error.FailedToResolveRelocationTarget;
1677 };1671 };
1672 log.warn(" | global symbol '{s}'", .{sym_name});
1678 break :blk global.inner.n_value;1673 break :blk global.inner.n_value;
1679 }1674 }
1680 },1675 },
...@@ -2144,8 +2139,8 @@ fn flush(self: *Zld) !void {...@@ -2144,8 +2139,8 @@ fn flush(self: *Zld) !void {
2144 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);2139 symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
2145 }2140 }
21462141
2147 // try self.writeDebugInfo();
2148 try self.populateStringTable();2142 try self.populateStringTable();
2143 try self.writeDebugInfo();
2149 try self.writeSymbolTable();2144 try self.writeSymbolTable();
2150 try self.writeDynamicSymbolTable();2145 try self.writeDynamicSymbolTable();
2151 try self.writeStringTable();2146 try self.writeStringTable();
...@@ -2556,20 +2551,10 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2556,20 +2551,10 @@ fn writeDebugInfo(self: *Zld) !void {
2556 });2551 });
2557 // Path to object file with debug info2552 // Path to object file with debug info
2558 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;2553 var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
2559 const full_path = blk: {2554 const stat = try object.file.?.stat();
2560 if (object.ar_name) |prefix| {
2561 const path = try std.os.realpath(prefix, &buffer);
2562 break :blk try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object.name });
2563 } else {
2564 const path = try std.os.realpath(object.name, &buffer);
2565 break :blk try mem.dupe(self.allocator, u8, path);
2566 }
2567 };
2568 defer self.allocator.free(full_path);
2569 const stat = try object.file.stat();
2570 const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));2555 const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
2571 try stabs.append(.{2556 try stabs.append(.{
2572 .n_strx = try self.makeString(full_path),2557 .n_strx = try self.makeString(object.name.?),
2573 .n_type = macho.N_OSO,2558 .n_type = macho.N_OSO,
2574 .n_sect = 0,2559 .n_sect = 0,
2575 .n_desc = 1,2560 .n_desc = 1,
...@@ -2578,19 +2563,12 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2578,19 +2563,12 @@ fn writeDebugInfo(self: *Zld) !void {
2578 }2563 }
2579 log.warn("analyzing debug info in '{s}'", .{object.name});2564 log.warn("analyzing debug info in '{s}'", .{object.name});
25802565
2581 for (object.symtab.items) |source_sym| {2566 for (object.symtab.items) |sym| {
2582 const symname = object.getString(source_sym.n_strx);2567 const sym_name = object.getString(sym.inner.n_strx);
2583 const source_addr = source_sym.n_value;
2584 const target_syms = self.locals.get(symname) orelse continue;
2585 const target_sym: Symbol = blk: {
2586 for (target_syms.items) |ts| {
2587 if (ts.object_id == @intCast(u16, object_id)) break :blk ts;
2588 } else continue;
2589 };
2590
2591 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {2568 const maybe_size = blk: for (debug_info.inner.func_list.items) |func| {
2592 if (func.pc_range) |range| {2569 if (func.pc_range) |range| {
2593 if (source_addr >= range.start and source_addr < range.end) {2570 // TODO source address needs to be preserved
2571 if (sym.inner.n_value >= range.start and sym.inner.n_value < range.end) {
2594 break :blk range.end - range.start;2572 break :blk range.end - range.start;
2595 }2573 }
2596 }2574 }
...@@ -2600,16 +2578,16 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2600,16 +2578,16 @@ fn writeDebugInfo(self: *Zld) !void {
2600 try stabs.append(.{2578 try stabs.append(.{
2601 .n_strx = 0,2579 .n_strx = 0,
2602 .n_type = macho.N_BNSYM,2580 .n_type = macho.N_BNSYM,
2603 .n_sect = target_sym.inner.n_sect,2581 .n_sect = sym.inner.n_sect,
2604 .n_desc = 0,2582 .n_desc = 0,
2605 .n_value = target_sym.inner.n_value,2583 .n_value = sym.inner.n_value,
2606 });2584 });
2607 try stabs.append(.{2585 try stabs.append(.{
2608 .n_strx = target_sym.inner.n_strx,2586 .n_strx = sym.inner.n_strx,
2609 .n_type = macho.N_FUN,2587 .n_type = macho.N_FUN,
2610 .n_sect = target_sym.inner.n_sect,2588 .n_sect = sym.inner.n_sect,
2611 .n_desc = 0,2589 .n_desc = 0,
2612 .n_value = target_sym.inner.n_value,2590 .n_value = sym.inner.n_value,
2613 });2591 });
2614 try stabs.append(.{2592 try stabs.append(.{
2615 .n_strx = 0,2593 .n_strx = 0,
...@@ -2621,18 +2599,18 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2621,18 +2599,18 @@ fn writeDebugInfo(self: *Zld) !void {
2621 try stabs.append(.{2599 try stabs.append(.{
2622 .n_strx = 0,2600 .n_strx = 0,
2623 .n_type = macho.N_ENSYM,2601 .n_type = macho.N_ENSYM,
2624 .n_sect = target_sym.inner.n_sect,2602 .n_sect = sym.inner.n_sect,
2625 .n_desc = 0,2603 .n_desc = 0,
2626 .n_value = size,2604 .n_value = size,
2627 });2605 });
2628 } else {2606 } else {
2629 // TODO need a way to differentiate symbols: global, static, local, etc.2607 // TODO need a way to differentiate symbols: global, static, local, etc.
2630 try stabs.append(.{2608 try stabs.append(.{
2631 .n_strx = target_sym.inner.n_strx,2609 .n_strx = sym.inner.n_strx,
2632 .n_type = macho.N_STSYM,2610 .n_type = macho.N_STSYM,
2633 .n_sect = target_sym.inner.n_sect,2611 .n_sect = sym.inner.n_sect,
2634 .n_desc = 0,2612 .n_desc = 0,
2635 .n_value = target_sym.inner.n_value,2613 .n_value = sym.inner.n_value,
2636 });2614 });
2637 }2615 }
2638 }2616 }
...@@ -2668,6 +2646,18 @@ fn writeDebugInfo(self: *Zld) !void {...@@ -2668,6 +2646,18 @@ fn writeDebugInfo(self: *Zld) !void {
2668}2646}
26692647
2670fn populateStringTable(self: *Zld) !void {2648fn populateStringTable(self: *Zld) !void {
2649 for (self.objects.items) |*object| {
2650 for (object.symtab.items) |*sym| {
2651 switch (sym.tag) {
2652 .Stab, .Local => {},
2653 else => continue,
2654 }
2655 const sym_name = object.getString(sym.inner.n_strx);
2656 const n_strx = try self.makeString(sym_name);
2657 sym.inner.n_strx = n_strx;
2658 }
2659 }
2660
2671 for (self.symtab.items()) |*entry| {2661 for (self.symtab.items()) |*entry| {
2672 const n_strx = try self.makeString(entry.key);2662 const n_strx = try self.makeString(entry.key);
2673 entry.value.inner.n_strx = n_strx;2663 entry.value.inner.n_strx = n_strx;
...@@ -2678,10 +2668,20 @@ fn writeSymbolTable(self: *Zld) !void {...@@ -2678,10 +2668,20 @@ fn writeSymbolTable(self: *Zld) !void {
2678 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;2668 const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
2679 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;2669 const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
26802670
2681 // TODO figure out how to add locals
2682 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);2671 var locals = std.ArrayList(macho.nlist_64).init(self.allocator);
2683 defer locals.deinit();2672 defer locals.deinit();
26842673
2674 for (self.objects.items) |object| {
2675 for (object.symtab.items) |sym| {
2676 switch (sym.tag) {
2677 .Stab, .Local => {},
2678 else => continue,
2679 }
2680
2681 try locals.append(sym.inner);
2682 }
2683 }
2684
2685 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);2685 var exports = std.ArrayList(macho.nlist_64).init(self.allocator);
2686 defer exports.deinit();2686 defer exports.deinit();
26872687