aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-07-02 00:13:46 +0200
committerJakub Konka <kubkon@jakubkonka.com>2021-07-15 18:49:46 +0200
commitee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2 (patch)
tree592e8d3db7226c8dbf79af9a3a0c0c1eb1b7b97b /src/link
parent2b3bda43e352152f0150bf2e795419cf1bcfcd90 (diff)
downloadzig-ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2.tar.gz
zig-ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2.zip
zld: add Symbol.Stab and move nlist creation logic there
Diffstat (limited to 'src/link')
-rw-r--r--src/link/MachO/Archive.zig6
-rw-r--r--src/link/MachO/Dylib.zig1
-rw-r--r--src/link/MachO/Object.zig69
-rw-r--r--src/link/MachO/Symbol.zig172
-rw-r--r--src/link/MachO/Zld.zig146
5 files changed, 216 insertions, 178 deletions
diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig
index 8f047b4968..4004cdaefc 100644
--- a/src/link/MachO/Archive.zig
+++ b/src/link/MachO/Archive.zig
@@ -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);
diff --git a/src/link/MachO/Dylib.zig b/src/link/MachO/Dylib.zig
index cfd5ae18d3..8fd4498931 100644
--- a/src/link/MachO/Dylib.zig
+++ b/src/link/MachO/Dylib.zig
@@ -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,
diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig
index 197c302316..952fbb794c 100644
--- a/src/link/MachO/Object.zig
+++ b/src/link/MachO/Object.zig
@@ -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 {
diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig
index 59a6f3d836..023e2ed7a8 100644
--- a/src/link/MachO/Symbol.zig
+++ b/src/link/MachO/Symbol.zig
@@ -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 &reg.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;
}
diff --git a/src/link/MachO/Zld.zig b/src/link/MachO/Zld.zig
index a20879f856..64e5a2af20 100644
--- a/src/link/MachO/Zld.zig
+++ b/src/link/MachO/Zld.zig
@@ -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;