authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-02 13:13:33+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-07 13:05:31+01:00
log1ef976880aa7a0be3a8c28ade99055d73ff6f2ac
treea6c02f016f48f52794c4c6ff0cfbfa7aa5a22f5c
parentf6656470df9f2eab664c0137c187a1b82207e469
signaturelock-open Commit is signed but in an unrecognized format.

Elf2(refactor): key `plt` on global symbol name

Local symbols never have PLT entries, so there is no need to key this map on `Symbol.Id`.

1 files changed, 16 insertions(+), 8 deletions(-)

src/link/Elf2.zig+16-8
......@@ -100,13 +100,15 @@ dynstr: StringTable,
100100///
101101/// Value is the output relocation in `.rela.dyn` for the GOT entry.
102102got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),
103/// Key is the name of a global.
104///
103105/// Indices map 1--1 to indices into the actual `.got.plt` section. These also equal indices into
104106/// the relocations in `.rela.plt`, because every PLT entry has one output relocation (if a runtime
105107/// relocation is no longer necessary, then neither is the corresponding PLT entry!).
106108///
107109/// PLT entries in this map may be "dead", meaning the PLT entry has been deemed unnecessary so is
108110/// available for reuse---see `Elf.pltEntryIsDead`. Such entries must not be targeted by relocs.
109plt: std.array_hash_map.Auto(Symbol.Id, void),
111plt: std.array_hash_map.Auto(String(.strtab), void),
110112/// The `.plt` section contains zero or more symbol relocations starting at this index.
111113plt_first_symbol_reloc: SymbolReloc.Index,
112114/// The `.dynamic` section contains zero or more symbol relocations starting at this index.
......@@ -1126,7 +1128,10 @@ const SymbolReloc = struct {
11261128 target_endian,
11271129 ),
11281130 .pltrel64 => {
1129 const plt_index = elf.plt.getIndex(reloc.target) orelse continue :type .rel64;
1131 const plt_index = switch (reloc.target.unwrap()) {
1132 .local => continue :type .rel64,
1133 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel64,
1134 };
11301135 if (elf.pltEntryIsDead(plt_index)) continue :type .rel64;
11311136 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
11321137 else => |machine| @panic(@tagName(machine)),
......@@ -1141,7 +1146,10 @@ const SymbolReloc = struct {
11411146 );
11421147 },
11431148 .pltrel32 => {
1144 const plt_index = elf.plt.getIndex(reloc.target) orelse continue :type .rel32;
1149 const plt_index = switch (reloc.target.unwrap()) {
1150 .local => continue :type .rel32,
1151 .global => |name| elf.plt.getIndex(name) orelse continue :type .rel32,
1152 };
11451153 if (elf.pltEntryIsDead(plt_index)) continue :type .rel32;
11461154 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
11471155 else => |machine| @panic(@tagName(machine)),
......@@ -1843,7 +1851,7 @@ fn setGlobalSymbolValue(
18431851 // If this symbol was previously undefined, it may have had a PLT entry. If so, we now need to
18441852 // delete its newly-unnecessary runtime relocation to avoid a runtime dynamic linker error.
18451853 // This also allows the PLT entry to be reused---see `pltEntryIsDead`.
1846 if (elf.plt.getIndex(.global(global_name))) |plt_index| {
1854 if (elf.plt.getIndex(global_name)) |plt_index| {
18471855 // TODO: we might still need the PLT entry if the symbol could be preempted/interposed! See
18481856 // matching comment at the end of `addGlobalSymbolAssumeCapacity`.
18491857 if (!elf.pltEntryIsDead(plt_index)) {
......@@ -2033,13 +2041,13 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
20332041
20342042 if (plt_index < elf.plt.count()) {
20352043 // We reused a free entry, so we're already done!
2036 elf.plt.setKey(plt_index, .global(global_name));
2044 elf.plt.setKey(plt_index, global_name);
20372045 return;
20382046 }
20392047
20402048 // We added a new entry, so we now need to extend the PLT sections.
20412049 assert(plt_index == elf.plt.count());
2042 elf.plt.putAssumeCapacityNoClobber(.global(global_name), {});
2050 elf.plt.putAssumeCapacityNoClobber(global_name, {});
20432051
20442052 switch (elf.ehdrField(.machine)) {
20452053 else => |machine| @panic(@tagName(machine)),
......@@ -6995,8 +7003,8 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
69957003 // its relocations are probably going through the PLT, so we don't bother with
69967004 // specific tracking for PLT relocations---instead just re-apply all relocations
69977005 // targeting symbols with PLT entries.
6998 for (elf.plt.keys()) |sym| {
6999 sym.applyTargetRelocs(elf);
7006 for (elf.plt.keys()) |name| {
7007 Symbol.Id.global(name).applyTargetRelocs(elf);
70007008 }
70017009 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
70027010 // However, if there's also a flush pending for `.got.plt`, don't bother doing