srctree

Jakub Konka parent 147beec7 9e402704
macho: correctly find N_GSYM symbols when parsing symbol stabs

In ld -r mode, the linker will emit N_GSYM for any definedexternal 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_PEXTbit set (non-extern, but was private external) which we also needto include when resolving symbol stabs.

The major change in the logic for parsing symbol stabs per inputobject file is that we no longer try to force-resolve a N_GSYMas a global symbol. This was a mistake since every symbol stabalways describes a symbol defined within the parsed input object file.We then work out if we should forward N_GSYM in the output symtabafter we have resolved all symbols, but never before - intel we lackwhen initially parsing symbol stabs. Therefore, we simply recordwhich symbol has a debug symbol stab, and work out its precise typewhen emitting output symtab after symbol resolution has been done.

inlinesplit
src/link/MachO.zig added: 40, removed: 39, total 1
@@ -4320,8 +4320,6 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
const default_entry_symbol_name = "_main";
 
pub const base_tag: link.File.Tag = link.File.Tag.macho;
pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));
pub const N_BOUNDARY: u16 = @as(u16, @bitCast(@as(i16, -2)));
 
const Section = struct {
header: macho.section_64,
 
src/link/MachO/Object.zig added: 40, removed: 39, total 1
@@ -590,6 +590,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
const syms = self.symtab.items(.nlist);
const sym_lookup = SymbolLookup{ .ctx = self, .entries = nlists };
 
// We need to cache nlists by name so that we can properly resolve local N_GSYM stabs.
// What happens is `ld -r` will emit an N_GSYM stab for a symbol that may be either an
// external or private external.
var addr_lookup = std.StringHashMap(u64).init(gpa);
defer addr_lookup.deinit();
for (syms) |sym| {
if (sym.sect() and (sym.ext() or sym.pext())) {
try addr_lookup.putNoClobber(self.getString(sym.n_strx), sym.n_value);
}
}
 
var i: u32 = start;
while (i < end) : (i += 1) {
const open = syms[i];
@@ -611,17 +622,17 @@ fn initSymbolStabs(self: *Object, nlists: anytype, macho_file: *MachO) !void {
var stab: StabFile.Stab = .{};
switch (nlist.n_type) {
macho.N_BNSYM => {
stab.tag = .func;
stab.is_func = true;
stab.symbol = sym_lookup.find(nlist.n_value);
// TODO validate
i += 3;
},
macho.N_GSYM => {
stab.tag = .global;
stab.symbol = macho_file.getGlobalByName(self.getString(nlist.n_strx));
stab.is_func = false;
stab.symbol = sym_lookup.find(addr_lookup.get(self.getString(nlist.n_strx)).?);
},
macho.N_STSYM => {
stab.tag = .static;
stab.is_func = false;
stab.symbol = sym_lookup.find(nlist.n_value);
},
else => {
@@ -1421,11 +1432,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
const file = sym.getFile(macho_file).?;
if (file.getIndex() != self.index) continue;
if (!sym.flags.output_symtab) continue;
const nstabs: u32 = switch (stab.tag) {
.func => 4, // N_BNSYM, N_FUN, N_FUN, N_ENSYM
.global => 1, // N_GSYM
.static => 1, // N_STSYM
};
const nstabs: u32 = if (stab.is_func) 4 else 1;
self.output_symtab_ctx.nstabs += nstabs;
}
}
@@ -1654,31 +1661,27 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
const sym_n_sect: u8 = if (!sym.flags.abs) @intCast(sym.out_n_sect + 1) else 0;
const sym_n_value = sym.getAddress(.{}, macho_file);
const sym_size = sym.getSize(macho_file);
switch (stab.tag) {
.func => {
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
index += 4;
},
.global => {
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_GSYM,
.n_sect = sym_n_sect,
.n_desc = 0,
.n_value = 0,
};
index += 1;
},
.static => {
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_STSYM,
.n_sect = sym_n_sect,
.n_desc = 0,
.n_value = sym_n_value,
};
index += 1;
},
if (stab.is_func) {
writeFuncStab(sym_n_strx, sym_n_sect, sym_n_value, sym_size, index, ctx);
index += 4;
} else if (sym.visibility == .global) {
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_GSYM,
.n_sect = sym_n_sect,
.n_desc = 0,
.n_value = 0,
};
index += 1;
} else {
ctx.symtab.items[index] = .{
.n_strx = sym_n_strx,
.n_type = macho.N_STSYM,
.n_sect = sym_n_sect,
.n_desc = 0,
.n_value = sym_n_value,
};
index += 1;
}
}
 
@@ -1976,7 +1979,7 @@ const StabFile = struct {
}
 
const Stab = struct {
tag: enum { func, global, static } = .func,
is_func: bool = true,
symbol: ?Symbol.Index = null,
 
fn getSymbol(stab: Stab, macho_file: *MachO) ?*Symbol {