mirror of
https://github.com/ziglang/zig.git
synced 2026-01-07 05:55:36 +00:00
zld: add Symbol.Stab and move nlist creation logic there
This commit is contained in:
parent
2b3bda43e3
commit
ee6e25bc13
@ -81,6 +81,11 @@ const ar_hdr = extern struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn date(self: ar_hdr) !u64 {
|
||||
const value = getValue(&self.ar_date);
|
||||
return std.fmt.parseInt(u64, value, 10);
|
||||
}
|
||||
|
||||
fn size(self: ar_hdr) !u32 {
|
||||
const value = getValue(&self.ar_size);
|
||||
return std.fmt.parseInt(u32, value, 10);
|
||||
@ -264,6 +269,7 @@ pub fn parseObject(self: Archive, offset: u32) !*Object {
|
||||
.file = try fs.cwd().openFile(self.name.?, .{}),
|
||||
.name = name,
|
||||
.file_offset = @intCast(u32, try reader.context.getPos()),
|
||||
.mtime = try self.header.?.date(),
|
||||
};
|
||||
try object.parse();
|
||||
try reader.context.seekTo(0);
|
||||
|
||||
@ -18,7 +18,6 @@ const LibStub = @import("../tapi.zig").LibStub;
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
|
||||
arch: ?Arch = null,
|
||||
header: ?macho.mach_header_64 = null,
|
||||
file: ?fs.File = null,
|
||||
|
||||
@ -24,6 +24,7 @@ header: ?macho.mach_header_64 = null,
|
||||
file: ?fs.File = null,
|
||||
file_offset: ?u32 = null,
|
||||
name: ?[]const u8 = null,
|
||||
mtime: ?u64 = null,
|
||||
|
||||
load_commands: std.ArrayListUnmanaged(LoadCommand) = .{},
|
||||
sections: std.ArrayListUnmanaged(Section) = .{},
|
||||
@ -45,12 +46,10 @@ dwarf_debug_line_index: ?u16 = null,
|
||||
dwarf_debug_ranges_index: ?u16 = null,
|
||||
|
||||
symbols: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
stabs: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
initializers: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
data_in_code_entries: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
|
||||
|
||||
tu_path: ?[]const u8 = null,
|
||||
tu_mtime: ?u64 = null,
|
||||
|
||||
pub const Section = struct {
|
||||
inner: macho.section_64,
|
||||
code: []u8,
|
||||
@ -223,16 +222,18 @@ pub fn deinit(self: *Object) void {
|
||||
}
|
||||
self.symbols.deinit(self.allocator);
|
||||
|
||||
for (self.stabs.items) |stab| {
|
||||
stab.deinit(self.allocator);
|
||||
self.allocator.destroy(stab);
|
||||
}
|
||||
self.stabs.deinit(self.allocator);
|
||||
|
||||
self.data_in_code_entries.deinit(self.allocator);
|
||||
self.initializers.deinit(self.allocator);
|
||||
|
||||
if (self.name) |n| {
|
||||
self.allocator.free(n);
|
||||
}
|
||||
|
||||
if (self.tu_path) |tu_path| {
|
||||
self.allocator.free(tu_path);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closeFile(self: Object) void {
|
||||
@ -484,11 +485,33 @@ pub fn parseDebugInfo(self: *Object) !void {
|
||||
const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name);
|
||||
const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir);
|
||||
|
||||
self.tu_path = try std.fs.path.join(self.allocator, &[_][]const u8{ comp_dir, name });
|
||||
self.tu_mtime = mtime: {
|
||||
const stat = try self.file.?.stat();
|
||||
break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
|
||||
};
|
||||
if (self.mtime == null) {
|
||||
self.mtime = mtime: {
|
||||
const file = self.file orelse break :mtime 0;
|
||||
const stat = file.stat() catch break :mtime 0;
|
||||
break :mtime @intCast(u64, @divFloor(stat.mtime, 1_000_000_000));
|
||||
};
|
||||
}
|
||||
|
||||
try self.stabs.ensureUnusedCapacity(self.allocator, self.symbols.items.len + 4);
|
||||
|
||||
// Current dir
|
||||
self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, comp_dir, .{
|
||||
.kind = .so,
|
||||
.file = self,
|
||||
}));
|
||||
|
||||
// Artifact name
|
||||
self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, name, .{
|
||||
.kind = .so,
|
||||
.file = self,
|
||||
}));
|
||||
|
||||
// Path to object file with debug info
|
||||
self.stabs.appendAssumeCapacity(try Symbol.Stab.new(self.allocator, self.name.?, .{
|
||||
.kind = .oso,
|
||||
.file = self,
|
||||
}));
|
||||
|
||||
for (self.symbols.items) |sym| {
|
||||
if (sym.cast(Symbol.Regular)) |reg| {
|
||||
@ -500,7 +523,7 @@ pub fn parseDebugInfo(self: *Object) !void {
|
||||
}
|
||||
} else 0;
|
||||
|
||||
reg.stab = .{
|
||||
const stab = try Symbol.Stab.new(self.allocator, sym.name, .{
|
||||
.kind = kind: {
|
||||
if (size > 0) break :kind .function;
|
||||
switch (reg.linkage) {
|
||||
@ -509,9 +532,27 @@ pub fn parseDebugInfo(self: *Object) !void {
|
||||
}
|
||||
},
|
||||
.size = size,
|
||||
};
|
||||
.symbol = sym,
|
||||
.file = self,
|
||||
});
|
||||
self.stabs.appendAssumeCapacity(stab);
|
||||
} else if (sym.cast(Symbol.Tentative)) |_| {
|
||||
const stab = try Symbol.Stab.new(self.allocator, sym.name, .{
|
||||
.kind = .global,
|
||||
.size = 0,
|
||||
.symbol = sym,
|
||||
.file = self,
|
||||
});
|
||||
self.stabs.appendAssumeCapacity(stab);
|
||||
}
|
||||
}
|
||||
|
||||
// Closing delimiter.
|
||||
const delim_stab = try Symbol.Stab.new(self.allocator, "", .{
|
||||
.kind = .so,
|
||||
.file = self,
|
||||
});
|
||||
self.stabs.appendAssumeCapacity(delim_stab);
|
||||
}
|
||||
|
||||
fn readSection(self: Object, allocator: *Allocator, index: u16) ![]u8 {
|
||||
|
||||
@ -10,6 +10,7 @@ const Object = @import("Object.zig");
|
||||
const StringTable = @import("StringTable.zig");
|
||||
|
||||
pub const Type = enum {
|
||||
stab,
|
||||
regular,
|
||||
proxy,
|
||||
unresolved,
|
||||
@ -31,6 +32,151 @@ got_index: ?u32 = null,
|
||||
/// Index in stubs table for late binding.
|
||||
stubs_index: ?u32 = null,
|
||||
|
||||
pub const Stab = struct {
|
||||
base: Symbol,
|
||||
|
||||
// Symbol kind: function, etc.
|
||||
kind: Kind,
|
||||
|
||||
// Size of stab.
|
||||
size: u64,
|
||||
|
||||
// Base regular symbol for this stub if defined.
|
||||
symbol: ?*Symbol = null,
|
||||
|
||||
// null means self-reference.
|
||||
file: ?*Object = null,
|
||||
|
||||
pub const base_type: Symbol.Type = .stab;
|
||||
|
||||
pub const Kind = enum {
|
||||
so,
|
||||
oso,
|
||||
function,
|
||||
global,
|
||||
static,
|
||||
};
|
||||
|
||||
const Opts = struct {
|
||||
kind: Kind = .so,
|
||||
size: u64 = 0,
|
||||
symbol: ?*Symbol = null,
|
||||
file: ?*Object = null,
|
||||
};
|
||||
|
||||
pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
|
||||
const stab = try allocator.create(Stab);
|
||||
errdefer allocator.destroy(stab);
|
||||
|
||||
stab.* = .{
|
||||
.base = .{
|
||||
.@"type" = .stab,
|
||||
.name = try allocator.dupe(u8, name),
|
||||
},
|
||||
.kind = opts.kind,
|
||||
.size = opts.size,
|
||||
.symbol = opts.symbol,
|
||||
.file = opts.file,
|
||||
};
|
||||
|
||||
return &stab.base;
|
||||
}
|
||||
|
||||
pub fn asNlists(stab: *Stab, allocator: *Allocator, strtab: *StringTable) ![]macho.nlist_64 {
|
||||
var out = std.ArrayList(macho.nlist_64).init(allocator);
|
||||
defer out.deinit();
|
||||
if (stab.kind == .so) {
|
||||
try out.append(.{
|
||||
.n_strx = try strtab.getOrPut(stab.base.name),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
} else if (stab.kind == .oso) {
|
||||
const mtime = mtime: {
|
||||
const object = stab.file orelse break :mtime 0;
|
||||
break :mtime object.mtime orelse 0;
|
||||
};
|
||||
try out.append(.{
|
||||
.n_strx = try strtab.getOrPut(stab.base.name),
|
||||
.n_type = macho.N_OSO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 1,
|
||||
.n_value = mtime,
|
||||
});
|
||||
} else outer: {
|
||||
const symbol = stab.symbol orelse unreachable;
|
||||
const regular = symbol.getTopmostAlias().cast(Regular) orelse unreachable;
|
||||
const is_match = blk: {
|
||||
if (regular.file == null and stab.file == null) break :blk true;
|
||||
if (regular.file) |f1| {
|
||||
if (stab.file) |f2| {
|
||||
if (f1 == f2) break :blk true;
|
||||
}
|
||||
}
|
||||
break :blk false;
|
||||
};
|
||||
if (!is_match) break :outer;
|
||||
|
||||
switch (stab.kind) {
|
||||
.function => {
|
||||
try out.ensureUnusedCapacity(4);
|
||||
out.appendAssumeCapacity(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_BNSYM,
|
||||
.n_sect = regular.section,
|
||||
.n_desc = 0,
|
||||
.n_value = regular.address,
|
||||
});
|
||||
out.appendAssumeCapacity(.{
|
||||
.n_strx = try strtab.getOrPut(stab.base.name),
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = regular.section,
|
||||
.n_desc = 0,
|
||||
.n_value = regular.address,
|
||||
});
|
||||
out.appendAssumeCapacity(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
out.appendAssumeCapacity(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_ENSYM,
|
||||
.n_sect = regular.section,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
},
|
||||
.global => {
|
||||
try out.append(.{
|
||||
.n_strx = try strtab.getOrPut(stab.base.name),
|
||||
.n_type = macho.N_GSYM,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
},
|
||||
.static => {
|
||||
try out.append(.{
|
||||
.n_strx = try strtab.getOrPut(stab.base.name),
|
||||
.n_type = macho.N_STSYM,
|
||||
.n_sect = regular.section,
|
||||
.n_desc = 0,
|
||||
.n_value = regular.address,
|
||||
});
|
||||
},
|
||||
.so, .oso => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
return out.toOwnedSlice();
|
||||
}
|
||||
};
|
||||
|
||||
pub const Regular = struct {
|
||||
base: Symbol,
|
||||
|
||||
@ -50,9 +196,6 @@ pub const Regular = struct {
|
||||
/// null means self-reference.
|
||||
file: ?*Object = null,
|
||||
|
||||
/// Debug stab if defined.
|
||||
stab: ?Stab = null,
|
||||
|
||||
/// True if symbol was already committed into the final
|
||||
/// symbol table.
|
||||
visited: bool = false,
|
||||
@ -65,25 +208,12 @@ pub const Regular = struct {
|
||||
global,
|
||||
};
|
||||
|
||||
pub const Stab = struct {
|
||||
/// Stab kind
|
||||
kind: enum {
|
||||
function,
|
||||
global,
|
||||
static,
|
||||
},
|
||||
|
||||
/// Size of the stab.
|
||||
size: u64,
|
||||
};
|
||||
|
||||
const Opts = struct {
|
||||
linkage: Linkage = .translation_unit,
|
||||
address: u64 = 0,
|
||||
section: u8 = 0,
|
||||
weak_ref: bool = false,
|
||||
file: ?*Object = null,
|
||||
stab: ?Stab = null,
|
||||
};
|
||||
|
||||
pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
|
||||
@ -100,7 +230,6 @@ pub const Regular = struct {
|
||||
.section = opts.section,
|
||||
.weak_ref = opts.weak_ref,
|
||||
.file = opts.file,
|
||||
.stab = opts.stab,
|
||||
};
|
||||
|
||||
return ®.base;
|
||||
@ -304,15 +433,6 @@ pub fn getTopmostAlias(base: *Symbol) *Symbol {
|
||||
return base;
|
||||
}
|
||||
|
||||
pub fn asNlist(base: *Symbol, strtab: *StringTable) !macho.nlist_64 {
|
||||
return switch (base.tag) {
|
||||
.regular => @fieldParentPtr(Regular, "base", base).asNlist(strtab),
|
||||
.proxy => @fieldParentPtr(Proxy, "base", base).asNlist(strtab),
|
||||
.unresolved => @fieldParentPtr(Unresolved, "base", base).asNlist(strtab),
|
||||
.tentative => @fieldParentPtr(Tentative, "base", base).asNlist(strtab),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn isStab(sym: macho.nlist_64) bool {
|
||||
return (macho.N_STAB & sym.n_type) != 0;
|
||||
}
|
||||
|
||||
@ -1137,10 +1137,6 @@ fn allocateTentativeSymbols(self: *Zld) !void {
|
||||
.section = section,
|
||||
.weak_ref = false,
|
||||
.file = tent.file,
|
||||
.stab = .{
|
||||
.kind = .global,
|
||||
.size = 0,
|
||||
},
|
||||
});
|
||||
reg.got_index = tent.base.got_index;
|
||||
reg.stubs_index = tent.base.stubs_index;
|
||||
@ -2338,7 +2334,6 @@ fn flush(self: *Zld) !void {
|
||||
symtab.symoff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
}
|
||||
|
||||
try self.writeDebugInfo();
|
||||
try self.writeSymbolTable();
|
||||
try self.writeStringTable();
|
||||
|
||||
@ -2711,138 +2706,6 @@ fn writeExportInfo(self: *Zld) !void {
|
||||
try self.file.?.pwriteAll(buffer, dyld_info.export_off);
|
||||
}
|
||||
|
||||
fn writeDebugInfo(self: *Zld) !void {
|
||||
var stabs = std.ArrayList(macho.nlist_64).init(self.allocator);
|
||||
defer stabs.deinit();
|
||||
|
||||
for (self.objects.items) |object| {
|
||||
const tu_path = object.tu_path orelse continue;
|
||||
const tu_mtime = object.tu_mtime orelse continue;
|
||||
_ = tu_mtime;
|
||||
const dirname = std.fs.path.dirname(tu_path) orelse "./";
|
||||
// Current dir
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(tu_path[0 .. dirname.len + 1]),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
// Artifact name
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(tu_path[dirname.len + 1 ..]),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
// Path to object file with debug info
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(object.name.?),
|
||||
.n_type = macho.N_OSO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 1,
|
||||
.n_value = 0, //tu_mtime, TODO figure out why precalculated mtime value doesn't work
|
||||
});
|
||||
|
||||
for (object.symbols.items) |sym| {
|
||||
const reg = reg: {
|
||||
switch (sym.@"type") {
|
||||
.regular => break :reg sym.cast(Symbol.Regular) orelse unreachable,
|
||||
.tentative => {
|
||||
const final = sym.getTopmostAlias().cast(Symbol.Regular) orelse unreachable;
|
||||
if (object != final.file) continue;
|
||||
break :reg final;
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
};
|
||||
|
||||
if (reg.isTemp() or reg.stab == null) continue;
|
||||
const stab = reg.stab orelse unreachable;
|
||||
|
||||
switch (stab.kind) {
|
||||
.function => {
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_BNSYM,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_ENSYM,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = stab.size,
|
||||
});
|
||||
},
|
||||
.global => {
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_GSYM,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
},
|
||||
.static => {
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_STSYM,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Close the source file!
|
||||
try stabs.append(.{
|
||||
.n_strx = 0,
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
});
|
||||
}
|
||||
|
||||
if (stabs.items.len == 0) return;
|
||||
|
||||
// Write stabs into the symbol table
|
||||
const linkedit = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
|
||||
symtab.nsyms = @intCast(u32, stabs.items.len);
|
||||
|
||||
const stabs_off = symtab.symoff;
|
||||
const stabs_size = symtab.nsyms * @sizeOf(macho.nlist_64);
|
||||
log.debug("writing symbol stabs from 0x{x} to 0x{x}", .{ stabs_off, stabs_size + stabs_off });
|
||||
try self.file.?.pwriteAll(mem.sliceAsBytes(stabs.items), stabs_off);
|
||||
|
||||
linkedit.inner.filesize += stabs_size;
|
||||
|
||||
// Update dynamic symbol table.
|
||||
const dysymtab = &self.load_commands.items[self.dysymtab_cmd_index.?].Dysymtab;
|
||||
dysymtab.nlocalsym = symtab.nsyms;
|
||||
}
|
||||
|
||||
fn writeSymbolTable(self: *Zld) !void {
|
||||
const seg = &self.load_commands.items[self.linkedit_segment_cmd_index.?].Segment;
|
||||
const symtab = &self.load_commands.items[self.symtab_cmd_index.?].Symtab;
|
||||
@ -2854,6 +2717,15 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
defer exports.deinit();
|
||||
|
||||
for (self.objects.items) |object| {
|
||||
for (object.stabs.items) |sym| {
|
||||
const stab = sym.cast(Symbol.Stab) orelse unreachable;
|
||||
|
||||
const nlists = try stab.asNlists(self.allocator, &self.strtab);
|
||||
defer self.allocator.free(nlists);
|
||||
|
||||
try locals.appendSlice(nlists);
|
||||
}
|
||||
|
||||
for (object.symbols.items) |sym| {
|
||||
const final = sym.getTopmostAlias();
|
||||
if (final.@"type" != .regular) continue;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user