zld: abstract Symbol creation logic
This commit is contained in:
@@ -724,7 +724,7 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
|
||||
try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
|
||||
}
|
||||
} else {
|
||||
var zld = Zld.init(self.base.allocator);
|
||||
var zld = try Zld.init(self.base.allocator);
|
||||
defer {
|
||||
zld.closeFiles();
|
||||
zld.deinit();
|
||||
|
||||
@@ -146,7 +146,12 @@ pub const CreateOpts = struct {
|
||||
id: ?Id = null,
|
||||
};
|
||||
|
||||
pub fn createAndParseFromPath(allocator: *Allocator, arch: Arch, path: []const u8, opts: CreateOpts) Error!?[]*Dylib {
|
||||
pub fn createAndParseFromPath(
|
||||
allocator: *Allocator,
|
||||
arch: Arch,
|
||||
path: []const u8,
|
||||
opts: CreateOpts,
|
||||
) Error!?[]*Dylib {
|
||||
const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
|
||||
error.FileNotFound => return null,
|
||||
else => |e| return e,
|
||||
@@ -505,18 +510,7 @@ pub fn parseDependentLibs(self: *Dylib, out: *std.ArrayList(*Dylib)) !void {
|
||||
|
||||
pub fn createProxy(self: *Dylib, sym_name: []const u8) !?*Symbol {
|
||||
if (!self.symbols.contains(sym_name)) return null;
|
||||
|
||||
const name = try self.allocator.dupe(u8, sym_name);
|
||||
const proxy = try self.allocator.create(Symbol.Proxy);
|
||||
errdefer self.allocator.destroy(proxy);
|
||||
|
||||
proxy.* = .{
|
||||
.base = .{
|
||||
.@"type" = .proxy,
|
||||
.name = name,
|
||||
},
|
||||
return Symbol.Proxy.new(self.allocator, sym_name, .{
|
||||
.file = self,
|
||||
};
|
||||
|
||||
return &proxy.base;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,12 +9,12 @@ const log = std.log.scoped(.object);
|
||||
const macho = std.macho;
|
||||
const mem = std.mem;
|
||||
const reloc = @import("reloc.zig");
|
||||
const parseName = @import("Zld.zig").parseName;
|
||||
|
||||
const Allocator = mem.Allocator;
|
||||
const Arch = std.Target.Cpu.Arch;
|
||||
const Relocation = reloc.Relocation;
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const parseName = @import("Zld.zig").parseName;
|
||||
|
||||
usingnamespace @import("commands.zig");
|
||||
|
||||
@@ -437,47 +437,26 @@ pub fn parseSymbols(self: *Object) !void {
|
||||
if (Symbol.isWeakDef(sym) or Symbol.isPext(sym)) break :linkage .linkage_unit;
|
||||
break :linkage .global;
|
||||
};
|
||||
const regular = try self.allocator.create(Symbol.Regular);
|
||||
errdefer self.allocator.destroy(regular);
|
||||
regular.* = .{
|
||||
.base = .{
|
||||
.@"type" = .regular,
|
||||
.name = name,
|
||||
},
|
||||
break :symbol try Symbol.Regular.new(self.allocator, name, .{
|
||||
.linkage = linkage,
|
||||
.address = sym.n_value,
|
||||
.section = sym.n_sect - 1,
|
||||
.weak_ref = Symbol.isWeakRef(sym),
|
||||
.file = self,
|
||||
};
|
||||
break :symbol ®ular.base;
|
||||
});
|
||||
}
|
||||
|
||||
if (sym.n_value != 0) {
|
||||
const tentative = try self.allocator.create(Symbol.Tentative);
|
||||
errdefer self.allocator.destroy(tentative);
|
||||
tentative.* = .{
|
||||
.base = .{
|
||||
.@"type" = .tentative,
|
||||
.name = name,
|
||||
},
|
||||
break :symbol try Symbol.Tentative.new(self.allocator, name, .{
|
||||
.size = sym.n_value,
|
||||
.alignment = (sym.n_desc >> 8) & 0x0f,
|
||||
.file = self,
|
||||
};
|
||||
break :symbol &tentative.base;
|
||||
});
|
||||
}
|
||||
|
||||
const undef = try self.allocator.create(Symbol.Unresolved);
|
||||
errdefer self.allocator.destroy(undef);
|
||||
undef.* = .{
|
||||
.base = .{
|
||||
.@"type" = .unresolved,
|
||||
.name = name,
|
||||
},
|
||||
break :symbol try Symbol.Unresolved.new(self.allocator, name, .{
|
||||
.file = self,
|
||||
};
|
||||
break :symbol &undef.base;
|
||||
});
|
||||
};
|
||||
|
||||
try self.symbols.append(self.allocator, symbol);
|
||||
|
||||
@@ -8,7 +8,6 @@ const Allocator = mem.Allocator;
|
||||
|
||||
allocator: *Allocator,
|
||||
buffer: std.ArrayListUnmanaged(u8) = .{},
|
||||
used_offsets: std.ArrayListUnmanaged(u32) = .{},
|
||||
cache: std.StringHashMapUnmanaged(u32) = .{},
|
||||
|
||||
pub const Error = error{OutOfMemory};
|
||||
@@ -22,8 +21,13 @@ pub fn init(allocator: *Allocator) Error!StringTable {
|
||||
}
|
||||
|
||||
pub fn deinit(self: *StringTable) void {
|
||||
{
|
||||
var it = self.cache.keyIterator();
|
||||
while (it.next()) |key| {
|
||||
self.allocator.free(key.*);
|
||||
}
|
||||
}
|
||||
self.cache.deinit(self.allocator);
|
||||
self.used_offsets.deinit(self.allocator);
|
||||
self.buffer.deinit(self.allocator);
|
||||
}
|
||||
|
||||
@@ -33,8 +37,6 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {
|
||||
return off;
|
||||
}
|
||||
|
||||
const invalidate_cache = self.needsToGrow(string.len + 1);
|
||||
|
||||
try self.buffer.ensureUnusedCapacity(self.allocator, string.len + 1);
|
||||
const new_off = @intCast(u32, self.buffer.items.len);
|
||||
|
||||
@@ -43,25 +45,7 @@ pub fn getOrPut(self: *StringTable, string: []const u8) Error!u32 {
|
||||
self.buffer.appendSliceAssumeCapacity(string);
|
||||
self.buffer.appendAssumeCapacity(0);
|
||||
|
||||
if (invalidate_cache) {
|
||||
log.debug("invalidating cache", .{});
|
||||
// Re-create the cache.
|
||||
self.cache.clearRetainingCapacity();
|
||||
for (self.used_offsets.items) |off| {
|
||||
try self.cache.putNoClobber(self.allocator, self.get(off).?, off);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
log.debug("cache:", .{});
|
||||
var it = self.cache.iterator();
|
||||
while (it.next()) |entry| {
|
||||
log.debug(" | {s} => {}", .{ entry.key_ptr.*, entry.value_ptr.* });
|
||||
}
|
||||
}
|
||||
|
||||
try self.cache.putNoClobber(self.allocator, self.get(new_off).?, new_off);
|
||||
try self.used_offsets.append(self.allocator, new_off);
|
||||
try self.cache.putNoClobber(self.allocator, try self.allocator.dupe(u8, string), new_off);
|
||||
|
||||
return new_off;
|
||||
}
|
||||
@@ -78,7 +62,3 @@ pub fn asSlice(self: StringTable) []const u8 {
|
||||
pub fn size(self: StringTable) u64 {
|
||||
return self.buffer.items.len;
|
||||
}
|
||||
|
||||
fn needsToGrow(self: StringTable, needed_space: u64) bool {
|
||||
return self.buffer.capacity < needed_space + self.size();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
const Dylib = @import("Dylib.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const StringTable = @import("StringTable.zig");
|
||||
|
||||
pub const Type = enum {
|
||||
regular,
|
||||
@@ -19,7 +20,7 @@ pub const Type = enum {
|
||||
@"type": Type,
|
||||
|
||||
/// Symbol name. Owned slice.
|
||||
name: []u8,
|
||||
name: []const u8,
|
||||
|
||||
/// Alias of.
|
||||
alias: ?*Symbol = null,
|
||||
@@ -43,23 +44,14 @@ pub const Regular = struct {
|
||||
section: u8,
|
||||
|
||||
/// Whether the symbol is a weak ref.
|
||||
weak_ref: bool,
|
||||
weak_ref: bool = false,
|
||||
|
||||
/// Object file where to locate this symbol.
|
||||
file: *Object,
|
||||
/// null means self-reference.
|
||||
file: ?*Object = null,
|
||||
|
||||
/// Debug stab if defined.
|
||||
stab: ?struct {
|
||||
/// Stab kind
|
||||
kind: enum {
|
||||
function,
|
||||
global,
|
||||
static,
|
||||
},
|
||||
|
||||
/// Size of the stab.
|
||||
size: u64,
|
||||
} = null,
|
||||
stab: ?Stab = null,
|
||||
|
||||
/// True if symbol was already committed into the final
|
||||
/// symbol table.
|
||||
@@ -73,6 +65,68 @@ 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 {
|
||||
const reg = try allocator.create(Regular);
|
||||
errdefer allocator.destroy(reg);
|
||||
|
||||
reg.* = .{
|
||||
.base = .{
|
||||
.@"type" = .regular,
|
||||
.name = try allocator.dupe(u8, name),
|
||||
},
|
||||
.linkage = opts.linkage,
|
||||
.address = opts.address,
|
||||
.section = opts.section,
|
||||
.weak_ref = opts.weak_ref,
|
||||
.file = opts.file,
|
||||
.stab = opts.stab,
|
||||
};
|
||||
|
||||
return ®.base;
|
||||
}
|
||||
|
||||
pub fn asNlist(regular: *Regular, strtab: *StringTable) !macho.nlist_64 {
|
||||
const n_strx = try strtab.getOrPut(regular.base.name);
|
||||
var nlist = macho.nlist_64{
|
||||
.n_strx = n_strx,
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = regular.section,
|
||||
.n_desc = 0,
|
||||
.n_value = regular.address,
|
||||
};
|
||||
|
||||
if (regular.linkage != .translation_unit) {
|
||||
nlist.n_type |= macho.N_EXT;
|
||||
}
|
||||
if (regular.linkage == .linkage_unit) {
|
||||
nlist.n_type |= macho.N_PEXT;
|
||||
nlist.n_desc |= macho.N_WEAK_DEF;
|
||||
}
|
||||
|
||||
return nlist;
|
||||
}
|
||||
|
||||
pub fn isTemp(regular: *Regular) bool {
|
||||
if (regular.linkage == .translation_unit) {
|
||||
return mem.startsWith(u8, regular.base.name, "l") or mem.startsWith(u8, regular.base.name, "L");
|
||||
@@ -97,6 +151,36 @@ pub const Proxy = struct {
|
||||
|
||||
pub const base_type: Symbol.Type = .proxy;
|
||||
|
||||
const Opts = struct {
|
||||
file: ?*Dylib = null,
|
||||
};
|
||||
|
||||
pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
|
||||
const proxy = try allocator.create(Proxy);
|
||||
errdefer allocator.destroy(proxy);
|
||||
|
||||
proxy.* = .{
|
||||
.base = .{
|
||||
.@"type" = .proxy,
|
||||
.name = try allocator.dupe(u8, name),
|
||||
},
|
||||
.file = opts.file,
|
||||
};
|
||||
|
||||
return &proxy.base;
|
||||
}
|
||||
|
||||
pub fn asNlist(proxy: *Proxy, strtab: *StringTable) !macho.nlist_64 {
|
||||
const n_strx = try strtab.getOrPut(proxy.base.name);
|
||||
return macho.nlist_64{
|
||||
.n_strx = n_strx,
|
||||
.n_type = macho.N_UNDF | macho.N_EXT,
|
||||
.n_sect = 0,
|
||||
.n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
|
||||
.n_value = 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(proxy: *Proxy, allocator: *Allocator) void {
|
||||
proxy.bind_info.deinit(allocator);
|
||||
}
|
||||
@@ -115,6 +199,36 @@ pub const Unresolved = struct {
|
||||
file: ?*Object = null,
|
||||
|
||||
pub const base_type: Symbol.Type = .unresolved;
|
||||
|
||||
const Opts = struct {
|
||||
file: ?*Object = null,
|
||||
};
|
||||
|
||||
pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
|
||||
const undef = try allocator.create(Unresolved);
|
||||
errdefer allocator.destroy(undef);
|
||||
|
||||
undef.* = .{
|
||||
.base = .{
|
||||
.@"type" = .unresolved,
|
||||
.name = try allocator.dupe(u8, name),
|
||||
},
|
||||
.file = opts.file,
|
||||
};
|
||||
|
||||
return &undef.base;
|
||||
}
|
||||
|
||||
pub fn asNlist(undef: *Unresolved, strtab: *StringTable) !macho.nlist_64 {
|
||||
const n_strx = try strtab.getOrPut(undef.base.name);
|
||||
return macho.nlist_64{
|
||||
.n_strx = n_strx,
|
||||
.n_type = macho.N_UNDF,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Tentative = struct {
|
||||
@@ -127,13 +241,49 @@ pub const Tentative = struct {
|
||||
alignment: u16,
|
||||
|
||||
/// File where this symbol was referenced.
|
||||
file: *Object,
|
||||
file: ?*Object = null,
|
||||
|
||||
pub const base_type: Symbol.Type = .tentative;
|
||||
|
||||
const Opts = struct {
|
||||
size: u64 = 0,
|
||||
alignment: u16 = 0,
|
||||
file: ?*Object = null,
|
||||
};
|
||||
|
||||
pub fn new(allocator: *Allocator, name: []const u8, opts: Opts) !*Symbol {
|
||||
const tent = try allocator.create(Tentative);
|
||||
errdefer allocator.destroy(tent);
|
||||
|
||||
tent.* = .{
|
||||
.base = .{
|
||||
.@"type" = .tentative,
|
||||
.name = try allocator.dupe(u8, name),
|
||||
},
|
||||
.size = opts.size,
|
||||
.alignment = opts.alignment,
|
||||
.file = opts.file,
|
||||
};
|
||||
|
||||
return &tent.base;
|
||||
}
|
||||
|
||||
pub fn asNlist(tent: *Tentative, strtab: *StringTable) !macho.nlist_64 {
|
||||
// TODO
|
||||
const n_strx = try strtab.getOrPut(tent.base.name);
|
||||
return macho.nlist_64{
|
||||
.n_strx = n_strx,
|
||||
.n_type = macho.N_UNDF,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
.n_value = 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub fn deinit(base: *Symbol, allocator: *Allocator) void {
|
||||
allocator.free(base.name);
|
||||
|
||||
switch (base.@"type") {
|
||||
.proxy => @fieldParentPtr(Proxy, "base", base).deinit(allocator),
|
||||
else => {},
|
||||
@@ -154,6 +304,15 @@ 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;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ const Archive = @import("Archive.zig");
|
||||
const CodeSignature = @import("CodeSignature.zig");
|
||||
const Dylib = @import("Dylib.zig");
|
||||
const Object = @import("Object.zig");
|
||||
const StringTable = @import("StringTable.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const Trie = @import("Trie.zig");
|
||||
|
||||
@@ -24,6 +25,7 @@ usingnamespace @import("commands.zig");
|
||||
usingnamespace @import("bind.zig");
|
||||
|
||||
allocator: *Allocator,
|
||||
strtab: StringTable,
|
||||
|
||||
target: ?std.Target = null,
|
||||
page_size: ?u16 = null,
|
||||
@@ -109,9 +111,6 @@ tentatives: std.StringArrayHashMapUnmanaged(*Symbol) = .{},
|
||||
/// Set if the linker found tentative definitions in any of the objects.
|
||||
tentative_defs_offset: u64 = 0,
|
||||
|
||||
strtab: std.ArrayListUnmanaged(u8) = .{},
|
||||
strtab_dir: std.StringHashMapUnmanaged(u32) = .{},
|
||||
|
||||
threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction
|
||||
local_rebases: std.ArrayListUnmanaged(Pointer) = .{},
|
||||
stubs: std.ArrayListUnmanaged(*Symbol) = .{},
|
||||
@@ -138,8 +137,11 @@ const TlvOffset = struct {
|
||||
/// Default path to dyld
|
||||
const DEFAULT_DYLD_PATH: [*:0]const u8 = "/usr/lib/dyld";
|
||||
|
||||
pub fn init(allocator: *Allocator) Zld {
|
||||
return .{ .allocator = allocator };
|
||||
pub fn init(allocator: *Allocator) !Zld {
|
||||
return Zld{
|
||||
.allocator = allocator,
|
||||
.strtab = try StringTable.init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Zld) void {
|
||||
@@ -180,15 +182,7 @@ pub fn deinit(self: *Zld) void {
|
||||
self.tentatives.deinit(self.allocator);
|
||||
self.globals.deinit(self.allocator);
|
||||
self.unresolved.deinit(self.allocator);
|
||||
self.strtab.deinit(self.allocator);
|
||||
|
||||
{
|
||||
var it = self.strtab_dir.keyIterator();
|
||||
while (it.next()) |key| {
|
||||
self.allocator.free(key.*);
|
||||
}
|
||||
}
|
||||
self.strtab_dir.deinit(self.allocator);
|
||||
self.strtab.deinit();
|
||||
}
|
||||
|
||||
pub fn closeFiles(self: Zld) void {
|
||||
@@ -1137,16 +1131,7 @@ fn allocateTentativeSymbols(self: *Zld) !void {
|
||||
// Convert tentative definitions into regular symbols.
|
||||
for (self.tentatives.values()) |sym| {
|
||||
const tent = sym.cast(Symbol.Tentative) orelse unreachable;
|
||||
const reg = try self.allocator.create(Symbol.Regular);
|
||||
errdefer self.allocator.destroy(reg);
|
||||
|
||||
reg.* = .{
|
||||
.base = .{
|
||||
.@"type" = .regular,
|
||||
.name = try self.allocator.dupe(u8, tent.base.name),
|
||||
.got_index = tent.base.got_index,
|
||||
.stubs_index = tent.base.stubs_index,
|
||||
},
|
||||
const reg = try Symbol.Regular.new(self.allocator, tent.base.name, .{
|
||||
.linkage = .global,
|
||||
.address = base_address,
|
||||
.section = section,
|
||||
@@ -1156,16 +1141,18 @@ fn allocateTentativeSymbols(self: *Zld) !void {
|
||||
.kind = .global,
|
||||
.size = 0,
|
||||
},
|
||||
};
|
||||
});
|
||||
reg.got_index = tent.base.got_index;
|
||||
reg.stubs_index = tent.base.stubs_index;
|
||||
|
||||
try self.globals.putNoClobber(self.allocator, reg.base.name, ®.base);
|
||||
tent.base.alias = ®.base;
|
||||
try self.globals.putNoClobber(self.allocator, reg.name, reg);
|
||||
tent.base.alias = reg;
|
||||
|
||||
if (tent.base.got_index) |idx| {
|
||||
self.got_entries.items[idx] = ®.base;
|
||||
self.got_entries.items[idx] = reg;
|
||||
}
|
||||
if (tent.base.stubs_index) |idx| {
|
||||
self.stubs.items[idx] = ®.base;
|
||||
self.stubs.items[idx] = reg;
|
||||
}
|
||||
|
||||
const address = mem.alignForwardGeneric(u64, base_address + tent.size, alignment);
|
||||
@@ -1615,15 +1602,8 @@ fn resolveSymbols(self: *Zld) !void {
|
||||
{
|
||||
const name = try self.allocator.dupe(u8, "dyld_stub_binder");
|
||||
errdefer self.allocator.free(name);
|
||||
const undef = try self.allocator.create(Symbol.Unresolved);
|
||||
errdefer self.allocator.destroy(undef);
|
||||
undef.* = .{
|
||||
.base = .{
|
||||
.@"type" = .unresolved,
|
||||
.name = name,
|
||||
},
|
||||
};
|
||||
try unresolved.append(&undef.base);
|
||||
const undef = try Symbol.Unresolved.new(self.allocator, name, .{});
|
||||
try unresolved.append(undef);
|
||||
}
|
||||
|
||||
var referenced = std.AutoHashMap(*Dylib, void).init(self.allocator);
|
||||
@@ -1641,16 +1621,7 @@ fn resolveSymbols(self: *Zld) !void {
|
||||
// TODO this is just a temp patch until I work out what to actually
|
||||
// do with ___dso_handle and __mh_execute_header symbols which are
|
||||
// synthetically created by the linker on macOS.
|
||||
const name = try self.allocator.dupe(u8, undef.name);
|
||||
const proxy = try self.allocator.create(Symbol.Proxy);
|
||||
errdefer self.allocator.destroy(proxy);
|
||||
proxy.* = .{
|
||||
.base = .{
|
||||
.@"type" = .proxy,
|
||||
.name = name,
|
||||
},
|
||||
};
|
||||
break :inner &proxy.base;
|
||||
break :inner try Symbol.Proxy.new(self.allocator, undef.name, .{});
|
||||
}
|
||||
|
||||
self.unresolved.putAssumeCapacityNoClobber(undef.name, undef);
|
||||
@@ -2126,7 +2097,6 @@ fn populateMetadata(self: *Zld) !void {
|
||||
.strsize = 0,
|
||||
},
|
||||
});
|
||||
try self.strtab.append(self.allocator, 0);
|
||||
}
|
||||
|
||||
if (self.dysymtab_cmd_index == null) {
|
||||
@@ -2752,7 +2722,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
const dirname = std.fs.path.dirname(tu_path) orelse "./";
|
||||
// Current dir
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(tu_path[0 .. dirname.len + 1]),
|
||||
.n_strx = try self.strtab.getOrPut(tu_path[0 .. dirname.len + 1]),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
@@ -2760,7 +2730,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
});
|
||||
// Artifact name
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(tu_path[dirname.len + 1 ..]),
|
||||
.n_strx = try self.strtab.getOrPut(tu_path[dirname.len + 1 ..]),
|
||||
.n_type = macho.N_SO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
@@ -2768,7 +2738,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
});
|
||||
// Path to object file with debug info
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(object.name.?),
|
||||
.n_strx = try self.strtab.getOrPut(object.name.?),
|
||||
.n_type = macho.N_OSO,
|
||||
.n_sect = 0,
|
||||
.n_desc = 1,
|
||||
@@ -2801,7 +2771,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_FUN,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
@@ -2824,7 +2794,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
},
|
||||
.global => {
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_GSYM,
|
||||
.n_sect = 0,
|
||||
.n_desc = 0,
|
||||
@@ -2833,7 +2803,7 @@ fn writeDebugInfo(self: *Zld) !void {
|
||||
},
|
||||
.static => {
|
||||
try stabs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_strx = try self.strtab.getOrPut(sym.name),
|
||||
.n_type = macho.N_STSYM,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
@@ -2892,24 +2862,14 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
if (reg.isTemp()) continue;
|
||||
if (reg.visited) continue;
|
||||
|
||||
const nlist = try reg.asNlist(&self.strtab);
|
||||
|
||||
switch (reg.linkage) {
|
||||
.translation_unit => {
|
||||
try locals.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try locals.append(nlist);
|
||||
},
|
||||
else => {
|
||||
try exports.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_SECT | macho.N_EXT,
|
||||
.n_sect = reg.section,
|
||||
.n_desc = 0,
|
||||
.n_value = reg.address,
|
||||
});
|
||||
try exports.append(nlist);
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2922,13 +2882,8 @@ fn writeSymbolTable(self: *Zld) !void {
|
||||
|
||||
for (self.imports.values()) |sym| {
|
||||
const proxy = sym.cast(Symbol.Proxy) orelse unreachable;
|
||||
try undefs.append(.{
|
||||
.n_strx = try self.makeString(sym.name),
|
||||
.n_type = macho.N_UNDF | macho.N_EXT,
|
||||
.n_sect = 0,
|
||||
.n_desc = (proxy.dylibOrdinal() * macho.N_SYMBOL_RESOLVER) | macho.REFERENCE_FLAG_UNDEFINED_NON_LAZY,
|
||||
.n_value = 0,
|
||||
});
|
||||
const nlist = try proxy.asNlist(&self.strtab);
|
||||
try undefs.append(nlist);
|
||||
}
|
||||
|
||||
const nlocals = locals.items.len;
|
||||
@@ -3017,14 +2972,14 @@ fn writeStringTable(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;
|
||||
symtab.stroff = @intCast(u32, seg.inner.fileoff + seg.inner.filesize);
|
||||
symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.items.len, @alignOf(u64)));
|
||||
symtab.strsize = @intCast(u32, mem.alignForwardGeneric(u64, self.strtab.size(), @alignOf(u64)));
|
||||
seg.inner.filesize += symtab.strsize;
|
||||
|
||||
log.debug("writing string table from 0x{x} to 0x{x}", .{ symtab.stroff, symtab.stroff + symtab.strsize });
|
||||
|
||||
try self.file.?.pwriteAll(self.strtab.items, symtab.stroff);
|
||||
try self.file.?.pwriteAll(self.strtab.asSlice(), symtab.stroff);
|
||||
|
||||
if (symtab.strsize > self.strtab.items.len and self.target.?.cpu.arch == .x86_64) {
|
||||
if (symtab.strsize > self.strtab.size() and self.target.?.cpu.arch == .x86_64) {
|
||||
// This is the last section, so we need to pad it out.
|
||||
try self.file.?.pwriteAll(&[_]u8{0}, seg.inner.fileoff + seg.inner.filesize - 1);
|
||||
}
|
||||
@@ -3173,26 +3128,6 @@ fn writeHeader(self: *Zld) !void {
|
||||
try self.file.?.pwriteAll(mem.asBytes(&header), 0);
|
||||
}
|
||||
|
||||
fn makeString(self: *Zld, bytes: []const u8) !u32 {
|
||||
if (self.strtab_dir.get(bytes)) |offset| {
|
||||
log.debug("reusing '{s}' from string table at offset 0x{x}", .{ bytes, offset });
|
||||
return offset;
|
||||
}
|
||||
|
||||
try self.strtab.ensureCapacity(self.allocator, self.strtab.items.len + bytes.len + 1);
|
||||
const offset = @intCast(u32, self.strtab.items.len);
|
||||
log.debug("writing new string '{s}' into string table at offset 0x{x}", .{ bytes, offset });
|
||||
self.strtab.appendSliceAssumeCapacity(bytes);
|
||||
self.strtab.appendAssumeCapacity(0);
|
||||
try self.strtab_dir.putNoClobber(self.allocator, try self.allocator.dupe(u8, bytes), offset);
|
||||
return offset;
|
||||
}
|
||||
|
||||
fn getString(self: *const Zld, str_off: u32) []const u8 {
|
||||
assert(str_off < self.strtab.items.len);
|
||||
return mem.spanZ(@ptrCast([*:0]const u8, self.strtab.items.ptr + str_off));
|
||||
}
|
||||
|
||||
pub fn parseName(name: *const [16]u8) []const u8 {
|
||||
const len = mem.indexOfScalar(u8, name, @as(u8, 0)) orelse name.len;
|
||||
return name[0..len];
|
||||
|
||||
Reference in New Issue
Block a user