authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-24 23:39:49+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-25 00:21:56+01:00
logfac41b3ec9237583f4d6bcb73c339464eb9a1edc
tree202820be01e843c5efd8c53a9413c969511cd188
parent8d471cd9018d99a3a39ee94212b2d42efe755ea1
signature Commit is signed but in an unrecognized format.

Elf2: minor performance improvements


1 files changed, 33 insertions(+), 21 deletions(-)

src/link/Elf2.zig+33-21
......@@ -21,6 +21,15 @@ const Alignment = MappedFile.Alignment;
2121base: link.File,
2222options: link.File.OpenOptions,
2323mf: MappedFile,
24
25/// These fields could simply be read from the ehdr node when needed, but it turns out that they are
26/// accessed frequently enough that we see measurable performance gains from caching them here.
27ehdr_fields: struct {
28 class: std.elf.CLASS,
29 type: EhdrType,
30 machine: EhdrMachine,
31},
32
2433ni: struct {
2534 elf: MappedFile.Node.Index,
2635 ehdr: MappedFile.Node.Index,
......@@ -5115,6 +5124,11 @@ fn create(
51155124 },
51165125 .options = options,
51175126 .mf = try .init(file, comp.gpa, io),
5127 .ehdr_fields = .{
5128 .class = class,
5129 .type = @"type",
5130 .machine = machine,
5131 },
51185132 .ni = .{
51195133 .elf = undefined,
51205134 .ehdr = undefined,
......@@ -7007,7 +7021,9 @@ fn flushMovedNodeRelocs(
70077021}
70087022
70097023fn identClass(elf: *const Elf) std.elf.CLASS {
7010 return @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.CLASS]);
7024 // We used to get this value from `elf.ni.ehdr`, but it turns out this function is called often
7025 // enough to see measurable performance gains from memoizing its result on `Elf`.
7026 return elf.ehdr_fields.class;
70117027}
70127028
70137029/// Like `std.elf.ET`, but only includes the ELF machine architectures we support, so that we can
......@@ -7039,24 +7055,14 @@ const EhdrType = enum(u16) {
70397055 }
70407056};
70417057fn ehdrMachine(elf: *const Elf) EhdrMachine {
7042 const ehdr_slice = elf.ni.ehdr.sliceConst(&elf.mf);
7043 switch (elf.identClass()) {
7044 .NONE, _ => unreachable,
7045 inline else => |class| {
7046 const ehdr: *const class.ElfN().Ehdr = @ptrCast(@alignCast(ehdr_slice));
7047 return @bitCast(elf.targetLoad(&ehdr.machine));
7048 },
7049 }
7058 // We used to get this value from `elf.ni.ehdr`, but it turns out this function is called often
7059 // enough to see measurable performance gains from memoizing its result on `Elf`.
7060 return elf.ehdr_fields.machine;
70507061}
70517062fn ehdrType(elf: *const Elf) EhdrType {
7052 const ehdr_slice = elf.ni.ehdr.sliceConst(&elf.mf);
7053 switch (elf.identClass()) {
7054 .NONE, _ => unreachable,
7055 inline else => |class| {
7056 const ehdr: *const class.ElfN().Ehdr = @ptrCast(@alignCast(ehdr_slice));
7057 return @bitCast(elf.targetLoad(&ehdr.type));
7058 },
7059 }
7063 // We used to get this value from `elf.ni.ehdr`, but it turns out this function is called often
7064 // enough to see measurable performance gains from memoizing its result on `Elf`.
7065 return elf.ehdr_fields.type;
70607066}
70617067
70627068fn baseLoadableSegmentVAddr(elf: *const Elf) u64 {
......@@ -7279,11 +7285,17 @@ const SymPtr = union(std.elf.CLASS) {
72797285 @"32": *std.elf.Elf32.Sym,
72807286 @"64": *std.elf.Elf64.Sym,
72817287};
7282fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
7288/// This function is marked as `inline` because performance measurements (specifically, using this
7289/// linker to link the Zig compiler against a static build of LLVM 23) show a measurable performance
7290/// improvement from doing so---it seems that this is one of the hottest functions in this linker!
7291inline fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr {
72837292 const raw_slice = Section.Index.symtab.node(elf).slice(&elf.mf);
7284 switch (elf.shdrPtr(.symtab)) {
7285 inline else => |shdr, class| {
7286 const size = elf.targetLoad(&shdr.size);
7293 // Avoid calling `shdrPtr` here: this function is extremely hot, so having to locate the shdr
7294 // actually noticably affects performance!
7295 switch (elf.identClass()) {
7296 .NONE, _ => unreachable,
7297 inline else => |class| {
7298 const size = elf.symtab.items.len * @sizeOf(class.ElfN().Sym);
72877299 const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)]));
72887300 return @unionInit(SymPtr, @tagName(class), &slice[@backingInt(index)]);
72897301 },