Bug 12248 - Linker plugin failed to preserve linking order
Summary: Linker plugin failed to preserve linking order
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: ld (show other bugs)
Version: 2.22
: P2 critical
Target Milestone: ---
Assignee: unassigned
URL: http://sourceware.org/ml/binutils/201...
Keywords:
Depends on:
Blocks: 12245
  Show dependency treegraph
 
Reported: 2010-11-20 18:55 UTC by H.J. Lu
Modified: 2012-12-07 20:04 UTC (History)
5 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
A testcase (556 bytes, application/octet-stream)
2010-11-20 18:55 UTC, H.J. Lu
Details
build results with static linking vs gold (5.29 KB, text/plain)
2010-11-20 20:48 UTC, Dave Korn
Details
A new testcase (755 bytes, application/octet-stream)
2010-11-23 23:39 UTC, H.J. Lu
Details
A testcase to show linker order (758 bytes, application/octet-stream)
2010-11-23 23:40 UTC, H.J. Lu
Details

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2010-11-20 18:55:17 UTC
Created attachment 5131 [details]
A testcase

[hjl@gnu-35 pr12245]$ make
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o x.o x.c
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o y.o y.c
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -o foo -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin x.o y.o
/tmp/ccVUrOVB.ltrans0.ltrans.o: In function `main':
ccVUrOVB.ltrans0.o:(.text+0x2b): undefined reference to `__udivdi3'
collect2: ld returned 1 exit status
make: *** [foo] Error 1
[hjl@gnu-35 pr12245]$
Comment 1 H.J. Lu 2010-11-20 19:06:52 UTC
This bug may generate incorrect binaries. We may need
to recheck all archives after all ltrans object files
are processed.
Comment 2 Dave Korn 2010-11-20 20:15:36 UTC
This is GCC PR42690, for which I have a patch that's just completed testing.
Comment 3 H.J. Lu 2010-11-20 20:37:29 UTC
(In reply to comment #2)
> This is GCC PR42690, for which I have a patch that's just completed testing.

Why does GOLD work fine? 

[hjl@gnu-35 pr12245]$ make
/export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o x.o x.c
/export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o y.o y.c
/export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/gcc -m32 -o foo -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin x.o y.o
/tmp/ccEqvHaO.ltrans0.ltrans.o: In function `main':
ccEqvHaO.ltrans0.o:(.text+0x2b): undefined reference to `__udivdi3'
collect2: ld returned 1 exit status
make: *** [foo] Error 1
[hjl@gnu-35 pr12245]$ /export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/gcc -v
Using built-in specs.
COLLECT_GCC=/export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/gcc
COLLECT_LTO_WRAPPER=/export/gnu/import/svn/gcc-test-spec/usr.bfd/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.6.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /export/gnu/import/git/gcc/configure --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld --enable-languages=c,c++,fortran --enable-shared --enable-threads=posix --enable-haifa --prefix=/usr/gcc-4.6.0 --with-local-prefix=/usr/local --with-fpmath=sse --with-plugin-ld=ld
Thread model: posix
gcc version 4.6.0 20101119 (experimental) (GCC) 
[hjl@gnu-35 pr12245]$ make clean
rm -f *.o foo a.out
[hjl@gnu-35 pr12245]$ make
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o x.o x.c
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o y.o y.c
/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -m32 -o foo -O3 -fwhole-program -flto=jobserver -fuse-linker-plugin x.o y.o
./foo
2147478250
[hjl@gnu-35 pr12245]$ /export/gnu/import/svn/gcc-test-spec/usr/bin/gcc -v
Using built-in specs.
COLLECT_GCC=/export/gnu/import/svn/gcc-test-spec/usr/bin/gcc
COLLECT_LTO_WRAPPER=/export/gnu/import/svn/gcc-test-spec/usr/bin/../libexec/gcc/x86_64-unknown-linux-gnu/4.6.0/lto-wrapper
Target: x86_64-unknown-linux-gnu
Configured with: /export/gnu/import/git/gcc/configure --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld --enable-languages=c,c++,fortran --enable-shared --enable-threads=posix --enable-haifa --prefix=/usr/gcc-4.6.0 --with-local-prefix=/usr/local --with-fpmath=sse --with-plugin-ld=ld.gold --enable-gold
Thread model: posix
gcc version 4.6.0 20101119 (experimental) (GCC) 
[hjl@gnu-35 pr12245]$
Comment 4 Dave Korn 2010-11-20 20:48:18 UTC
Created attachment 5132 [details]
build results with static linking vs gold

Even GOLD fails when static linking is in use, as in this LTO-bootstrap run of GCC configured with "--disable-shared --enable-shared=lto-plugin --with-plugin-ld=gold --enable-gold".

I am not yet sure what it is exactly that GOLD does differently internally that makes it pick up dynamic library references.
Comment 5 H.J. Lu 2010-11-23 23:39:05 UTC
Created attachment 5136 [details]
A new testcase

-pass-through is a hack, not a real solution. Here is a testcase
where __udivdi3 in div.c should override the one in libgcc.a:

[hjl@gnu-6 pr12245-2]$ make
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o y.o y.c
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin   -c -o x.o x.c
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32    -c -o div.o div.c
ar rv libdiv.a div.o
r - div.o
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin y.o x.o libdiv.a
./foo
2145852098
make: *** [all] Aborted
[hjl@gnu-6 pr12245-2]$ make clean
rm -f *.o foo a.out
[hjl@gnu-6 pr12245-2]$ make CFLAGS=-O3
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -O3   -c -o y.o y.c
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -O3   -c -o x.o x.c
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -O3   -c -o div.o div.c
ar rv libdiv.a div.o
r - div.o
/export/build/gnu/gcc/release/usr/gcc-4.6.0/bin/gcc -m32 -B./ -o foo -O3 y.o x.o libdiv.a
./foo
1
[hjl@gnu-6 pr12245-2]$
Comment 6 H.J. Lu 2010-11-23 23:40:57 UTC
Created attachment 5137 [details]
A testcase to show linker order

LTO plugin should preserve linker order.  Otherwise, we will generate
incorrect executables.
Comment 7 H.J. Lu 2010-12-06 05:43:54 UTC
The patch is posted at

http://sourceware.org/ml/binutils/2010-12/msg00207.html
Comment 8 Dmitry Gorbachev 2011-01-22 23:37:57 UTC
(In reply to comment #6)

This testcase shows that 2-stage BFD linker changes the order of linking.

ld.hjl takes a definition of __udivdi3 (which is referred to by bar in x.o) from libdiv.a (not from libgcc, not from libc), though libdiv.a appears before x.o on the command line:

gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin y.o libdiv.a x.o

GCC documentation: "[T]he linker searches and processes libraries and object files in the order they are specified.  Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o.  If bar.o refers to functions in z, those functions may not be loaded."

Can this behavior cause any problems in practice?
Comment 9 H.J. Lu 2011-01-23 00:11:13 UTC
(In reply to comment #8)
> (In reply to comment #6)
> 
> This testcase shows that 2-stage BFD linker changes the order of linking.
> 
> ld.hjl takes a definition of __udivdi3 (which is referred to by bar in x.o)
> from libdiv.a (not from libgcc, not from libc), though libdiv.a appears before
> x.o on the command line:
> 
> gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin y.o
> libdiv.a x.o
> 

When there are "IR-object non-IR-archive IR-object" on command line,
LTO makes it equivalent to "IR-object IR-object non-IR-archive".
Comment 10 Dmitry Gorbachev 2011-01-23 01:10:35 UTC
(In reply to comment #9)
> When there are "IR-object non-IR-archive IR-object" on command line,
> LTO makes it equivalent to "IR-object IR-object non-IR-archive".

It seems this behavior isn't documented.

> When there are "IR-object non-IR-archive IR-object" on command line,
> LTO makes it equivalent to "IR-object IR-object non-IR-archive".

It also happens with IR-archive (though IR is not used: "ld.hjl: LTO IR sections in libdiv.a(div.o) aren't used in stage 2 linking").

Behavior of ld.ian depends on pass-through hack in the driver. With a hack, it takes __udivdi3 from libgcc. Without -pass-through options, it silently uses non-IR part of libdiv.a.
Comment 11 H.J. Lu 2011-01-23 03:19:03 UTC
(In reply to comment #10)
> (In reply to comment #9)
> > When there are "IR-object non-IR-archive IR-object" on command line,
> > LTO makes it equivalent to "IR-object IR-object non-IR-archive".
> 
> It seems this behavior isn't documented.
> 
> > When there are "IR-object non-IR-archive IR-object" on command line,
> > LTO makes it equivalent to "IR-object IR-object non-IR-archive".
> 
> It also happens with IR-archive (though IR is not used: "ld.hjl: LTO IR
> sections in libdiv.a(div.o) aren't used in stage 2 linking").

I can change linker to skip archives between LTO claimed objects
in stage 2 linking.
Comment 12 H.J. Lu 2011-01-23 18:36:38 UTC
(In reply to comment #10)
> (In reply to comment #9)
> > When there are "IR-object non-IR-archive IR-object" on command line,
> > LTO makes it equivalent to "IR-object IR-object non-IR-archive".
> 
> It seems this behavior isn't documented.

It is fixed by commit 5ec86f21a2370249ae49ffb3dc0e438d67a39522 on
hjl/lto-mixed branch.

> > When there are "IR-object non-IR-archive IR-object" on command line,
> > LTO makes it equivalent to "IR-object IR-object non-IR-archive".
> 
> It also happens with IR-archive (though IR is not used: "ld.hjl: LTO IR
> sections in libdiv.a(div.o) aren't used in stage 2 linking").
> 

I will try to change linker to ignore libdiv.a(div.o) in this
case.
Comment 13 H.J. Lu 2011-01-23 19:13:20 UTC
(In reply to comment #10)
> It also happens with IR-archive (though IR is not used: "ld.hjl: LTO IR
> sections in libdiv.a(div.o) aren't used in stage 2 linking").
> 

Fixed by commit baf9b44566e088687f28f9fe476122876c1d2f4d on hjl/lto-mixed
branch.
Comment 14 Dmitry Gorbachev 2011-01-23 23:14:20 UTC
Now `gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin x.o
libdiv.a y.o' uses __udivdi3 from libgcc. Plain non-LTO link takes it from libdiv.a. Inconsistency, again...
Comment 15 H.J. Lu 2011-01-23 23:38:41 UTC
(In reply to comment #14)
> Now `gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin
> x.o
> libdiv.a y.o' uses __udivdi3 from libgcc. Plain non-LTO link takes it from
> libdiv.a. Inconsistency, again...

It is consistent since LTO in x.o doesn't reference __udivdi3 while
non-LTO in x.o references __udivdi3.
Comment 16 Dmitry Gorbachev 2011-01-24 00:37:53 UTC
It looks counterintuitive to me.

> LTO in x.o doesn't reference __udivdi3

But a reference to __udivdi3 from bar is generated on LTO step:
/tmp/cczLpgd5.ltrans0.ltrans.o: reference to __udivdi3

BTW, behavior of `gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver -fuse-linker-plugin y.o x.o libdiv.a' depends on the presence / absence of IR sections in libdiv.a (links with libgcc / libdiv.a). I think it's a bug.
Comment 17 H.J. Lu 2011-01-24 01:24:01 UTC
(In reply to comment #16)
> It looks counterintuitive to me.
> 
> > LTO in x.o doesn't reference __udivdi3
> 
> But a reference to __udivdi3 from bar is generated on LTO step:
> /tmp/cczLpgd5.ltrans0.ltrans.o: reference to __udivdi3

This is internal implementation of LTO, which calls __udivdi3
in libgcc. LTO may also choose to inline it.

> BTW, behavior of `gcc -B./ -o foo -O2 -fwhole-program -flto=jobserver
> -fuse-linker-plugin y.o x.o libdiv.a' depends on the presence / absence of IR
> sections in libdiv.a (links with libgcc / libdiv.a). I think it's a bug.

This is intentional. Since libdiv.a with IR isn't used by LTO in stage 1
linking, it can't be used in stage 2 either. Otherwise, stage 2 linking
may lead to undefined symbols if libdiv uses some external variables,
which are defined in some IR inputs and optimized out by LTO since LTO
didn't see their references in libdiv.a. I checked some LTO testcases
into hjl/lto-mixed branch to verify it.
Comment 18 Dmitry Gorbachev 2011-02-01 21:53:45 UTC
If ld.hjl behavior is correct, then it should be documented, and other linkers (ld.bfd/ld.dk, ld.gold) should be changed to conform to it; or there can be bugs in programs due to subtle differences in the linking order.
Comment 19 H.J. Lu 2011-02-02 17:46:17 UTC
(In reply to comment #18)
> If ld.hjl behavior is correct, then it should be documented, and other linkers
> (ld.bfd/ld.dk, ld.gold) should be changed to conform to it; or there can be
> bugs in programs due to subtle differences in the linking order.

I think you should raise this issue in the gcc mailing list.
Comment 20 H.J. Lu 2012-12-07 20:01:56 UTC
2.23 works correctly.
Comment 21 H.J. Lu 2012-12-07 20:04:27 UTC
It is tracked by "LTO 1" test in ld-plugin.