link/elf: introduce Atom extras for out-of-band storage

This commit is contained in:
Jakub Konka 2024-04-15 19:54:53 +02:00
parent c7ffdbcd41
commit 700644d35d
3 changed files with 92 additions and 8 deletions

View File

@ -205,6 +205,7 @@ num_ifunc_dynrelocs: usize = 0,
/// List of atoms that are owned directly by the linker.
atoms: std.ArrayListUnmanaged(Atom) = .{},
atoms_extra: std.ArrayListUnmanaged(u32) = .{},
/// List of range extension thunks.
thunks: std.ArrayListUnmanaged(Thunk) = .{},
@ -369,6 +370,7 @@ pub fn createEmpty(
try self.symbols_extra.append(gpa, 0);
// Allocate atom index 0 to null atom
try self.atoms.append(gpa, .{});
try self.atoms_extra.append(gpa, 0);
// Append null file at index 0
try self.files.append(gpa, .null);
// Append null byte to string tables
@ -491,6 +493,10 @@ pub fn deinit(self: *Elf) void {
self.start_stop_indexes.deinit(gpa);
self.atoms.deinit(gpa);
self.atoms_extra.deinit(gpa);
for (self.thunks.items) |*th| {
th.deinit(gpa);
}
self.thunks.deinit(gpa);
for (self.last_atom_and_free_list_table.values()) |*value| {
value.free_list.deinit(gpa);
@ -5458,6 +5464,50 @@ pub fn addAtom(self: *Elf) !Atom.Index {
return index;
}
pub fn addAtomExtra(self: *Elf, extra: Atom.Extra) !u32 {
const fields = @typeInfo(Atom.Extra).Struct.fields;
try self.atoms_extra.ensureUnusedCapacity(self.base.comp.gpa, fields.len);
return self.addAtomExtraAssumeCapacity(extra);
}
pub fn addAtomExtraAssumeCapacity(self: *Elf, extra: Atom.Extra) u32 {
const index = @as(u32, @intCast(self.atoms_extra.items.len));
const fields = @typeInfo(Atom.Extra).Struct.fields;
inline for (fields) |field| {
self.atoms_extra.appendAssumeCapacity(switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
});
}
return index;
}
pub fn atomExtra(self: *Elf, index: u32) ?Atom.Extra {
if (index == 0) return null;
const fields = @typeInfo(Atom.Extra).Struct.fields;
var i: usize = index;
var result: Atom.Extra = undefined;
inline for (fields) |field| {
@field(result, field.name) = switch (field.type) {
u32 => self.atoms_extra.items[i],
else => @compileError("bad field type"),
};
i += 1;
}
return result;
}
pub fn setAtomExtra(self: *Elf, index: u32, extra: Atom.Extra) void {
assert(index > 0);
const fields = @typeInfo(Atom.Extra).Struct.fields;
inline for (fields, 0..) |field, i| {
self.atoms_extra.items[index + i] = switch (field.type) {
u32 => @field(extra, field.name),
else => @compileError("bad field type"),
};
}
}
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);

View File

@ -31,12 +31,6 @@ rel_num: u32 = 0,
/// Index of this atom in the linker's atoms table.
atom_index: Index = 0,
/// Index of the thunk for this atom.
thunk_index: Thunk.Index = 0,
/// Flags we use for state tracking.
flags: Flags = .{},
/// Start index of FDEs referencing this atom.
fde_start: u32 = 0,
@ -48,6 +42,11 @@ fde_end: u32 = 0,
prev_index: Index = 0,
next_index: Index = 0,
/// Flags we use for state tracking.
flags: Flags = .{},
extra_index: u32 = 0,
pub const Alignment = @import("../../InternPool.zig").Alignment;
pub fn name(self: Atom, elf_file: *Elf) []const u8 {
@ -68,7 +67,9 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
}
pub fn thunk(self: Atom, elf_file: *Elf) *Thunk {
return elf_file.thunk(self.thunk_index);
assert(self.flags.thunk);
const extras = self.extra(elf_file).?;
return elf_file.thunk(extras.thunk);
}
pub fn inputShdr(self: Atom, elf_file: *Elf) elf.Elf64_Shdr {
@ -981,6 +982,31 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
if (has_reloc_errors) return error.RelocFailure;
}
const AddExtraOpts = struct {
thunk: ?u32 = null,
};
pub fn addExtra(atom: *Atom, opts: AddExtraOpts, elf_file: *Elf) !void {
if (atom.extra(elf_file) == null) {
atom.extra_index = try elf_file.addAtomExtra(.{});
}
var extras = atom.extra(elf_file).?;
inline for (@typeInfo(@TypeOf(opts)).Struct.fields) |field| {
if (@field(opts, field.name)) |x| {
@field(extras, field.name) = x;
}
}
atom.setExtra(extras, elf_file);
}
pub inline fn extra(atom: Atom, elf_file: *Elf) ?Extra {
return elf_file.atomExtra(atom.extra_index);
}
pub inline fn setExtra(atom: Atom, extras: Extra, elf_file: *Elf) void {
elf_file.setAtomExtra(atom.extra_index, extras);
}
pub fn format(
atom: Atom,
comptime unused_fmt_string: []const u8,
@ -1042,6 +1068,9 @@ pub const Flags = packed struct {
/// Specifies if the atom has been visited during garbage collection.
visited: bool = false,
/// Whether this symbol has a range extension thunk.
thunk: bool = false,
};
const x86_64 = struct {
@ -2167,6 +2196,10 @@ const RelocsIterator = struct {
}
};
pub const Extra = struct {
thunk: u32 = 0,
};
const std = @import("std");
const assert = std.debug.assert;
const elf = std.elf;

View File

@ -50,7 +50,8 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void {
};
try thunk.symbols.put(gpa, target, {});
}
atom.thunk_index = thunk_index;
try atom.addExtra(.{ .thunk = thunk_index }, elf_file);
atom.flags.thunk = true;
}
thunk.value = try advance(shdr, thunk.size(elf_file), Atom.Alignment.fromNonzeroByteUnits(2));