Merge pull request #20971 from ziglang/elf-ownership-2

elf: move ownership of symbols into owning objects
This commit is contained in:
Jakub Konka 2024-08-08 00:27:36 +02:00 committed by GitHub
commit cfe6ff4301
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1623 additions and 1245 deletions

View File

@ -4354,8 +4354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, pt)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });

View File

@ -4336,8 +4336,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, pt)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
const got_addr: u32 = @intCast(sym.zigGotAddress(elf_file));
try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });

View File

@ -1409,14 +1409,14 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
defer func.register_manager.unlockReg(data_lock);
const elf_file = func.bin_file.cast(link.File.Elf).?;
const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, .{
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, .{
.kind = .const_data,
.ty = enum_ty,
}) catch |err|
return func.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym = elf_file.symbol(sym_index);
try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym.esym_index } });
try func.genSetReg(Type.u64, data_reg, .{ .lea_symbol = .{ .sym = sym_index } });
const cmp_reg, const cmp_lock = try func.allocReg(.int);
defer func.register_manager.unlockReg(cmp_lock);
@ -4946,13 +4946,13 @@ fn genCall(
}) {
.func => |func_val| {
if (func.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func_val.owner_decl);
if (func.mod.pic) {
return func.fail("TODO: genCall pic", .{});
} else {
try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } });
_ = try func.addInst(.{
.tag = .jalr,
.data = .{ .i_type = .{
@ -7822,14 +7822,14 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
const lazy_sym = link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(zcu), zcu);
const elf_file = func.bin_file.cast(link.File.Elf).?;
const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
return func.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym = elf_file.symbol(sym_index);
if (func.mod.pic) {
return func.fail("TODO: airTagName pic", .{});
} else {
try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym_index } });
_ = try func.addInst(.{
.tag = .jalr,
.data = .{ .i_type = .{
@ -8047,11 +8047,7 @@ fn genTypedValue(func: *Func, val: Value) InnerError!MCValue {
return error.CodegenFail;
};
switch (lf.tag) {
.elf => {
const elf_file = lf.cast(link.File.Elf).?;
const local = elf_file.symbol(local_sym_index);
return MCValue{ .undef = local.esym_index };
},
.elf => return MCValue{ .undef = local_sym_index },
else => unreachable,
}
}

View File

@ -50,16 +50,16 @@ pub fn emitMir(emit: *Emit) Error!void {
};
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);
const sym = elf_file.symbol(sym_index);
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
const sym = zo.symbol(symbol.sym_index);
var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
_ = try sym.getOrCreateZigGotEntry(symbol.sym_index, elf_file);
hi_r_type = Elf.R_ZIG_GOT_HI20;
lo_r_type = Elf.R_ZIG_GOT_LO12;
@ -82,8 +82,9 @@ pub fn emitMir(emit: *Emit) Error!void {
},
.load_tlv_reloc => |symbol| {
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
const R_RISCV = std.elf.R_RISCV;
@ -107,7 +108,8 @@ pub fn emitMir(emit: *Emit) Error!void {
},
.call_extern_fn_reloc => |symbol| {
const elf_file = emit.bin_file.cast(link.File.Elf).?;
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);

View File

@ -1354,8 +1354,9 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
.func => |func| {
const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = zo.symbol(sym_index);
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
} else unreachable;

View File

@ -12327,8 +12327,8 @@ fn genCall(self: *Self, info: union(enum) {
}) {
.func => |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
if (self.mod.pic) {
const callee_reg: Register = switch (resolved_cc) {
.SysV => callee: {
@ -12345,14 +12345,14 @@ fn genCall(self: *Self, info: union(enum) {
try self.genSetReg(
callee_reg,
Type.usize,
.{ .load_symbol = .{ .sym = sym.esym_index } },
.{ .load_symbol = .{ .sym = sym_index } },
.{},
);
try self.asmRegister(.{ ._, .call }, callee_reg);
} else try self.asmMemory(.{ ._, .call }, .{
.base = .{ .reloc = .{
.atom_index = try self.owner.getSymbolIndex(self),
.sym_index = sym.esym_index,
.sym_index = sym_index,
} },
.mod = .{ .rm = .{ .size = .qword } },
});
@ -15320,16 +15320,16 @@ fn genLazySymbolRef(
) InnerError!void {
const pt = self.pt;
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
const zo = elf_file.zigObjectPtr().?;
const sym_index = zo.getOrCreateMetadataForLazySymbol(elf_file, pt, lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
const sym = elf_file.symbol(sym_index);
if (self.mod.pic) {
switch (tag) {
.lea, .call => try self.genSetReg(reg, Type.usize, .{
.load_symbol = .{ .sym = sym.esym_index },
.load_symbol = .{ .sym = sym_index },
}, .{}),
.mov => try self.genSetReg(reg, Type.usize, .{
.load_symbol = .{ .sym = sym.esym_index },
.load_symbol = .{ .sym = sym_index },
}, .{}),
else => unreachable,
}
@ -15341,7 +15341,7 @@ fn genLazySymbolRef(
} else {
const reloc = bits.Symbol{
.atom_index = try self.owner.getSymbolIndex(self),
.sym_index = sym.esym_index,
.sym_index = sym_index,
};
switch (tag) {
.lea, .mov => try self.asmRegisterMemory(.{ ._, .mov }, reg.to64(), .{

View File

@ -42,7 +42,8 @@ pub fn emitMir(emit: *Emit) Error!void {
}),
.linker_extern_fn => |symbol| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
// Add relocation to the decl.
const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
const zo = elf_file.zigObjectPtr().?;
const atom_ptr = zo.symbol(symbol.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.PLT32);
try atom_ptr.addReloc(elf_file, .{
.r_offset = end_offset - 4,
@ -88,7 +89,8 @@ pub fn emitMir(emit: *Emit) Error!void {
}),
.linker_tlsld => |data| {
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.TLSLD);
try atom.addReloc(elf_file, .{
.r_offset = end_offset - 4,
@ -98,7 +100,8 @@ pub fn emitMir(emit: *Emit) Error!void {
},
.linker_dtpoff => |data| {
const elf_file = emit.lower.bin_file.cast(link.File.Elf).?;
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const r_type = @intFromEnum(std.elf.R_X86_64.DTPOFF32);
try atom.addReloc(elf_file, .{
.r_offset = end_offset - 4,
@ -112,11 +115,11 @@ pub fn emitMir(emit: *Emit) Error!void {
.Obj => true,
.Lib => emit.lower.link_mode == .static,
};
const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
const sym_index = elf_file.zigObjectPtr().?.symbol(data.sym_index);
const sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const atom = zo.symbol(data.atom_index).atom(elf_file).?;
const sym = zo.symbol(data.sym_index);
if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
_ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
_ = try sym.getOrCreateZigGotEntry(data.sym_index, elf_file);
}
if (emit.lower.pic) {
const r_type: u32 = if (sym.flags.needs_zig_got and !is_obj_or_static_lib)

View File

@ -349,8 +349,8 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
assert(mem_op.sib.scale_index.scale == 0);
if (lower.bin_file.cast(link.File.Elf)) |elf_file| {
const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
const elf_sym = elf_file.symbol(sym_index);
const zo = elf_file.zigObjectPtr().?;
const elf_sym = zo.symbol(sym.sym_index);
if (elf_sym.flags.is_tls) {
// TODO handle extern TLS vars, i.e., emit GD model

View File

@ -906,20 +906,20 @@ fn genDeclRef(
const is_extern = decl.isExtern(zcu);
if (lf.cast(link.File.Elf)) |elf_file| {
const zo = elf_file.zigObjectPtr().?;
if (is_extern) {
const name = decl.name.toSlice(ip);
// TODO audit this
const lib_name = if (decl.getOwnedVariable(zcu)) |ov| ov.lib_name.toSlice(ip) else null;
const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;
zo.symbol(sym_index).flags.needs_got = true;
return GenResult.mcv(.{ .load_symbol = sym_index });
}
const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
const sym = elf_file.symbol(sym_index);
const sym_index = try zo.getOrCreateMetadataForDecl(elf_file, decl_index);
if (is_threadlocal) {
return GenResult.mcv(.{ .load_tlv = sym.esym_index });
return GenResult.mcv(.{ .load_tlv = sym_index });
}
return GenResult.mcv(.{ .load_symbol = sym.esym_index });
return GenResult.mcv(.{ .load_symbol = sym_index });
} else if (lf.cast(link.File.MachO)) |macho_file| {
const zo = macho_file.getZigObject().?;
if (is_extern) {
@ -971,9 +971,7 @@ fn genUnnamedConst(
};
switch (lf.tag) {
.elf => {
const elf_file = lf.cast(link.File.Elf).?;
const local = elf_file.symbol(local_sym_index);
return GenResult.mcv(.{ .load_symbol = local.esym_index });
return GenResult.mcv(.{ .load_symbol = local_sym_index });
},
.macho => {
const macho_file = lf.cast(link.File.MachO).?;

View File

@ -173,12 +173,7 @@ shstrtab_section_index: ?u32 = null,
strtab_section_index: ?u32 = null,
symtab_section_index: ?u32 = null,
/// An array of symbols parsed across all input files.
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
resolver: SymbolResolver = .{},
has_text_reloc: bool = false,
num_ifunc_dynrelocs: usize = 0,
@ -192,10 +187,6 @@ merge_sections: std.ArrayListUnmanaged(MergeSection) = .{},
/// Table of last atom index in a section and matching atom free list if any.
last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
/// Global string table used to provide quick access to global symbol resolvers
/// such as `resolver`.
strings: StringTable = .{},
first_eflags: ?elf.Elf64_Word = null,
/// When allocating, the ideal_capacity is calculated by
@ -341,10 +332,6 @@ pub fn createEmpty(
const gpa = comp.gpa;
// Index 0 is always a null symbol.
try self.symbols.append(gpa, .{});
// Index 0 is always a null symbol.
try self.symbols_extra.append(gpa, 0);
// Append null file at index 0
try self.files.append(gpa, .null);
// Append null byte to string tables
@ -460,9 +447,6 @@ pub fn deinit(self: *Elf) void {
self.shstrtab.deinit(gpa);
self.symtab.deinit(gpa);
self.strtab.deinit(gpa);
self.symbols.deinit(gpa);
self.symbols_extra.deinit(gpa);
self.symbols_free_list.deinit(gpa);
self.resolver.deinit(gpa);
for (self.thunks.items) |*th| {
@ -478,8 +462,6 @@ pub fn deinit(self: *Elf) void {
}
self.last_atom_and_free_list_table.deinit(gpa);
self.strings.deinit(gpa);
self.got.deinit(gpa);
self.plt.deinit(gpa);
self.plt_got.deinit(gpa);
@ -1300,6 +1282,9 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod
try self.finalizeMergeSections();
try self.initOutputSections();
try self.initMergeSections();
if (self.linkerDefinedPtr()) |obj| {
try obj.initStartStopSymbols(self);
}
self.claimUnresolved();
// Scan and create missing synthetic entries such as GOT indirection.
@ -1922,20 +1907,17 @@ fn accessLibPath(
/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
pub fn resolveSymbols(self: *Elf) !void {
// Resolve symbols in the ZigObject. For now, we assume that it's always live.
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
// Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
// Mark live objects.
self.markLive();
// Reset state of all globals after marking live objects.
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
if (self.linkerDefinedPtr()) |obj| obj.asFile().resetGlobals(self);
self.resolver.reset();
// Prune dead objects and shared objects.
var i: usize = 0;
@ -1968,10 +1950,10 @@ pub fn resolveSymbols(self: *Elf) !void {
}
// Re-resolve the symbols.
if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| obj.asFile().resolveSymbols(self);
if (self.zigObjectPtr()) |zo| try zo.asFile().resolveSymbols(self);
for (self.objects.items) |index| try self.file(index).?.resolveSymbols(self);
for (self.shared_objects.items) |index| try self.file(index).?.resolveSymbols(self);
if (self.linkerDefinedPtr()) |obj| try obj.asFile().resolveSymbols(self);
}
/// Traverses all objects and shared objects marking any object referenced by
@ -2005,46 +1987,17 @@ fn convertCommonSymbols(self: *Elf) !void {
}
fn markImportsExports(self: *Elf) void {
const mark = struct {
fn mark(elf_file: *Elf, file_index: File.Index) void {
for (elf_file.file(file_index).?.globals()) |global_index| {
const global = elf_file.symbol(global_index);
if (global.version_index == elf.VER_NDX_LOCAL) continue;
const file_ptr = global.file(elf_file) orelse continue;
const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
if (vis == .HIDDEN) continue;
if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
global.flags.import = true;
continue;
}
if (file_ptr.index() == file_index) {
global.flags.@"export" = true;
if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
global.flags.import = true;
}
}
}
}
}.mark;
if (self.zigObjectPtr()) |zo| {
zo.markImportsExports(self);
}
for (self.objects.items) |index| {
self.file(index).?.object.markImportsExports(self);
}
if (!self.isEffectivelyDynLib()) {
for (self.shared_objects.items) |index| {
for (self.file(index).?.globals()) |global_index| {
const global = self.symbol(global_index);
const file_ptr = global.file(self) orelse continue;
const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
}
self.file(index).?.shared_object.markImportExports(self);
}
}
if (self.zig_object_index) |index| {
mark(self, index);
}
for (self.objects.items) |index| {
mark(self, index);
}
}
fn claimUnresolved(self: *Elf) void {
@ -2063,22 +2016,27 @@ fn claimUnresolved(self: *Elf) void {
fn scanRelocs(self: *Elf) !void {
const gpa = self.base.comp.gpa;
var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
defer {
var it = undefs.iterator();
while (it.next()) |entry| {
entry.value_ptr.deinit();
for (undefs.values()) |*refs| {
refs.deinit();
}
undefs.deinit();
}
var objects = try std.ArrayList(File.Index).initCapacity(gpa, self.objects.items.len + 1);
defer objects.deinit();
if (self.zigObjectPtr()) |zo| objects.appendAssumeCapacity(zo.index);
objects.appendSliceAssumeCapacity(self.objects.items);
var has_reloc_errors = false;
for (objects.items) |index| {
if (self.zigObjectPtr()) |zo| {
zo.asFile().scanRelocs(self, &undefs) catch |err| switch (err) {
error.RelaxFailure => unreachable,
error.UnsupportedCpuArch => {
try self.reportUnsupportedCpuArch();
return error.FlushFailure;
},
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
};
}
for (self.objects.items) |index| {
self.file(index).?.scanRelocs(self, &undefs) catch |err| switch (err) {
error.RelaxFailure => unreachable,
error.UnsupportedCpuArch => {
@ -2094,47 +2052,18 @@ fn scanRelocs(self: *Elf) !void {
if (has_reloc_errors) return error.FlushFailure;
for (self.symbols.items, 0..) |*sym, i| {
const index = @as(u32, @intCast(i));
if (!sym.isLocal(self) and !sym.flags.has_dynamic) {
log.debug("'{s}' is non-local", .{sym.name(self)});
try self.dynsym.addSymbol(index, self);
}
if (sym.flags.needs_got) {
log.debug("'{s}' needs GOT", .{sym.name(self)});
_ = try self.got.addGotSymbol(index, self);
}
if (sym.flags.needs_plt) {
if (sym.flags.is_canonical) {
log.debug("'{s}' needs CPLT", .{sym.name(self)});
sym.flags.@"export" = true;
try self.plt.addSymbol(index, self);
} else if (sym.flags.needs_got) {
log.debug("'{s}' needs PLTGOT", .{sym.name(self)});
try self.plt_got.addSymbol(index, self);
} else {
log.debug("'{s}' needs PLT", .{sym.name(self)});
try self.plt.addSymbol(index, self);
}
}
if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
log.debug("'{s}' needs COPYREL", .{sym.name(self)});
try self.copy_rel.addSymbol(index, self);
}
if (sym.flags.needs_tlsgd) {
log.debug("'{s}' needs TLSGD", .{sym.name(self)});
try self.got.addTlsGdSymbol(index, self);
}
if (sym.flags.needs_gottp) {
log.debug("'{s}' needs GOTTP", .{sym.name(self)});
try self.got.addGotTpSymbol(index, self);
}
if (sym.flags.needs_tlsdesc) {
log.debug("'{s}' needs TLSDESC", .{sym.name(self)});
try self.got.addTlsDescSymbol(index, self);
}
if (self.zigObjectPtr()) |zo| {
try zo.asFile().createSymbolIndirection(self);
}
for (self.objects.items) |index| {
try self.file(index).?.createSymbolIndirection(self);
}
for (self.shared_objects.items) |index| {
try self.file(index).?.createSymbolIndirection(self);
}
if (self.linkerDefinedPtr()) |obj| {
try obj.asFile().createSymbolIndirection(self);
}
if (self.got.flags.needs_tlsld) {
log.debug("program needs TLSLD", .{});
try self.got.addTlsLdSymbol(self);
@ -2911,8 +2840,8 @@ pub fn writeElfHeader(self: *Elf) !void {
index += 4;
const e_entry: u64 = if (self.linkerDefinedPtr()) |obj| blk: {
const entry_index = obj.entry_index orelse break :blk 0;
break :blk @intCast(self.symbol(entry_index).address(.{}, self));
const entry_sym = obj.entrySymbol(self) orelse break :blk 0;
break :blk @intCast(entry_sym.address(.{}, self));
} else 0;
const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
switch (self.ptr_width) {
@ -3043,7 +2972,7 @@ pub fn deleteExport(
fn checkDuplicates(self: *Elf) !void {
const gpa = self.base.comp.gpa;
var dupes = std.AutoArrayHashMap(Symbol.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
var dupes = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayListUnmanaged(File.Index)).init(gpa);
defer {
for (dupes.values()) |*list| {
list.deinit(gpa);
@ -3351,7 +3280,7 @@ fn initSyntheticSections(self: *Elf) !void {
});
const needs_versions = for (self.dynsym.entries.items) |entry| {
const sym = self.symbol(entry.symbol_index);
const sym = self.symbol(entry.ref).?;
if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
} else false;
if (needs_versions) {
@ -3565,7 +3494,7 @@ fn setVersionSymtab(self: *Elf) !void {
try self.versym.resize(gpa, self.dynsym.count());
self.versym.items[0] = elf.VER_NDX_LOCAL;
for (self.dynsym.entries.items, 1..) |entry, i| {
const sym = self.symbol(entry.symbol_index);
const sym = self.symbol(entry.ref).?;
self.versym.items[i] = sym.version_index;
}
@ -4357,11 +4286,10 @@ fn allocateSpecialPhdrs(self: *Elf) void {
fn writeAtoms(self: *Elf) !void {
const gpa = self.base.comp.gpa;
var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Ref)).init(gpa);
var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
defer {
var it = undefs.iterator();
while (it.next()) |entry| {
entry.value_ptr.deinit();
for (undefs.values()) |*refs| {
refs.deinit();
}
undefs.deinit();
}
@ -4507,11 +4435,13 @@ pub fn updateSymtabSize(self: *Elf) !void {
strsize += ctx.strsize;
}
if (self.zig_got_section_index) |_| {
self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
self.zig_got.updateSymtabSize(self);
nlocals += self.zig_got.output_symtab_ctx.nlocals;
strsize += self.zig_got.output_symtab_ctx.strsize;
if (self.zigObjectPtr()) |_| {
if (self.zig_got_section_index) |_| {
self.zig_got.output_symtab_ctx.ilocal = nlocals + 1;
self.zig_got.updateSymtabSize(self);
nlocals += self.zig_got.output_symtab_ctx.nlocals;
strsize += self.zig_got.output_symtab_ctx.strsize;
}
}
if (self.got_section_index) |_| {
@ -4650,7 +4580,9 @@ fn writeSyntheticSections(self: *Elf) !void {
const shdr = self.shdrs.items[shndx];
try self.got.addRela(self);
try self.copy_rel.addRela(self);
try self.zig_got.addRela(self);
if (self.zigObjectPtr()) |_| {
try self.zig_got.addRela(self);
}
self.sortRelaDyn();
try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
}
@ -5311,13 +5243,21 @@ pub fn calcNumIRelativeRelocs(self: *Elf) usize {
for (self.got.entries.items) |entry| {
if (entry.tag != .got) continue;
const sym = self.symbol(entry.symbol_index);
const sym = self.symbol(entry.ref).?;
if (sym.isIFunc(self)) count += 1;
}
return count;
}
pub fn getStartStopBasename(self: Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
const name = self.getShString(shdr.sh_name);
if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
if (Elf.isCIdentifier(name)) return name;
}
return null;
}
pub fn isCIdentifier(name: []const u8) bool {
if (name.len == 0) return false;
const first_c = name[0];
@ -5328,14 +5268,6 @@ pub fn isCIdentifier(name: []const u8) bool {
return true;
}
pub fn getStartStopBasename(self: *Elf, shdr: elf.Elf64_Shdr) ?[]const u8 {
const name = self.getShString(shdr.sh_name);
if (shdr.sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
if (isCIdentifier(name)) return name;
}
return null;
}
pub fn addThunk(self: *Elf) !Thunk.Index {
const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
const th = try self.thunks.addOne(self.base.comp.gpa);
@ -5381,95 +5313,9 @@ pub fn comdatGroup(self: *Elf, ref: Ref) *ComdatGroup {
return self.file(ref.file).?.comdatGroup(ref.index);
}
/// Returns pointer-to-symbol described at sym_index.
pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
return &self.symbols.items[sym_index];
}
pub fn addSymbol(self: *Elf) !Symbol.Index {
const gpa = self.base.comp.gpa;
try self.symbols.ensureUnusedCapacity(gpa, 1);
const index = blk: {
if (self.symbols_free_list.popOrNull()) |index| {
log.debug(" (reusing symbol index {d})", .{index});
break :blk index;
} else {
log.debug(" (allocating symbol index {d})", .{self.symbols.items.len});
const index: Symbol.Index = @intCast(self.symbols.items.len);
_ = self.symbols.addOneAssumeCapacity();
break :blk index;
}
};
self.symbols.items[index] = .{};
return index;
}
pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
const gpa = self.base.comp.gpa;
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(gpa, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra {
if (index == 0) return null;
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void {
assert(index > 0);
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
const GetOrPutGlobalResult = struct {
found_existing: bool,
index: Symbol.Index,
};
pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
const gpa = self.base.comp.gpa;
const name_off = try self.strings.insert(gpa, name);
const gop = try self.resolver.getOrPut(gpa, name_off);
if (!gop.found_existing) {
const index = try self.addSymbol();
log.debug("added symbol '{s}' at index {d}", .{ name, index });
const global = self.symbol(index);
global.name_offset = name_off;
global.flags.global = true;
gop.value_ptr.* = index;
}
return .{
.found_existing = gop.found_existing,
.index = gop.value_ptr.*,
};
pub fn symbol(self: *Elf, ref: Ref) ?*Symbol {
const file_ptr = self.file(ref.file) orelse return null;
return file_ptr.symbol(ref.index);
}
pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
@ -5579,36 +5425,34 @@ fn reportUndefinedSymbols(self: *Elf, undefs: anytype) !void {
try self.base.comp.link_errors.ensureUnusedCapacity(gpa, undefs.count());
var it = undefs.iterator();
while (it.next()) |entry| {
const undef_index = entry.key_ptr.*;
const atoms = entry.value_ptr.*.items;
const natoms = @min(atoms.len, max_notes);
const nnotes = natoms + @intFromBool(atoms.len > max_notes);
for (undefs.keys(), undefs.values()) |key, refs| {
const undef_sym = self.resolver.keys.items[key - 1];
const nrefs = @min(refs.items.len, max_notes);
const nnotes = nrefs + @intFromBool(refs.items.len > max_notes);
var err = try self.base.addErrorWithNotesAssumeCapacity(nnotes);
try err.addMsg("undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
try err.addMsg("undefined symbol: {s}", .{undef_sym.name(self)});
for (atoms[0..natoms]) |ref| {
for (refs.items[0..nrefs]) |ref| {
const atom_ptr = self.atom(ref).?;
const file_ptr = self.file(ref.file).?;
const file_ptr = atom_ptr.file(self).?;
try err.addNote("referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
}
if (atoms.len > max_notes) {
const remaining = atoms.len - max_notes;
if (refs.items.len > max_notes) {
const remaining = refs.items.len - max_notes;
try err.addNote("referenced {d} more times", .{remaining});
}
}
}
fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemory }!void {
if (dupes.keys().len == 0) return; // Nothing to do
const max_notes = 3;
var has_dupes = false;
var it = dupes.iterator();
while (it.next()) |entry| {
const sym = self.symbol(entry.key_ptr.*);
const notes = entry.value_ptr.*;
for (dupes.keys(), dupes.values()) |key, notes| {
const sym = self.resolver.keys.items[key - 1];
const nnotes = @min(notes.items.len, max_notes) + @intFromBool(notes.items.len > max_notes);
var err = try self.base.addErrorWithNotes(nnotes + 1);
@ -5625,11 +5469,9 @@ fn reportDuplicates(self: *Elf, dupes: anytype) error{ HasDuplicates, OutOfMemor
const remaining = notes.items.len - max_notes;
try err.addNote("defined {d} more times", .{remaining});
}
has_dupes = true;
}
if (has_dupes) return error.HasDuplicates;
return error.HasDuplicates;
}
fn reportMissingLibraryError(
@ -6018,6 +5860,10 @@ pub const Ref = struct {
index: u32,
file: u32,
pub fn eql(ref: Ref, other: Ref) bool {
return ref.index == other.index and ref.file == other.file;
}
pub fn format(
ref: Ref,
comptime unused_fmt_string: []const u8,
@ -6030,6 +5876,96 @@ pub const Ref = struct {
}
};
pub const SymbolResolver = struct {
keys: std.ArrayListUnmanaged(Key) = .{},
values: std.ArrayListUnmanaged(Ref) = .{},
table: std.AutoArrayHashMapUnmanaged(void, void) = .{},
const Result = struct {
found_existing: bool,
index: Index,
ref: *Ref,
};
pub fn deinit(resolver: *SymbolResolver, allocator: Allocator) void {
resolver.keys.deinit(allocator);
resolver.values.deinit(allocator);
resolver.table.deinit(allocator);
}
pub fn getOrPut(
resolver: *SymbolResolver,
allocator: Allocator,
ref: Ref,
elf_file: *Elf,
) !Result {
const adapter = Adapter{ .keys = resolver.keys.items, .elf_file = elf_file };
const key = Key{ .index = ref.index, .file_index = ref.file };
const gop = try resolver.table.getOrPutAdapted(allocator, key, adapter);
if (!gop.found_existing) {
try resolver.keys.append(allocator, key);
_ = try resolver.values.addOne(allocator);
}
return .{
.found_existing = gop.found_existing,
.index = @intCast(gop.index + 1),
.ref = &resolver.values.items[gop.index],
};
}
pub fn get(resolver: SymbolResolver, index: Index) ?Ref {
if (index == 0) return null;
return resolver.values.items[index - 1];
}
pub fn reset(resolver: *SymbolResolver) void {
resolver.keys.clearRetainingCapacity();
resolver.values.clearRetainingCapacity();
resolver.table.clearRetainingCapacity();
}
const Key = struct {
index: Symbol.Index,
file_index: File.Index,
fn name(key: Key, elf_file: *Elf) [:0]const u8 {
const ref = Ref{ .index = key.index, .file = key.file_index };
return elf_file.symbol(ref).?.name(elf_file);
}
fn file(key: Key, elf_file: *Elf) ?File {
return elf_file.file(key.file_index);
}
fn eql(key: Key, other: Key, elf_file: *Elf) bool {
const key_name = key.name(elf_file);
const other_name = other.name(elf_file);
return mem.eql(u8, key_name, other_name);
}
fn hash(key: Key, elf_file: *Elf) u32 {
return @truncate(Hash.hash(0, key.name(elf_file)));
}
};
const Adapter = struct {
keys: []const Key,
elf_file: *Elf,
pub fn eql(ctx: @This(), key: Key, b_void: void, b_map_index: usize) bool {
_ = b_void;
const other = ctx.keys[b_map_index];
return key.eql(other, ctx.elf_file);
}
pub fn hash(ctx: @This(), key: Key) u32 {
return key.hash(ctx.elf_file);
}
};
pub const Index = u32;
};
const LastAtomAndFreeList = struct {
/// Index of the last allocated atom in this section.
last_atom_index: Atom.Index = 0,
@ -6143,6 +6079,7 @@ const File = @import("Elf/file.zig").File;
const GnuHashSection = synthetic_sections.GnuHashSection;
const GotSection = synthetic_sections.GotSection;
const GotPltSection = synthetic_sections.GotPltSection;
const Hash = std.hash.Wyhash;
const HashSection = synthetic_sections.HashSection;
const InputMergeSection = merge_section.InputMergeSection;
const LdScript = @import("Elf/LdScript.zig");

View File

@ -326,12 +326,8 @@ pub fn writeRelocs(self: Atom, elf_file: *Elf, out_relocs: *std.ArrayList(elf.El
const cpu_arch = elf_file.getTarget().cpu.arch;
const file_ptr = self.file(elf_file).?;
for (self.relocs(elf_file)) |rel| {
const target_index = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};
const target = elf_file.symbol(target_index);
const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
const target = elf_file.symbol(target_ref).?;
const r_type = rel.r_type();
const r_offset: u64 = @intCast(self.value + @as(i64, @intCast(rel.r_offset)));
var r_addend = rel.r_addend;
@ -422,12 +418,21 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
const r_kind = relocation.decode(rel.r_type(), cpu_arch);
if (r_kind == .none) continue;
const symbol_index = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
const symbol_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
const symbol = elf_file.symbol(symbol_ref) orelse {
const sym_name = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()).name(elf_file),
inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file),
};
// Violation of One Definition Rule for COMDATs.
// TODO convert into an error
log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
file_ptr.fmtPath(),
self.name(elf_file),
sym_name,
});
continue;
};
const symbol = elf_file.symbol(symbol_index);
const is_synthetic_symbol = switch (file_ptr) {
.zig_object => false, // TODO: implement this once we support merge sections in ZigObject
@ -435,19 +440,8 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
else => unreachable,
};
// Check for violation of One Definition Rule for COMDATs.
if (symbol.file(elf_file) == null) {
// TODO convert into an error
log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
file_ptr.fmtPath(),
self.name(elf_file),
symbol.name(elf_file),
});
continue;
}
// Report an undefined symbol.
if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, symbol_index, rel, undefs)))
if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, symbol, rel, undefs)))
continue;
if (symbol.isIFunc(elf_file)) {
@ -694,16 +688,15 @@ fn reportUndefined(
self: Atom,
elf_file: *Elf,
sym: *const Symbol,
sym_index: Symbol.Index,
rel: elf.Elf64_Rela,
undefs: anytype,
) !bool {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const rel_esym = switch (self.file(elf_file).?) {
.zig_object => |x| x.elfSym(rel.r_sym()).*,
.object => |x| x.symtab.items[rel.r_sym()],
else => unreachable,
const file_ptr = self.file(elf_file).?;
const rel_esym = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()).elfSym(elf_file),
inline else => |x| x.symtab.items[rel.r_sym()],
};
const esym = sym.elfSym(elf_file);
if (rel_esym.st_shndx == elf.SHN_UNDEF and
@ -712,7 +705,12 @@ fn reportUndefined(
!sym.flags.import and
esym.st_shndx == elf.SHN_UNDEF)
{
const gop = try undefs.getOrPut(sym_index);
const idx = switch (file_ptr) {
.zig_object => |x| x.symbols_resolver.items[rel.r_sym() & ZigObject.symbol_mask],
.object => |x| x.symbols_resolver.items[rel.r_sym() - x.first_global.?],
inline else => |x| x.symbols_resolver.items[rel.r_sym()],
};
const gop = try undefs.getOrPut(idx);
if (!gop.found_existing) {
gop.value_ptr.* = std.ArrayList(Elf.Ref).init(gpa);
}
@ -737,11 +735,8 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) RelocError!voi
const r_kind = relocation.decode(rel.r_type(), cpu_arch);
if (r_kind == .none) continue;
const target = switch (file_ptr) {
.zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
.object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
else => unreachable,
};
const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
const target = elf_file.symbol(target_ref).?;
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
// We will use equation format to resolve relocations:
@ -845,7 +840,7 @@ fn resolveDynAbsReloc(
if (is_writeable or elf_file.z_nocopyreloc) {
elf_file.addRelaDynAssumeCapacity(.{
.offset = P,
.sym = target.extra(elf_file).?.dynamic,
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
});
@ -859,7 +854,7 @@ fn resolveDynAbsReloc(
if (is_writeable) {
elf_file.addRelaDynAssumeCapacity(.{
.offset = P,
.sym = target.extra(elf_file).?.dynamic,
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
});
@ -872,7 +867,7 @@ fn resolveDynAbsReloc(
.dynrel => {
elf_file.addRelaDynAssumeCapacity(.{
.offset = P,
.sym = target.extra(elf_file).?.dynamic,
.sym = target.extra(elf_file).dynamic,
.type = relocation.encode(.abs, cpu_arch),
.addend = A,
});
@ -923,31 +918,29 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
const target_index = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
const target_ref = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
const target = elf_file.symbol(target_ref) orelse {
const sym_name = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()).name(elf_file),
inline else => |x| x.symbols.items[rel.r_sym()].name(elf_file),
};
// Violation of One Definition Rule for COMDATs.
// TODO convert into an error
log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
file_ptr.fmtPath(),
self.name(elf_file),
sym_name,
});
continue;
};
const target = elf_file.symbol(target_index);
const is_synthetic_symbol = switch (file_ptr) {
.zig_object => false, // TODO: implement this once we support merge sections in ZigObject
.object => |x| rel.r_sym() >= x.symtab.items.len,
else => unreachable,
};
// Check for violation of One Definition Rule for COMDATs.
if (target.file(elf_file) == null) {
// TODO convert into an error
log.debug("{}: {s}: {s} refers to a discarded COMDAT section", .{
file_ptr.fmtPath(),
self.name(elf_file),
target.name(elf_file),
});
continue;
}
// Report an undefined symbol.
if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, target_index, rel, undefs)))
if (!is_synthetic_symbol and (try self.reportUndefined(elf_file, target, rel, undefs)))
continue;
// We will use equation format to resolve relocations:
@ -1766,11 +1759,7 @@ const aarch64 = struct {
=> {
const disp: i28 = math.cast(i28, S + A - P) orelse blk: {
const th = atom.thunk(elf_file);
const target_index = switch (file_ptr) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};
const target_index = file_ptr.resolveSymbol(rel.r_sym(), elf_file);
const S_ = th.targetAddress(target_index, elf_file);
break :blk math.cast(i28, S_ + A - P) orelse return error.Overflow;
};
@ -2106,11 +2095,8 @@ const riscv = struct {
return error.RelocFailure;
};
it.pos = pos;
const target_ = switch (file_ptr) {
.zig_object => |x| elf_file.symbol(x.symbol(pair.r_sym())),
.object => |x| elf_file.symbol(x.symbols.items[pair.r_sym()]),
else => unreachable,
};
const target_ref_ = file_ptr.resolveSymbol(pair.r_sym(), elf_file);
const target_ = elf_file.symbol(target_ref_).?;
const S_ = target_.address(.{}, elf_file);
const A_ = pair.r_addend;
const P_ = atom_addr + @as(i64, @intCast(pair.r_offset));
@ -2313,4 +2299,5 @@ const File = @import("file.zig").File;
const Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");
const Thunk = @import("thunks.zig").Thunk;
const ZigObject = @import("ZigObject.zig");
const dev = @import("../../dev.zig");

View File

@ -2,7 +2,10 @@ index: File.Index,
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
entry_index: ?Symbol.Index = null,
dynamic_index: ?Symbol.Index = null,
@ -29,6 +32,8 @@ pub fn deinit(self: *LinkerDefined, allocator: Allocator) void {
self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
self.symbols.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.symbols_resolver.deinit(allocator);
self.start_stop_indexes.deinit(allocator);
}
@ -37,86 +42,150 @@ pub fn init(self: *LinkerDefined, allocator: Allocator) !void {
try self.strtab.append(allocator, 0);
}
pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
if (elf_file.entry_name) |name| {
self.entry_index = try self.addGlobal(name, elf_file);
}
self.dynamic_index = try self.addGlobal("_DYNAMIC", elf_file);
self.ehdr_start_index = try self.addGlobal("__ehdr_start", elf_file);
self.init_array_start_index = try self.addGlobal("__init_array_start", elf_file);
self.init_array_end_index = try self.addGlobal("__init_array_end", elf_file);
self.fini_array_start_index = try self.addGlobal("__fini_array_start", elf_file);
self.fini_array_end_index = try self.addGlobal("__fini_array_end", elf_file);
self.preinit_array_start_index = try self.addGlobal("__preinit_array_start", elf_file);
self.preinit_array_end_index = try self.addGlobal("__preinit_array_end", elf_file);
self.got_index = try self.addGlobal("_GLOBAL_OFFSET_TABLE_", elf_file);
self.plt_index = try self.addGlobal("_PROCEDURE_LINKAGE_TABLE_", elf_file);
self.end_index = try self.addGlobal("_end", elf_file);
if (elf_file.base.comp.link_eh_frame_hdr) {
self.gnu_eh_frame_hdr_index = try self.addGlobal("__GNU_EH_FRAME_HDR", elf_file);
}
self.dso_handle_index = try self.addGlobal("__dso_handle", elf_file);
self.rela_iplt_start_index = try self.addGlobal("__rela_iplt_start", elf_file);
self.rela_iplt_end_index = try self.addGlobal("__rela_iplt_end", elf_file);
for (elf_file.shdrs.items) |shdr| {
if (elf_file.getStartStopBasename(shdr)) |name| {
try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
defer gpa.free(start);
const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
defer gpa.free(stop);
self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(start, elf_file));
self.start_stop_indexes.appendAssumeCapacity(try self.addGlobal(stop, elf_file));
}
}
if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
self.global_pointer_index = try self.addGlobal("__global_pointer$", elf_file);
}
}
fn addGlobal(self: *LinkerDefined, name: []const u8, elf_file: *Elf) !u32 {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
try self.symtab.ensureUnusedCapacity(gpa, 1);
try self.symbols.ensureUnusedCapacity(gpa, 1);
const name_off = @as(u32, @intCast(self.strtab.items.len));
try self.strtab.writer(gpa).print("{s}\x00", .{name});
self.symtab.appendAssumeCapacity(.{
fn newSymbolAssumeCapacity(self: *LinkerDefined, name_off: u32, elf_file: *Elf) Symbol.Index {
const esym_index: u32 = @intCast(self.symtab.items.len);
const esym = self.symtab.addOneAssumeCapacity();
esym.* = .{
.st_name = name_off,
.st_info = elf.STB_GLOBAL << 4,
.st_other = @intFromEnum(elf.STV.HIDDEN),
.st_shndx = elf.SHN_ABS,
.st_value = 0,
.st_size = 0,
});
const gop = try elf_file.getOrPutGlobal(name);
self.symbols.addOneAssumeCapacity().* = gop.index;
return gop.index;
};
const index = self.addSymbolAssumeCapacity();
const symbol = &self.symbols.items[index];
symbol.name_offset = name_off;
symbol.extra_index = self.addSymbolExtraAssumeCapacity(.{});
symbol.ref = .{ .index = 0, .file = 0 };
symbol.esym_index = esym_index;
symbol.version_index = elf_file.default_sym_version;
return index;
}
pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
for (self.symbols.items, 0..) |index, i| {
const sym_idx = @as(Symbol.Index, @intCast(i));
const this_sym = self.symtab.items[sym_idx];
pub fn initSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
var nsyms: usize = 0;
if (elf_file.entry_name) |_| {
nsyms += 1; // entry
}
nsyms += 1; // _DYNAMIC
nsyms += 1; // __ehdr_start
nsyms += 1; // __init_array_start
nsyms += 1; // __init_array_end
nsyms += 1; // __fini_array_start
nsyms += 1; // __fini_array_end
nsyms += 1; // __preinit_array_start
nsyms += 1; // __preinit_array_end
nsyms += 1; // _GLOBAL_OFFSET_TABLE_
nsyms += 1; // _PROCEDURE_LINKAGE_TABLE_
nsyms += 1; // _end
if (elf_file.base.comp.link_eh_frame_hdr) {
nsyms += 1; // __GNU_EH_FRAME_HDR
}
nsyms += 1; // __dso_handle
nsyms += 1; // __rela_iplt_start
nsyms += 1; // __rela_iplt_end
if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
nsyms += 1; // __global_pointer$
}
const global = elf_file.symbol(index);
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
global.file_index = self.index;
global.esym_index = sym_idx;
global.version_index = elf_file.default_sym_version;
try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
@memset(self.symbols_resolver.items, 0);
if (elf_file.entry_name) |name| {
self.entry_index = self.newSymbolAssumeCapacity(try self.addString(gpa, name), elf_file);
}
self.dynamic_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_DYNAMIC"), elf_file);
self.ehdr_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__ehdr_start"), elf_file);
self.init_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_start"), elf_file);
self.init_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__init_array_end"), elf_file);
self.fini_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_start"), elf_file);
self.fini_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__fini_array_end"), elf_file);
self.preinit_array_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_start"), elf_file);
self.preinit_array_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__preinit_array_end"), elf_file);
self.got_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_GLOBAL_OFFSET_TABLE_"), elf_file);
self.plt_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_PROCEDURE_LINKAGE_TABLE_"), elf_file);
self.end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "_end"), elf_file);
if (elf_file.base.comp.link_eh_frame_hdr) {
self.gnu_eh_frame_hdr_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__GNU_EH_FRAME_HDR"), elf_file);
}
self.dso_handle_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__dso_handle"), elf_file);
self.rela_iplt_start_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_start"), elf_file);
self.rela_iplt_end_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__rela_iplt_end"), elf_file);
if (elf_file.getTarget().cpu.arch.isRISCV() and elf_file.isEffectivelyDynLib()) {
self.global_pointer_index = self.newSymbolAssumeCapacity(try self.addString(gpa, "__global_pointer$"), elf_file);
}
}
pub fn initStartStopSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
var nsyms: usize = 0;
for (elf_file.shdrs.items) |shdr| {
if (elf_file.getStartStopBasename(shdr)) |_| {
nsyms += 2; // __start_, __stop_
}
}
try self.start_stop_indexes.ensureTotalCapacityPrecise(gpa, nsyms);
try self.symtab.ensureUnusedCapacity(gpa, nsyms);
try self.symbols.ensureUnusedCapacity(gpa, nsyms);
try self.symbols_extra.ensureUnusedCapacity(gpa, nsyms * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureUnusedCapacity(gpa, nsyms);
for (elf_file.shdrs.items) |shdr| {
if (elf_file.getStartStopBasename(shdr)) |name| {
const start_name = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
defer gpa.free(start_name);
const stop_name = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
defer gpa.free(stop_name);
for (&[_][]const u8{ start_name, stop_name }) |nn| {
const index = self.newSymbolAssumeCapacity(try self.addString(gpa, nn), elf_file);
self.start_stop_indexes.appendAssumeCapacity(index);
const gop = try elf_file.resolver.getOrPut(gpa, .{
.index = index,
.file = self.index,
}, elf_file);
assert(!gop.found_existing);
gop.ref.* = .{ .index = index, .file = self.index };
self.symbols_resolver.appendAssumeCapacity(gop.index);
}
}
}
}
pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
const gop = try elf_file.resolver.getOrPut(gpa, .{
.index = @intCast(i),
.file = self.index,
}, elf_file);
if (!gop.found_existing) {
gop.ref.* = .{ .index = 0, .file = 0 };
}
resolv.* = gop.index;
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (elf_file.symbol(gop.ref.*) == null) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
continue;
}
if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
}
}
}
@ -125,93 +194,73 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
const comp = elf_file.base.comp;
const link_mode = comp.config.link_mode;
const allocSymbol = struct {
fn allocSymbol(ld: *LinkerDefined, index: Symbol.Index, value: u64, osec: u32, ef: *Elf) void {
const sym = ef.symbol(ld.resolveSymbol(index, ef)).?;
sym.value = @intCast(value);
sym.output_section_index = osec;
}
}.allocSymbol;
// _DYNAMIC
if (elf_file.dynamic_section_index) |shndx| {
const shdr = &elf_file.shdrs.items[shndx];
const symbol_ptr = elf_file.symbol(self.dynamic_index.?);
symbol_ptr.value = @intCast(shdr.sh_addr);
symbol_ptr.output_section_index = shndx;
allocSymbol(self, self.dynamic_index.?, shdr.sh_addr, shndx, elf_file);
}
// __ehdr_start
{
const symbol_ptr = elf_file.symbol(self.ehdr_start_index.?);
symbol_ptr.value = @intCast(elf_file.image_base);
symbol_ptr.output_section_index = 1;
}
allocSymbol(self, self.ehdr_start_index.?, elf_file.image_base, 1, elf_file);
// __init_array_start, __init_array_end
if (elf_file.sectionByName(".init_array")) |shndx| {
const start_sym = elf_file.symbol(self.init_array_start_index.?);
const end_sym = elf_file.symbol(self.init_array_end_index.?);
const shdr = &elf_file.shdrs.items[shndx];
start_sym.output_section_index = shndx;
start_sym.value = @intCast(shdr.sh_addr);
end_sym.output_section_index = shndx;
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
allocSymbol(self, self.init_array_start_index.?, shdr.sh_addr, shndx, elf_file);
allocSymbol(self, self.init_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
}
// __fini_array_start, __fini_array_end
if (elf_file.sectionByName(".fini_array")) |shndx| {
const start_sym = elf_file.symbol(self.fini_array_start_index.?);
const end_sym = elf_file.symbol(self.fini_array_end_index.?);
const shdr = &elf_file.shdrs.items[shndx];
start_sym.output_section_index = shndx;
start_sym.value = @intCast(shdr.sh_addr);
end_sym.output_section_index = shndx;
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
allocSymbol(self, self.fini_array_start_index.?, shdr.sh_addr, shndx, elf_file);
allocSymbol(self, self.fini_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
}
// __preinit_array_start, __preinit_array_end
if (elf_file.sectionByName(".preinit_array")) |shndx| {
const start_sym = elf_file.symbol(self.preinit_array_start_index.?);
const end_sym = elf_file.symbol(self.preinit_array_end_index.?);
const shdr = &elf_file.shdrs.items[shndx];
start_sym.output_section_index = shndx;
start_sym.value = @intCast(shdr.sh_addr);
end_sym.output_section_index = shndx;
end_sym.value = @intCast(shdr.sh_addr + shdr.sh_size);
allocSymbol(self, self.preinit_array_start_index.?, shdr.sh_addr, shndx, elf_file);
allocSymbol(self, self.preinit_array_end_index.?, shdr.sh_addr + shdr.sh_size, shndx, elf_file);
}
// _GLOBAL_OFFSET_TABLE_
if (elf_file.getTarget().cpu.arch == .x86_64) {
if (elf_file.got_plt_section_index) |shndx| {
const shdr = elf_file.shdrs.items[shndx];
const sym = elf_file.symbol(self.got_index.?);
sym.value = @intCast(shdr.sh_addr);
sym.output_section_index = shndx;
allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file);
}
} else {
if (elf_file.got_section_index) |shndx| {
const shdr = elf_file.shdrs.items[shndx];
const sym = elf_file.symbol(self.got_index.?);
sym.value = @intCast(shdr.sh_addr);
sym.output_section_index = shndx;
allocSymbol(self, self.got_index.?, shdr.sh_addr, shndx, elf_file);
}
}
// _PROCEDURE_LINKAGE_TABLE_
if (elf_file.plt_section_index) |shndx| {
const shdr = &elf_file.shdrs.items[shndx];
const symbol_ptr = elf_file.symbol(self.plt_index.?);
symbol_ptr.value = @intCast(shdr.sh_addr);
symbol_ptr.output_section_index = shndx;
allocSymbol(self, self.plt_index.?, shdr.sh_addr, shndx, elf_file);
}
// __dso_handle
if (self.dso_handle_index) |index| {
const shdr = &elf_file.shdrs.items[1];
const symbol_ptr = elf_file.symbol(index);
symbol_ptr.value = @intCast(shdr.sh_addr);
symbol_ptr.output_section_index = 0;
allocSymbol(self, index, shdr.sh_addr, 0, elf_file);
}
// __GNU_EH_FRAME_HDR
if (elf_file.eh_frame_hdr_section_index) |shndx| {
const shdr = &elf_file.shdrs.items[shndx];
const symbol_ptr = elf_file.symbol(self.gnu_eh_frame_hdr_index.?);
symbol_ptr.value = @intCast(shdr.sh_addr);
symbol_ptr.output_section_index = shndx;
allocSymbol(self, self.gnu_eh_frame_hdr_index.?, shdr.sh_addr, shndx, elf_file);
}
// __rela_iplt_start, __rela_iplt_end
@ -220,32 +269,41 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
const shdr = &elf_file.shdrs.items[shndx];
const end_addr = shdr.sh_addr + shdr.sh_size;
const start_addr = end_addr - elf_file.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
const start_sym = elf_file.symbol(self.rela_iplt_start_index.?);
const end_sym = elf_file.symbol(self.rela_iplt_end_index.?);
start_sym.value = @intCast(start_addr);
start_sym.output_section_index = shndx;
end_sym.value = @intCast(end_addr);
end_sym.output_section_index = shndx;
allocSymbol(self, self.rela_iplt_start_index.?, start_addr, shndx, elf_file);
allocSymbol(self, self.rela_iplt_end_index.?, end_addr, shndx, elf_file);
}
// _end
{
const end_symbol = elf_file.symbol(self.end_index.?);
var value: u64 = 0;
var osec: u32 = 0;
for (elf_file.shdrs.items, 0..) |shdr, shndx| {
if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
end_symbol.value = @intCast(shdr.sh_addr + shdr.sh_size);
end_symbol.output_section_index = @intCast(shndx);
value = shdr.sh_addr + shdr.sh_size;
osec = @intCast(shndx);
}
}
allocSymbol(self, self.end_index.?, value, osec, elf_file);
}
// __global_pointer$
if (self.global_pointer_index) |index| {
const value, const osec = if (elf_file.sectionByName(".sdata")) |shndx| .{
elf_file.shdrs.items[shndx].sh_addr + 0x800,
shndx,
} else .{ 0, 0 };
allocSymbol(self, index, value, osec, elf_file);
}
// __start_*, __stop_*
{
var index: usize = 0;
while (index < self.start_stop_indexes.items.len) : (index += 2) {
const start = elf_file.symbol(self.start_stop_indexes.items[index]);
const start_ref = self.resolveSymbol(self.start_stop_indexes.items[index], elf_file);
const start = elf_file.symbol(start_ref).?;
const name = start.name(elf_file);
const stop = elf_file.symbol(self.start_stop_indexes.items[index + 1]);
const stop_ref = self.resolveSymbol(self.start_stop_indexes.items[index + 1], elf_file);
const stop = elf_file.symbol(stop_ref).?;
const shndx = elf_file.sectionByName(name["__start_".len..]).?;
const shdr = &elf_file.shdrs.items[shndx];
start.value = @intCast(shdr.sh_addr);
@ -254,47 +312,30 @@ pub fn allocateSymbols(self: *LinkerDefined, elf_file: *Elf) void {
stop.output_section_index = shndx;
}
}
// __global_pointer$
if (self.global_pointer_index) |index| {
const sym = elf_file.symbol(index);
if (elf_file.sectionByName(".sdata")) |shndx| {
const shdr = elf_file.shdrs.items[shndx];
sym.value = @intCast(shdr.sh_addr + 0x800);
sym.output_section_index = shndx;
} else {
sym.value = 0;
sym.output_section_index = 0;
}
}
}
pub fn globals(self: LinkerDefined) []const Symbol.Index {
return self.symbols.items;
}
pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) !void {
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
pub fn updateSymtabSize(self: *LinkerDefined, elf_file: *Elf) void {
for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
const ref = elf_file.resolver.get(resolv).?;
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
global.flags.output_symtab = true;
if (global.isLocal(elf_file)) {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
} else {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
self.output_symtab_ctx.nglobals += 1;
}
self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
}
}
pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void {
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
pub fn writeSymtab(self: *LinkerDefined, elf_file: *Elf) void {
for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
const ref = elf_file.resolver.get(resolv).?;
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
const idx = global.outputSymtabIndex(elf_file) orelse continue;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
@ -305,15 +346,93 @@ pub fn writeSymtab(self: LinkerDefined, elf_file: *Elf) void {
}
}
pub fn dynamicSymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol {
const index = self.dynamic_index orelse return null;
const resolv = self.resolveSymbol(index, elf_file);
return elf_file.symbol(resolv);
}
pub fn entrySymbol(self: LinkerDefined, elf_file: *Elf) ?*Symbol {
const index = self.entry_index orelse return null;
const resolv = self.resolveSymbol(index, elf_file);
return elf_file.symbol(resolv);
}
pub fn asFile(self: *LinkerDefined) File {
return .{ .linker_defined = self };
}
fn addString(self: *LinkerDefined, allocator: Allocator, str: []const u8) !u32 {
const off: u32 = @intCast(self.strtab.items.len);
try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
self.strtab.appendSliceAssumeCapacity(str);
self.strtab.appendAssumeCapacity(0);
return off;
}
pub fn getString(self: LinkerDefined, off: u32) [:0]const u8 {
assert(off < self.strtab.items.len);
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
}
pub fn resolveSymbol(self: LinkerDefined, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
const resolv = self.symbols_resolver.items[index];
return elf_file.resolver.get(resolv).?;
}
fn addSymbol(self: *LinkerDefined, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
return self.addSymbolAssumeCapacity();
}
fn addSymbolAssumeCapacity(self: *LinkerDefined) Symbol.Index {
const index: Symbol.Index = @intCast(self.symbols.items.len);
self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
return index;
}
pub fn addSymbolExtra(self: *LinkerDefined, allocator: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
pub fn addSymbolExtraAssumeCapacity(self: *LinkerDefined, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn symbolExtra(self: *LinkerDefined, index: u32) Symbol.Extra {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *LinkerDefined, index: u32, extra: Symbol.Extra) void {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
return .{ .data = .{
.self = self,
@ -334,10 +453,16 @@ fn formatSymtab(
) !void {
_ = unused_fmt_string;
_ = options;
const self = ctx.self;
const elf_file = ctx.elf_file;
try writer.writeAll(" globals\n");
for (ctx.self.globals()) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
for (self.symbols.items, 0..) |sym, i| {
const ref = self.resolveSymbol(@intCast(i), elf_file);
if (elf_file.symbol(ref)) |ref_sym| {
try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
} else {
try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
}
}
}

View File

@ -9,7 +9,9 @@ shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
strtab: std.ArrayListUnmanaged(u8) = .{},
first_global: ?Symbol.Index = null,
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
relocs: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
atoms: std.ArrayListUnmanaged(Atom) = .{},
@ -51,6 +53,8 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
self.symbols.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.symbols_resolver.deinit(allocator);
self.atoms.deinit(allocator);
self.atoms_indexes.deinit(allocator);
self.atoms_extra.deinit(allocator);
@ -80,7 +84,7 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) });
try self.initAtoms(gpa, handle, elf_file);
try self.initSymtab(gpa, elf_file);
try self.initSymbols(gpa, elf_file);
for (self.shdrs.items, 0..) |shdr, i| {
const atom_ptr = self.atom(self.atoms_indexes.items[i]) orelse continue;
@ -374,29 +378,29 @@ fn skipShdr(self: *Object, index: u32, elf_file: *Elf) bool {
return ignore;
}
fn initSymtab(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
fn initSymbols(self: *Object, allocator: Allocator, elf_file: *Elf) !void {
const first_global = self.first_global orelse self.symtab.items.len;
const nglobals = self.symtab.items.len - first_global;
try self.symbols.ensureTotalCapacityPrecise(allocator, self.symtab.items.len);
try self.symbols_extra.ensureTotalCapacityPrecise(allocator, self.symtab.items.len * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureTotalCapacityPrecise(allocator, nglobals);
self.symbols_resolver.resize(allocator, nglobals) catch unreachable;
@memset(self.symbols_resolver.items, 0);
for (self.symtab.items[0..first_global], 0..) |sym, i| {
const index = try elf_file.addSymbol();
self.symbols.appendAssumeCapacity(index);
const sym_ptr = elf_file.symbol(index);
for (self.symtab.items, 0..) |sym, i| {
const index = self.addSymbolAssumeCapacity();
const sym_ptr = &self.symbols.items[index];
sym_ptr.value = @intCast(sym.st_value);
sym_ptr.name_offset = sym.st_name;
sym_ptr.esym_index = @as(u32, @intCast(i));
sym_ptr.file_index = self.index;
if (sym.st_shndx != elf.SHN_ABS) {
sym_ptr.esym_index = @intCast(i);
sym_ptr.extra_index = self.addSymbolExtraAssumeCapacity(.{});
sym_ptr.version_index = if (i >= first_global) elf_file.default_sym_version else elf.VER_NDX_LOCAL;
sym_ptr.flags.weak = sym.st_bind() == elf.STB_WEAK;
if (sym.st_shndx != elf.SHN_ABS and sym.st_shndx != elf.SHN_COMMON) {
sym_ptr.ref = .{ .index = self.atoms_indexes.items[sym.st_shndx], .file = self.index };
}
}
for (self.symtab.items[first_global..]) |sym| {
const name = self.getString(sym.st_name);
const gop = try elf_file.getOrPutGlobal(name);
self.symbols.addOneAssumeCapacity().* = gop.index;
}
}
fn parseEhFrame(self: *Object, allocator: Allocator, handle: std.fs.File, shndx: u32, elf_file: *Elf) !void {
@ -543,7 +547,7 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
for (self.cies.items) |cie| {
for (cie.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(self.symbols.items[rel.r_sym()]);
const sym = elf_file.symbol(self.resolveSymbol(rel.r_sym(), elf_file)).?;
if (sym.flags.import) {
if (sym.type(elf_file) != elf.STT_FUNC)
// TODO convert into an error
@ -557,49 +561,47 @@ pub fn scanRelocs(self: *Object, elf_file: *Elf, undefs: anytype) !void {
}
}
pub fn resolveSymbols(self: *Object, elf_file: *Elf) void {
pub fn resolveSymbols(self: *Object, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(first_global + i));
const esym = self.symtab.items[esym_index];
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
for (self.globals(), first_global..) |_, i| {
const esym = self.symtab.items[i];
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) {
const atom_index = self.atoms_indexes.items[esym.st_shndx];
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.alive) continue;
}
const global = elf_file.symbol(index);
if (self.asFile().symbolRank(esym, !self.alive) < global.symbolRank(elf_file)) {
switch (esym.st_shndx) {
elf.SHN_ABS, elf.SHN_COMMON => {},
else => global.ref = .{
.index = self.atoms_indexes.items[esym.st_shndx],
.file = self.index,
},
}
global.value = @intCast(esym.st_value);
global.esym_index = esym_index;
global.file_index = self.index;
global.version_index = elf_file.default_sym_version;
if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
const resolv = &self.symbols_resolver.items[i - first_global];
const gop = try elf_file.resolver.getOrPut(gpa, .{
.index = @intCast(i),
.file = self.index,
}, elf_file);
if (!gop.found_existing) {
gop.ref.* = .{ .index = 0, .file = 0 };
}
resolv.* = gop.index;
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (elf_file.symbol(gop.ref.*) == null) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
continue;
}
if (self.asFile().symbolRank(esym, !self.alive) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
}
}
}
pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
for (self.globals(), 0..) |*sym, i| {
const esym_index = @as(u32, @intCast(first_global + i));
const esym = self.symtab.items[esym_index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
const global = elf_file.symbol(index);
if (global.file(elf_file)) |_| {
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
}
if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue;
const is_import = blk: {
if (!elf_file.isEffectivelyDynLib()) break :blk false;
@ -608,45 +610,48 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
break :blk true;
};
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = esym_index;
global.file_index = self.index;
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
global.flags.import = is_import;
sym.value = 0;
sym.ref = .{ .index = 0, .file = 0 };
sym.esym_index = esym_index;
sym.file_index = self.index;
sym.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
sym.flags.import = is_import;
const idx = self.symbols_resolver.items[i];
elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index };
}
}
pub fn claimUnresolvedObject(self: *Object, elf_file: *Elf) void {
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
for (self.globals(), 0..) |*sym, i| {
const esym_index = @as(u32, @intCast(first_global + i));
const esym = self.symtab.items[esym_index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
if (elf_file.symbol(self.resolveSymbol(esym_index, elf_file)) != null) continue;
const global = elf_file.symbol(index);
if (global.file(elf_file)) |file| {
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
}
sym.value = 0;
sym.ref = .{ .index = 0, .file = 0 };
sym.esym_index = esym_index;
sym.file_index = self.index;
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = esym_index;
global.file_index = self.index;
const idx = self.symbols_resolver.items[i];
elf_file.resolver.values.items[idx - 1] = .{ .index = esym_index, .file = self.index };
}
}
pub fn markLive(self: *Object, elf_file: *Elf) void {
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
const sym_idx = first_global + i;
const sym = self.symtab.items[sym_idx];
if (sym.st_bind() == elf.STB_WEAK) continue;
for (0..self.globals().len) |i| {
const esym_idx = first_global + i;
const esym = self.symtab.items[esym_idx];
if (esym.st_bind() == elf.STB_WEAK) continue;
const global = elf_file.symbol(index);
const file = global.file(elf_file) orelse continue;
const should_keep = sym.st_shndx == elf.SHN_UNDEF or
(sym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
const should_keep = esym.st_shndx == elf.SHN_UNDEF or
(esym.st_shndx == elf.SHN_COMMON and sym.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
if (should_keep and !file.isAlive()) {
file.setAlive();
file.markLive(elf_file);
@ -664,26 +669,50 @@ pub fn markEhFrameAtomsDead(self: *Object, elf_file: *Elf) void {
}
}
pub fn markImportsExports(self: *Object, elf_file: *Elf) void {
const first_global = self.first_global orelse return;
for (0..self.globals().len) |i| {
const idx = first_global + i;
const ref = self.resolveSymbol(@intCast(idx), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
if (sym.version_index == elf.VER_NDX_LOCAL) continue;
const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
if (vis == .HIDDEN) continue;
if (file == .shared_object and !sym.isAbs(elf_file)) {
sym.flags.import = true;
continue;
}
if (file.index() == self.index) {
sym.flags.@"export" = true;
if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
sym.flags.import = true;
}
}
}
}
pub fn checkDuplicates(self: *Object, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
const sym_idx = first_global + i;
const sym = self.symtab.items[sym_idx];
const global = elf_file.symbol(index);
const global_file = global.file(elf_file) orelse continue;
for (0..self.globals().len) |i| {
const esym_idx = first_global + i;
const esym = self.symtab.items[esym_idx];
const ref = self.resolveSymbol(@intCast(esym_idx), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
const ref_file = ref_sym.file(elf_file).?;
if (self.index == global_file.index() or
sym.st_shndx == elf.SHN_UNDEF or
sym.st_bind() == elf.STB_WEAK or
sym.st_shndx == elf.SHN_COMMON) continue;
if (self.index == ref_file.index() or
esym.st_shndx == elf.SHN_UNDEF or
esym.st_bind() == elf.STB_WEAK or
esym.st_shndx == elf.SHN_COMMON) continue;
if (sym.st_shndx != elf.SHN_ABS) {
const atom_index = self.atoms_indexes.items[sym.st_shndx];
if (esym.st_shndx != elf.SHN_ABS) {
const atom_index = self.atoms_indexes.items[esym.st_shndx];
const atom_ptr = self.atom(atom_index) orelse continue;
if (!atom_ptr.alive) continue;
}
const gop = try dupes.getOrPut(index);
const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
@ -813,9 +842,7 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
}
for (self.symtab.items, 0..) |*esym, idx| {
const sym_index = self.symbols.items[idx];
const sym = elf_file.symbol(sym_index);
const sym = &self.symbols.items[idx];
if (esym.st_shndx == elf.SHN_COMMON or esym.st_shndx == elf.SHN_UNDEF or esym.st_shndx == elf.SHN_ABS) continue;
const imsec_index = self.input_merge_sections_indexes.items[esym.st_shndx];
@ -854,22 +881,20 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
return error.MalformedObject;
};
const out_sym_idx: u64 = @intCast(self.symbols.items.len);
try self.symbols.ensureUnusedCapacity(gpa, 1);
const sym_index = try self.addSymbol(gpa);
const sym = &self.symbols.items[sym_index];
const name = try std.fmt.allocPrint(gpa, "{s}$subsection{d}", .{ msec.name(elf_file), res.msub_index });
defer gpa.free(name);
const sym_index = try elf_file.addSymbol();
const sym = elf_file.symbol(sym_index);
sym.* = .{
.value = @bitCast(@as(i64, @intCast(res.offset)) - rel.r_addend),
.name_offset = try self.addString(gpa, name),
.esym_index = rel.r_sym(),
.file_index = self.index,
.extra_index = try self.addSymbolExtra(gpa, .{}),
};
sym.ref = .{ .index = res.msub_index, .file = imsec.merge_section_index };
sym.flags.merge_subsection = true;
self.symbols.addOneAssumeCapacity().* = sym_index;
rel.r_info = (out_sym_idx << 32) | rel.r_type();
rel.r_info = (@as(u64, @intCast(sym_index)) << 32) | rel.r_type();
}
}
}
@ -878,27 +903,16 @@ pub fn resolveMergeSubsections(self: *Object, elf_file: *Elf) !void {
/// play nicely with the rest of the system.
pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
const first_global = self.first_global orelse return;
for (self.globals(), 0..) |index, i| {
const sym_idx = @as(u32, @intCast(first_global + i));
const this_sym = self.symtab.items[sym_idx];
if (this_sym.st_shndx != elf.SHN_COMMON) continue;
const global = elf_file.symbol(index);
const global_file = global.file(elf_file).?;
if (global_file.index() != self.index) {
// if (elf_file.options.warn_common) {
// elf_file.base.warn("{}: multiple common symbols: {s}", .{
// self.fmtPath(),
// global.getName(elf_file),
// });
// }
continue;
}
for (self.globals(), self.symbols_resolver.items, 0..) |*sym, resolv, i| {
const esym_idx = @as(u32, @intCast(first_global + i));
const esym = self.symtab.items[esym_idx];
if (esym.st_shndx != elf.SHN_COMMON) continue;
if (elf_file.resolver.get(resolv).?.file != self.index) continue;
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const is_tls = global.type(elf_file) == elf.STT_TLS;
const is_tls = sym.type(elf_file) == elf.STT_TLS;
const name = if (is_tls) ".tls_common" else ".common";
const name_offset = @as(u32, @intCast(self.strtab.items.len));
try self.strtab.writer(gpa).print("{s}\x00", .{name});
@ -907,7 +921,7 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
if (is_tls) sh_flags |= elf.SHF_TLS;
const shndx = @as(u32, @intCast(self.shdrs.items.len));
const shdr = try self.shdrs.addOne(gpa);
const sh_size = math.cast(usize, this_sym.st_size) orelse return error.Overflow;
const sh_size = math.cast(usize, esym.st_size) orelse return error.Overflow;
shdr.* = .{
.sh_name = name_offset,
.sh_type = elf.SHT_NOBITS,
@ -917,21 +931,21 @@ pub fn convertCommonSymbols(self: *Object, elf_file: *Elf) !void {
.sh_size = sh_size,
.sh_link = 0,
.sh_info = 0,
.sh_addralign = this_sym.st_value,
.sh_addralign = esym.st_value,
.sh_entsize = 0,
};
const atom_index = try self.addAtom(gpa, .{
.name = name_offset,
.shndx = shndx,
.size = this_sym.st_size,
.alignment = Alignment.fromNonzeroByteUnits(this_sym.st_value),
.size = esym.st_size,
.alignment = Alignment.fromNonzeroByteUnits(esym.st_value),
});
try self.atoms_indexes.append(gpa, atom_index);
global.value = 0;
global.ref = .{ .index = atom_index, .file = self.index };
global.flags.weak = false;
sym.value = 0;
sym.ref = .{ .index = atom_index, .file = self.index };
sym.flags.weak = false;
}
}
@ -1073,7 +1087,7 @@ pub fn writeAr(self: Object, elf_file: *Elf, writer: anytype) !void {
try writer.writeAll(data);
}
pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
pub fn updateSymtabSize(self: *Object, elf_file: *Elf) void {
const isAlive = struct {
fn isAlive(sym: *const Symbol, ctx: *Elf) bool {
if (sym.mergeSubsection(ctx)) |msub| return msub.alive;
@ -1082,8 +1096,7 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
}
}.isAlive;
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
for (self.locals()) |*local| {
if (!isAlive(local, elf_file)) continue;
const esym = local.elfSym(elf_file);
switch (esym.st_type()) {
@ -1092,31 +1105,30 @@ pub fn updateSymtabSize(self: *Object, elf_file: *Elf) !void {
else => {},
}
local.flags.output_symtab = true;
try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
}
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
for (self.globals(), self.symbols_resolver.items) |*global, resolv| {
const ref = elf_file.resolver.values.items[resolv - 1];
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
if (!isAlive(global, elf_file)) continue;
global.flags.output_symtab = true;
if (global.isLocal(elf_file)) {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
} else {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
self.output_symtab_ctx.nglobals += 1;
}
self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
}
}
pub fn writeSymtab(self: Object, elf_file: *Elf) void {
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
pub fn writeSymtab(self: *Object, elf_file: *Elf) void {
for (self.locals()) |local| {
const idx = local.outputSymtabIndex(elf_file) orelse continue;
const out_sym = &elf_file.symtab.items[idx];
out_sym.st_name = @intCast(elf_file.strtab.items.len);
@ -1125,10 +1137,10 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
local.setOutputSym(elf_file, out_sym);
}
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
for (self.globals(), self.symbols_resolver.items) |global, resolv| {
const ref = elf_file.resolver.values.items[resolv - 1];
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
const idx = global.outputSymtabIndex(elf_file) orelse continue;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
@ -1139,20 +1151,6 @@ pub fn writeSymtab(self: Object, elf_file: *Elf) void {
}
}
pub fn locals(self: Object) []const Symbol.Index {
if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
assert(self.symbols.items.len >= self.symtab.items.len);
const end = self.first_global orelse self.symtab.items.len;
return self.symbols.items[0..end];
}
pub fn globals(self: Object) []const Symbol.Index {
if (self.symbols.items.len == 0) return &[0]Symbol.Index{};
assert(self.symbols.items.len >= self.symtab.items.len);
const start = self.first_global orelse self.symtab.items.len;
return self.symbols.items[start..self.symtab.items.len];
}
/// Returns atom's code and optionally uncompresses data if required (for compressed sections).
/// Caller owns the memory.
pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
@ -1185,6 +1183,81 @@ pub fn codeDecompressAlloc(self: *Object, elf_file: *Elf, atom_index: Atom.Index
return data;
}
fn locals(self: *Object) []Symbol {
if (self.symbols.items.len == 0) return &[0]Symbol{};
assert(self.symbols.items.len >= self.symtab.items.len);
const end = self.first_global orelse self.symtab.items.len;
return self.symbols.items[0..end];
}
pub fn globals(self: *Object) []Symbol {
if (self.symbols.items.len == 0) return &[0]Symbol{};
assert(self.symbols.items.len >= self.symtab.items.len);
const start = self.first_global orelse self.symtab.items.len;
return self.symbols.items[start..self.symtab.items.len];
}
pub fn resolveSymbol(self: Object, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
const start = self.first_global orelse self.symtab.items.len;
const end = self.symtab.items.len;
if (index < start or index >= end) return .{ .index = index, .file = self.index };
const resolv = self.symbols_resolver.items[index - start];
return elf_file.resolver.get(resolv).?;
}
fn addSymbol(self: *Object, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
return self.addSymbolAssumeCapacity();
}
fn addSymbolAssumeCapacity(self: *Object) Symbol.Index {
const index: Symbol.Index = @intCast(self.symbols.items.len);
self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
return index;
}
pub fn addSymbolExtra(self: *Object, allocator: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
pub fn addSymbolExtraAssumeCapacity(self: *Object, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn symbolExtra(self: *Object, index: u32) Symbol.Extra {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *Object, index: u32, extra: Symbol.Extra) void {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
pub fn asFile(self: *Object) File {
return .{ .object = self };
}
@ -1352,15 +1425,20 @@ fn formatSymtab(
_ = unused_fmt_string;
_ = options;
const object = ctx.object;
const elf_file = ctx.elf_file;
try writer.writeAll(" locals\n");
for (object.locals()) |index| {
const local = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
for (object.locals()) |sym| {
try writer.print(" {}\n", .{sym.fmt(elf_file)});
}
try writer.writeAll(" globals\n");
for (object.globals()) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
for (object.globals(), 0..) |sym, i| {
const first_global = object.first_global.?;
const ref = object.resolveSymbol(@intCast(i + first_global), elf_file);
if (elf_file.symbol(ref)) |ref_sym| {
try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
} else {
try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
}
}
}

View File

@ -10,7 +10,10 @@ strtab: std.ArrayListUnmanaged(u8) = .{},
versyms: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
verstrings: std.ArrayListUnmanaged(u32) = .{},
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
aliases: ?std.ArrayListUnmanaged(u32) = null,
dynamic_table: std.ArrayListUnmanaged(elf.Elf64_Dyn) = .{},
@ -38,6 +41,8 @@ pub fn deinit(self: *SharedObject, allocator: Allocator) void {
self.versyms.deinit(allocator);
self.verstrings.deinit(allocator);
self.symbols.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.symbols_resolver.deinit(allocator);
if (self.aliases) |*aliases| aliases.deinit(allocator);
self.dynamic_table.deinit(allocator);
}
@ -129,7 +134,7 @@ pub fn parse(self: *SharedObject, elf_file: *Elf, handle: std.fs.File) !void {
.versym_sect_index = versym_sect_index,
});
try self.initSymtab(elf_file, .{
try self.initSymbols(elf_file, .{
.symtab = symtab,
.strtab = strtab,
});
@ -188,16 +193,20 @@ fn parseVersions(self: *SharedObject, elf_file: *Elf, handle: std.fs.File, opts:
}
}
fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {
fn initSymbols(self: *SharedObject, elf_file: *Elf, opts: struct {
symtab: []align(1) const elf.Elf64_Sym,
strtab: []const u8,
}) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const gpa = elf_file.base.comp.gpa;
const nsyms = opts.symtab.len;
try self.strtab.appendSlice(gpa, opts.strtab);
try self.symtab.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
try self.symbols.ensureTotalCapacityPrecise(gpa, opts.symtab.len);
try self.symtab.ensureTotalCapacityPrecise(gpa, nsyms);
try self.symbols.ensureTotalCapacityPrecise(gpa, nsyms);
try self.symbols_extra.ensureTotalCapacityPrecise(gpa, nsyms * @sizeOf(Symbol.Extra));
try self.symbols_resolver.ensureTotalCapacityPrecise(gpa, nsyms);
self.symbols_resolver.resize(gpa, nsyms) catch unreachable;
@memset(self.symbols_resolver.items, 0);
for (opts.symtab, 0..) |sym, i| {
const hidden = self.versyms.items[i] & elf.VERSYM_HIDDEN != 0;
@ -210,45 +219,57 @@ fn initSymtab(self: *SharedObject, elf_file: *Elf, opts: struct {
self.versionString(self.versyms.items[i]),
});
defer gpa.free(mangled);
const name_off = @as(u32, @intCast(self.strtab.items.len));
try self.strtab.writer(gpa).print("{s}\x00", .{mangled});
break :blk name_off;
break :blk try self.addString(gpa, mangled);
} else sym.st_name;
const out_sym = self.symtab.addOneAssumeCapacity();
out_sym.* = sym;
out_sym.st_name = name_off;
const gop = try elf_file.getOrPutGlobal(self.getString(name_off));
self.symbols.addOneAssumeCapacity().* = gop.index;
const out_esym_index: u32 = @intCast(self.symtab.items.len);
const out_esym = self.symtab.addOneAssumeCapacity();
out_esym.* = sym;
out_esym.st_name = name_off;
const out_sym_index = self.addSymbolAssumeCapacity();
const out_sym = &self.symbols.items[out_sym_index];
out_sym.value = @intCast(out_esym.st_value);
out_sym.name_offset = name_off;
out_sym.ref = .{ .index = 0, .file = 0 };
out_sym.esym_index = out_esym_index;
out_sym.version_index = self.versyms.items[out_esym_index];
out_sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
}
}
pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(u32, @intCast(i));
const this_sym = self.symtab.items[esym_index];
pub fn resolveSymbols(self: *SharedObject, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
for (self.symtab.items, self.symbols_resolver.items, 0..) |esym, *resolv, i| {
const gop = try elf_file.resolver.getOrPut(gpa, .{
.index = @intCast(i),
.file = self.index,
}, elf_file);
if (!gop.found_existing) {
gop.ref.* = .{ .index = 0, .file = 0 };
}
resolv.* = gop.index;
const global = elf_file.symbol(index);
if (self.asFile().symbolRank(this_sym, false) < global.symbolRank(elf_file)) {
global.value = @intCast(this_sym.st_value);
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = esym_index;
global.version_index = self.versyms.items[esym_index];
global.file_index = self.index;
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (elf_file.symbol(gop.ref.*) == null) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
continue;
}
if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
gop.ref.* = .{ .index = @intCast(i), .file = self.index };
}
}
}
pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const sym = self.symtab.items[i];
if (sym.st_shndx != elf.SHN_UNDEF) continue;
for (self.symtab.items, 0..) |esym, i| {
if (esym.st_shndx != elf.SHN_UNDEF) continue;
const global = elf_file.symbol(index);
const file = global.file(elf_file) orelse continue;
const ref = self.resolveSymbol(@intCast(i), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
const should_drop = switch (file) {
.shared_object => |sh| !sh.needed and sym.st_bind() == elf.STB_WEAK,
.shared_object => |sh| !sh.needed and esym.st_bind() == elf.STB_WEAK,
else => false,
};
if (!should_drop and !file.isAlive()) {
@ -258,28 +279,34 @@ pub fn markLive(self: *SharedObject, elf_file: *Elf) void {
}
}
pub fn globals(self: SharedObject) []const Symbol.Index {
return self.symbols.items;
pub fn markImportExports(self: *SharedObject, elf_file: *Elf) void {
for (0..self.symbols.items.len) |i| {
const ref = self.resolveSymbol(@intCast(i), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
const ref_file = ref_sym.file(elf_file).?;
const vis = @as(elf.STV, @enumFromInt(ref_sym.elfSym(elf_file).st_other));
if (ref_file != .shared_object and vis != .HIDDEN) ref_sym.flags.@"export" = true;
}
}
pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) !void {
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
pub fn updateSymtabSize(self: *SharedObject, elf_file: *Elf) void {
for (self.symbols.items, self.symbols_resolver.items) |*global, resolv| {
const ref = elf_file.resolver.get(resolv).?;
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
if (global.isLocal(elf_file)) continue;
global.flags.output_symtab = true;
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
self.output_symtab_ctx.nglobals += 1;
self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
}
}
pub fn writeSymtab(self: SharedObject, elf_file: *Elf) void {
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
pub fn writeSymtab(self: *SharedObject, elf_file: *Elf) void {
for (self.symbols.items, self.symbols_resolver.items) |global, resolv| {
const ref = elf_file.resolver.get(resolv).?;
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
const idx = global.outputSymtabIndex(elf_file) orelse continue;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
@ -319,9 +346,12 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
assert(self.aliases == null);
const SortAlias = struct {
pub fn lessThan(ctx: *Elf, lhs: Symbol.Index, rhs: Symbol.Index) bool {
const lhs_sym = ctx.symbol(lhs).elfSym(ctx);
const rhs_sym = ctx.symbol(rhs).elfSym(ctx);
so: *SharedObject,
ef: *Elf,
pub fn lessThan(ctx: @This(), lhs: Symbol.Index, rhs: Symbol.Index) bool {
const lhs_sym = ctx.so.symbols.items[lhs].elfSym(ctx.ef);
const rhs_sym = ctx.so.symbols.items[rhs].elfSym(ctx.ef);
return lhs_sym.st_value < rhs_sym.st_value;
}
};
@ -330,16 +360,16 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
const gpa = comp.gpa;
var aliases = std.ArrayList(Symbol.Index).init(gpa);
defer aliases.deinit();
try aliases.ensureTotalCapacityPrecise(self.globals().len);
try aliases.ensureTotalCapacityPrecise(self.symbols.items.len);
for (self.globals()) |index| {
const global = elf_file.symbol(index);
const global_file = global.file(elf_file) orelse continue;
if (global_file.index() != self.index) continue;
aliases.appendAssumeCapacity(index);
for (self.symbols_resolver.items, 0..) |resolv, index| {
const ref = elf_file.resolver.get(resolv).?;
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
aliases.appendAssumeCapacity(@intCast(index));
}
std.mem.sort(u32, aliases.items, elf_file, SortAlias.lessThan);
std.mem.sort(u32, aliases.items, SortAlias{ .so = self, .ef = elf_file }, SortAlias.lessThan);
self.aliases = aliases.moveToUnmanaged();
}
@ -347,27 +377,93 @@ pub fn initSymbolAliases(self: *SharedObject, elf_file: *Elf) !void {
pub fn symbolAliases(self: *SharedObject, index: u32, elf_file: *Elf) []const u32 {
assert(self.aliases != null);
const symbol = elf_file.symbol(index).elfSym(elf_file);
const symbol = self.symbols.items[index].elfSym(elf_file);
const aliases = self.aliases.?;
const start = for (aliases.items, 0..) |alias, i| {
const alias_sym = elf_file.symbol(alias).elfSym(elf_file);
const alias_sym = self.symbols.items[alias].elfSym(elf_file);
if (symbol.st_value == alias_sym.st_value) break i;
} else aliases.items.len;
const end = for (aliases.items[start..], 0..) |alias, i| {
const alias_sym = elf_file.symbol(alias).elfSym(elf_file);
const alias_sym = self.symbols.items[alias].elfSym(elf_file);
if (symbol.st_value < alias_sym.st_value) break i + start;
} else aliases.items.len;
return aliases.items[start..end];
}
fn addString(self: *SharedObject, allocator: Allocator, str: []const u8) !u32 {
const off: u32 = @intCast(self.strtab.items.len);
try self.strtab.ensureUnusedCapacity(allocator, str.len + 1);
self.strtab.appendSliceAssumeCapacity(str);
self.strtab.appendAssumeCapacity(0);
return off;
}
pub fn getString(self: SharedObject, off: u32) [:0]const u8 {
assert(off < self.strtab.items.len);
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
}
pub fn resolveSymbol(self: SharedObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
const resolv = self.symbols_resolver.items[index];
return elf_file.resolver.get(resolv).?;
}
fn addSymbol(self: *SharedObject, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
return self.addSymbolAssumeCapacity();
}
fn addSymbolAssumeCapacity(self: *SharedObject) Symbol.Index {
const index: Symbol.Index = @intCast(self.symbols.items.len);
self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
return index;
}
pub fn addSymbolExtra(self: *SharedObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
pub fn addSymbolExtraAssumeCapacity(self: *SharedObject, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn symbolExtra(self: *SharedObject, index: u32) Symbol.Extra {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *SharedObject, index: u32, extra: Symbol.Extra) void {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
pub fn format(
self: SharedObject,
comptime unused_fmt_string: []const u8,
@ -402,10 +498,15 @@ fn formatSymtab(
_ = unused_fmt_string;
_ = options;
const shared = ctx.shared;
const elf_file = ctx.elf_file;
try writer.writeAll(" globals\n");
for (shared.symbols.items) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
for (shared.symbols.items, 0..) |sym, i| {
const ref = shared.resolveSymbol(@intCast(i), elf_file);
if (elf_file.symbol(ref)) |ref_sym| {
try writer.print(" {}\n", .{ref_sym.fmt(elf_file)});
} else {
try writer.print(" {s} : unclaimed\n", .{sym.name(elf_file)});
}
}
}

View File

@ -63,9 +63,7 @@ pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
}
pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
if (symbol.flags.global) return elf_file.strings.getAssumeExists(symbol.name_offset);
const file_ptr = symbol.file(elf_file).?;
return switch (file_ptr) {
return switch (symbol.file(elf_file).?) {
inline else => |x| x.getString(symbol.name_offset),
};
}
@ -87,9 +85,8 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
}
pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
const file_ptr = symbol.file(elf_file).?;
return switch (file_ptr) {
.zig_object => |x| x.elfSym(symbol.esym_index).*,
return switch (symbol.file(elf_file).?) {
.zig_object => |x| x.symtab.items(.elf_sym)[symbol.esym_index],
inline else => |x| x.symtab.items[symbol.esym_index],
};
}
@ -159,20 +156,20 @@ pub fn outputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
const symtab_ctx = switch (file_ptr) {
inline else => |x| x.output_symtab_ctx,
};
const idx = symbol.extra(elf_file).?.symtab;
const idx = symbol.extra(elf_file).symtab;
return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
}
pub fn gotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_got) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const entry = elf_file.got.entries.items[extras.got];
return entry.address(elf_file);
}
pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!(symbol.flags.has_plt and symbol.flags.has_got)) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const shdr = elf_file.shdrs.items[elf_file.plt_got_section_index.?];
const cpu_arch = elf_file.getTarget().cpu.arch;
return @intCast(shdr.sh_addr + extras.plt_got * PltGotSection.entrySize(cpu_arch));
@ -180,7 +177,7 @@ pub fn pltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_plt) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const shdr = elf_file.shdrs.items[elf_file.plt_section_index.?];
const cpu_arch = elf_file.getTarget().cpu.arch;
return @intCast(shdr.sh_addr + extras.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch));
@ -188,7 +185,7 @@ pub fn pltAddress(symbol: Symbol, elf_file: *Elf) i64 {
pub fn gotPltAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_plt) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const shdr = elf_file.shdrs.items[elf_file.got_plt_section_index.?];
return @intCast(shdr.sh_addr + extras.plt * 8 + GotPltSection.preamble_size);
}
@ -201,21 +198,21 @@ pub fn copyRelAddress(symbol: Symbol, elf_file: *Elf) i64 {
pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_tlsgd) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const entry = elf_file.got.entries.items[extras.tlsgd];
return entry.address(elf_file);
}
pub fn gotTpAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_gottp) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const entry = elf_file.got.entries.items[extras.gottp];
return entry.address(elf_file);
}
pub fn tlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_tlsdesc) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
const entry = elf_file.got.entries.items[extras.tlsdesc];
return entry.address(elf_file);
}
@ -228,14 +225,14 @@ const GetOrCreateZigGotEntryResult = struct {
pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, elf_file: *Elf) !GetOrCreateZigGotEntryResult {
assert(!elf_file.base.isRelocatable());
assert(symbol.flags.needs_zig_got);
if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).?.zig_got };
if (symbol.flags.has_zig_got) return .{ .found_existing = true, .index = symbol.extra(elf_file).zig_got };
const index = try elf_file.zig_got.addSymbol(symbol_index, elf_file);
return .{ .found_existing = false, .index = index };
}
pub fn zigGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.has_zig_got) return 0;
const extras = symbol.extra(elf_file).?;
const extras = symbol.extra(elf_file);
return elf_file.zig_got.entryAddress(extras.zig_got, elf_file);
}
@ -265,11 +262,8 @@ const AddExtraOpts = struct {
zig_got: ?u32 = null,
};
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
if (symbol.extra(elf_file) == null) {
symbol.extra_index = try elf_file.addSymbolExtra(.{});
}
var extras = symbol.extra(elf_file).?;
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
var extras = symbol.extra(elf_file);
inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
if (@field(opts, field.name)) |x| {
@field(extras, field.name) = x;
@ -278,12 +272,16 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
symbol.setExtra(extras, elf_file);
}
pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {
return elf_file.symbolExtra(symbol.extra_index);
pub fn extra(symbol: Symbol, elf_file: *Elf) Extra {
return switch (symbol.file(elf_file).?) {
inline else => |x| x.symbolExtra(symbol.extra_index),
};
}
pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
elf_file.setSymbolExtra(symbol.extra_index, extras);
return switch (symbol.file(elf_file).?) {
inline else => |x| x.setSymbolExtra(symbol.extra_index, extras),
};
}
pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
@ -426,12 +424,6 @@ pub const Flags = packed struct {
/// Whether this symbol is weak.
weak: bool = false,
/// Whether the symbol has its name interned in global symbol
/// resolver table.
/// This happens for any symbol that is considered a global
/// symbol, but is not necessarily an import or export.
global: bool = false,
/// Whether the symbol makes into the output symtab.
output_symtab: bool = false,

View File

@ -8,9 +8,11 @@ data: std.ArrayListUnmanaged(u8) = .{},
path: []const u8,
index: File.Index,
local_esyms: std.MultiArrayList(ElfSym) = .{},
global_esyms: std.MultiArrayList(ElfSym) = .{},
symtab: std.MultiArrayList(ElfSym) = .{},
strtab: StringTable = .{},
symbols: std.ArrayListUnmanaged(Symbol) = .{},
symbols_extra: std.ArrayListUnmanaged(u32) = .{},
symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
@ -87,18 +89,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
try self.strtab.buffer.append(gpa, 0);
const name_off = try self.strtab.insert(gpa, self.path);
const symbol_index = try elf_file.addSymbol();
try self.local_symbols.append(gpa, symbol_index);
const symbol_ptr = elf_file.symbol(symbol_index);
symbol_ptr.file_index = self.index;
symbol_ptr.name_offset = name_off;
const esym_index = try self.addLocalEsym(gpa);
const esym = &self.local_esyms.items(.elf_sym)[esym_index];
esym.st_name = name_off;
const symbol_index = try self.newLocalSymbol(gpa, name_off);
const sym = self.symbol(symbol_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
esym.st_info = elf.STT_FILE;
esym.st_shndx = elf.SHN_ABS;
symbol_ptr.esym_index = esym_index;
switch (comp.config.debug_format) {
.strip => {},
@ -112,9 +107,11 @@ pub fn init(self: *ZigObject, elf_file: *Elf) !void {
pub fn deinit(self: *ZigObject, allocator: Allocator) void {
self.data.deinit(allocator);
self.local_esyms.deinit(allocator);
self.global_esyms.deinit(allocator);
self.symtab.deinit(allocator);
self.strtab.deinit(allocator);
self.symbols.deinit(allocator);
self.symbols_extra.deinit(allocator);
self.symbols_resolver.deinit(allocator);
self.local_symbols.deinit(allocator);
self.global_symbols.deinit(allocator);
self.globals_lookup.deinit(allocator);
@ -262,50 +259,75 @@ fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
}
}
pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
try self.local_esyms.ensureUnusedCapacity(allocator, 1);
const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
var esym = ElfSym{ .elf_sym = Elf.null_sym };
esym.elf_sym.st_info = elf.STB_LOCAL << 4;
self.local_esyms.set(index, esym);
fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
try self.symtab.ensureUnusedCapacity(allocator, 1);
try self.symbols.ensureUnusedCapacity(allocator, 1);
try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra));
const index = self.addSymbolAssumeCapacity();
const sym = &self.symbols.items[index];
sym.name_offset = name_off;
sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity());
const esym = ElfSym{ .elf_sym = .{
.st_value = 0,
.st_name = name_off,
.st_info = @as(u8, @intCast(st_bind)) << 4,
.st_other = 0,
.st_size = 0,
.st_shndx = 0,
} };
self.symtab.set(index, esym);
sym.esym_index = esym_idx;
return index;
}
pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
try self.global_esyms.ensureUnusedCapacity(allocator, 1);
const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
var esym = ElfSym{ .elf_sym = Elf.null_sym };
esym.elf_sym.st_info = elf.STB_GLOBAL << 4;
self.global_esyms.set(index, esym);
return index | global_symbol_bit;
fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
try self.local_symbols.ensureUnusedCapacity(allocator, 1);
const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len);
const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL);
self.local_symbols.appendAssumeCapacity(index);
return fake_index;
}
pub fn newAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
const gpa = elf_file.base.comp.gpa;
const atom_index = try self.addAtom(gpa);
const symbol_index = try elf_file.addSymbol();
const esym_index = try self.addLocalEsym(gpa);
fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
try self.global_symbols.ensureUnusedCapacity(allocator, 1);
try self.symbols_resolver.ensureUnusedCapacity(allocator, 1);
const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len);
const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL);
self.global_symbols.appendAssumeCapacity(index);
self.symbols_resolver.addOneAssumeCapacity().* = 0;
return fake_index | global_symbol_bit;
}
try self.atoms_indexes.append(gpa, atom_index);
try self.local_symbols.append(gpa, symbol_index);
fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
try self.atoms.ensureUnusedCapacity(allocator, 1);
try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
try self.atoms_indexes.ensureUnusedCapacity(allocator, 1);
try self.relocs.ensureUnusedCapacity(allocator, 1);
const symbol_ptr = elf_file.symbol(symbol_index);
symbol_ptr.file_index = self.index;
symbol_ptr.ref = .{ .index = atom_index, .file = self.index };
const index = self.addAtomAssumeCapacity();
self.atoms_indexes.appendAssumeCapacity(index);
const atom_ptr = self.atom(index).?;
atom_ptr.name_offset = name_off;
self.local_esyms.items(.shndx)[esym_index] = atom_index;
self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
symbol_ptr.esym_index = esym_index;
// TODO I'm thinking that maybe we shouldn' set this value unless it's actually needed?
const relocs_index = @as(u32, @intCast(self.relocs.items.len));
const relocs = try self.relocs.addOne(gpa);
relocs.* = .{};
const atom_ptr = self.atom(atom_index).?;
const relocs_index: u32 = @intCast(self.relocs.items.len);
self.relocs.addOneAssumeCapacity().* = .{};
atom_ptr.relocs_section_index = relocs_index;
return symbol_index;
return index;
}
fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
const atom_index = try self.newAtom(allocator, name_off);
const sym_index = try self.newLocalSymbol(allocator, name_off);
const sym = self.symbol(sym_index);
sym.ref = .{ .index = atom_index, .file = self.index };
self.symtab.items(.shndx)[sym.esym_index] = atom_index;
self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
return sym_index;
}
/// TODO actually create fake input shdrs and return that instead.
@ -320,48 +342,47 @@ pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.E
return shdr;
}
pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
const esym = self.global_esyms.items(.elf_sym)[i];
const shndx = self.global_esyms.items(.shndx)[i];
pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void {
const gpa = elf_file.base.comp.gpa;
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
for (self.global_symbols.items, 0..) |index, i| {
const global = &self.symbols.items[index];
const esym = global.elfSym(elf_file);
const shndx = self.symtab.items(.shndx)[global.esym_index];
if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) {
assert(esym.st_shndx == SHN_ATOM);
const atom_ptr = self.atom(shndx) orelse continue;
if (!atom_ptr.alive) continue;
}
const global = elf_file.symbol(index);
if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
const atom_index = switch (esym.st_shndx) {
elf.SHN_ABS, elf.SHN_COMMON => 0,
SHN_ATOM => shndx,
else => unreachable,
};
global.value = @intCast(esym.st_value);
global.ref = .{ .index = atom_index, .file = self.index };
global.esym_index = esym_index;
global.file_index = self.index;
global.version_index = elf_file.default_sym_version;
if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
const resolv = &self.symbols_resolver.items[i];
const gop = try elf_file.resolver.getOrPut(gpa, .{
.index = @intCast(i | global_symbol_bit),
.file = self.index,
}, elf_file);
if (!gop.found_existing) {
gop.ref.* = .{ .index = 0, .file = 0 };
}
resolv.* = gop.index;
if (esym.st_shndx == elf.SHN_UNDEF) continue;
if (elf_file.symbol(gop.ref.*) == null) {
gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
continue;
}
if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
}
}
}
pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
const esym = self.global_esyms.items(.elf_sym)[i];
pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
for (self.global_symbols.items, 0..) |index, i| {
const global = &self.symbols.items[index];
const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
const global = elf_file.symbol(index);
if (global.file(elf_file)) |_| {
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
}
if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
const is_import = blk: {
if (!elf_file.isEffectivelyDynLib()) break :blk false;
@ -372,29 +393,30 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = esym_index;
global.esym_index = @intCast(index);
global.file_index = self.index;
global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
global.flags.import = is_import;
const idx = self.symbols_resolver.items[i];
elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
}
}
pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
const esym = self.global_esyms.items(.elf_sym)[i];
for (self.global_symbols.items, 0..) |index, i| {
const global = &self.symbols.items[index];
const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_shndx != elf.SHN_UNDEF) continue;
const global = elf_file.symbol(index);
if (global.file(elf_file)) |file| {
if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF or file.index() <= self.index) continue;
}
if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
global.value = 0;
global.ref = .{ .index = 0, .file = 0 };
global.esym_index = esym_index;
global.esym_index = @intCast(index);
global.file_index = self.index;
const idx = self.symbols_resolver.items[i];
elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
}
}
@ -417,12 +439,14 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
}
pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
for (self.globals(), 0..) |index, i| {
const esym = self.global_esyms.items(.elf_sym)[i];
for (self.global_symbols.items, 0..) |index, i| {
const global = self.symbols.items[index];
const esym = self.symtab.items(.elf_sym)[index];
if (esym.st_bind() == elf.STB_WEAK) continue;
const global = elf_file.symbol(index);
const file = global.file(elf_file) orelse continue;
const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
const should_keep = esym.st_shndx == elf.SHN_UNDEF or
(esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
if (should_keep and !file.isAlive()) {
@ -432,14 +456,36 @@ pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
}
}
pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
for (self.globals(), 0..) |index, i| {
const esym = self.global_esyms.items(.elf_sym)[i];
const shndx = self.global_esyms.items(.shndx)[i];
const global = elf_file.symbol(index);
const global_file = global.file(elf_file) orelse continue;
pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
for (0..self.global_symbols.items.len) |i| {
const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
const file = sym.file(elf_file).?;
if (sym.version_index == elf.VER_NDX_LOCAL) continue;
const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
if (vis == .HIDDEN) continue;
if (file == .shared_object and !sym.isAbs(elf_file)) {
sym.flags.import = true;
continue;
}
if (file.index() == self.index) {
sym.flags.@"export" = true;
if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
sym.flags.import = true;
}
}
}
}
if (self.index == global_file.index() or
pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
for (self.global_symbols.items, 0..) |index, i| {
const esym = self.symtab.items(.elf_sym)[index];
const shndx = self.symtab.items(.shndx)[index];
const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
const ref_file = ref_sym.file(elf_file).?;
if (self.index == ref_file.index() or
esym.st_shndx == elf.SHN_UNDEF or
esym.st_bind() == elf.STB_WEAK or
esym.st_shndx == elf.SHN_COMMON) continue;
@ -449,7 +495,7 @@ pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{O
if (!atom_ptr.alive) continue;
}
const gop = try dupes.getOrPut(index);
const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
@ -481,12 +527,13 @@ pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
const gpa = elf_file.base.comp.gpa;
try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.globals().len);
try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len);
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file).?;
assert(file_ptr.index() == self.index);
for (self.global_symbols.items, 0..) |index, i| {
const global = self.symbols.items[index];
const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
const sym = elf_file.symbol(ref).?;
assert(sym.file(elf_file).?.index() == self.index);
if (global.outputShndx(elf_file) == null) continue;
const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
@ -528,33 +575,9 @@ pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
}
}
inline fn isGlobal(index: Symbol.Index) bool {
return index & global_symbol_bit != 0;
}
pub fn symbol(self: ZigObject, index: Symbol.Index) Symbol.Index {
const actual_index = index & symbol_mask;
if (isGlobal(index)) return self.globals()[actual_index];
return self.locals()[actual_index];
}
pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
const actual_index = index & symbol_mask;
if (isGlobal(index)) return &self.global_esyms.items(.elf_sym)[actual_index];
return &self.local_esyms.items(.elf_sym)[actual_index];
}
pub fn locals(self: ZigObject) []const Symbol.Index {
return self.local_symbols.items;
}
pub fn globals(self: ZigObject) []const Symbol.Index {
return self.global_symbols.items;
}
pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
for (self.local_symbols.items) |index| {
const local = &self.symbols.items[index];
if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
const esym = local.elfSym(elf_file);
switch (esym.st_type()) {
@ -562,22 +585,23 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
else => {},
}
local.flags.output_symtab = true;
try local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
self.output_symtab_ctx.strsize += @as(u32, @intCast(local.name(elf_file).len)) + 1;
}
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
const global = &self.symbols.items[index];
const ref = elf_file.resolver.values.items[resolv - 1];
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
global.flags.output_symtab = true;
if (global.isLocal(elf_file)) {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
self.output_symtab_ctx.nlocals += 1;
} else {
try global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
self.output_symtab_ctx.nglobals += 1;
}
self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
@ -585,8 +609,8 @@ pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
}
pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
for (self.locals()) |local_index| {
const local = elf_file.symbol(local_index);
for (self.local_symbols.items) |index| {
const local = &self.symbols.items[index];
const idx = local.outputSymtabIndex(elf_file) orelse continue;
const out_sym = &elf_file.symtab.items[idx];
out_sym.st_name = @intCast(elf_file.strtab.items.len);
@ -595,10 +619,11 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
local.setOutputSym(elf_file, out_sym);
}
for (self.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const file_ptr = global.file(elf_file) orelse continue;
if (file_ptr.index() != self.index) continue;
for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
const global = self.symbols.items[index];
const ref = elf_file.resolver.values.items[resolv - 1];
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != self.index) continue;
const idx = global.outputSymtabIndex(elf_file) orelse continue;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
@ -609,10 +634,6 @@ pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
}
}
pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
/// Returns atom's code.
/// Caller owns the memory.
pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
@ -645,13 +666,13 @@ pub fn getDeclVAddr(
reloc_info: link.File.RelocInfo,
) !u64 {
const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
const this_sym = elf_file.symbol(this_sym_index);
const this_sym = self.symbol(this_sym_index);
const vaddr = this_sym.address(.{}, elf_file);
const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
try parent_atom.addReloc(elf_file, .{
.r_offset = reloc_info.offset,
.r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | r_type,
.r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
.r_addend = reloc_info.addend,
});
return @intCast(vaddr);
@ -664,13 +685,13 @@ pub fn getAnonDeclVAddr(
reloc_info: link.File.RelocInfo,
) !u64 {
const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
const sym = elf_file.symbol(sym_index);
const sym = self.symbol(sym_index);
const vaddr = sym.address(.{}, elf_file);
const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
try parent_atom.addReloc(elf_file, .{
.r_offset = reloc_info.offset,
.r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | r_type,
.r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
.r_addend = reloc_info.addend,
});
return @intCast(vaddr);
@ -692,7 +713,7 @@ pub fn lowerAnonDecl(
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
const existing_alignment = self.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
if (decl_alignment.order(existing_alignment).compare(.lte))
return .ok;
}
@ -753,8 +774,8 @@ pub fn getOrCreateMetadataForLazySymbol(
};
switch (metadata.state.*) {
.unused => {
const symbol_index = try self.newAtom(elf_file);
const sym = elf_file.symbol(symbol_index);
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const sym = self.symbol(symbol_index);
sym.flags.needs_zig_got = true;
metadata.symbol_index.* = symbol_index;
},
@ -778,13 +799,10 @@ fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: InternPool.De
}
fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
_ = self;
const gpa = elf_file.base.comp.gpa;
const sym = elf_file.symbol(sym_index);
const sym = self.symbol(sym_index);
sym.atom(elf_file).?.free(elf_file);
log.debug("adding %{d} to local symbols free list", .{sym_index});
elf_file.symbols_free_list.append(gpa, sym_index) catch {};
elf_file.symbols.items[sym_index] = .{};
self.symbols.items[sym_index] = .{};
// TODO free GOT entry here
}
@ -817,10 +835,10 @@ pub fn getOrCreateMetadataForDecl(
const gop = try self.decls.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
const symbol_index = try self.newAtom(elf_file);
const symbol_index = try self.newSymbolWithAtom(gpa, 0);
const mod = elf_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
const sym = elf_file.symbol(symbol_index);
const sym = self.symbol(symbol_index);
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
sym.flags.is_tls = true;
@ -909,8 +927,8 @@ fn updateDeclCode(
target_util.minFunctionAlignment(mod.getTarget()),
);
const sym = elf_file.symbol(sym_index);
const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
const atom_ptr = sym.atom(elf_file).?;
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
@ -940,7 +958,7 @@ fn updateDeclCode(
if (!elf_file.base.isRelocatable()) {
log.debug(" (writing new offset table entry)", .{});
assert(sym.flags.has_zig_got);
const extra = sym.extra(elf_file).?;
const extra = sym.extra(elf_file);
try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
}
}
@ -1007,8 +1025,8 @@ fn updateTlv(
const required_alignment = decl.getAlignment(pt);
const sym = elf_file.symbol(sym_index);
const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
const sym = self.symbol(sym_index);
const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
const atom_ptr = sym.atom(elf_file).?;
const name_offset = try self.strtab.insert(gpa, decl.fqn.toSlice(ip));
@ -1064,7 +1082,7 @@ pub fn updateFunc(
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
self.freeUnnamedConsts(elf_file, decl_index);
elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
@ -1096,7 +1114,7 @@ pub fn updateFunc(
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_FUNC);
if (decl_state) |*ds| {
const sym = elf_file.symbol(sym_index);
const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@ -1130,13 +1148,13 @@ pub fn updateDecl(
const variable = decl.getOwnedVariable(mod).?;
const name = decl.name.toSlice(&mod.intern_pool);
const lib_name = variable.lib_name.toSlice(&mod.intern_pool);
const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;
const sym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
self.symbol(sym_index).flags.needs_got = true;
return;
}
const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
self.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
const gpa = elf_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
@ -1174,7 +1192,7 @@ pub fn updateDecl(
try self.updateDeclCode(elf_file, pt, decl_index, sym_index, shndx, code, elf.STT_OBJECT);
if (decl_state) |*ds| {
const sym = elf_file.symbol(sym_index);
const sym = self.symbol(sym_index);
try self.dwarf.?.commitDeclState(
pt,
decl_index,
@ -1233,9 +1251,9 @@ fn updateLazySymbol(
.code => elf_file.zig_text_section_index.?,
.const_data => elf_file.zig_data_rel_ro_section_index.?,
};
const local_sym = elf_file.symbol(symbol_index);
const local_sym = self.symbol(symbol_index);
local_sym.name_offset = name_str_index;
const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
local_esym.st_name = name_str_index;
local_esym.st_info |= elf.STT_OBJECT;
local_esym.st_size = code.len;
@ -1323,7 +1341,8 @@ fn lowerConst(
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const sym_index = try self.newAtom(elf_file);
const name_off = try self.addString(gpa, name);
const sym_index = try self.newSymbolWithAtom(gpa, name_off);
const res = try codegen.generateSymbol(
&elf_file.base,
@ -1339,27 +1358,19 @@ fn lowerConst(
.fail => |em| return .{ .fail = em },
};
const local_sym = elf_file.symbol(sym_index);
const name_str_index = try self.strtab.insert(gpa, name);
local_sym.name_offset = name_str_index;
const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
local_esym.st_name = name_str_index;
const local_sym = self.symbol(sym_index);
const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
local_esym.st_info |= elf.STT_OBJECT;
local_esym.st_size = code.len;
const atom_ptr = local_sym.atom(elf_file).?;
atom_ptr.alive = true;
atom_ptr.name_offset = name_str_index;
atom_ptr.alignment = required_alignment;
atom_ptr.size = code.len;
atom_ptr.output_section_index = output_section_index;
try atom_ptr.allocate(elf_file);
// TODO rename and re-audit this method
errdefer self.freeDeclMetadata(elf_file, sym_index);
local_sym.value = 0;
local_esym.st_value = 0;
const shdr = elf_file.shdrs.items[output_section_index];
const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
try elf_file.base.file.?.pwriteAll(code, file_offset);
@ -1401,9 +1412,9 @@ pub fn updateExports(
},
};
const sym_index = metadata.symbol_index;
const esym_index = elf_file.symbol(sym_index).esym_index;
const esym = self.local_esyms.items(.elf_sym)[esym_index];
const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
const esym_index = self.symbol(sym_index).esym_index;
const esym = self.symtab.items(.elf_sym)[esym_index];
const esym_shndx = self.symtab.items(.shndx)[esym_index];
for (export_indices) |export_idx| {
const exp = mod.all_exports.items[export_idx];
@ -1437,22 +1448,27 @@ pub fn updateExports(
const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
const name_off = try self.strtab.insert(gpa, exp_name);
const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
exp_index.*
else blk: {
const global_esym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
try metadata.exports.append(gpa, global_esym_index);
break :blk global_esym_index;
const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
try metadata.exports.append(gpa, global_sym_index);
break :blk global_sym_index;
};
const actual_esym_index = global_esym_index & symbol_mask;
const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];
global_esym.st_value = @intCast(elf_file.symbol(sym_index).value);
const value = self.symbol(sym_index).value;
const global_sym = self.symbol(global_sym_index);
global_sym.value = value;
global_sym.flags.weak = exp.opts.linkage == .weak;
global_sym.version_index = elf_file.default_sym_version;
global_sym.ref = .{ .index = esym_shndx, .file = self.index };
const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index];
global_esym.st_value = @intCast(value);
global_esym.st_shndx = esym.st_shndx;
global_esym.st_info = (stb_bits << 4) | stt_bits;
global_esym.st_name = name_off;
global_esym.st_size = esym.st_size;
self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx;
}
}
@ -1488,16 +1504,10 @@ pub fn deleteExport(
const exp_name = name.toSlice(&mod.intern_pool);
const esym_index = metadata.@"export"(self, exp_name) orelse return;
log.debug("deleting export '{s}'", .{exp_name});
const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
const esym = &self.symtab.items(.elf_sym)[esym_index.*];
_ = self.globals_lookup.remove(esym.st_name);
const sym_index = elf_file.resolver.get(esym.st_name).?;
const sym = elf_file.symbol(sym_index);
if (sym.file_index == self.index) {
_ = elf_file.resolver.swapRemove(esym.st_name);
sym.* = .{};
}
esym.* = Elf.null_sym;
self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
}
pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
@ -1506,16 +1516,19 @@ pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_n
const off = try self.strtab.insert(gpa, name);
const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
if (!lookup_gop.found_existing) {
const esym_index = try self.addGlobalEsym(gpa);
const esym = self.elfSym(esym_index);
esym.st_name = off;
lookup_gop.value_ptr.* = esym_index;
const gop = try elf_file.getOrPutGlobal(name);
try self.global_symbols.append(gpa, gop.index);
lookup_gop.value_ptr.* = try self.newGlobalSymbol(gpa, off);
}
return lookup_gop.value_ptr.*;
}
pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
return self.strtab.insert(allocator, string);
}
pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
return self.strtab.getAssumeExists(off);
}
@ -1586,6 +1599,77 @@ pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
}
}
inline fn isGlobal(index: Symbol.Index) bool {
return index & global_symbol_bit != 0;
}
pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol {
const actual_index = index & symbol_mask;
if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]];
return &self.symbols.items[self.local_symbols.items[actual_index]];
}
pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
if (isGlobal(index)) {
const resolv = self.symbols_resolver.items[index & symbol_mask];
return elf_file.resolver.get(resolv).?;
}
return .{ .index = index, .file = self.index };
}
fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
try self.symbols.ensureUnusedCapacity(allocator, 1);
return self.addSymbolAssumeCapacity();
}
fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index {
const index: Symbol.Index = @intCast(self.symbols.items.len);
self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
return index;
}
pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
return self.addSymbolExtraAssumeCapacity(extra);
}
pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
const index = @as(u32, @intCast(self.symbols_extra.items.len));
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields) |field| {
self.symbols_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
var i: usize = index;
var result: Symbol.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.symbols_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
const fields = @typeInfo(Symbol.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.symbols_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
return .{ .data = .{
.self = self,
@ -1606,15 +1690,17 @@ fn formatSymtab(
) !void {
_ = unused_fmt_string;
_ = options;
const self = ctx.self;
const elf_file = ctx.elf_file;
try writer.writeAll(" locals\n");
for (ctx.self.locals()) |index| {
const local = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
for (self.local_symbols.items) |index| {
const local = self.symbols.items[index];
try writer.print(" {}\n", .{local.fmt(elf_file)});
}
try writer.writeAll(" globals\n");
for (ctx.self.globals()) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
for (ctx.self.global_symbols.items) |index| {
const global = self.symbols.items[index];
try writer.print(" {}\n", .{global.fmt(elf_file)});
}
}
@ -1658,9 +1744,9 @@ const DeclMetadata = struct {
/// A list of all exports aliases of this Decl.
exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
fn @"export"(m: DeclMetadata, zo: *ZigObject, name: []const u8) ?*u32 {
for (m.exports.items) |*exp| {
const exp_name = zig_object.getString(zig_object.elfSym(exp.*).st_name);
const exp_name = zo.getString(zo.symbol(exp.*).name_offset);
if (mem.eql(u8, name, exp_name)) return exp;
}
return null;

View File

@ -145,10 +145,10 @@ pub const Cie = struct {
if (cie_rel.r_addend != other_rel.r_addend) return false;
const cie_object = elf_file.file(cie.file_index).?.object;
const cie_ref = cie_object.resolveSymbol(cie_rel.r_sym(), elf_file);
const other_object = elf_file.file(other.file_index).?.object;
const cie_sym = cie_object.symbols.items[cie_rel.r_sym()];
const other_sym = other_object.symbols.items[other_rel.r_sym()];
if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false;
const other_ref = other_object.resolveSymbol(other_rel.r_sym(), elf_file);
if (!cie_ref.eql(other_ref)) return false;
}
return true;
}
@ -339,7 +339,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
const contents = cie.data(elf_file);
for (cie.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
resolveReloc(cie, sym, rel, elf_file, contents) catch |err| switch (err) {
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
@ -366,7 +367,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
);
for (fde.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
resolveReloc(fde, sym, rel, elf_file, contents) catch |err| switch (err) {
error.RelocFailure => has_reloc_errors = true,
else => |e| return e,
@ -452,7 +454,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
for (object.cies.items) |cie| {
if (!cie.alive) continue;
for (cie.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
const out_rel = emitReloc(elf_file, cie, sym, rel);
try writer.writeStruct(out_rel);
}
@ -461,7 +464,8 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
for (fde.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
const out_rel = emitReloc(elf_file, fde, sym, rel);
try writer.writeStruct(out_rel);
}
@ -513,7 +517,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
const relocs = fde.relocs(elf_file);
assert(relocs.len > 0); // Should this be an error? Things are completely broken anyhow if this trips...
const rel = relocs[0];
const sym = elf_file.symbol(object.symbols.items[rel.r_sym()]);
const ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.symbol(ref).?;
const P = @as(i64, @intCast(fde.address(elf_file)));
const S = @as(i64, @intCast(sym.address(.{}, elf_file)));
const A = rel.r_addend;

View File

@ -61,20 +61,10 @@ pub const File = union(enum) {
return (@as(u32, base) << 24) + file.index();
}
pub fn resolveSymbols(file: File, elf_file: *Elf) void {
switch (file) {
pub fn resolveSymbols(file: File, elf_file: *Elf) !void {
return switch (file) {
inline else => |x| x.resolveSymbols(elf_file),
}
}
pub fn resetGlobals(file: File, elf_file: *Elf) void {
for (file.globals()) |global_index| {
const global = elf_file.symbol(global_index);
const name_offset = global.name_offset;
global.* = .{};
global.name_offset = name_offset;
global.flags.global = true;
}
};
}
pub fn setAlive(file: File) void {
@ -98,6 +88,77 @@ pub const File = union(enum) {
}
}
pub fn createSymbolIndirection(file: File, elf_file: *Elf) !void {
const impl = struct {
fn impl(sym: *Symbol, ref: Elf.Ref, ef: *Elf) !void {
if (!sym.isLocal(ef) and !sym.flags.has_dynamic) {
log.debug("'{s}' is non-local", .{sym.name(ef)});
try ef.dynsym.addSymbol(ref, ef);
}
if (sym.flags.needs_got) {
log.debug("'{s}' needs GOT", .{sym.name(ef)});
_ = try ef.got.addGotSymbol(ref, ef);
}
if (sym.flags.needs_plt) {
if (sym.flags.is_canonical) {
log.debug("'{s}' needs CPLT", .{sym.name(ef)});
sym.flags.@"export" = true;
try ef.plt.addSymbol(ref, ef);
} else if (sym.flags.needs_got) {
log.debug("'{s}' needs PLTGOT", .{sym.name(ef)});
try ef.plt_got.addSymbol(ref, ef);
} else {
log.debug("'{s}' needs PLT", .{sym.name(ef)});
try ef.plt.addSymbol(ref, ef);
}
}
if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
log.debug("'{s}' needs COPYREL", .{sym.name(ef)});
try ef.copy_rel.addSymbol(ref, ef);
}
if (sym.flags.needs_tlsgd) {
log.debug("'{s}' needs TLSGD", .{sym.name(ef)});
try ef.got.addTlsGdSymbol(ref, ef);
}
if (sym.flags.needs_gottp) {
log.debug("'{s}' needs GOTTP", .{sym.name(ef)});
try ef.got.addGotTpSymbol(ref, ef);
}
if (sym.flags.needs_tlsdesc) {
log.debug("'{s}' needs TLSDESC", .{sym.name(ef)});
try ef.got.addTlsDescSymbol(ref, ef);
}
}
}.impl;
switch (file) {
.zig_object => |x| {
for (x.local_symbols.items, 0..) |idx, i| {
const sym = &x.symbols.items[idx];
const ref = x.resolveSymbol(@intCast(i), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != x.index) continue;
try impl(sym, ref, elf_file);
}
for (x.global_symbols.items, 0..) |idx, i| {
const sym = &x.symbols.items[idx];
const ref = x.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != x.index) continue;
try impl(sym, ref, elf_file);
}
},
inline else => |x| {
for (x.symbols.items, 0..) |*sym, i| {
const ref = x.resolveSymbol(@intCast(i), elf_file);
const ref_sym = elf_file.symbol(ref) orelse continue;
if (ref_sym.file(elf_file).?.index() != x.index) continue;
try impl(sym, ref, elf_file);
}
},
}
}
pub fn atom(file: File, atom_index: Atom.Index) ?*Atom {
return switch (file) {
.shared_object => unreachable,
@ -144,23 +205,16 @@ pub const File = union(enum) {
};
}
pub fn symbol(file: File, ind: Symbol.Index) Symbol.Index {
pub fn resolveSymbol(file: File, ind: Symbol.Index, elf_file: *Elf) Elf.Ref {
return switch (file) {
inline else => |x| x.resolveSymbol(ind, elf_file),
};
}
pub fn symbol(file: File, ind: Symbol.Index) *Symbol {
return switch (file) {
.zig_object => |x| x.symbol(ind),
inline else => |x| x.symbols.items[ind],
};
}
pub fn locals(file: File) []const Symbol.Index {
return switch (file) {
.linker_defined, .shared_object => &[0]Symbol.Index{},
inline else => |x| x.locals(),
};
}
pub fn globals(file: File) []const Symbol.Index {
return switch (file) {
inline else => |x| x.globals(),
inline else => |x| &x.symbols.items[ind],
};
}
@ -237,6 +291,7 @@ pub const File = union(enum) {
const std = @import("std");
const elf = std.elf;
const log = std.log.scoped(.link);
const Allocator = std.mem.Allocator;
const Archive = @import("Archive.zig");

View File

@ -1,72 +1,85 @@
pub fn gcAtoms(elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const num_files = elf_file.objects.items.len + @intFromBool(elf_file.zig_object_index != null);
var files = try std.ArrayList(File.Index).initCapacity(gpa, num_files);
defer files.deinit();
if (elf_file.zig_object_index) |index| files.appendAssumeCapacity(index);
for (elf_file.objects.items) |index| files.appendAssumeCapacity(index);
var roots = std.ArrayList(*Atom).init(gpa);
defer roots.deinit();
try collectRoots(&roots, files.items, elf_file);
try collectRoots(&roots, elf_file);
mark(roots, elf_file);
prune(files.items, elf_file);
prune(elf_file);
}
fn collectRoots(roots: *std.ArrayList(*Atom), files: []const File.Index, elf_file: *Elf) !void {
fn collectRoots(roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
if (elf_file.linkerDefinedPtr()) |obj| {
if (obj.entry_index) |index| {
const global = elf_file.symbol(index);
try markSymbol(global, roots, elf_file);
if (obj.entrySymbol(elf_file)) |sym| {
try markSymbol(sym, roots, elf_file);
}
}
for (files) |index| {
for (elf_file.file(index).?.globals()) |global_index| {
const global = elf_file.symbol(global_index);
if (global.file(elf_file)) |file| {
if (file.index() == index and global.flags.@"export")
try markSymbol(global, roots, elf_file);
}
}
}
for (files) |index| {
const file = elf_file.file(index).?;
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (!atom.alive) continue;
const shdr = atom.inputShdr(elf_file);
const name = atom.name(elf_file);
const is_gc_root = blk: {
if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true;
if (shdr.sh_type == elf.SHT_NOTE) break :blk true;
if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true;
if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true;
if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true;
if (mem.startsWith(u8, name, ".ctors")) break :blk true;
if (mem.startsWith(u8, name, ".dtors")) break :blk true;
if (mem.startsWith(u8, name, ".init")) break :blk true;
if (mem.startsWith(u8, name, ".fini")) break :blk true;
if (Elf.isCIdentifier(name)) break :blk true;
break :blk false;
};
if (is_gc_root and markAtom(atom)) try roots.append(atom);
if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
}
// Mark every atom referenced by CIE as alive.
for (file.cies()) |cie| {
for (cie.relocs(elf_file)) |rel| {
const sym = elf_file.symbol(file.symbol(rel.r_sym()));
if (elf_file.zigObjectPtr()) |zo| {
for (0..zo.global_symbols.items.len) |i| {
const ref = zo.resolveSymbol(@intCast(i | ZigObject.global_symbol_bit), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
if (sym.file(elf_file).?.index() != zo.index) continue;
if (sym.flags.@"export") {
try markSymbol(sym, roots, elf_file);
}
}
}
for (elf_file.objects.items) |index| {
const object = elf_file.file(index).?.object;
for (0..object.globals().len) |i| {
const ref = object.resolveSymbol(@intCast(i), elf_file);
const sym = elf_file.symbol(ref) orelse continue;
if (sym.file(elf_file).?.index() != object.index) continue;
if (sym.flags.@"export") {
try markSymbol(sym, roots, elf_file);
}
}
}
const atomRoots = struct {
fn atomRoots(file: File, rs: anytype, ef: *Elf) !void {
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (!atom.alive) continue;
const shdr = atom.inputShdr(ef);
const name = atom.name(ef);
const is_gc_root = blk: {
if (shdr.sh_flags & elf.SHF_GNU_RETAIN != 0) break :blk true;
if (shdr.sh_type == elf.SHT_NOTE) break :blk true;
if (shdr.sh_type == elf.SHT_PREINIT_ARRAY) break :blk true;
if (shdr.sh_type == elf.SHT_INIT_ARRAY) break :blk true;
if (shdr.sh_type == elf.SHT_FINI_ARRAY) break :blk true;
if (mem.startsWith(u8, name, ".ctors")) break :blk true;
if (mem.startsWith(u8, name, ".dtors")) break :blk true;
if (mem.startsWith(u8, name, ".init")) break :blk true;
if (mem.startsWith(u8, name, ".fini")) break :blk true;
if (Elf.isCIdentifier(name)) break :blk true;
break :blk false;
};
if (is_gc_root and markAtom(atom)) try rs.append(atom);
if (shdr.sh_flags & elf.SHF_ALLOC == 0) atom.visited = true;
}
// Mark every atom referenced by CIE as alive.
for (file.cies()) |cie| {
for (cie.relocs(ef)) |rel| {
const ref = file.resolveSymbol(rel.r_sym(), ef);
const sym = ef.symbol(ref) orelse continue;
try markSymbol(sym, rs, ef);
}
}
}
}.atomRoots;
if (elf_file.zigObjectPtr()) |zo| {
try atomRoots(zo.asFile(), roots, elf_file);
}
for (elf_file.objects.items) |index| {
try atomRoots(elf_file.file(index).?, roots, elf_file);
}
}
fn markSymbol(sym: *Symbol, roots: *std.ArrayList(*Atom), elf_file: *Elf) !void {
@ -92,7 +105,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
for (atom.fdes(elf_file)) |fde| {
for (fde.relocs(elf_file)[1..]) |rel| {
const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
const ref = file.resolveSymbol(rel.r_sym(), elf_file);
const target_sym = elf_file.symbol(ref) orelse continue;
const target_atom = target_sym.atom(elf_file) orelse continue;
target_atom.alive = true;
gc_track_live_log.debug("{}marking live atom({d})", .{ track_live_level, target_atom.atom_index });
@ -101,7 +115,8 @@ fn markLive(atom: *Atom, elf_file: *Elf) void {
}
for (atom.relocs(elf_file)) |rel| {
const target_sym = elf_file.symbol(file.symbol(rel.r_sym()));
const ref = file.resolveSymbol(rel.r_sym(), elf_file);
const target_sym = elf_file.symbol(ref) orelse continue;
if (target_sym.mergeSubsection(elf_file)) |msub| {
msub.alive = true;
continue;
@ -120,16 +135,23 @@ fn mark(roots: std.ArrayList(*Atom), elf_file: *Elf) void {
}
}
fn prune(files: []const File.Index, elf_file: *Elf) void {
for (files) |index| {
const file = elf_file.file(index).?;
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (atom.alive and !atom.visited) {
atom.alive = false;
atom.markFdesDead(elf_file);
fn prune(elf_file: *Elf) void {
const pruneInFile = struct {
fn pruneInFile(file: File, ef: *Elf) void {
for (file.atoms()) |atom_index| {
const atom = file.atom(atom_index) orelse continue;
if (atom.alive and !atom.visited) {
atom.alive = false;
atom.markFdesDead(ef);
}
}
}
}.pruneInFile;
if (elf_file.zigObjectPtr()) |zo| {
pruneInFile(zo.asFile(), elf_file);
}
for (elf_file.objects.items) |index| {
pruneInFile(elf_file.file(index).?, elf_file);
}
}
@ -181,3 +203,4 @@ const Atom = @import("Atom.zig");
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;
const Symbol = @import("Symbol.zig");
const ZigObject = @import("ZigObject.zig");

View File

@ -37,7 +37,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co
// First, we flush relocatable object file generated with our backends.
if (elf_file.zigObjectPtr()) |zig_object| {
zig_object.resolveSymbols(elf_file);
try zig_object.resolveSymbols(elf_file);
try elf_file.addCommentString();
try elf_file.finalizeMergeSections();
zig_object.claimUnresolvedObject(elf_file);
@ -383,7 +383,7 @@ fn updateComdatGroupsSizes(elf_file: *Elf) void {
shdr.sh_size = cg.size(elf_file);
shdr.sh_link = elf_file.symtab_section_index.?;
const sym = elf_file.symbol(cg.symbol(elf_file));
const sym = cg.symbol(elf_file);
shdr.sh_info = sym.outputSymtabIndex(elf_file) orelse
elf_file.sectionSymbolOutputSymtabIndex(sym.outputShndx(elf_file).?);
}

View File

@ -251,15 +251,16 @@ pub const ZigGotSection = struct {
pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const zo = elf_file.zigObjectPtr().?;
const index = try zig_got.allocateEntry(gpa);
const entry = &zig_got.entries.items[index];
entry.* = sym_index;
const symbol = elf_file.symbol(sym_index);
const symbol = zo.symbol(sym_index);
symbol.flags.has_zig_got = true;
if (elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) {
zig_got.flags.needs_rela = true;
}
try symbol.addExtra(.{ .zig_got = index }, elf_file);
symbol.addExtra(.{ .zig_got = index }, elf_file);
return index;
}
@ -282,6 +283,7 @@ pub const ZigGotSection = struct {
}
pub fn writeOne(zig_got: *ZigGotSection, elf_file: *Elf, index: Index) !void {
const zo = elf_file.zigObjectPtr().?;
if (zig_got.flags.dirty) {
const needed_size = zig_got.size(elf_file);
try elf_file.growAllocSection(elf_file.zig_got_section_index.?, needed_size);
@ -293,7 +295,7 @@ pub const ZigGotSection = struct {
const off = zig_got.entryOffset(index, elf_file);
const vaddr: u64 = @intCast(zig_got.entryAddress(index, elf_file));
const entry = zig_got.entries.items[index];
const value = elf_file.symbol(entry).address(.{}, elf_file);
const value = zo.symbol(entry).address(.{}, elf_file);
switch (entry_size) {
2 => {
var buf: [2]u8 = undefined;
@ -336,8 +338,9 @@ pub const ZigGotSection = struct {
}
pub fn writeAll(zig_got: ZigGotSection, elf_file: *Elf, writer: anytype) !void {
const zo = elf_file.zigObjectPtr().?;
for (zig_got.entries.items) |entry| {
const symbol = elf_file.symbol(entry);
const symbol = zo.symbol(entry);
const value = symbol.address(.{ .plt = false }, elf_file);
try writeInt(value, elf_file, writer);
}
@ -351,9 +354,10 @@ pub const ZigGotSection = struct {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
const zo = elf_file.zigObjectPtr().?;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, zig_got.numRela());
for (zig_got.entries.items) |entry| {
const symbol = elf_file.symbol(entry);
const symbol = zo.symbol(entry);
const offset = symbol.zigGotAddress(elf_file);
elf_file.addRelaDynAssumeCapacity(.{
.offset = @intCast(offset),
@ -364,16 +368,18 @@ pub const ZigGotSection = struct {
}
pub fn updateSymtabSize(zig_got: *ZigGotSection, elf_file: *Elf) void {
const zo = elf_file.zigObjectPtr().?;
zig_got.output_symtab_ctx.nlocals = @as(u32, @intCast(zig_got.entries.items.len));
for (zig_got.entries.items) |entry| {
const name = elf_file.symbol(entry).name(elf_file);
const name = zo.symbol(entry).name(elf_file);
zig_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$ziggot".len)) + 1;
}
}
pub fn writeSymtab(zig_got: ZigGotSection, elf_file: *Elf) void {
const zo = elf_file.zigObjectPtr().?;
for (zig_got.entries.items, zig_got.output_symtab_ctx.ilocal.., 0..) |entry, ilocal, index| {
const symbol = elf_file.symbol(entry);
const symbol = zo.symbol(entry);
const symbol_name = symbol.name(elf_file);
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
@ -409,15 +415,18 @@ pub const ZigGotSection = struct {
) !void {
_ = options;
_ = unused_fmt_string;
const zig_got = ctx.zig_got;
const elf_file = ctx.elf_file;
try writer.writeAll(".zig.got\n");
for (ctx.zig_got.entries.items, 0..) |entry, index| {
const symbol = ctx.elf_file.symbol(entry);
for (zig_got.entries.items, 0..) |entry, index| {
const zo = elf_file.zigObjectPtr().?;
const symbol = zo.symbol(entry);
try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
index,
ctx.zig_got.entryAddress(@intCast(index), ctx.elf_file),
zig_got.entryAddress(@intCast(index), elf_file),
entry,
symbol.address(.{}, ctx.elf_file),
symbol.name(ctx.elf_file),
symbol.address(.{}, elf_file),
symbol.name(elf_file),
});
}
}
@ -446,7 +455,7 @@ pub const GotSection = struct {
const Entry = struct {
tag: Tag,
symbol_index: Symbol.Index,
ref: Elf.Ref,
cell_index: Index,
/// Returns how many indexes in the GOT this entry uses.
@ -477,25 +486,25 @@ pub const GotSection = struct {
const last = got.entries.items[index - 1];
break :blk last.cell_index + @as(Index, @intCast(last.len()));
} else 0;
entry.* = .{ .tag = undefined, .symbol_index = undefined, .cell_index = cell_index };
entry.* = .{ .tag = undefined, .ref = undefined, .cell_index = cell_index };
return index;
}
pub fn addGotSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !Index {
pub fn addGotSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !Index {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = try got.allocateEntry(gpa);
const entry = &got.entries.items[index];
entry.tag = .got;
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
entry.ref = ref;
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_got = true;
if (symbol.flags.import or symbol.isIFunc(elf_file) or
((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and !symbol.isAbs(elf_file)))
{
got.flags.needs_rela = true;
}
try symbol.addExtra(.{ .got = index }, elf_file);
symbol.addExtra(.{ .got = index }, elf_file);
return index;
}
@ -506,48 +515,48 @@ pub const GotSection = struct {
const index = try got.allocateEntry(gpa);
const entry = &got.entries.items[index];
entry.tag = .tlsld;
entry.symbol_index = undefined; // unused
entry.ref = .{ .index = 0, .file = 0 }; // unused
got.flags.needs_rela = true;
got.tlsld_index = index;
}
pub fn addTlsGdSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addTlsGdSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = try got.allocateEntry(gpa);
const entry = &got.entries.items[index];
entry.tag = .tlsgd;
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
entry.ref = ref;
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_tlsgd = true;
if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
try symbol.addExtra(.{ .tlsgd = index }, elf_file);
symbol.addExtra(.{ .tlsgd = index }, elf_file);
}
pub fn addGotTpSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addGotTpSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = try got.allocateEntry(gpa);
const entry = &got.entries.items[index];
entry.tag = .gottp;
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
entry.ref = ref;
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_gottp = true;
if (symbol.flags.import or elf_file.isEffectivelyDynLib()) got.flags.needs_rela = true;
try symbol.addExtra(.{ .gottp = index }, elf_file);
symbol.addExtra(.{ .gottp = index }, elf_file);
}
pub fn addTlsDescSymbol(got: *GotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addTlsDescSymbol(got: *GotSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = try got.allocateEntry(gpa);
const entry = &got.entries.items[index];
entry.tag = .tlsdesc;
entry.symbol_index = sym_index;
const symbol = elf_file.symbol(sym_index);
entry.ref = ref;
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_tlsdesc = true;
got.flags.needs_rela = true;
try symbol.addExtra(.{ .tlsdesc = index }, elf_file);
symbol.addExtra(.{ .tlsdesc = index }, elf_file);
}
pub fn size(got: GotSection, elf_file: *Elf) usize {
@ -564,10 +573,7 @@ pub const GotSection = struct {
const apply_relocs = true; // TODO add user option for this
for (got.entries.items) |entry| {
const symbol = switch (entry.tag) {
.tlsld => null,
inline else => elf_file.symbol(entry.symbol_index),
};
const symbol = elf_file.symbol(entry.ref);
switch (entry.tag) {
.got => {
const value = blk: {
@ -637,11 +643,8 @@ pub const GotSection = struct {
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, got.numRela(elf_file));
for (got.entries.items) |entry| {
const symbol = switch (entry.tag) {
.tlsld => null,
inline else => elf_file.symbol(entry.symbol_index),
};
const extra = if (symbol) |s| s.extra(elf_file).? else null;
const symbol = elf_file.symbol(entry.ref);
const extra = if (symbol) |s| s.extra(elf_file) else null;
switch (entry.tag) {
.got => {
@ -740,10 +743,7 @@ pub const GotSection = struct {
const is_dyn_lib = elf_file.isEffectivelyDynLib();
var num: usize = 0;
for (got.entries.items) |entry| {
const symbol = switch (entry.tag) {
.tlsld => null,
inline else => elf_file.symbol(entry.symbol_index),
};
const symbol = elf_file.symbol(entry.ref);
switch (entry.tag) {
.got => if (symbol.?.flags.import or symbol.?.isIFunc(elf_file) or
((elf_file.isEffectivelyDynLib() or (elf_file.base.isExe() and comp.config.pie)) and
@ -775,24 +775,15 @@ pub const GotSection = struct {
pub fn updateSymtabSize(got: *GotSection, elf_file: *Elf) void {
got.output_symtab_ctx.nlocals = @as(u32, @intCast(got.entries.items.len));
for (got.entries.items) |entry| {
const symbol_name = switch (entry.tag) {
.tlsld => "",
inline else => elf_file.symbol(entry.symbol_index).name(elf_file),
};
const symbol_name = if (elf_file.symbol(entry.ref)) |sym| sym.name(elf_file) else "";
got.output_symtab_ctx.strsize += @as(u32, @intCast(symbol_name.len + @tagName(entry.tag).len)) + 1 + 1;
}
}
pub fn writeSymtab(got: GotSection, elf_file: *Elf) void {
for (got.entries.items, got.output_symtab_ctx.ilocal..) |entry, ilocal| {
const symbol = switch (entry.tag) {
.tlsld => null,
inline else => elf_file.symbol(entry.symbol_index),
};
const symbol_name = switch (entry.tag) {
.tlsld => "",
inline else => symbol.?.name(elf_file),
};
const symbol = elf_file.symbol(entry.ref);
const symbol_name = if (symbol) |s| s.name(elf_file) else "";
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(symbol_name);
elf_file.strtab.appendAssumeCapacity('$');
@ -828,36 +819,38 @@ pub const GotSection = struct {
) !void {
_ = options;
_ = unused_fmt_string;
const got = ctx.got;
const elf_file = ctx.elf_file;
try writer.writeAll("GOT\n");
for (ctx.got.entries.items) |entry| {
const symbol = ctx.elf_file.symbol(entry.symbol_index);
try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
for (got.entries.items) |entry| {
const symbol = elf_file.symbol(entry.ref).?;
try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
entry.cell_index,
entry.address(ctx.elf_file),
entry.symbol_index,
symbol.address(.{}, ctx.elf_file),
symbol.name(ctx.elf_file),
entry.address(elf_file),
entry.ref,
symbol.address(.{}, elf_file),
symbol.name(elf_file),
});
}
}
};
pub const PltSection = struct {
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
output_symtab_ctx: Elf.SymtabCtx = .{},
pub fn deinit(plt: *PltSection, allocator: Allocator) void {
plt.symbols.deinit(allocator);
}
pub fn addSymbol(plt: *PltSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addSymbol(plt: *PltSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = @as(u32, @intCast(plt.symbols.items.len));
const symbol = elf_file.symbol(sym_index);
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_plt = true;
try symbol.addExtra(.{ .plt = index }, elf_file);
try plt.symbols.append(gpa, sym_index);
symbol.addExtra(.{ .plt = index }, elf_file);
try plt.symbols.append(gpa, ref);
}
pub fn size(plt: PltSection, elf_file: *Elf) usize {
@ -895,10 +888,10 @@ pub const PltSection = struct {
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_plt.ensureUnusedCapacity(gpa, plt.numRela());
for (plt.symbols.items) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (plt.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
assert(sym.flags.import);
const extra = sym.extra(elf_file).?;
const extra = sym.extra(elf_file);
const r_offset: u64 = @intCast(sym.gotPltAddress(elf_file));
const r_sym: u64 = extra.dynamic;
const r_type = relocation.encode(.jump_slot, cpu_arch);
@ -916,16 +909,16 @@ pub const PltSection = struct {
pub fn updateSymtabSize(plt: *PltSection, elf_file: *Elf) void {
plt.output_symtab_ctx.nlocals = @as(u32, @intCast(plt.symbols.items.len));
for (plt.symbols.items) |sym_index| {
const name = elf_file.symbol(sym_index).name(elf_file);
for (plt.symbols.items) |ref| {
const name = elf_file.symbol(ref).?.name(elf_file);
plt.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$plt".len)) + 1;
}
}
pub fn writeSymtab(plt: PltSection, elf_file: *Elf) void {
const cpu_arch = elf_file.getTarget().cpu.arch;
for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |sym_index, ilocal| {
const sym = elf_file.symbol(sym_index);
for (plt.symbols.items, plt.output_symtab_ctx.ilocal..) |ref, ilocal| {
const sym = elf_file.symbol(ref).?;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
elf_file.strtab.appendSliceAssumeCapacity("$plt");
@ -958,15 +951,17 @@ pub const PltSection = struct {
) !void {
_ = options;
_ = unused_fmt_string;
const plt = ctx.plt;
const elf_file = ctx.elf_file;
try writer.writeAll("PLT\n");
for (ctx.plt.symbols.items, 0..) |symbol_index, i| {
const symbol = ctx.elf_file.symbol(symbol_index);
try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
for (plt.symbols.items, 0..) |ref, i| {
const symbol = elf_file.symbol(ref).?;
try writer.print(" {d}@0x{x} => {}@0x{x} ({s})\n", .{
i,
symbol.pltAddress(ctx.elf_file),
symbol_index,
symbol.address(.{}, ctx.elf_file),
symbol.name(ctx.elf_file),
symbol.pltAddress(elf_file),
ref,
symbol.address(.{}, elf_file),
symbol.name(elf_file),
});
}
}
@ -988,8 +983,8 @@ pub const PltSection = struct {
try writer.writeAll(&preamble);
try writer.writeByteNTimes(0xcc, preambleSize(.x86_64) - preamble.len);
for (plt.symbols.items, 0..) |sym_index, i| {
const sym = elf_file.symbol(sym_index);
for (plt.symbols.items, 0..) |ref, i| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotPltAddress(elf_file);
const source_addr = sym.pltAddress(elf_file);
disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 12)) - 4;
@ -1037,8 +1032,8 @@ pub const PltSection = struct {
}
}
for (plt.symbols.items) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (plt.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotPltAddress(elf_file);
const source_addr = sym.pltAddress(elf_file);
const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
@ -1075,7 +1070,7 @@ pub const GotPltSection = struct {
_ = got_plt;
{
// [0]: _DYNAMIC
const symbol = elf_file.symbol(elf_file.linkerDefinedPtr().?.dynamic_index.?);
const symbol = elf_file.linkerDefinedPtr().?.dynamicSymbol(elf_file).?;
try writer.writeInt(u64, @intCast(symbol.address(.{}, elf_file)), .little);
}
// [1]: 0x0
@ -1093,22 +1088,22 @@ pub const GotPltSection = struct {
};
pub const PltGotSection = struct {
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
output_symtab_ctx: Elf.SymtabCtx = .{},
pub fn deinit(plt_got: *PltGotSection, allocator: Allocator) void {
plt_got.symbols.deinit(allocator);
}
pub fn addSymbol(plt_got: *PltGotSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addSymbol(plt_got: *PltGotSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = @as(u32, @intCast(plt_got.symbols.items.len));
const symbol = elf_file.symbol(sym_index);
const symbol = elf_file.symbol(ref).?;
symbol.flags.has_plt = true;
symbol.flags.has_got = true;
try symbol.addExtra(.{ .plt_got = index }, elf_file);
try plt_got.symbols.append(gpa, sym_index);
symbol.addExtra(.{ .plt_got = index }, elf_file);
try plt_got.symbols.append(gpa, ref);
}
pub fn size(plt_got: PltGotSection, elf_file: *Elf) usize {
@ -1134,15 +1129,15 @@ pub const PltGotSection = struct {
pub fn updateSymtabSize(plt_got: *PltGotSection, elf_file: *Elf) void {
plt_got.output_symtab_ctx.nlocals = @as(u32, @intCast(plt_got.symbols.items.len));
for (plt_got.symbols.items) |sym_index| {
const name = elf_file.symbol(sym_index).name(elf_file);
for (plt_got.symbols.items) |ref| {
const name = elf_file.symbol(ref).?.name(elf_file);
plt_got.output_symtab_ctx.strsize += @as(u32, @intCast(name.len + "$pltgot".len)) + 1;
}
}
pub fn writeSymtab(plt_got: PltGotSection, elf_file: *Elf) void {
for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |sym_index, ilocal| {
const sym = elf_file.symbol(sym_index);
for (plt_got.symbols.items, plt_got.output_symtab_ctx.ilocal..) |ref, ilocal| {
const sym = elf_file.symbol(ref).?;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
elf_file.strtab.appendSliceAssumeCapacity("$pltgot");
@ -1160,8 +1155,8 @@ pub const PltGotSection = struct {
const x86_64 = struct {
pub fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
for (plt_got.symbols.items) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (plt_got.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotAddress(elf_file);
const source_addr = sym.pltGotAddress(elf_file);
const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr + 6)) - 4;
@ -1178,8 +1173,8 @@ pub const PltGotSection = struct {
const aarch64 = struct {
fn write(plt_got: PltGotSection, elf_file: *Elf, writer: anytype) !void {
for (plt_got.symbols.items) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (plt_got.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
const target_addr = sym.gotAddress(elf_file);
const source_addr = sym.pltGotAddress(elf_file);
const pages = try aarch64_util.calcNumberOfPages(source_addr, target_addr);
@ -1204,56 +1199,56 @@ pub const PltGotSection = struct {
};
pub const CopyRelSection = struct {
symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
symbols: std.ArrayListUnmanaged(Elf.Ref) = .{},
pub fn deinit(copy_rel: *CopyRelSection, allocator: Allocator) void {
copy_rel.symbols.deinit(allocator);
}
pub fn addSymbol(copy_rel: *CopyRelSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addSymbol(copy_rel: *CopyRelSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = @as(u32, @intCast(copy_rel.symbols.items.len));
const symbol = elf_file.symbol(sym_index);
const symbol = elf_file.symbol(ref).?;
symbol.flags.import = true;
symbol.flags.@"export" = true;
symbol.flags.has_copy_rel = true;
symbol.flags.weak = false;
try symbol.addExtra(.{ .copy_rel = index }, elf_file);
try copy_rel.symbols.append(gpa, sym_index);
symbol.addExtra(.{ .copy_rel = index }, elf_file);
try copy_rel.symbols.append(gpa, ref);
const shared_object = symbol.file(elf_file).?.shared_object;
if (shared_object.aliases == null) {
try shared_object.initSymbolAliases(elf_file);
}
const aliases = shared_object.symbolAliases(sym_index, elf_file);
const aliases = shared_object.symbolAliases(ref.index, elf_file);
for (aliases) |alias| {
if (alias == sym_index) continue;
const alias_sym = elf_file.symbol(alias);
if (alias == ref.index) continue;
const alias_sym = &shared_object.symbols.items[alias];
alias_sym.flags.import = true;
alias_sym.flags.@"export" = true;
alias_sym.flags.has_copy_rel = true;
alias_sym.flags.needs_copy_rel = true;
alias_sym.flags.weak = false;
try elf_file.dynsym.addSymbol(alias, elf_file);
try elf_file.dynsym.addSymbol(.{ .index = alias, .file = shared_object.index }, elf_file);
}
}
pub fn updateSectionSize(copy_rel: CopyRelSection, shndx: u32, elf_file: *Elf) !void {
const shdr = &elf_file.shdrs.items[shndx];
for (copy_rel.symbols.items) |sym_index| {
const symbol = elf_file.symbol(sym_index);
for (copy_rel.symbols.items) |ref| {
const symbol = elf_file.symbol(ref).?;
const shared_object = symbol.file(elf_file).?.shared_object;
const alignment = try symbol.dsoAlignment(elf_file);
symbol.value = @intCast(mem.alignForward(u64, shdr.sh_size, alignment));
shdr.sh_addralign = @max(shdr.sh_addralign, alignment);
shdr.sh_size = @as(u64, @intCast(symbol.value)) + symbol.elfSym(elf_file).st_size;
const aliases = shared_object.symbolAliases(sym_index, elf_file);
const aliases = shared_object.symbolAliases(ref.index, elf_file);
for (aliases) |alias| {
if (alias == sym_index) continue;
const alias_sym = elf_file.symbol(alias);
if (alias == ref.index) continue;
const alias_sym = &shared_object.symbols.items[alias];
alias_sym.value = symbol.value;
}
}
@ -1264,10 +1259,10 @@ pub const CopyRelSection = struct {
const gpa = comp.gpa;
const cpu_arch = elf_file.getTarget().cpu.arch;
try elf_file.rela_dyn.ensureUnusedCapacity(gpa, copy_rel.numRela());
for (copy_rel.symbols.items) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (copy_rel.symbols.items) |ref| {
const sym = elf_file.symbol(ref).?;
assert(sym.flags.import and sym.flags.has_copy_rel);
const extra = sym.extra(elf_file).?;
const extra = sym.extra(elf_file);
elf_file.addRelaDynAssumeCapacity(.{
.offset = @intCast(sym.address(.{}, elf_file)),
.sym = extra.dynamic,
@ -1285,8 +1280,8 @@ pub const DynsymSection = struct {
entries: std.ArrayListUnmanaged(Entry) = .{},
pub const Entry = struct {
/// Index of the symbol which gets privilege of getting a dynamic treatment
symbol_index: Symbol.Index,
/// Ref of the symbol which gets privilege of getting a dynamic treatment
ref: Elf.Ref,
/// Offset into .dynstrtab
off: u32,
};
@ -1295,22 +1290,22 @@ pub const DynsymSection = struct {
dynsym.entries.deinit(allocator);
}
pub fn addSymbol(dynsym: *DynsymSection, sym_index: Symbol.Index, elf_file: *Elf) !void {
pub fn addSymbol(dynsym: *DynsymSection, ref: Elf.Ref, elf_file: *Elf) !void {
const comp = elf_file.base.comp;
const gpa = comp.gpa;
const index = @as(u32, @intCast(dynsym.entries.items.len + 1));
const sym = elf_file.symbol(sym_index);
const sym = elf_file.symbol(ref).?;
sym.flags.has_dynamic = true;
try sym.addExtra(.{ .dynamic = index }, elf_file);
sym.addExtra(.{ .dynamic = index }, elf_file);
const off = try elf_file.insertDynString(sym.name(elf_file));
try dynsym.entries.append(gpa, .{ .symbol_index = sym_index, .off = off });
try dynsym.entries.append(gpa, .{ .ref = ref, .off = off });
}
pub fn sort(dynsym: *DynsymSection, elf_file: *Elf) void {
const Sort = struct {
pub fn lessThan(ctx: *Elf, lhs: Entry, rhs: Entry) bool {
const lhs_sym = ctx.symbol(lhs.symbol_index);
const rhs_sym = ctx.symbol(rhs.symbol_index);
const lhs_sym = ctx.symbol(lhs.ref).?;
const rhs_sym = ctx.symbol(rhs.ref).?;
if (lhs_sym.flags.@"export" != rhs_sym.flags.@"export") {
return rhs_sym.flags.@"export";
@ -1322,14 +1317,14 @@ pub const DynsymSection = struct {
const rhs_hash = GnuHashSection.hasher(rhs_sym.name(ctx)) % nbuckets;
if (lhs_hash == rhs_hash)
return lhs_sym.extra(ctx).?.dynamic < rhs_sym.extra(ctx).?.dynamic;
return lhs_sym.extra(ctx).dynamic < rhs_sym.extra(ctx).dynamic;
return lhs_hash < rhs_hash;
}
};
var num_exports: u32 = 0;
for (dynsym.entries.items) |entry| {
const sym = elf_file.symbol(entry.symbol_index);
const sym = elf_file.symbol(entry.ref).?;
if (sym.flags.@"export") num_exports += 1;
}
@ -1338,8 +1333,8 @@ pub const DynsymSection = struct {
std.mem.sort(Entry, dynsym.entries.items, elf_file, Sort.lessThan);
for (dynsym.entries.items, 1..) |entry, index| {
const sym = elf_file.symbol(entry.symbol_index);
var extra = sym.extra(elf_file).?;
const sym = elf_file.symbol(entry.ref).?;
var extra = sym.extra(elf_file);
extra.dynamic = @as(u32, @intCast(index));
sym.setExtra(extra, elf_file);
}
@ -1356,7 +1351,7 @@ pub const DynsymSection = struct {
pub fn write(dynsym: DynsymSection, elf_file: *Elf, writer: anytype) !void {
try writer.writeStruct(Elf.null_sym);
for (dynsym.entries.items) |entry| {
const sym = elf_file.symbol(entry.symbol_index);
const sym = elf_file.symbol(entry.ref).?;
var out_sym: elf.Elf64_Sym = Elf.null_sym;
sym.setOutputSym(elf_file, &out_sym);
out_sym.st_name = entry.off;
@ -1429,7 +1424,7 @@ pub const GnuHashSection = struct {
fn getExports(elf_file: *Elf) []const DynsymSection.Entry {
const start = for (elf_file.dynsym.entries.items, 0..) |entry, i| {
const sym = elf_file.symbol(entry.symbol_index);
const sym = elf_file.symbol(entry.ref).?;
if (sym.flags.@"export") break i;
} else elf_file.dynsym.entries.items.len;
return elf_file.dynsym.entries.items[start..];
@ -1477,7 +1472,7 @@ pub const GnuHashSection = struct {
@memset(bloom, 0);
for (exports, 0..) |entry, i| {
const sym = elf_file.symbol(entry.symbol_index);
const sym = elf_file.symbol(entry.ref).?;
const h = hasher(sym.name(elf_file));
hashes[i] = h;
indices[i] = h % hash.num_buckets;
@ -1574,7 +1569,7 @@ pub const VerneedSection = struct {
try verneed.ensureTotalCapacity(dynsyms.len);
for (dynsyms, 1..) |entry, i| {
const symbol = elf_file.symbol(entry.symbol_index);
const symbol = elf_file.symbol(entry.ref).?;
if (symbol.flags.import and symbol.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) {
const shared_object = symbol.file(elf_file).?.shared_object;
verneed.appendAssumeCapacity(.{
@ -1677,11 +1672,11 @@ pub const ComdatGroupSection = struct {
return cg_file.object.comdatGroup(cgs.cg_ref.index);
}
pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) Symbol.Index {
pub fn symbol(cgs: ComdatGroupSection, elf_file: *Elf) *Symbol {
const cg = cgs.comdatGroup(elf_file);
const object = cg.file(elf_file).object;
const shdr = object.shdrs.items[cg.shndx];
return object.symbols.items[shdr.sh_info];
return &object.symbols.items[shdr.sh_info];
}
pub fn size(cgs: ComdatGroupSection, elf_file: *Elf) usize {

View File

@ -43,11 +43,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
else => @panic("unsupported arch"),
};
if (is_reachable) continue;
const target = switch (file) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};
const target = file.resolveSymbol(rel.r_sym(), elf_file);
try thunk.symbols.put(gpa, target, {});
}
atom.addExtra(.{ .thunk = thunk_index }, elf_file);
@ -80,7 +76,7 @@ fn maxAllowedDistance(cpu_arch: std.Target.Cpu.Arch) u32 {
pub const Thunk = struct {
value: i64 = 0,
output_section_index: u32 = 0,
symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .{},
output_symtab_ctx: Elf.SymtabCtx = .{},
pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
@ -97,9 +93,9 @@ pub const Thunk = struct {
return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
}
pub fn targetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 {
pub fn targetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
const cpu_arch = elf_file.getTarget().cpu.arch;
return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch)));
return thunk.address(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
}
pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
@ -112,16 +108,16 @@ pub const Thunk = struct {
pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
for (thunk.symbols.keys()) |sym_index| {
const sym = elf_file.symbol(sym_index);
for (thunk.symbols.keys()) |ref| {
const sym = elf_file.symbol(ref).?;
thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.name(elf_file).len + "$thunk".len + 1));
}
}
pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
const cpu_arch = elf_file.getTarget().cpu.arch;
for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| {
const sym = elf_file.symbol(sym_index);
for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
const sym = elf_file.symbol(ref).?;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(sym.name(elf_file));
elf_file.strtab.appendSliceAssumeCapacity("$thunk");
@ -131,7 +127,7 @@ pub const Thunk = struct {
.st_info = elf.STT_FUNC,
.st_other = 0,
.st_shndx = @intCast(thunk.output_section_index),
.st_value = @intCast(thunk.targetAddress(sym_index, elf_file)),
.st_value = @intCast(thunk.targetAddress(ref, elf_file)),
.st_size = trampolineSize(cpu_arch),
};
}
@ -181,9 +177,9 @@ pub const Thunk = struct {
const thunk = ctx.thunk;
const elf_file = ctx.elf_file;
try writer.print("@{x} : size({x})\n", .{ thunk.value, thunk.size(elf_file) });
for (thunk.symbols.keys()) |index| {
const sym = elf_file.symbol(index);
try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.name(elf_file), sym.value });
for (thunk.symbols.keys()) |ref| {
const sym = elf_file.symbol(ref).?;
try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.name(elf_file), sym.value });
}
}
@ -195,12 +191,8 @@ const aarch64 = struct {
const r_type: elf.R_AARCH64 = @enumFromInt(rel.r_type());
if (r_type != .CALL26 and r_type != .JUMP26) return true;
const file = atom.file(elf_file).?;
const target_index = switch (file) {
.zig_object => |x| x.symbol(rel.r_sym()),
.object => |x| x.symbols.items[rel.r_sym()],
else => unreachable,
};
const target = elf_file.symbol(target_index);
const target_ref = file.resolveSymbol(rel.r_sym(), elf_file);
const target = elf_file.symbol(target_ref).?;
if (target.flags.has_plt) return false;
if (atom.output_section_index != target.output_section_index) return false;
const target_atom = target.atom(elf_file).?;
@ -212,8 +204,8 @@ const aarch64 = struct {
}
fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void {
for (thunk.symbols.keys(), 0..) |sym_index, i| {
const sym = elf_file.symbol(sym_index);
for (thunk.symbols.keys(), 0..) |ref, i| {
const sym = elf_file.symbol(ref).?;
const saddr = thunk.address(elf_file) + @as(i64, @intCast(i * trampoline_size));
const taddr = sym.address(.{}, elf_file);
const pages = try util.calcNumberOfPages(saddr, taddr);