authorgravatar for loic@gregoire.devLoïc Grégoire <loic@gregoire.dev> 2026-10-04 21:30:10-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-16 12:41:30+01:00
logbdd6bc06ca5f9b4cc6dc141470a6efe1ed7e1f6c
tree83e573f8ef0e65cd76c6a1c0c00c21268a661932
parent7a6eb167bcde3ed8fdc81f88bd683b30b6290e45
signature Commit is signed but in an unrecognized format.

Elf2: keep track of nodeless symbols

Instead of iterating through *all* symbols, instead keep track of symbols without a node and iterate through that. The downside is that e.g TBSS and BSS symbols are mixed together, but the overall iteration size is much smaller than before.

1 files changed, 25 insertions(+), 6 deletions(-)

src/link/Elf2.zig+25-6
...@@ -137,6 +137,9 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa...@@ -137,6 +137,9 @@ node_global_symbols: std.array_hash_map.Auto(MappedFile.Node.Index, Symbol.Globa
137/// See the definition of `DsoGlobals`.137/// See the definition of `DsoGlobals`.
138dso_globals: DsoGlobals,138dso_globals: DsoGlobals,
139139
140/// Contains all defined global symbols that do not have a node.
141nodeless_globals: std.array_hash_map.Auto(Symbol.Global.Index, void),
142
140// These are needed to find local symbols when a nodeless section moves.143// These are needed to find local symbols when a nodeless section moves.
141bss_inputs: std.ArrayList(Node.InputIndex),144bss_inputs: std.ArrayList(Node.InputIndex),
142tbss_inputs: std.ArrayList(Node.InputIndex),145tbss_inputs: std.ArrayList(Node.InputIndex),
...@@ -2744,6 +2747,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{...@@ -2744,6 +2747,7 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
2744 try elf.globals.ensureUnusedCapacity(gpa, 1);2747 try elf.globals.ensureUnusedCapacity(gpa, 1);
2745 try elf.globals_by_name.ensureUnusedCapacity(gpa, 1);2748 try elf.globals_by_name.ensureUnusedCapacity(gpa, 1);
2746 try elf.node_global_symbols.ensureUnusedCapacity(gpa, 1);2749 try elf.node_global_symbols.ensureUnusedCapacity(gpa, 1);
2750 try elf.nodeless_globals.ensureUnusedCapacity(gpa, 1);
27472751
2748 try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) {2752 try Section.Index.symtab.node(elf).ensureMinimumSize(gpa, &elf.mf, switch (elf.shdrPtr(.symtab)) {
2749 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),2753 inline else => |shdr, class| elf.targetLoad(&shdr.size) + @sizeOf(class.ElfN().Sym),
...@@ -2911,6 +2915,10 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{...@@ -2911,6 +2915,10 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{
2911 old_head_ptr.prev_in_node = .wrap(gsi);2915 old_head_ptr.prev_in_node = .wrap(gsi);
2912 }2916 }
29132917
2918 if (opts.node == .none and opts.shndx != .UNDEF) {
2919 elf.nodeless_globals.putAssumeCapacity(gsi, {});
2920 }
2921
2914 if (force_local_bind) {2922 if (force_local_bind) {
2915 elf.moveDemotedGlobal(gsi);2923 elf.moveDemotedGlobal(gsi);
2916 }2924 }
...@@ -3373,6 +3381,11 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {...@@ -3373,6 +3381,11 @@ fn setGlobalSymbolValue(elf: *Elf, gsi: Symbol.Global.Index, new: struct {
3373 assert(global_ptr.prev_in_node == .none);3381 assert(global_ptr.prev_in_node == .none);
3374 }3382 }
33753383
3384 _ = elf.nodeless_globals.swapRemove(gsi);
3385 if (new.node == .none) {
3386 try elf.nodeless_globals.put(elf.base.comp.gpa, gsi, {});
3387 }
3388
3376 global_ptr.symtab_index.ptr(elf).node = new.node;3389 global_ptr.symtab_index.ptr(elf).node = new.node;
33773390
3378 const old_head: Symbol.Global.Index.Optional = old_head: {3391 const old_head: Symbol.Global.Index.Optional = old_head: {
...@@ -4770,6 +4783,7 @@ fn create(...@@ -4770,6 +4783,7 @@ fn create(
4770 .symbols = .empty,4783 .symbols = .empty,
4771 .default_sym_vers = .empty,4784 .default_sym_vers = .empty,
4772 },4785 },
4786 .nodeless_globals = .empty,
4773 .bss_inputs = .empty,4787 .bss_inputs = .empty,
4774 .tbss_inputs = .empty,4788 .tbss_inputs = .empty,
4775 .shstrtab = .{ .map = .empty },4789 .shstrtab = .{ .map = .empty },
...@@ -4854,6 +4868,7 @@ pub fn deinit(elf: *Elf) void {...@@ -4854,6 +4868,7 @@ pub fn deinit(elf: *Elf) void {
4854 elf.dso_globals.string_bytes.deinit(gpa);4868 elf.dso_globals.string_bytes.deinit(gpa);
4855 elf.dso_globals.symbols.deinit(gpa);4869 elf.dso_globals.symbols.deinit(gpa);
4856 elf.dso_globals.default_sym_vers.deinit(gpa);4870 elf.dso_globals.default_sym_vers.deinit(gpa);
4871 elf.nodeless_globals.deinit(gpa);
4857 elf.bss_inputs.deinit(gpa);4872 elf.bss_inputs.deinit(gpa);
4858 elf.tbss_inputs.deinit(gpa);4873 elf.tbss_inputs.deinit(gpa);
4859 elf.shstrtab.map.deinit(gpa);4874 elf.shstrtab.map.deinit(gpa);
...@@ -11627,15 +11642,19 @@ fn updateNobitsAddress(...@@ -11627,15 +11642,19 @@ fn updateNobitsAddress(
1162711642
11628 // Update globals.11643 // Update globals.
11629 // Since nobits sections have no nodes, we can't just iterate over `node_global_symbols`,11644 // Since nobits sections have no nodes, we can't just iterate over `node_global_symbols`,
11630 // so instead filter manually.11645 // so instead filter manually through nodeless symbols.
11631 for (elf.globals.items, 0..) |global, global_index| {11646 for (elf.nodeless_globals.keys()) |gsi| {
11632 if (global.symtab_index.ptr(elf).node != .none) continue;11647 const symbol: Symbol.Id = .global(gsi);
11633 const symbol: Symbol.Id = .global(@fromBackingInt(@intCast(global_index)));11648
11634 const symbol_shndx = switch (elf.symPtr(global.symtab_index)) {11649 const symbol_shndx = switch (elf.symPtr(symbol.index(elf))) {
11635 inline else => |sym| elf.targetLoad(&sym.shndx),11650 inline else => |sym| elf.targetLoad(&sym.shndx),
11636 };11651 };
11637 if (symbol_shndx != expected_shndx) continue;11652 if (symbol_shndx != expected_shndx) continue;
11638 symbol.flushMoved(elf, symbol.value(elf) - old_symbol_base + new_symbol_base);11653
11654 symbol.flushMoved(
11655 elf,
11656 symbol.value(elf) - old_symbol_base + new_symbol_base,
11657 );
11639 }11658 }
1164011659
11641 Symbol.Id.local(shndx.get(elf).lsi).flushMoved(11660 Symbol.Id.local(shndx.get(elf).lsi).flushMoved(