diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-02 00:13:46 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2021-07-15 18:49:46 +0200 |
| commit | ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2 (patch) | |
| tree | 592e8d3db7226c8dbf79af9a3a0c0c1eb1b7b97b /src | |
| parent | 2b3bda43e352152f0150bf2e795419cf1bcfcd90 (diff) | |
| download | zig-ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2.tar.gz zig-ee6e25bc13b3f23b5f2fd0c8b57f0d115c239fc2.zip | |
zld: add Symbol.Stab and move nlist creation logic there
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO/Archive.zig | 6 | ||||
| -rw-r--r-- | src/link/MachO/Dylib.zig | 1 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 69 | ||||
| -rw-r--r-- | src/link/MachO/Symbol.zig | 172 | ||||
| -rw-r--r-- | src/link/MachO/Zld.zig | 146 |
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 ®.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; |
