elf: make everything upside down - track by Symbol.Index rather than Atom.Index

This commit is contained in:
Jakub Konka 2023-09-05 23:10:04 +02:00
parent d9fffd431a
commit a9df098cd2
13 changed files with 624 additions and 605 deletions

View File

@ -4314,10 +4314,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(atom.getOffsetTableAddress(elf_file)));
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
try self.genSetReg(Type.usize, .x30, .{ .memory = got_addr });
} else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl);

View File

@ -4294,10 +4294,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
if (func_value.getFunction(mod)) |func| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(atom.getOffsetTableAddress(elf_file)));
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
try self.genSetReg(Type.usize, .lr, .{ .memory = got_addr });
} else if (self.bin_file.cast(link.File.MachO)) |_| {
unreachable; // unsupported architecture for MachO

View File

@ -1747,10 +1747,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
if (try self.air.value(callee, mod)) |func_value| {
switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
.func => |func| {
const atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(atom.getOffsetTableAddress(elf_file)));
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
const got_addr = @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
try self.genSetReg(Type.usize, .ra, .{ .memory = got_addr });
_ = try self.addInst(.{
.tag = .jalr,

View File

@ -1349,10 +1349,10 @@ 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 atom_index = try elf_file.getOrCreateAtomForDecl(func.owner_decl);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
break :blk @as(u32, @intCast(atom.getOffsetTableAddress(elf_file)));
const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
break :blk @as(u32, @intCast(sym.getOffsetTableAddress(elf_file)));
} else unreachable;
try self.genSetReg(Type.usize, .o7, .{ .memory = got_addr });

View File

@ -8149,10 +8149,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
else => null,
}) |owner_decl| {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = try elf_file.getOrCreateAtomForDecl(owner_decl);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
const got_addr = atom.getOffsetTableAddress(elf_file);
const sym_index = try elf_file.getOrCreateMetadataForDecl(owner_decl);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
const got_addr = sym.getOffsetTableAddress(elf_file);
try self.asmMemory(.{ ._, .call }, Memory.sib(.qword, .{
.base = .{ .reg = .ds },
.disp = @intCast(got_addr),
@ -10215,11 +10215,11 @@ fn genLazySymbolRef(
lazy_sym: link.File.LazySymbol,
) InnerError!void {
if (self.bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|
return self.fail("{s} creating lazy symbol", .{@errorName(err)});
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
const got_addr = atom.getOffsetTableAddress(elf_file);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
const got_addr = sym.getOffsetTableAddress(elf_file);
const got_mem =
Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(got_addr) });
switch (tag) {

View File

@ -854,10 +854,10 @@ fn genDeclRef(
const is_threadlocal = tv.val.isPtrToThreadLocal(mod) and !bin_file.options.single_threaded;
if (bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
const atom = elf_file.atom(atom_index);
_ = try atom.getOrCreateOffsetTableEntry(elf_file);
return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) });
const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
const sym = elf_file.symbol(sym_index);
_ = try sym.getOrCreateOffsetTableEntry(elf_file);
return GenResult.mcv(.{ .memory = sym.getOffsetTableAddress(elf_file) });
} else if (bin_file.cast(link.File.MachO)) |macho_file| {
const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
@ -892,7 +892,7 @@ fn genUnnamedConst(
return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)});
};
if (bin_file.cast(link.File.Elf)) |elf_file| {
return GenResult.mcv(.{ .memory = elf_file.symbol(local_sym_index).st_value });
return GenResult.mcv(.{ .memory = elf_file.symbol(local_sym_index).value });
} else if (bin_file.cast(link.File.MachO)) |_| {
return GenResult.mcv(.{ .load_direct = local_sym_index });
} else if (bin_file.cast(link.File.Coff)) |_| {

File diff suppressed because it is too large Load Diff

View File

@ -1,81 +1,65 @@
/// Each decl always gets a local symbol with the fully qualified name.
/// The vaddr and size are found here directly.
/// The file offset is found by computing the vaddr offset from the section vaddr
/// the symbol references, and adding that to the file offset of the section.
/// If this field is 0, it means the codegen size = 0 and there is no symbol or
/// offset table entry.
sym_index: u32 = 0,
/// Address allocated for this Atom.
value: u64 = 0,
/// Name of this Atom.
name_offset: u32 = 0,
/// Index into linker's input file table.
file_index: File.Index = 0,
/// Size of this atom
size: u64 = 0,
/// Alignment of this atom as a power of two.
alignment: u8 = 0,
/// Index of the input section.
input_section_index: u16 = 0,
/// Index of the output section.
output_section_index: u16 = 0,
/// Index of the input section containing this atom's relocs.
relocs_section_index: u16 = 0,
/// Index of this atom in the linker's atoms table.
atom_index: Index = 0,
/// Specifies whether this atom is alive or has been garbage collected.
alive: bool = true,
/// Specifies if the atom has been visited during garbage collection.
visited: bool = false,
/// Start index of FDEs referencing this atom.
fde_start: u32 = 0,
/// End index of FDEs referencing this atom.
fde_end: u32 = 0,
/// Points to the previous and next neighbors, based on the `text_offset`.
/// This can be used to find, for example, the capacity of this `TextBlock`.
prev_index: ?Index = null,
next_index: ?Index = null,
pub const Index = u32;
pub const Reloc = struct {
target: u32,
offset: u64,
addend: u32,
prev_vaddr: u64,
};
pub fn symbolIndex(self: *const Atom) ?u32 {
if (self.sym_index == 0) return null;
return self.sym_index;
}
pub fn symbol(self: *const Atom, elf_file: *Elf) *elf.Elf64_Sym {
return elf_file.symbol(self.symbolIndex().?);
}
pub fn name(self: *const Atom, elf_file: *Elf) []const u8 {
return elf_file.symbolName(self.symbolIndex().?);
}
/// If entry already exists, returns index to it.
/// Otherwise, creates a new entry in the Global Offset Table for this Atom.
pub fn getOrCreateOffsetTableEntry(self: *const Atom, elf_file: *Elf) !u32 {
const sym_index = self.symbolIndex().?;
if (elf_file.got_table.lookup.get(sym_index)) |index| return index;
const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, sym_index);
elf_file.got_table_count_dirty = true;
return index;
}
pub fn getOffsetTableAddress(self: *const Atom, elf_file: *Elf) u64 {
const sym_index = self.symbolIndex().?;
const got_entry_index = elf_file.got_table.lookup.get(sym_index).?;
const target = elf_file.base.options.target;
const ptr_bits = target.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];
return got.p_vaddr + got_entry_index * ptr_bytes;
pub fn name(self: Atom, elf_file: *Elf) []const u8 {
return elf_file.strtab.getAssumeExists(self.name_offset);
}
/// Returns how much room there is to grow in virtual address space.
/// File offset relocation happens transparently, so it is not included in
/// this calculation.
pub fn capacity(self: *const Atom, elf_file: *Elf) u64 {
const self_sym = self.symbol(elf_file);
if (self.next_index) |next_index| {
const next = elf_file.atom(next_index);
const next_sym = next.symbol(elf_file);
return next_sym.st_value - self_sym.st_value;
} else {
// We are the last block. The capacity is limited only by virtual address space.
return std.math.maxInt(u32) - self_sym.st_value;
}
pub fn capacity(self: Atom, elf_file: *Elf) u64 {
const next_value = if (self.next_index) |next_index| elf_file.atom(next_index).value else std.math.maxInt(u32);
return next_value - self.value;
}
pub fn freeListEligible(self: *const Atom, elf_file: *Elf) bool {
pub fn freeListEligible(self: Atom, elf_file: *Elf) bool {
// No need to keep a free list node for the last block.
const next_index = self.next_index orelse return false;
const next = elf_file.atom(next_index);
const self_sym = self.symbol(elf_file);
const next_sym = next.symbol(elf_file);
const cap = next_sym.st_value - self_sym.st_value;
const ideal_cap = Elf.padToIdeal(self_sym.st_size);
const cap = next.value - self.value;
const ideal_cap = Elf.padToIdeal(self.size);
if (cap <= ideal_cap) return false;
const surplus = cap - ideal_cap;
return surplus >= Elf.min_text_capacity;
@ -95,10 +79,149 @@ pub fn freeRelocations(elf_file: *Elf, atom_index: Index) void {
if (removed_relocs) |*relocs| relocs.value.deinit(elf_file.base.allocator);
}
const Atom = @This();
pub fn allocate(self: *Atom, elf_file: *Elf) !u64 {
const phdr_index = elf_file.sections.items(.phdr_index)[self.output_section_index];
const phdr = &elf_file.program_headers.items[phdr_index];
const shdr = &elf_file.sections.items(.shdr)[self.output_section_index];
const free_list = &elf_file.sections.items(.free_list)[self.output_section_index];
const maybe_last_atom_index = &elf_file.sections.items(.last_atom_index)[self.output_section_index];
const new_atom_ideal_capacity = Elf.padToIdeal(self.size);
const alignment = try std.math.powi(u64, 2, self.alignment);
// We use these to indicate our intention to update metadata, placing the new atom,
// and possibly removing a free list node.
// It would be simpler to do it inside the for loop below, but that would cause a
// problem if an error was returned later in the function. So this action
// is actually carried out at the end of the function, when errors are no longer possible.
var atom_placement: ?Atom.Index = null;
var free_list_removal: ?usize = null;
// First we look for an appropriately sized free list node.
// The list is unordered. We'll just take the first thing that works.
const vaddr = blk: {
var i: usize = if (elf_file.base.child_pid == null) 0 else free_list.items.len;
while (i < free_list.items.len) {
const big_atom_index = free_list.items[i];
const big_atom = elf_file.atom(big_atom_index);
// We now have a pointer to a live atom that has too much capacity.
// Is it enough that we could fit this new atom?
const cap = big_atom.capacity(elf_file);
const ideal_capacity = Elf.padToIdeal(cap);
const ideal_capacity_end_vaddr = std.math.add(u64, big_atom.value, ideal_capacity) catch ideal_capacity;
const capacity_end_vaddr = big_atom.value + cap;
const new_start_vaddr_unaligned = capacity_end_vaddr - new_atom_ideal_capacity;
const new_start_vaddr = std.mem.alignBackward(u64, new_start_vaddr_unaligned, alignment);
if (new_start_vaddr < ideal_capacity_end_vaddr) {
// Additional bookkeeping here to notice if this free list node
// should be deleted because the block that it points to has grown to take up
// more of the extra capacity.
if (!big_atom.freeListEligible(elf_file)) {
_ = free_list.swapRemove(i);
} else {
i += 1;
}
continue;
}
// At this point we know that we will place the new block here. But the
// remaining question is whether there is still yet enough capacity left
// over for there to still be a free list node.
const remaining_capacity = new_start_vaddr - ideal_capacity_end_vaddr;
const keep_free_list_node = remaining_capacity >= Elf.min_text_capacity;
// Set up the metadata to be updated, after errors are no longer possible.
atom_placement = big_atom_index;
if (!keep_free_list_node) {
free_list_removal = i;
}
break :blk new_start_vaddr;
} else if (maybe_last_atom_index.*) |last_index| {
const last = elf_file.atom(last_index);
const ideal_capacity = Elf.padToIdeal(last.size);
const ideal_capacity_end_vaddr = last.value + ideal_capacity;
const new_start_vaddr = std.mem.alignForward(u64, ideal_capacity_end_vaddr, alignment);
// Set up the metadata to be updated, after errors are no longer possible.
atom_placement = last_index;
break :blk new_start_vaddr;
} else {
break :blk phdr.p_vaddr;
}
};
const expand_section = if (atom_placement) |placement_index|
elf_file.atom(placement_index).next_index == null
else
true;
if (expand_section) {
const needed_size = (vaddr + self.size) - phdr.p_vaddr;
try elf_file.growAllocSection(self.output_section_index, needed_size);
maybe_last_atom_index.* = self.atom_index;
if (elf_file.dwarf) |_| {
// The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
// range of the compilation unit. When we expand the text section, this range changes,
// so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
elf_file.debug_info_header_dirty = true;
// This becomes dirty for the same reason. We could potentially make this more
// fine-grained with the addition of support for more compilation units. It is planned to
// model each package as a different compilation unit.
elf_file.debug_aranges_section_dirty = true;
}
}
shdr.sh_addralign = @max(shdr.sh_addralign, alignment);
// This function can also reallocate an atom.
// In this case we need to "unplug" it from its previous location before
// plugging it in to its new location.
if (self.prev_index) |prev_index| {
const prev = elf_file.atom(prev_index);
prev.next_index = self.next_index;
}
if (self.next_index) |next_index| {
const next = elf_file.atom(next_index);
next.prev_index = self.prev_index;
}
if (atom_placement) |big_atom_index| {
const big_atom = elf_file.atom(big_atom_index);
self.prev_index = big_atom_index;
self.next_index = big_atom.next_index;
big_atom.next_index = self.atom_index;
} else {
self.prev_index = null;
self.next_index = null;
}
if (free_list_removal) |i| {
_ = free_list.swapRemove(i);
}
return vaddr;
}
pub fn shrink(self: *Atom, elf_file: *Elf) void {
_ = self;
_ = elf_file;
}
pub fn grow(self: *Atom, elf_file: *Elf) !u64 {
const alignment = try std.math.powi(u64, 2, self.alignment);
const align_ok = std.mem.alignBackward(u64, self.value, alignment) == self.value;
const need_realloc = !align_ok or self.size > self.capacity(elf_file);
if (!need_realloc) return self.value;
return self.allocate(elf_file);
}
pub const Index = u32;
pub const Reloc = struct {
target: u32,
offset: u64,
addend: u32,
prev_vaddr: u64,
};
const std = @import("std");
const assert = std.debug.assert;
const elf = std.elf;
const Atom = @This();
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;

View File

@ -23,14 +23,14 @@ pub fn addGlobal(self: *LinkerDefined, name: [:0]const u8, elf_file: *Elf) !u32
.st_size = 0,
});
const off = try elf_file.internString("{s}", .{name});
const gop = try elf_file.getOrCreateGlobal(off);
const gop = try elf_file.getOrPutGlobal(off);
self.symbols.addOneAssumeCapacity().* = gop.index;
return gop.index;
}
pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
for (self.symbols.items, 0..) |index, i| {
const sym_idx = @as(u32, @intCast(i));
const sym_idx = @as(Symbol.Index, @intCast(i));
const this_sym = self.symtab.items[sym_idx];
if (this_sym.st_shndx == elf.SHN_UNDEF) continue;
@ -86,15 +86,19 @@ pub fn resolveSymbols(self: *LinkerDefined, elf_file: *Elf) void {
// }
// }
pub fn sourceSymbol(self: *LinkerDefined, symbol_index: Symbol.Index) *elf.Elf64_Sym {
return &self.symtab.items[symbol_index];
}
pub fn globals(self: *LinkerDefined) []const Symbol.Index {
return self.symbols.items;
}
pub fn asFile(self: *LinkerDefined) File {
return .{ .linker_defined = self };
}
pub inline fn getGlobals(self: *LinkerDefined) []const u32 {
return self.symbols.items;
}
pub fn fmtSymtab(self: *InternalObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
pub fn fmtSymtab(self: *LinkerDefined, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
return .{ .data = .{
.self = self,
.elf_file = elf_file,
@ -102,7 +106,7 @@ pub fn fmtSymtab(self: *InternalObject, elf_file: *Elf) std.fmt.Formatter(format
}
const FormatContext = struct {
self: *InternalObject,
self: *LinkerDefined,
elf_file: *Elf,
};
@ -115,8 +119,8 @@ fn formatSymtab(
_ = unused_fmt_string;
_ = options;
try writer.writeAll(" globals\n");
for (ctx.self.getGlobals()) |index| {
const global = ctx.elf_file.getSymbol(index);
for (ctx.self.globals()) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
}
}

View File

@ -32,9 +32,8 @@ extra_index: u32 = 0,
pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
const file_ptr = symbol.file(elf_file).?;
if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.shndx == 0
and file_ptr != .linker_defined and file_ptr != .zig_module;
// if (file_ptr == .shared) return symbol.sourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
return !symbol.flags.import and symbol.atom(elf_file) == null and symbol.output_section_index == 0 and file_ptr != .linker_defined and file_ptr != .zig_module;
}
pub fn isLocal(symbol: Symbol) bool {
@ -42,34 +41,30 @@ pub fn isLocal(symbol: Symbol) bool {
}
pub inline fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
return symbol.@"type"(elf_file) == elf.STT_GNU_IFUNC;
return symbol.type(elf_file) == elf.STT_GNU_IFUNC;
}
pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
const file_ptr = symbol.file(elf_file).?;
const s_sym = symbol.sourceSymbol(elf_file);
if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared) return elf.STT_FUNC;
// const file_ptr = symbol.file(elf_file).?;
// if (s_sym.st_type() == elf.STT_GNU_IFUNC and file_ptr == .shared) return elf.STT_FUNC;
return s_sym.st_type();
}
pub fn name(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
return elf_file.strtab.getAssumeExists(symbol.name);
return elf_file.strtab.getAssumeExists(symbol.name_offset);
}
pub fn atom(symbol: Symbol, elf_file: *Elf) ?*Atom {
return elf_file.atom(symbol.atom);
return elf_file.atom(symbol.atom_index);
}
pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
return elf_file.file(symbol.file);
return elf_file.file(symbol.file_index);
}
pub fn sourceSymbol(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
const file_ptr = symbol.file(elf_file).?;
return switch (file_ptr) {
.linker_defined, .zig_module => |x| x.symtab.items[symbol.sym_idx],
inline else => |x| x.symtab[symbol.sym_idx],
};
pub fn sourceSymbol(symbol: Symbol, elf_file: *Elf) *elf.Elf64_Sym {
return symbol.file(elf_file).?.sourceSymbol(symbol.symbol_index);
}
pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
@ -82,9 +77,29 @@ pub fn symbolRank(symbol: Symbol, elf_file: *Elf) u32 {
return file_ptr.symbolRank(sym, in_archive);
}
/// If entry already exists, returns index to it.
/// Otherwise, creates a new entry in the Global Offset Table for this Symbol.
pub fn getOrCreateOffsetTableEntry(self: Symbol, elf_file: *Elf) !Symbol.Index {
if (elf_file.got_table.lookup.get(self.symbol_index)) |index| return index;
const index = try elf_file.got_table.allocateEntry(elf_file.base.allocator, self.symbol_index);
elf_file.got_table_count_dirty = true;
return index;
}
pub fn getOffsetTableAddress(self: Symbol, elf_file: *Elf) u64 {
const got_entry_index = elf_file.got_table.lookup.get(self.symbol_index).?;
const target = elf_file.base.options.target;
const ptr_bits = target.ptrBitWidth();
const ptr_bytes: u64 = @divExact(ptr_bits, 8);
const got = elf_file.program_headers.items[elf_file.phdr_got_index.?];
return got.p_vaddr + got_entry_index * ptr_bytes;
}
pub fn address(symbol: Symbol, opts: struct {
plt: bool = true,
}, elf_file: *Elf) u64 {
_ = elf_file;
_ = opts;
// if (symbol.flags.copy_rel) {
// return elf_file.sectionAddress(elf_file.copy_rel_sect_index.?) + symbol.value;
// }
@ -100,11 +115,11 @@ pub fn address(symbol: Symbol, opts: struct {
return symbol.value;
}
pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
if (!symbol.flags.got) return 0;
const extra = symbol.extra(elf_file).?;
return elf_file.gotEntryAddress(extra.got);
}
// pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
// if (!symbol.flags.got) return 0;
// const extra = symbol.extra(elf_file).?;
// return elf_file.gotEntryAddress(extra.got);
// }
// pub fn tlsGdAddress(symbol: Symbol, elf_file: *Elf) u64 {
// if (!symbol.flags.tlsgd) return 0;
@ -136,22 +151,22 @@ pub fn gotAddress(symbol: Symbol, elf_file: *Elf) u64 {
// @min(alignment, try std.math.powi(u64, 2, @ctz(s_sym.st_value)));
// }
pub fn addExtra(symbol: *Symbol, extra: Extra, elf_file: *Elf) !void {
symbol.extra = try elf_file.addSymbolExtra(extra);
pub fn addExtra(symbol: *Symbol, extras: Extra, elf_file: *Elf) !void {
symbol.extra = try elf_file.addSymbolExtra(extras);
}
pub fn extra(symbol: Symbol, elf_file: *Elf) ?Extra {
return elf_file.symbolExtra(symbol.extra);
return elf_file.symbolExtra(symbol.extra_index);
}
pub fn setExtra(symbol: Symbol, extra: Extra, elf_file: *Elf) void {
elf_file.setSymbolExtra(symbol.extra, extra);
pub fn setExtra(symbol: Symbol, extras: Extra, elf_file: *Elf) void {
elf_file.setSymbolExtra(symbol.extra_index, extras);
}
pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {
const file_ptr = symbol.file(elf_file).?;
const s_sym = symbol.sourceSymbol(elf_file);
const st_type = symbol.@"type"(elf_file);
const st_type = symbol.type(elf_file);
const st_bind: u8 = blk: {
if (symbol.isLocal()) break :blk 0;
if (symbol.flags.weak) break :blk elf.STB_WEAK;
@ -161,7 +176,7 @@ pub fn asElfSym(symbol: Symbol, st_name: u32, elf_file: *Elf) elf.Elf64_Sym {
const st_shndx = blk: {
// if (symbol.flags.copy_rel) break :blk elf_file.copy_rel_sect_index.?;
// if (file_ptr == .shared or s_sym.st_shndx == elf.SHN_UNDEF) break :blk elf.SHN_UNDEF;
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)
if (symbol.atom(elf_file) == null and file_ptr != .linker_defined and file_ptr != .zig_module)
break :blk elf.SHN_ABS;
break :blk symbol.shndx;
};
@ -221,13 +236,13 @@ fn formatName(
_ = unused_fmt_string;
const elf_file = ctx.elf_file;
const symbol = ctx.symbol;
try writer.writeAll(symbol.getName(elf_file));
switch (symbol.ver_idx & elf.VERSYM_VERSION) {
try writer.writeAll(symbol.name(elf_file));
switch (symbol.version_index & elf.VERSYM_VERSION) {
elf.VER_NDX_LOCAL, elf.VER_NDX_GLOBAL => {},
else => {
unreachable;
// const shared = symbol.getFile(elf_file).?.shared;
// try writer.print("@{s}", .{shared.getVersionString(symbol.ver_idx)});
// try writer.print("@{s}", .{shared.getVersionString(symbol.version_index)});
},
}
}
@ -248,29 +263,27 @@ fn format2(
_ = options;
_ = unused_fmt_string;
const symbol = ctx.symbol;
try writer.print("%{d} : {s} : @{x}", .{ symbol.sym_idx, symbol.fmtName(ctx.elf_file), symbol.value });
if (symbol.getFile(ctx.elf_file)) |file| {
try writer.print("%{d} : {s} : @{x}", .{ symbol.symbol_index, symbol.fmtName(ctx.elf_file), symbol.value });
if (symbol.file(ctx.elf_file)) |file_ptr| {
if (symbol.isAbs(ctx.elf_file)) {
if (symbol.getSourceSymbol(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
if (symbol.sourceSymbol(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
try writer.writeAll(" : undef");
} else {
try writer.writeAll(" : absolute");
}
} else if (symbol.shndx != 0) {
try writer.print(" : sect({d})", .{symbol.shndx});
} else if (symbol.output_section_index != 0) {
try writer.print(" : sect({d})", .{symbol.output_section_index});
}
if (symbol.getAtom(ctx.elf_file)) |atom| {
try writer.print(" : atom({d})", .{atom.atom_index});
if (symbol.atom(ctx.elf_file)) |atom_ptr| {
try writer.print(" : atom({d})", .{atom_ptr.atom_index});
}
var buf: [2]u8 = .{'_'} ** 2;
if (symbol.flags.@"export") buf[0] = 'E';
if (symbol.flags.import) buf[1] = 'I';
try writer.print(" : {s}", .{&buf});
if (symbol.flags.weak) try writer.writeAll(" : weak");
switch (file) {
.internal => |x| try writer.print(" : internal({d})", .{x.index}),
.object => |x| try writer.print(" : object({d})", .{x.index}),
.shared => |x| try writer.print(" : shared({d})", .{x.index}),
switch (file_ptr) {
inline else => |x| try writer.print(" : {s}({d})", .{ @tagName(file_ptr), x.index }),
}
} else try writer.writeAll(" : unresolved");
}
@ -331,7 +344,8 @@ const elf = std.elf;
const Atom = @import("Atom.zig");
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;
const InternalObject = @import("InternalObject.zig");
const Object = @import("Object.zig");
const SharedObject = @import("SharedObject.zig");
const LinkerDefined = @import("LinkerDefined.zig");
// const Object = @import("Object.zig");
// const SharedObject = @import("SharedObject.zig");
const Symbol = @This();
const ZigModule = @import("ZigModule.zig");

View File

@ -1,31 +1,91 @@
index: File.Index,
elf_locals: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
locals: std.ArrayListUnmanaged(Symbol.Index) = .{},
elf_globals: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
globals: std.ArrayListUnmanaged(Symbol.Index) = .{},
elf_local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
local_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
elf_global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
global_symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
alive: bool = true,
// output_symtab_size: Elf.SymtabSize = .{},
pub fn deinit(self: *ZigModule, allocator: Allocator) void {
self.elf_locals.deinit(allocator);
self.locals.deinit(allocator);
self.elf_globals.deinit(allocator);
self.globals.deinit(allocator);
self.elf_local_symbols.deinit(allocator);
self.local_symbols.deinit(allocator);
self.elf_global_symbols.deinit(allocator);
self.global_symbols.deinit(allocator);
self.atoms.deinit(allocator);
}
pub fn createAtom(self: *ZigModule, output_section_index: u16, elf_file: *Elf) !Symbol.Index {
const gpa = elf_file.base.allocator;
const atom_index = try elf_file.addAtom();
const symbol_index = try elf_file.addSymbol();
const atom_ptr = elf_file.atom(atom_index);
atom_ptr.file_index = self.index;
atom_ptr.output_section_index = output_section_index;
const symbol_ptr = elf_file.symbol(symbol_index);
symbol_ptr.file_index = self.index;
symbol_ptr.atom_index = atom_index;
symbol_ptr.output_section_index = output_section_index;
const local_esym = try self.elf_local_symbols.addOne(gpa);
local_esym.* = .{
.st_name = 0,
.st_info = elf.STB_LOCAL << 4,
.st_other = 0,
.st_shndx = output_section_index,
.st_value = 0,
.st_size = 0,
};
try self.atoms.append(gpa, atom_index);
try self.local_symbols.putNoClobber(gpa, symbol_index, {});
return symbol_index;
}
pub fn addGlobal(self: *ZigModule, name: [:0]const u8, elf_file: *Elf) !Symbol.Index {
const gpa = elf_file.base.allocator;
try self.elf_global_symbols.ensureUnusedCapacity(gpa, 1);
try self.global_symbols.ensureUnusedCapacity(gpa, 1);
const off = try elf_file.strtab.insert(gpa, name);
self.elf_global_symbols.appendAssumeCapacity(.{
.st_name = off,
.st_info = elf.STB_GLOBAL << 4,
.st_other = 0,
.st_shndx = 0,
.st_value = 0,
.st_size = 0,
});
const gop = try elf_file.getOrPutGlobal(off);
self.global_symbols.putAssumeCapacityNoClobber(gop.index, {});
return gop.index;
}
pub fn sourceSymbol(self: *ZigModule, symbol_index: Symbol.Index) *elf.Elf64_Sym {
if (self.local_symbols.get(symbol_index)) |_| return &self.elf_local_symbols.items[symbol_index];
assert(self.global_symbols.get(symbol_index) != null);
return &self.elf_global_symbols.items[symbol_index];
}
pub fn locals(self: *ZigModule) []const Symbol.Index {
return self.local_symbols.keys();
}
pub fn globals(self: *ZigModule) []const Symbol.Index {
return self.global_symbols.keys();
}
pub fn asFile(self: *ZigModule) File {
return .{ .zig_module = self };
}
pub fn getLocals(self: *ZigModule) []const Symbol.Index {
return self.locals.items;
}
pub fn getGlobals(self: *ZigModule) []const Symbol.Index {
return self.globals.items;
}
pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
return .{ .data = .{
.self = self,
@ -47,23 +107,26 @@ fn formatSymtab(
_ = unused_fmt_string;
_ = options;
try writer.writeAll(" locals\n");
for (ctx.self.getLocals()) |index| {
for (ctx.self.locals()) |index| {
const local = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
}
try writer.writeAll(" globals\n");
for (ctx.self.getGlobals()) |index| {
const global = ctx.elf_file.getSymbol(index);
for (ctx.self.globals()) |index| {
const global = ctx.elf_file.symbol(index);
try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
}
}
const assert = std.debug.assert;
const std = @import("std");
const elf = std.elf;
const Allocator = std.mem.Allocator;
const Atom = @import("Atom.zig");
const Elf = @import("../Elf.zig");
const File = @import("file.zig").File;
const Module = @import("../../Module.zig");
const ZigModule = @This();
// const Object = @import("Object.zig");
const Symbol = @import("Symbol.zig");

View File

@ -10,6 +10,12 @@ pub const File = union(enum) {
};
}
pub fn sourceSymbol(file: File, symbol_index: Symbol.Index) *elf.Elf64_Sym {
return switch (file) {
inline else => |x| x.sourceSymbol(symbol_index),
};
}
pub fn fmtPath(file: File) std.fmt.Formatter(formatPath) {
return .{ .data = file };
}
@ -107,4 +113,5 @@ const Elf = @import("../Elf.zig");
const LinkerDefined = @import("LinkerDefined.zig");
// const Object = @import("Object.zig");
// const SharedObject = @import("SharedObject.zig");
const Symbol = @import("Symbol.zig");
const ZigModule = @import("ZigModule.zig");

View File

@ -100,13 +100,13 @@ pub fn StringTable(comptime log_scope: @Type(.EnumLiteral)) type {
});
}
pub fn get(self: Self, off: u32) ?[]const u8 {
pub fn get(self: Self, off: u32) ?[:0]const u8 {
log.debug("getting string at 0x{x}", .{off});
if (off >= self.buffer.items.len) return null;
return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.buffer.items.ptr + off)), 0);
}
pub fn getAssumeExists(self: Self, off: u32) []const u8 {
pub fn getAssumeExists(self: Self, off: u32) [:0]const u8 {
return self.get(off) orelse unreachable;
}