mirror of
https://github.com/ziglang/zig.git
synced 2024-11-22 04:10:13 +00:00
Merge pull request #20971 from ziglang/elf-ownership-2
elf: move ownership of symbols into owning objects
This commit is contained in:
commit
cfe6ff4301
@ -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 });
|
||||
|
@ -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 });
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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(), .{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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).?;
|
||||
|
435
src/link/Elf.zig
435
src/link/Elf.zig
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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).?);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user