From 0ec01348a545e76c11ebcd3d57eedb33a959ba58 Mon Sep 17 00:00:00 2001 From: aszlig Date: Mon, 18 May 2026 16:25:02 +0200 Subject: [PATCH] gensyms: Don't use PROVIDE() in linker script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A while ago we had a report[1] about integration test failure/timeout on aarch64 on OpenSUSE, but we didn't have that failure on Nix(OS). Recently, this has also turned up on x86_64-linux and @mweinelt has bisected this issue to a recent binutils update in nixpkgs[2]. I decided to go from there and bisected binutils itself, which led to a commit[3] that led to that failure: x86-64: Estimate output section layout before sizing dynamic sections When sizing dynamic sections, elf_x86_64_scan_relocs converts GOTPCREL relocations to R_X86_64_PC32, R_X86_64_32S or R_X86_64_32 for local symbols. But at that time, since the output section layout is unknown, the local symbol values can't be determined. Later linker issues an error if the converted relocation overflows when resolving relocations against these local symbols. Update the x86-64 ELF linker to estimate output section layout before sizing dynamic sections and use the preliminary output section layout info to skip the GOTPCREL relocation conversion if the converted relocation overflows. Since the output section layout is now computed before bfd_elf_size_dynamic_sections, my guess is that the PROVIDE directives we're using are now turned into no-ops. From the documentation[4]: In some cases, it is desirable for a linker script to define a symbol only if it is referenced and is not defined by any object included in the link. For example, traditional linkers defined the symbol ‘etext’. However, ANSI C requires that the user be able to use ‘etext’ as a function name without encountering an error. The PROVIDE keyword may be used to define a symbol, such as ‘etext’, only if it is referenced but not defined. We only reference the symbol via version script, so my guess is that this now no longer counts as a reference since we only really reference the symbols via dlsym(). I also looked at recent Hydra builds of ip2unix and the integration test failure on OpenSUSE might also be the one we're hitting since mid-2025. What I'm not sure however is why I used PROVIDE in the first place instead of just an assignment, especially after I now read through the full documentation. I guess back then I only skimmed the documentation and made assumptions on what PROVIDE does. So while I can't 100% confirm that my reasoning above is really what happened, I'm pretty sure that we shouldn't use PROVIDE here. Given that 100% confirming the former would require lots of research, I'm stopping here since in any case, direct assignment should fix the issue. [1]: https://github.com/nixcloud/ip2unix/issues/37 [2]: https://github.com/NixOS/nixpkgs/commit/e2a60581caf760b9b0d195ff8c2e6111138c6cf1 [3]: https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=73ab3b9825d232f0f3a4ad811e88697f9b9ab162 [4]: https://sourceware.org/binutils/docs/ld/PROVIDE.html Signed-off-by: aszlig --- scripts/gensyms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gensyms.py b/scripts/gensyms.py index e9d376f..076f865 100644 --- a/scripts/gensyms.py +++ b/scripts/gensyms.py @@ -37,5 +37,5 @@ def find_symbols(*wrapper_names: str) -> List[str]: sys.stdout.write("{\n global:" + exported + "\n local: *;\n};\n") elif ACTION == '--ldscript': symbols = find_symbols('WRAP_SYM') - lines = map(lambda s: f'PROVIDE({s} = ip2unix_wrap_{s});', symbols) + lines = map(lambda s: f'{s} = ip2unix_wrap_{s};', symbols) sys.stdout.write("\n".join(lines) + "\n")