Commit 700644d35d

Jakub Konka <kubkon@jakubkonka.com>
2024-04-15 19:54:53
link/elf: introduce Atom extras for out-of-band storage
1 parent c7ffdbc
Changed files (3)
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);