authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-29 23:47:48+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-03-01 10:18:10+01:00
log9e402704e2fc01369dfbf2c9a20ac1ee7d66ca7c
tree3d7d9e687088cec8ca5495709d8daa57b859a81a
parent147beec7da5f3eb3a858037b806ad8b1b66bfffc

macho: correctly find N_GSYM symbols when parsing symbol stabs

In `ld -r` mode, the linker will emit `N_GSYM` for any defined external symbols as well as private externals. In the former case, the thing is easy since `N_EXT` bit will be set in the nlist's type. In the latter however we will encounter a local symbol with `N_PEXT` bit set (non-extern, but was private external) which we also need to include when resolving symbol stabs. The major change in the logic for parsing symbol stabs per input object file is that we no longer try to force-resolve a `N_GSYM` as a global symbol. This was a mistake since every symbol stab always describes a symbol defined within the parsed input object file. We then work out if we should forward `N_GSYM` in the output symtab after we have resolved all symbols, but never before - intel we lack when initially parsing symbol stabs. Therefore, we simply record which symbol has a debug symbol stab, and work out its precise type when emitting output symtab after symbol resolution has been done.

2 files changed, 38 insertions(+), 37 deletions(-)

src/link/MachO.zig-2
...@@ -4320,8 +4320,6 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {...@@ -4320,8 +4320,6 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
4320const default_entry_symbol_name = "_main";4320const default_entry_symbol_name = "_main";
43214321
4322pub const base_tag: link.File.Tag = link.File.Tag.macho;4322pub const base_tag: link.File.Tag = link.File.Tag.macho;
4323pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));
4324pub const N_BOUNDARY: u16 = @as(u16, @bitCast(@as(i16, -2)));
43254323
4326const Section = struct {4324const Section = struct {
4327 header: macho.section_64,4325 header: macho.section_64,
src/link/MachO/Object.zig+38-35
...@@ -590,6 +590,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -590,6 +590,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
590 const syms = self.symtab.items(.nlist);590 const syms = self.symtab.items(.nlist);
591 const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };591 const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };
592592
593 // We need to cache nlists by name so that we can properly resolve local N_GSYM stabs.
594 // What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an
595 // external or private external.
596 var addr_lookup = std.StringHashMap(u64).init(gpa);
597 defer addr_lookup.deinit();
598 for (syms) |sym| {
599 if (sym.sect() and (sym.ext() or sym.pext())) {
600 try addr_lookup.putNoClobber(self.getString(sym.n_strx), sym.n_value);
601 }
602 }
603
593 var i: u32 = start;604 var i: u32 = start;
594 while (i < end) : (i += 1) {605 while (i < end) : (i += 1) {
595 const open = syms[i];606 const open = syms[i];
...@@ -611,17 +622,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -611,17 +622,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
611 var stab: StabFile.Stab = .{};622 var stab: StabFile.Stab = .{};
612 switch (nlist.n_type) {623 switch (nlist.n_type) {
613 macho.N_BNSYM => {624 macho.N_BNSYM => {
614 stab.tag = .func;625 stab.is_func = true;
615 stab.symbol = sym_lookup.find(nlist.n_value);626 stab.symbol = sym_lookup.find(nlist.n_value);
616 // TODO validate627 // TODO validate
617 i += 3;628 i += 3;
618 },629 },
619 macho.N_GSYM => {630 macho.N_GSYM => {
620 stab.tag = .global;631 stab.is_func = false;
621 stab.symbol = macho_file.getGlobalByName(self.getString(nlist.n_strx));632 stab.symbol = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?);
622 },633 },
623 macho.N_STSYM => {634 macho.N_STSYM => {
624 stab.tag = .static;635 stab.is_func = false;
625 stab.symbol = sym_lookup.find(nlist.n_value);636 stab.symbol = sym_lookup.find(nlist.n_value);
626 },637 },
627 else => {638 else => {
...@@ -1421,11 +1432,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1421,11 +1432,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1421 const file = sym.getFile(macho_file).?;1432 const file = sym.getFile(macho_file).?;
1422 if (file.getIndex() != self.index) continue;1433 if (file.getIndex() != self.index) continue;
1423 if (!sym.flags.output_symtab) continue;1434 if (!sym.flags.output_symtab) continue;
1424 const nstabs: u32 = switch (stab.tag) {1435 const nstabs: u32 = if (stab.is_func) 4 else 1;
1425 .func => 4, // N_BNSYM, N_FUN, N_FUN, N_ENSYM
1426 .global => 1, // N_GSYM
1427 .static => 1, // N_STSYM
1428 };
1429 self.output_symtab_ctx.nstabs += nstabs;1436 self.output_symtab_ctx.nstabs += nstabs;
1430 }1437 }
1431 }1438 }
...@@ -1654,31 +1661,27 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O...@@ -1654,31 +1661,27 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1654 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;1661 const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;
1655 const sym_n_value = sym.getAddress(.{}, macho_file);1662 const sym_n_value = sym.getAddress(.{}, macho_file);
1656 const sym_size = sym.getSize(macho_file);1663 const sym_size = sym.getSize(macho_file);
1657 switch (stab.tag) {1664 if (stab.is_func) {
1658 .func => {1665 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
1659 writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);1666 index += 4;
1660 index += 4;1667 } else if (sym.visibility == .global) {
1661 },1668 ctx.symtab.items[index] = .{
1662 .global => {1669 .n_strx = sym_n_strx,
1663 ctx.symtab.items[index] = .{1670 .n_type = macho.N_GSYM,
1664 .n_strx = sym_n_strx,1671 .n_sect = sym_n_sect,
1665 .n_type = macho.N_GSYM,1672 .n_desc = 0,
1666 .n_sect = sym_n_sect,1673 .n_value = 0,
1667 .n_desc = 0,1674 };
1668 .n_value = 0,1675 index += 1;
1669 };1676 } else {
1670 index += 1;1677 ctx.symtab.items[index] = .{
1671 },1678 .n_strx = sym_n_strx,
1672 .static => {1679 .n_type = macho.N_STSYM,
1673 ctx.symtab.items[index] = .{1680 .n_sect = sym_n_sect,
1674 .n_strx = sym_n_strx,1681 .n_desc = 0,
1675 .n_type = macho.N_STSYM,1682 .n_value = sym_n_value,
1676 .n_sect = sym_n_sect,1683 };
1677 .n_desc = 0,1684 index += 1;
1678 .n_value = sym_n_value,
1679 };
1680 index += 1;
1681 },
1682 }1685 }
1683 }1686 }
16841687
...@@ -1976,7 +1979,7 @@ const StabFile = struct {...@@ -1976,7 +1979,7 @@ const StabFile = struct {
1976 }1979 }
19771980
1978 const Stab = struct {1981 const Stab = struct {
1979 tag: enum { func, global, static } = .func,1982 is_func: bool = true,
1980 symbol: ?Symbol.Index = null,1983 symbol: ?Symbol.Index = null,
19811984
1982 fn getSymbol(stab: Stab, macho_file: *MachO) ?*Symbol {1985 fn getSymbol(stab: Stab, macho_file: *MachO) ?*Symbol {