ld: Maintain the input file order
Commit Message
When adding a new input archive, which comes from a linker script file
and isn't referenced by any inputs, ld appends it to the input file list.
On Linux, the input file order looks like
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
/usr/lib64/libmvec.a
/usr/lib64/libm-2.42.a
since the compiler may not add compiler builtin functions to the LTO
symbol table as it doesn't really know if builtin functions will have
real symbols. When ld extracts an element from the archive later during
LTO rescan, the final input file order is
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
fclrexcpt.o
where x.o references the builtin function, feclearexcept which is defined
in fclrexcpt.o from /usr/lib64/libm-2.42.a.
As the result, the .eh_frame section terminator in crtn.o is placed before
fclrexcpt.o and the .eh_frame section in the output isn't terminated. The
output crashes when it runs over the .eh_frame section during EH frame
registration. Insert the new input file after the current input file to
maintain the input file order:
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib64/libmvec.a
/usr/lib64/libm-2.42.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
to properly terminate the .eh_frame section.
PR ld/34088
* ldlang.c (current_input_file): Changed to the pointer to
lang_input_statement_type.
(new_afile): Insert the new input file after the current input
file to maintain the input file order.
(lang_add_input_file): Updated.
(load_symbols): Likewise.
* testsuite/ld-plugin/lto.exp: Run PR ld/34088 test.
* testsuite/ld-plugin/pr34088.c: New file.
From 02a7da29c49d760f07ba33d1689d473d4e9009b0 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Wed, 22 Apr 2026 03:53:20 +0800
Subject: [PATCH] ld: Maintain the input file order
When adding a new input archive, which comes from a linker script file
and isn't referenced by any inputs, ld appends it to the input file list.
On Linux, the input file order looks like
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
/usr/lib64/libmvec.a
/usr/lib64/libm-2.42.a
since the compiler may not add compiler builtin functions to the LTO
symbol table as it doesn't really know if builtin functions will have
real symbols. When ld extracts an element from the archive later during
LTO rescan, the final input file order is
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
fclrexcpt.o
where x.o references the builtin function, feclearexcept which is defined
in fclrexcpt.o from /usr/lib64/libm-2.42.a.
As the result, the .eh_frame section terminator in crtn.o is placed before
fclrexcpt.o and the .eh_frame section in the output isn't terminated. The
output crashes when it runs over the .eh_frame section during EH frame
registration. Insert the new input file after the current input file to
maintain the input file order:
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crti.o
/usr/lib/gcc/x86_64-redhat-linux/15/crtbeginT.o
x.o (symbol from plugin)
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libm.a
/usr/lib64/libmvec.a
/usr/lib64/libm-2.42.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc.a
/usr/lib/gcc/x86_64-redhat-linux/15/libgcc_eh.a
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/libc.a
/usr/lib/gcc/x86_64-redhat-linux/15/crtend.o
/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crtn.o
to properly terminate the .eh_frame section.
PR ld/34088
* ldlang.c (current_input_file): Changed to the pointer to
lang_input_statement_type.
(new_afile): Insert the new input file after the current input
file to maintain the input file order.
(lang_add_input_file): Updated.
(load_symbols): Likewise.
* testsuite/ld-plugin/lto.exp: Run PR ld/34088 test.
* testsuite/ld-plugin/pr34088.c: New file.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
ld/ldlang.c | 31 +++++++++++++++++++++++++++----
ld/testsuite/ld-plugin/lto.exp | 10 ++++++++++
ld/testsuite/ld-plugin/pr34088.c | 10 ++++++++++
3 files changed, 47 insertions(+), 4 deletions(-)
create mode 100644 ld/testsuite/ld-plugin/pr34088.c
@@ -135,7 +135,7 @@ lang_statement_list_type file_chain = { NULL, NULL };
lang_input_statement_type statement (reached via input_statement field in a
lang_statement_union). */
lang_statement_list_type input_file_chain;
-static const char *current_input_file;
+static lang_input_statement_type *current_input_file;
struct bfd_elf_dynamic_list **current_dynamic_list_p;
struct bfd_sym_chain entry_symbol = { NULL, NULL };
const char *entry_section = ".text";
@@ -1287,7 +1287,27 @@ new_afile (const char *name,
FAIL ();
}
- lang_statement_append (&input_file_chain, p, &p->next_real_file);
+ if (current_input_file != NULL)
+ {
+ lang_input_statement_type *f;
+
+ /* Insert the new input file after the current input file to
+ maintain the input file order. */
+ for (f = (void *) input_file_chain.head;
+ f != NULL;
+ f = f->next_real_file)
+ if (f == current_input_file)
+ {
+ p->next_real_file = f->next_real_file;
+ f->next_real_file = p;
+ break;
+ }
+
+ if (f == NULL)
+ abort ();
+ }
+ else
+ lang_statement_append (&input_file_chain, p, &p->next_real_file);
return p;
}
@@ -1319,7 +1339,10 @@ lang_add_input_file (const char *name,
return ret;
}
- return new_afile (name, file_type, target, current_input_file);
+ return new_afile (name, file_type, target,
+ (current_input_file
+ ? current_input_file->filename
+ : NULL));
}
struct out_section_hash_entry
@@ -3225,7 +3248,7 @@ load_symbols (lang_input_statement_type *entry,
ldfile_assumed_script = true;
parser_input = input_script;
- current_input_file = entry->filename;
+ current_input_file = entry;
yyparse ();
current_input_file = NULL;
ldfile_assumed_script = false;
@@ -929,6 +929,16 @@ set lto_run_elf_shared_tests [list \
{-Wl,-R,tmpdir} {} \
{pr31644a.c} {pr31644b.exe} {pass.out} {-flto} {c} {} \
{-Wl,--as-needed tmpdir/pr31644b.a tmpdir/pr31644c.so}] \
+ [list {PR ld/34088} \
+ {-static -flto -fuse-linker-plugin} \
+ {} \
+ {pr34088.c} \
+ {pr34088.exe} \
+ {pass.out} \
+ {-flto -O0} \
+ {c} \
+ {} \
+ {-lm}] \
]
# LTO run-time tests for ELF
new file mode 100644
@@ -0,0 +1,10 @@
+#include <stdio.h>
+#include <fenv.h>
+
+int
+main (void)
+{
+ feclearexcept(FE_ALL_EXCEPT);
+ printf ("PASS\n");
+ return 0;
+}
--
2.53.0