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,...@@ -100,13 +100,15 @@ dynstr: StringTable,
100///100///
101/// Value is the output relocation in `.rela.dyn` for the GOT entry.101/// Value is the output relocation in `.rela.dyn` for the GOT entry.
102got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),102got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional),
103/// Key is the name of a global.
104///
103/// Indices map 1--1 to indices into the actual `.got.plt` section. These also equal indices into105/// Indices map 1--1 to indices into the actual `.got.plt` section. These also equal indices into
104/// the relocations in `.rela.plt`, because every PLT entry has one output relocation (if a runtime106/// the relocations in `.rela.plt`, because every PLT entry has one output relocation (if a runtime
105/// relocation is no longer necessary, then neither is the corresponding PLT entry!).107/// relocation is no longer necessary, then neither is the corresponding PLT entry!).
106///108///
107/// PLT entries in this map may be "dead", meaning the PLT entry has been deemed unnecessary so is109/// PLT entries in this map may be "dead", meaning the PLT entry has been deemed unnecessary so is
108/// available for reuse---see `Elf.pltEntryIsDead`. Such entries must not be targeted by relocs.110/// 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),
110/// The `.plt` section contains zero or more symbol relocations starting at this index.112/// The `.plt` section contains zero or more symbol relocations starting at this index.
111plt_first_symbol_reloc: SymbolReloc.Index,113plt_first_symbol_reloc: SymbolReloc.Index,
112/// The `.dynamic` section contains zero or more symbol relocations starting at this index.114/// The `.dynamic` section contains zero or more symbol relocations starting at this index.
...@@ -1126,7 +1128,10 @@ const SymbolReloc = struct {...@@ -1126,7 +1128,10 @@ const SymbolReloc = struct {
1126 target_endian,1128 target_endian,
1127 ),1129 ),
1128 .pltrel64 => {1130 .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 };
1130 if (elf.pltEntryIsDead(plt_index)) continue :type .rel64;1135 if (elf.pltEntryIsDead(plt_index)) continue :type .rel64;
1131 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {1136 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1132 else => |machine| @panic(@tagName(machine)),1137 else => |machine| @panic(@tagName(machine)),
...@@ -1141,7 +1146,10 @@ const SymbolReloc = struct {...@@ -1141,7 +1146,10 @@ const SymbolReloc = struct {
1141 );1146 );
1142 },1147 },
1143 .pltrel32 => {1148 .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 };
1145 if (elf.pltEntryIsDead(plt_index)) continue :type .rel32;1153 if (elf.pltEntryIsDead(plt_index)) continue :type .rel32;
1146 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {1154 const plt_shndx: Section.Index, const plt_entry_size: u64 = switch (elf.ehdrField(.machine)) {
1147 else => |machine| @panic(@tagName(machine)),1155 else => |machine| @panic(@tagName(machine)),
...@@ -1843,7 +1851,7 @@ fn setGlobalSymbolValue(...@@ -1843,7 +1851,7 @@ fn setGlobalSymbolValue(
1843 // If this symbol was previously undefined, it may have had a PLT entry. If so, we now need to1851 // If this symbol was previously undefined, it may have had a PLT entry. If so, we now need to
1844 // delete its newly-unnecessary runtime relocation to avoid a runtime dynamic linker error.1852 // delete its newly-unnecessary runtime relocation to avoid a runtime dynamic linker error.
1845 // This also allows the PLT entry to be reused---see `pltEntryIsDead`.1853 // 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| {
1847 // TODO: we might still need the PLT entry if the symbol could be preempted/interposed! See1855 // TODO: we might still need the PLT entry if the symbol could be preempted/interposed! See
1848 // matching comment at the end of `addGlobalSymbolAssumeCapacity`.1856 // matching comment at the end of `addGlobalSymbolAssumeCapacity`.
1849 if (!elf.pltEntryIsDead(plt_index)) {1857 if (!elf.pltEntryIsDead(plt_index)) {
...@@ -2033,13 +2041,13 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void...@@ -2033,13 +2041,13 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void
20332041
2034 if (plt_index < elf.plt.count()) {2042 if (plt_index < elf.plt.count()) {
2035 // We reused a free entry, so we're already done!2043 // 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);
2037 return;2045 return;
2038 }2046 }
20392047
2040 // We added a new entry, so we now need to extend the PLT sections.2048 // We added a new entry, so we now need to extend the PLT sections.
2041 assert(plt_index == elf.plt.count());2049 assert(plt_index == elf.plt.count());
2042 elf.plt.putAssumeCapacityNoClobber(.global(global_name), {});2050 elf.plt.putAssumeCapacityNoClobber(global_name, {});
20432051
2044 switch (elf.ehdrField(.machine)) {2052 switch (elf.ehdrField(.machine)) {
2045 else => |machine| @panic(@tagName(machine)),2053 else => |machine| @panic(@tagName(machine)),
...@@ -6995,8 +7003,8 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad...@@ -6995,8 +7003,8 @@ fn flushMovedPltSection(elf: *Elf, which: enum { plt, plt_sec, got_plt }, old_ad
6995 // its relocations are probably going through the PLT, so we don't bother with7003 // its relocations are probably going through the PLT, so we don't bother with
6996 // specific tracking for PLT relocations---instead just re-apply all relocations7004 // specific tracking for PLT relocations---instead just re-apply all relocations
6997 // targeting symbols with PLT entries.7005 // targeting symbols with PLT entries.
6998 for (elf.plt.keys()) |sym| {7006 for (elf.plt.keys()) |name| {
6999 sym.applyTargetRelocs(elf);7007 Symbol.Id.global(name).applyTargetRelocs(elf);
7000 }7008 }
7001 // We also need to update all of the references from `.plt.sec` to `.got.plt`.7009 // We also need to update all of the references from `.plt.sec` to `.got.plt`.
7002 // However, if there's also a flush pending for `.got.plt`, don't bother doing7010 // However, if there's also a flush pending for `.got.plt`, don't bother doing