Commit 700644d35d
Changed files (3)
src
link
src/link/Elf/Atom.zig
@@ -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;
src/link/Elf/thunks.zig
@@ -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));
src/link/Elf.zig
@@ -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);