| ... | ... | @@ -21,6 +21,15 @@ const Alignment = MappedFile.Alignment; |
| 21 | 21 | base: link.File, |
| 22 | 22 | options: link.File.OpenOptions, |
| 23 | 23 | mf: 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. |
| 27 | ehdr_fields: struct { |
| 28 | class: std.elf.CLASS, |
| 29 | type: EhdrType, |
| 30 | machine: EhdrMachine, |
| 31 | }, |
| 32 | |
| 24 | 33 | ni: struct { |
| 25 | 34 | elf: MappedFile.Node.Index, |
| 26 | 35 | ehdr: MappedFile.Node.Index, |
| ... | ... | @@ -5115,6 +5124,11 @@ fn create( |
| 5115 | 5124 | }, |
| 5116 | 5125 | .options = options, |
| 5117 | 5126 | .mf = try .init(file, comp.gpa, io), |
| 5127 | .ehdr_fields = .{ |
| 5128 | .class = class, |
| 5129 | .type = @"type", |
| 5130 | .machine = machine, |
| 5131 | }, |
| 5118 | 5132 | .ni = .{ |
| 5119 | 5133 | .elf = undefined, |
| 5120 | 5134 | .ehdr = undefined, |
| ... | ... | @@ -7007,7 +7021,9 @@ fn flushMovedNodeRelocs( |
| 7007 | 7021 | } |
| 7008 | 7022 | |
| 7009 | 7023 | fn 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; |
| 7011 | 7027 | } |
| 7012 | 7028 | |
| 7013 | 7029 | /// 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) { |
| 7039 | 7055 | } |
| 7040 | 7056 | }; |
| 7041 | 7057 | fn 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; |
| 7050 | 7061 | } |
| 7051 | 7062 | fn 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; |
| 7060 | 7066 | } |
| 7061 | 7067 | |
| 7062 | 7068 | fn baseLoadableSegmentVAddr(elf: *const Elf) u64 { |
| ... | ... | @@ -7279,11 +7285,17 @@ const SymPtr = union(std.elf.CLASS) { |
| 7279 | 7285 | @"32": *std.elf.Elf32.Sym, |
| 7280 | 7286 | @"64": *std.elf.Elf64.Sym, |
| 7281 | 7287 | }; |
| 7282 | | fn 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! |
| 7291 | inline fn symPtr(elf: *Elf, index: Symbol.Index) SymPtr { |
| 7283 | 7292 | 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); |
| 7287 | 7299 | const slice: []class.ElfN().Sym = @ptrCast(@alignCast(raw_slice[0..@intCast(size)])); |
| 7288 | 7300 | return @unionInit(SymPtr, @tagName(class), &slice[@backingInt(index)]); |
| 7289 | 7301 | }, |