Skip to content

Commit

Permalink
elf: move ownership of symbols into objects
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Sep 15, 2024
1 parent 1445d7a commit caf8f34
Show file tree
Hide file tree
Showing 13 changed files with 1,476 additions and 1,075 deletions.
744 changes: 252 additions & 492 deletions src/Elf.zig

Large diffs are not rendered by default.

149 changes: 80 additions & 69 deletions src/Elf/Atom.zig

Large diffs are not rendered by default.

442 changes: 399 additions & 43 deletions src/Elf/InternalObject.zig

Large diffs are not rendered by default.

395 changes: 260 additions & 135 deletions src/Elf/Object.zig

Large diffs are not rendered by default.

330 changes: 227 additions & 103 deletions src/Elf/SharedObject.zig

Large diffs are not rendered by default.

75 changes: 39 additions & 36 deletions src/Elf/Symbol.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ file: File.Index = 0,

/// Atom containing this symbol if any.
/// Use `getAtom` to get the pointer to the atom.
atom_ref: Elf.Ref = .{},
ref: Elf.Ref = .{},

/// Assigned output section index for this symbol.
shndx: u32 = 0,

/// Index of the source symbol this symbol references.
/// Use `getSourceSymbol` to pull the source symbol from the relevant file.
sym_idx: Index = 0,
/// Use `getElfSym` to pull the source symbol from the relevant file.
esym_idx: Index = 0,

/// Index of the source version symbol this symbol references if any.
/// If the symbol is unversioned it will have either VER_NDX_LOCAL or VER_NDX_GLOBAL.
Expand All @@ -31,12 +31,12 @@ extra: u32 = 0,

pub fn isAbs(symbol: Symbol, elf_file: *Elf) bool {
const file = symbol.getFile(elf_file).?;
if (file == .shared) return symbol.getSourceSymbol(elf_file).st_shndx == elf.SHN_ABS;
return !symbol.flags.import and symbol.getAtom(elf_file) == null and symbol.getMergeSubsection(elf_file) == null and symbol.shndx == 0 and file != .internal;
if (file == .shared) return symbol.getElfSym(elf_file).st_shndx == elf.SHN_ABS;
return !symbol.flags.import and symbol.getMergeSubsection(elf_file) == null and symbol.getAtom(elf_file) == null and symbol.shndx == 0 and file != .internal;
}

pub fn isLocal(symbol: Symbol, elf_file: *Elf) bool {
if (elf_file.options.relocatable) return symbol.getSourceSymbol(elf_file).st_bind() == elf.STB_LOCAL;
if (elf_file.options.relocatable) return symbol.getElfSym(elf_file).st_bind() == elf.STB_LOCAL;
return !(symbol.flags.import or symbol.flags.@"export");
}

Expand All @@ -46,39 +46,41 @@ pub inline fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {

pub fn getType(symbol: Symbol, elf_file: *Elf) u4 {
const file = symbol.getFile(elf_file).?;
const s_sym = symbol.getSourceSymbol(elf_file);
const s_sym = symbol.getElfSym(elf_file);
if (s_sym.st_type() == elf.STT_GNU_IFUNC and file == .shared) return elf.STT_FUNC;
return s_sym.st_type();
}

pub fn getName(symbol: Symbol, elf_file: *Elf) [:0]const u8 {
return elf_file.string_intern.getAssumeExists(symbol.name);
return switch (symbol.getFile(elf_file).?) {
inline else => |x| x.getString(symbol.name),
};
}

pub fn getAtom(symbol: Symbol, elf_file: *Elf) ?*Atom {
return elf_file.getAtom(symbol.atom_ref);
return elf_file.getAtom(symbol.ref);
}

pub fn getMergeSubsection(symbol: Symbol, elf_file: *Elf) ?*MergeSubsection {
if (!symbol.flags.merge_subsection) return null;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
return elf_file.getMergeSubsection(extra.subsection);
}

pub inline fn getFile(symbol: Symbol, elf_file: *Elf) ?File {
pub fn getFile(symbol: Symbol, elf_file: *Elf) ?File {
return elf_file.getFile(symbol.file);
}

pub fn getSourceSymbol(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
pub fn getElfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
const file = symbol.getFile(elf_file).?;
return switch (file) {
inline else => |x| x.symtab.items[symbol.sym_idx],
inline else => |x| x.symtab.items[symbol.esym_idx],
};
}

pub fn getSymbolRank(symbol: Symbol, elf_file: *Elf) u32 {
const file = symbol.getFile(elf_file) orelse return std.math.maxInt(u32);
const sym = symbol.getSourceSymbol(elf_file);
const sym = symbol.getElfSym(elf_file);
const in_archive = switch (file) {
.object => |x| !x.alive,
else => false,
Expand Down Expand Up @@ -116,7 +118,7 @@ pub fn getAddress(symbol: Symbol, opts: struct {
if (mem.startsWith(u8, sym_name, "__EH_FRAME_BEGIN__") or
mem.startsWith(u8, sym_name, "__EH_FRAME_LIST__") or
mem.startsWith(u8, sym_name, ".eh_frame_seg") or
symbol.getSourceSymbol(elf_file).st_type() == elf.STT_SECTION)
symbol.getElfSym(elf_file).st_type() == elf.STT_SECTION)
{
return @intCast(sh_addr);
}
Expand All @@ -143,36 +145,36 @@ pub fn getOutputSymtabIndex(symbol: Symbol, elf_file: *Elf) ?u32 {
const symtab_ctx = switch (file) {
inline else => |x| x.output_symtab_ctx,
};
const idx = symbol.getExtra(elf_file).?.symtab;
const idx = symbol.getExtra(elf_file).symtab;
return if (symbol.isLocal(elf_file)) idx + symtab_ctx.ilocal else idx + symtab_ctx.iglobal;
}

pub fn getGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.got) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const entry = elf_file.got.entries.items[extra.got];
return entry.getAddress(elf_file);
}

pub fn getPltGotAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!(symbol.flags.plt and symbol.flags.got)) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const shdr = elf_file.sections.items(.shdr)[elf_file.plt_got_sect_index.?];
const cpu_arch = elf_file.options.cpu_arch.?;
return @intCast(shdr.sh_addr + extra.plt_got * PltGotSection.entrySize(cpu_arch));
}

pub fn getPltAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.plt) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const shdr = elf_file.sections.items(.shdr)[elf_file.plt_sect_index.?];
const cpu_arch = elf_file.options.cpu_arch.?;
return @intCast(shdr.sh_addr + extra.plt * PltSection.entrySize(cpu_arch) + PltSection.preambleSize(cpu_arch));
}

pub fn getGotPltAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.plt) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const shdr = elf_file.sections.items(.shdr)[elf_file.got_plt_sect_index.?];
return @intCast(shdr.sh_addr + extra.plt * 8 + GotPltSection.preamble_size);
}
Expand All @@ -185,29 +187,29 @@ pub fn getCopyRelAddress(symbol: Symbol, elf_file: *Elf) i64 {

pub fn getTlsGdAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.tlsgd) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const entry = elf_file.got.entries.items[extra.tlsgd];
return entry.getAddress(elf_file);
}

pub fn getGotTpAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.gottp) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const entry = elf_file.got.entries.items[extra.gottp];
return entry.getAddress(elf_file);
}

pub fn getTlsDescAddress(symbol: Symbol, elf_file: *Elf) i64 {
if (!symbol.flags.tlsdesc) return 0;
const extra = symbol.getExtra(elf_file).?;
const extra = symbol.getExtra(elf_file);
const entry = elf_file.got.entries.items[extra.tlsdesc];
return entry.getAddress(elf_file);
}

pub fn getAlignment(symbol: Symbol, elf_file: *Elf) !u64 {
const file = symbol.getFile(elf_file) orelse return 0;
const shared = file.shared;
const s_sym = symbol.getSourceSymbol(elf_file);
const s_sym = symbol.getElfSym(elf_file);
const shdr = shared.shdrs.items[s_sym.st_shndx];
const alignment = @max(1, shdr.sh_addralign);
return if (s_sym.st_value == 0)
Expand All @@ -229,11 +231,8 @@ const AddExtraOpts = struct {
subsection: ?u32 = null,
};

pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
if (symbol.getExtra(elf_file) == null) {
symbol.extra = try elf_file.addSymbolExtra(.{});
}
var extra = symbol.getExtra(elf_file).?;
pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) void {
var extra = symbol.getExtra(elf_file);
inline for (@typeInfo(@TypeOf(opts)).@"struct".fields) |field| {
if (@field(opts, field.name)) |x| {
@field(extra, field.name) = x;
Expand All @@ -242,17 +241,21 @@ pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, elf_file: *Elf) !void {
symbol.setExtra(extra, elf_file);
}

pub inline fn getExtra(symbol: Symbol, elf_file: *Elf) ?Extra {
return elf_file.getSymbolExtra(symbol.extra);
pub fn getExtra(symbol: Symbol, elf_file: *Elf) Extra {
return switch (symbol.getFile(elf_file).?) {
inline else => |x| x.getSymbolExtra(symbol.extra),
};
}

pub inline fn setExtra(symbol: Symbol, extra: Extra, elf_file: *Elf) void {
elf_file.setSymbolExtra(symbol.extra, extra);
pub fn setExtra(symbol: Symbol, extra: Extra, elf_file: *Elf) void {
return switch (symbol.getFile(elf_file).?) {
inline else => |x| x.setSymbolExtra(symbol.extra, extra),
};
}

pub fn setOutputSym(symbol: Symbol, elf_file: *Elf, out: *elf.Elf64_Sym) void {
const file = symbol.getFile(elf_file).?;
const s_sym = symbol.getSourceSymbol(elf_file);
const s_sym = symbol.getElfSym(elf_file);
const st_type = symbol.getType(elf_file);
const st_bind: u8 = blk: {
if (symbol.isLocal(elf_file)) break :blk 0;
Expand Down Expand Up @@ -347,10 +350,10 @@ 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.getAddress(.{}, ctx.elf_file) });
try writer.print("%{d} : {s} : @{x}", .{ symbol.esym_idx, symbol.fmtName(ctx.elf_file), symbol.getAddress(.{}, ctx.elf_file) });
if (symbol.getFile(ctx.elf_file)) |file| {
if (symbol.isAbs(ctx.elf_file)) {
if (symbol.getSourceSymbol(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
if (symbol.getElfSym(ctx.elf_file).st_shndx == elf.SHN_UNDEF) {
try writer.writeAll(" : undef");
} else {
try writer.writeAll(" : absolute");
Expand Down
29 changes: 15 additions & 14 deletions src/Elf/Thunk.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
value: i64 = 0,
out_shndx: u32 = 0,
symbols: std.AutoArrayHashMapUnmanaged(Symbol.Index, void) = .{},
symbols: std.AutoArrayHashMapUnmanaged(Elf.Ref, void) = .empty,
output_symtab_ctx: Elf.SymtabCtx = .{},

pub fn deinit(thunk: *Thunk, allocator: Allocator) void {
Expand All @@ -17,9 +17,9 @@ pub fn getAddress(thunk: Thunk, elf_file: *Elf) i64 {
return @as(i64, @intCast(shdr.sh_addr)) + thunk.value;
}

pub fn getTargetAddress(thunk: Thunk, sym_index: Symbol.Index, elf_file: *Elf) i64 {
pub fn getTargetAddress(thunk: Thunk, ref: Elf.Ref, elf_file: *Elf) i64 {
const cpu_arch = elf_file.options.cpu_arch.?;
return thunk.getAddress(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(sym_index).? * trampolineSize(cpu_arch)));
return thunk.getAddress(elf_file) + @as(i64, @intCast(thunk.symbols.getIndex(ref).? * trampolineSize(cpu_arch)));
}

pub fn isReachable(atom: *const Atom, rel: elf.Elf64_Rela, elf_file: *Elf) bool {
Expand Down Expand Up @@ -52,8 +52,8 @@ pub fn calcSymtabSize(thunk: *Thunk, elf_file: *Elf) void {
if (elf_file.options.strip_all) return;

thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len));
for (thunk.symbols.keys()) |sym_index| {
const sym = elf_file.getSymbol(sym_index);
for (thunk.symbols.keys()) |ref| {
const sym = elf_file.getSymbol(ref).?;
thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(elf_file).len + "$thunk".len + 1));
}
}
Expand All @@ -62,8 +62,8 @@ pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
if (elf_file.options.strip_all) return;
const cpu_arch = elf_file.options.cpu_arch.?;

for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |sym_index, ilocal| {
const sym = elf_file.getSymbol(sym_index);
for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| {
const sym = elf_file.getSymbol(ref).?;
const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
elf_file.strtab.appendSliceAssumeCapacity(sym.getName(elf_file));
elf_file.strtab.appendSliceAssumeCapacity("$thunk");
Expand All @@ -73,7 +73,7 @@ pub fn writeSymtab(thunk: Thunk, elf_file: *Elf) void {
.st_info = elf.STT_FUNC,
.st_other = 0,
.st_shndx = @intCast(thunk.out_shndx),
.st_value = @intCast(thunk.getTargetAddress(sym_index, elf_file)),
.st_value = @intCast(thunk.getTargetAddress(ref, elf_file)),
.st_size = trampolineSize(cpu_arch),
};
}
Expand Down Expand Up @@ -123,9 +123,9 @@ fn format2(
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.getSymbol(index);
try writer.print(" %{d} : {s} : @{x}\n", .{ index, sym.getName(elf_file), sym.value });
for (thunk.symbols.keys()) |ref| {
const sym = elf_file.getSymbol(ref).?;
try writer.print(" {} : {s} : @{x}\n", .{ ref, sym.getName(elf_file), sym.value });
}
}

Expand All @@ -136,7 +136,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 object = atom.getObject(elf_file);
const target = object.getSymbol(rel.r_sym(), elf_file);
const target_ref = object.resolveSymbol(rel.r_sym(), elf_file);
const target = elf_file.getSymbol(target_ref).?;
if (target.flags.plt) return false;
if (atom.out_shndx != target.shndx) return false;
const target_atom = target.getAtom(elf_file).?;
Expand All @@ -148,8 +149,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.getSymbol(sym_index);
for (thunk.symbols.keys(), 0..) |ref, i| {
const sym = elf_file.getSymbol(ref).?;
const saddr = thunk.getAddress(elf_file) + @as(i64, @intCast(i * trampoline_size));
const taddr = sym.getAddress(.{}, elf_file);
const pages = try util.calcNumberOfPages(saddr, taddr);
Expand Down
19 changes: 11 additions & 8 deletions src/Elf/eh_frame.zig
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ pub const Cie = struct {
if (cie_rel.r_type() != other_rel.r_type()) return false;
if (cie_rel.r_addend != other_rel.r_addend) return false;

const cie_sym = cie.getObject(elf_file).getSymbol(cie_rel.r_sym(), elf_file);
const other_sym = other.getObject(elf_file).getSymbol(other_rel.r_sym(), elf_file);
const cie_sym = cie.getObject(elf_file).symbols.items[cie_rel.r_sym()];
const other_sym = other.getObject(elf_file).symbols.items[other_rel.r_sym()];
if (!std.mem.eql(u8, std.mem.asBytes(&cie_sym), std.mem.asBytes(&other_sym))) return false;
}
return true;
Expand Down Expand Up @@ -361,7 +361,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
const data = cie.getData(elf_file);

for (cie.getRelocs(elf_file)) |rel| {
const sym = object.getSymbol(rel.r_sym(), elf_file);
const sym_ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.getSymbol(sym_ref).?;
resolveReloc(cie, sym, rel, elf_file, data) catch |err| switch (err) {
error.RelocError => has_reloc_errors = true,
else => |e| return e,
Expand All @@ -388,7 +389,8 @@ pub fn writeEhFrame(elf_file: *Elf, writer: anytype) !void {
);

for (fde.getRelocs(elf_file)) |rel| {
const sym = object.getSymbol(rel.r_sym(), elf_file);
const sym_ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.getSymbol(sym_ref).?;
resolveReloc(fde, sym, rel, elf_file, data) catch |err| switch (err) {
error.RelocError => has_reloc_errors = true,
else => |e| return e,
Expand Down Expand Up @@ -437,7 +439,7 @@ pub fn writeEhFrameRelocatable(elf_file: *Elf, writer: anytype) !void {
}
}

fn emitReloc(elf_file: *Elf, rec: anytype, sym: *const Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
fn emitReloc(elf_file: *Elf, rec: anytype, sym: Symbol, rel: elf.Elf64_Rela) elf.Elf64_Rela {
const tracy = trace(@src());
defer tracy.end();

Expand Down Expand Up @@ -483,7 +485,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
for (object.cies.items) |cie| {
if (!cie.alive) continue;
for (cie.getRelocs(elf_file)) |rel| {
const sym = object.getSymbol(rel.r_sym(), elf_file);
const sym = object.symbols.items[rel.r_sym()];
const out_rel = emitReloc(elf_file, cie, sym, rel);
try writer.writeStruct(out_rel);
}
Expand All @@ -492,7 +494,7 @@ pub fn writeEhFrameRelocs(elf_file: *Elf, writer: anytype) !void {
for (object.fdes.items) |fde| {
if (!fde.alive) continue;
for (fde.getRelocs(elf_file)) |rel| {
const sym = object.getSymbol(rel.r_sym(), elf_file);
const sym = object.symbols.items[rel.r_sym()];
const out_rel = emitReloc(elf_file, fde, sym, rel);
try writer.writeStruct(out_rel);
}
Expand Down Expand Up @@ -544,7 +546,8 @@ pub fn writeEhFrameHdr(elf_file: *Elf, writer: anytype) !void {
const relocs = fde.getRelocs(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 = object.getSymbol(rel.r_sym(), elf_file);
const sym_ref = object.resolveSymbol(rel.r_sym(), elf_file);
const sym = elf_file.getSymbol(sym_ref).?;
const P = @as(i64, @intCast(fde.getAddress(elf_file)));
const S = @as(i64, @intCast(sym.getAddress(.{}, elf_file)));
const A = rel.r_addend;
Expand Down
Loading

0 comments on commit caf8f34

Please sign in to comment.