| ... | ... | @@ -933,56 +933,69 @@ fn allocateSegment(self: *Zld, index: u16, offset: u64) !void { |
| 933 | 933 | } |
| 934 | 934 | |
| 935 | 935 | fn allocateSymbols(self: *Zld) !void { |
| 936 | | for (self.symtab.items()) |*entry| { |
| 937 | | if (entry.value.tag == .Import) continue; |
| 938 | | |
| 939 | | const object_id = entry.value.file orelse unreachable; |
| 940 | | const index = entry.value.index orelse unreachable; |
| 936 | for (self.objects.items) |*object, object_id| { |
| 937 | for (object.symtab.items) |*sym| { |
| 938 | switch (sym.tag) { |
| 939 | .Import => unreachable, |
| 940 | .Undef => continue, |
| 941 | else => {}, |
| 942 | } |
| 941 | 943 | |
| 942 | | const object = self.objects.items[object_id]; |
| 943 | | const source_sym = object.symtab.items[index]; |
| 944 | | const source_sect_id = source_sym.inner.n_sect - 1; |
| 944 | const sym_name = object.getString(sym.inner.n_strx); |
| 945 | const source_sect_id = sym.inner.n_sect - 1; |
| 945 | 946 | |
| 946 | | // 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 | | .object_id = object_id, |
| 949 | | .source_sect_id = source_sect_id, |
| 950 | | }) orelse { |
| 951 | | if (self.unhandled_sections.get(.{ |
| 952 | | .object_id = object_id, |
| 947 | // TODO I am more and more convinced we should store the mapping as part of the Object struct. |
| 948 | const target_mapping = self.mappings.get(.{ |
| 949 | .object_id = @intCast(u16, object_id), |
| 953 | 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; |
| 955 | 956 | |
| 956 | | log.err("section not mapped for symbol '{s}': {}", .{ entry.key, source_sym }); |
| 957 | | return error.SectionNotMappedForSymbol; |
| 958 | | }; |
| 957 | log.err("section not mapped for symbol '{s}': {}", .{ sym_name, sym }); |
| 958 | return error.SectionNotMappedForSymbol; |
| 959 | }; |
| 959 | 960 | |
| 960 | | 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 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_addr = target_sect.addr + target_mapping.offset; |
| 965 | | const n_value = source_sym.inner.n_value - source_sect.addr + target_addr; |
| 966 | | |
| 967 | | log.warn("resolving '{s}' symbol at 0x{x}", .{ entry.key, n_value }); |
| 968 | | |
| 969 | | // TODO there might be a more generic way of doing this. |
| 970 | | var n_sect: u8 = 0; |
| 971 | | for (self.load_commands.items) |cmd, cmd_id| { |
| 972 | | if (cmd != .Segment) break; |
| 973 | | if (cmd_id == target_mapping.target_seg_id) { |
| 974 | | n_sect += @intCast(u8, target_mapping.target_sect_id) + 1; |
| 975 | | break; |
| 961 | const source_seg = object.load_commands.items[object.segment_cmd_index.?].Segment; |
| 962 | const source_sect = source_seg.sections.items[source_sect_id]; |
| 963 | const target_seg = self.load_commands.items[target_mapping.target_seg_id].Segment; |
| 964 | const target_sect = target_seg.sections.items[target_mapping.target_sect_id]; |
| 965 | const target_addr = target_sect.addr + target_mapping.offset; |
| 966 | const n_value = sym.inner.n_value - source_sect.addr + target_addr; |
| 967 | |
| 968 | log.warn("resolving local symbol '{s}' at 0x{x}", .{ sym_name, n_value }); |
| 969 | |
| 970 | // TODO there might be a more generic way of doing this. |
| 971 | var n_sect: u8 = 0; |
| 972 | for (self.load_commands.items) |cmd, cmd_id| { |
| 973 | if (cmd != .Segment) break; |
| 974 | if (cmd_id == target_mapping.target_seg_id) { |
| 975 | n_sect += @intCast(u8, target_mapping.target_sect_id) + 1; |
| 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]; |
| 979 | 994 | |
| 980 | | entry.value.inner.n_value = n_value; |
| 981 | | entry.value.inner.n_sect = n_sect; |
| 995 | log.warn("resolving {} symbol '{s}' at 0x{x}", .{ entry.value.tag, entry.key, sym.inner.n_value }); |
| 982 | 996 | |
| 983 | | // TODO This will need to be redone for any CU locals that end up in the final symbol table. |
| 984 | | // This could be part of writing debug info since this is the only valid reason (is it?) for |
| 985 | | // including CU locals in the final MachO symbol table. |
| 997 | entry.value.inner.n_value = sym.inner.n_value; |
| 998 | entry.value.inner.n_sect = sym.inner.n_sect; |
| 986 | 999 | } |
| 987 | 1000 | } |
| 988 | 1001 | |
| ... | ... | @@ -995,23 +1008,12 @@ fn allocateStubsAndGotEntries(self: *Zld) !void { |
| 995 | 1008 | const sym_name = object.getString(sym.inner.n_strx); |
| 996 | 1009 | assert(mem.eql(u8, sym_name, entry.key)); |
| 997 | 1010 | |
| 998 | | // TODO clean this up |
| 999 | 1011 | entry.value.target_addr = target_addr: { |
| 1000 | | if (sym.tag != .Local) { |
| 1012 | if (sym.tag == .Undef) { |
| 1001 | 1013 | const glob = self.symtab.get(sym_name) orelse unreachable; |
| 1002 | 1014 | break :target_addr glob.inner.n_value; |
| 1003 | 1015 | } |
| 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; |
| 1016 | break :target_addr sym.inner.n_value; |
| 1015 | 1017 | }; |
| 1016 | 1018 | |
| 1017 | 1019 | log.warn("resolving GOT entry '{s}' at 0x{x}", .{ |
| ... | ... | @@ -1315,7 +1317,7 @@ fn resolveSymbolsInObject(self: *Zld, object_id: u16) !void { |
| 1315 | 1317 | continue; |
| 1316 | 1318 | }; |
| 1317 | 1319 | |
| 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 | 1321 | if (global.value.tag == .Strong) { // If both symbols are strong, we have a collision. |
| 1320 | 1322 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 1321 | 1323 | return error.MultipleSymbolDefinitions; |
| ... | ... | @@ -1363,9 +1365,10 @@ fn resolveSymbols(self: *Zld) !void { |
| 1363 | 1365 | |
| 1364 | 1366 | // Second pass, resolve symbols in static libraries. |
| 1365 | 1367 | var next: usize = 0; |
| 1368 | var hit: bool = undefined; |
| 1366 | 1369 | while (true) { |
| 1367 | 1370 | var archive = &self.archives.items[next]; |
| 1368 | | var hit: bool = false; |
| 1371 | hit = false; |
| 1369 | 1372 | |
| 1370 | 1373 | for (self.symtab.items()) |entry| { |
| 1371 | 1374 | if (entry.value.tag != .Undef) continue; |
| ... | ... | @@ -1444,7 +1447,7 @@ fn resolveSymbols(self: *Zld) !void { |
| 1444 | 1447 | |
| 1445 | 1448 | fn resolveStubsAndGotEntries(self: *Zld) !void { |
| 1446 | 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}); |
| 1448 | 1451 | |
| 1449 | 1452 | for (object.sections.items) |sect| { |
| 1450 | 1453 | const relocs = sect.relocs orelse continue; |
| ... | ... | @@ -1574,7 +1577,7 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1574 | 1577 | const sym_name = object.getString(sym.inner.n_strx); |
| 1575 | 1578 | |
| 1576 | 1579 | // 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; |
| 1578 | 1581 | |
| 1579 | 1582 | const base_addr = blk: { |
| 1580 | 1583 | if (self.tlv_data_section_index) |index| { |
| ... | ... | @@ -1646,27 +1649,18 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 { |
| 1646 | 1649 | const sym_name = object.getString(sym.inner.n_strx); |
| 1647 | 1650 | |
| 1648 | 1651 | switch (sym.tag) { |
| 1649 | | .Stab => unreachable, // TODO is this even allowed to happen? |
| 1650 | | .Local, .Weak, .Strong => { |
| 1651 | | // Relocate using section offsets only. |
| 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; |
| 1652 | .Stab, .Local, .Weak, .Strong => { |
| 1653 | log.warn(" | local symbol '{s}'", .{sym_name}); |
| 1654 | break :blk sym.inner.n_value; |
| 1662 | 1655 | }, |
| 1663 | 1656 | else => { |
| 1664 | 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 | 1659 | const segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment; |
| 1667 | 1660 | const stubs = segment.sections.items[self.stubs_section_index.?]; |
| 1668 | 1661 | break :blk stubs.addr + index * stubs.reserved2; |
| 1669 | 1662 | } else if (mem.eql(u8, sym_name, "__tlv_bootstrap")) { |
| 1663 | log.warn(" | symbol '__tlv_bootstrap'", .{}); |
| 1670 | 1664 | const segment = self.load_commands.items[self.data_segment_cmd_index.?].Segment; |
| 1671 | 1665 | const tlv = segment.sections.items[self.tlv_section_index.?]; |
| 1672 | 1666 | break :blk tlv.addr; |
| ... | ... | @@ -1675,6 +1669,7 @@ fn relocTargetAddr(self: *Zld, object_id: u16, target: Relocation.Target) !u64 { |
| 1675 | 1669 | log.err("failed to resolve symbol '{s}' as a relocation target", .{sym_name}); |
| 1676 | 1670 | return error.FailedToResolveRelocationTarget; |
| 1677 | 1671 | }; |
| 1672 | log.warn(" | global symbol '{s}'", .{sym_name}); |
| 1678 | 1673 | break :blk global.inner.n_value; |
| 1679 | 1674 | } |
| 1680 | 1675 | }, |
| ... | ... | @@ -2144,8 +2139,8 @@ fn flush(self: *Zld) !void { |
| 2144 | 2139 | symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize); |
| 2145 | 2140 | } |
| 2146 | 2141 | |
| 2147 | | // try self.writeDebugInfo(); |
| 2148 | 2142 | try self.populateStringTable(); |
| 2143 | try self.writeDebugInfo(); |
| 2149 | 2144 | try self.writeSymbolTable(); |
| 2150 | 2145 | try self.writeDynamicSymbolTable(); |
| 2151 | 2146 | try self.writeStringTable(); |
| ... | ... | @@ -2556,20 +2551,10 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2556 | 2551 | }); |
| 2557 | 2552 | // Path to object file with debug info |
| 2558 | 2553 | var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; |
| 2559 | | const full_path = blk: { |
| 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(); |
| 2554 | const stat = try object.file.?.stat(); |
| 2570 | 2555 | const mtime = @intCast(u64, @divFloor(stat.mtime, 1_000_000_000)); |
| 2571 | 2556 | try stabs.append(.{ |
| 2572 | | .n_strx = try self.makeString(full_path), |
| 2557 | .n_strx = try self.makeString(object.name.?), |
| 2573 | 2558 | .n_type = macho.N_OSO, |
| 2574 | 2559 | .n_sect = 0, |
| 2575 | 2560 | .n_desc = 1, |
| ... | ... | @@ -2578,19 +2563,12 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2578 | 2563 | } |
| 2579 | 2564 | log.warn("analyzing debug info in '{s}'", .{object.name}); |
| 2580 | 2565 | |
| 2581 | | for (object.symtab.items) |source_sym| { |
| 2582 | | const symname = object.getString(source_sym.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 | | |
| 2566 | for (object.symtab.items) |sym| { |
| 2567 | const sym_name = object.getString(sym.inner.n_strx); |
| 2591 | 2568 | const maybe_size = blk: for (debug_info.inner.func_list.items) |func| { |
| 2592 | 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 | 2572 | break :blk range.end - range.start; |
| 2595 | 2573 | } |
| 2596 | 2574 | } |
| ... | ... | @@ -2600,16 +2578,16 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2600 | 2578 | try stabs.append(.{ |
| 2601 | 2579 | .n_strx = 0, |
| 2602 | 2580 | .n_type = macho.N_BNSYM, |
| 2603 | | .n_sect = target_sym.inner.n_sect, |
| 2581 | .n_sect = sym.inner.n_sect, |
| 2604 | 2582 | .n_desc = 0, |
| 2605 | | .n_value = target_sym.inner.n_value, |
| 2583 | .n_value = sym.inner.n_value, |
| 2606 | 2584 | }); |
| 2607 | 2585 | try stabs.append(.{ |
| 2608 | | .n_strx = target_sym.inner.n_strx, |
| 2586 | .n_strx = sym.inner.n_strx, |
| 2609 | 2587 | .n_type = macho.N_FUN, |
| 2610 | | .n_sect = target_sym.inner.n_sect, |
| 2588 | .n_sect = sym.inner.n_sect, |
| 2611 | 2589 | .n_desc = 0, |
| 2612 | | .n_value = target_sym.inner.n_value, |
| 2590 | .n_value = sym.inner.n_value, |
| 2613 | 2591 | }); |
| 2614 | 2592 | try stabs.append(.{ |
| 2615 | 2593 | .n_strx = 0, |
| ... | ... | @@ -2621,18 +2599,18 @@ fn writeDebugInfo(self: *Zld) !void { |
| 2621 | 2599 | try stabs.append(.{ |
| 2622 | 2600 | .n_strx = 0, |
| 2623 | 2601 | .n_type = macho.N_ENSYM, |
| 2624 | | .n_sect = target_sym.inner.n_sect, |
| 2602 | .n_sect = sym.inner.n_sect, |
| 2625 | 2603 | .n_desc = 0, |
| 2626 | 2604 | .n_value = size, |
| 2627 | 2605 | }); |
| 2628 | 2606 | } else { |
| 2629 | 2607 | // TODO need a way to differentiate symbols: global, static, local, etc. |
| 2630 | 2608 | try stabs.append(.{ |
| 2631 | | .n_strx = target_sym.inner.n_strx, |
| 2609 | .n_strx = sym.inner.n_strx, |
| 2632 | 2610 | .n_type = macho.N_STSYM, |
| 2633 | | .n_sect = target_sym.inner.n_sect, |
| 2611 | .n_sect = sym.inner.n_sect, |
| 2634 | 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 | 2646 | } |
| 2669 | 2647 | |
| 2670 | 2648 | fn 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 | 2661 | for (self.symtab.items()) |*entry| { |
| 2672 | 2662 | const n_strx = try self.makeString(entry.key); |
| 2673 | 2663 | entry.value.inner.n_strx = n_strx; |
| ... | ... | @@ -2678,10 +2668,20 @@ fn writeSymbolTable(self: *Zld) !void { |
| 2678 | 2668 | const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment; |
| 2679 | 2669 | const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab; |
| 2680 | 2670 | |
| 2681 | | // TODO figure out how to add locals |
| 2682 | 2671 | var locals = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2683 | 2672 | defer locals.deinit(); |
| 2684 | 2673 | |
| 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 | 2685 | var exports = std.ArrayList(macho.nlist_64).init(self.allocator); |
| 2686 | 2686 | defer exports.deinit(); |
| 2687 | 2687 | |