[PATCH v2] ld: Maintain the input file order

H.J. Lu hjl.tools@gmail.com
Wed Apr 22 06:54:26 GMT 2026


On Wed, Apr 22, 2026 at 2:17 PM Jan Beulich <jbeulich@suse.com> wrote:
>
> On 21.04.2026 23:12, H.J. Lu wrote:
> > On Wed, Apr 22, 2026 at 4:22 AM H.J. Lu <hjl.tools@gmail.com> wrote:
> >>
> >> 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.
> >>
> >> --
> >> H.J.
> >
> > Changes from v1:
> >
> > 1. Add debug_input_files.
> > 2. Insert the new input file before the current input file to keep
> > the order within the linker script file.
>
> Why would "before" vs "after" matter? Plus in the new code in new_afile()

/usr/lib64/libm.a has

GROUP ( /usr/lib64/libm-2.42.a /usr/lib64/libmvec.a )

With before -lm, the 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/lib64/libm-2.42.a
/usr/lib64/libmvec.a
/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

which is the same as x.o isn't an LTO input.   With after -lm,
the 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/lib64/libmvec.a
/usr/lib64/libm-2.42.a
/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

"before" makes the input file order the same with and without
LTO input.

> it very much looks as if prev still being NULL could be de-referenced.
> input_file_chain.head starts out as NULL, after all, and hence it could

input_file_chain.head starts with a "null" item:

(gdb) r `cat doit`
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program:
/export/build/gnu/tools-build/binutils-gitlab/build-x86_64-linux/ld/ld-new
`cat doit`
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, lang_add_input_file (name=0x0,
    file_type=lang_input_file_is_marker_enum, target=0x0)
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldlang.c:1323
1323   if (name != NULL
(gdb) call debug_input_files ()
(gdb) c
Continuing.

Breakpoint 1, lang_add_input_file (
    name=0x7fffffffddba
"/usr/lib/gcc/x86_64-redhat-linux/15/../../../../lib64/crt1.o",
file_type=lang_input_file_is_file_enum, target=0x0)
    at /export/gnu/import/git/gitlab/x86-binutils/ld/ldlang.c:1323
1323   if (name != NULL
(gdb) call debug_input_files ()
input: (null)
(gdb)

"prev" will never be NULL.

> very well point at current_input_file.
>
> The casting to void * there also isn't nice. Can't this be
> &input_file_chain.head->input_statement? Same in debug_input_files().
> There f also wants to be pointer-to-const.

This is how the current input_file_chain.head is referenced in all other places.
I'd like to keep it this way for consistency.

> As to the new testcase: Doesn't that make assumptions on how runtime
> libraries are structured on the target? IOW is the test passing really
> an indication of the issue at hand not occurring?
>

It is true that such a test won't fail without libm.a being a linker script
if the bug isn't fixed.   But it will fail on glibc targets.  Its coverage
should be sufficient.

-- 
H.J.


More information about the Binutils mailing list