mirror of
https://github.com/ziglang/zig.git
synced 2025-12-24 23:23:07 +00:00
elf: make everything upside down - track by Symbol.Index rather than Atom.Index
This commit is contained in:
parent
d9fffd431a
commit
a9df098cd2
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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 });
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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)) |_| {
|
||||
|
||||
684
src/link/Elf.zig
684
src/link/Elf.zig
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
||||
@ -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)});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user