Bug 21777

Summary: libdrm-2.4.11 fails with LDFLAGS="-Wl,--as-needed"
Product: DRI Reporter: Adrian Dannberg <neustadt>
Component: libdrmAssignee: Default DRI bug account <dri-devel>
Status: RESOLVED FIXED QA Contact:
Severity: normal    
Priority: medium CC: remi
Version: XOrg git   
Hardware: x86 (IA32)   
OS: Linux (All)   
Whiteboard:
i915 platform: i915 features:
Attachments:
Description Flags
Explicitly link test programs to $(CLOCK_LIB) none

Description Adrian Dannberg 2009-05-17 03:47:13 UTC
Distro: Gentoo-Linux
Gcc:    4.3.2

without as-needed it compiles fine.

Code:
/bin/sh ../libtool --tag=CC   --mode=link i686-pc-linux-gnu-gcc  -march=athlon64-sse3 -O2 -pipe -fomit-frame-pointer  -Wl,-O1 -Wl,--sort-common -Wl,--hash-style=gnu -Wl,--as-needed -o drmstat drmstat.o ../libdrm/libdrm.la
/bin/sh ../libtool --tag=CC   --mode=link i686-pc-linux-gnu-gcc  -march=athlon64-sse3 -O2 -pipe -fomit-frame-pointer  -Wl,-O1 -Wl,--sort-common -Wl,--hash-style=gnu -Wl,--as-needed -o dristat dristat.o ../libdrm/libdrm.la
libtool: link: i686-pc-linux-gnu-gcc -march=athlon64-sse3 -O2 -pipe -fomit-frame-pointer -Wl,-O1 -Wl,--sort-common -Wl,--hash-style=gnu -o .libs/drmstat drmstat.o  -Wl,--as-needed ../libdrm/.libs/libdrm.so
libtool: link: i686-pc-linux-gnu-gcc -march=athlon64-sse3 -O2 -pipe -fomit-frame-pointer -Wl,-O1 -Wl,--sort-common -Wl,--hash-style=gnu -o .libs/dristat dristat.o  -Wl,--as-needed ../libdrm/.libs/libdrm.so
dristat.o: In function `drmWaitVBlank':
dristat.c:(.text+0x1a3f): undefined reference to `clock_gettime'
dristat.c:(.text+0x1a94): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make[2]: *** [dristat] Error 1
make[2]: *** Waiting for unfinished jobs....
make[2]: Leaving directory `/var/tmp/portage/x11-libs/libdrm-2.4.11/work/libdrm-2.4.11/tests'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/var/tmp/portage/x11-libs/libdrm-2.4.11/work/libdrm-2.4.11/tests'
make: *** [all-recursive] Error 1
 *
 * ERROR: x11-libs/libdrm-2.4.11 failed.
 * Call stack:
 *               ebuild.sh, line   48:  Called src_compile
 *             environment, line 3097:  Called x-modular_src_compile
 *             environment, line 3877:  Called x-modular_src_make
 *             environment, line 3916:  Called die
 * The specific snippet of code:
 *       emake || die "emake failed"
 *  The die message:
 *   emake failed
Comment 1 Dan Nicholson 2009-05-18 06:38:26 UTC
On Fedora, clock_gettime comes from librt, but that gets added in the build when linking to libdrm.la. Can you check that -lrt is actually getting added to libdrm?

$ grep 'LIBADD *=' libdrm/Makefile
libdrm_la_LIBADD = -lrt
$ grep dependency_libs libdrm/libdrm.la 
dependency_libs=' -lrt'

Because it links dristat correctly for me, but that's because libtool is specifically adding -lrt:

gcc -DHAVE_CONFIG_H -I. -I../libdrm  -I ../shared-core -I ../libdrm   -g -O2 -MT dristat.o -MD -MP -MF .deps/dristat.Tpo -c -o dristat.o dristat.c
mv -f .deps/dristat.Tpo .deps/dristat.Po
/bin/sh ../libtool --tag=CC   --mode=link gcc  -g -O2  -Wl,--as-needed -o dristat dristat.o ../libdrm/libdrm.la
gcc -g -O2 -Wl,--as-needed -o .libs/dristat dristat.o  ../libdrm/.libs/libdrm.so -lrt
creating dristat
Comment 2 Adrian Dannberg 2009-05-18 07:20:34 UTC
Looks good

dionysos libdrm-2.4.11 # grep 'LIBADD *=' libdrm/Makefile
libdrm_la_LIBADD = -lrt
dionysos libdrm-2.4.11 # grep dependency_libs libdrm/libdrm.la
# Linker flags that can not go in dependency_libs.
dependency_libs=' -lrt'
Comment 3 Dan Nicholson 2009-05-18 12:18:22 UTC
Created attachment 25974 [details] [review]
Explicitly link test programs to $(CLOCK_LIB)
Comment 4 Dan Nicholson 2009-05-18 12:19:40 UTC
Hmm, well libtool is supposed to add the -lrt for you. You're using this right from the tarball, right? I was actually using git and generating libtool myself, but I can confirm it now when I use the tarball. It looks like what was used for the tarball was libtool-2.2.6, and it includes the debian patch to not add $dependency_libs for programs on linux. Probably the easiest way to fix this is to explicitly link the programs to $(CLOCK_LIB) in addition to -ldrm.

Actually, this seems to really only be an issue for dristat since it uses internal symbols from libdrm.so. The linker reacts to this by adding all of libdrm.so to the executable. See the difference in size between dristat and drmstat even though they're essentially the same program:

$ size tests/.libs/*
   text    data     bss     dec     hex filename
  30756     864    2400   34020    84e4 tests/.libs/dristat
   9581     788     104   10473    28e9 tests/.libs/drmstat

When using --as-needed, the linker will skip the DT_NEEDED tags for both libdrm.so and librt.so unless -lrt is specified on the command line. I think this is actually a linker bug, but we can work around it here.

See if the attached patch helps. You should just need to run automake and then ./configure.
Comment 5 Adrian Dannberg 2009-05-18 13:44:09 UTC
> Hmm, well libtool is supposed to add the -lrt for you. You're using this right
> from the tarball, right?

Right

> See if the attached patch helps. You should just need to run automake and then
> ./configure.

Great, the patch works! Tests compile fine.

> When using --as-needed, the linker will skip the DT_NEEDED tags for both
> libdrm.so and librt.so unless -lrt is specified on the command line. I think
> this is actually a linker bug, but we can work around it here.

I hope someone will tell them ;)

Anyways, will this be integrated in upstream?
I wonder whether to open a bug report about this on bugs.gentoo.org

Comment 6 Dan Nicholson 2009-05-18 14:04:36 UTC
(In reply to comment #5)
> > When using --as-needed, the linker will skip the DT_NEEDED tags for both
> > libdrm.so and librt.so unless -lrt is specified on the command line. I think
> > this is actually a linker bug, but we can work around it here.
> 
> I hope someone will tell them ;)

I don't keep up with binutils upstream anymore, but I may try to setup a test case and see if it's reproducible. Maybe you can mention to the gentoo toolchain people. They may determine that my analysis is crack. :)

> Anyways, will this be integrated in upstream?
> I wonder whether to open a bug report about this on bugs.gentoo.org

I can push it to libdrm git, but you'll want to open a gentoo bug if you want this release fixed. I don't know when the next libdrm release will be made.
Comment 7 Adrian Dannberg 2009-05-18 14:14:13 UTC
(In reply to comment #6)
> I don't keep up with binutils upstream anymore, but I may try to setup a test
> case and see if it's reproducible. Maybe you can mention to the gentoo
> toolchain people. They may determine that my analysis is crack. :)

hehe, allrighty will do.
I'll post a link if you or others are interested in following this.

 

Comment 8 Rémi Cardona 2009-05-19 09:08:58 UTC
Gentoo build has already been fixed, we basically run autoreconf before running configure.

After digging into this for an hour straight (without knowing about this bug...), my brain hurts a bit but I'd be interested in knowing who's to blame: libtool, ld or Debian ;)

Cheers
Comment 9 Dan Nicholson 2009-05-19 11:15:57 UTC
(In reply to comment #8)
> After digging into this for an hour straight (without knowing about this
> bug...), my brain hurts a bit but I'd be interested in knowing who's to blame:
> libtool, ld or Debian ;)

Just to boil down the test case.

Works: gcc -Wl,--as-needed -o .libs/dristat dristat.o ../libdrm/.libs/libdrm.so -lrt

Fails: gcc -Wl,--as-needed -o .libs/dristat dristat.o ../libdrm/.libs/libdrm.so

There's two things going on.

1. The vanilla behavior of libtool is to add all dependency_libs in a .la file to the link command line. So, for the case of libdrm.la, this means programs will be linked explicitly to -lrt like in the Works case. With binutils ld, this is not necessary as the linker will search DT_NEEDED entries in the libraries on the command line and add them to ensure symbols are resolved.

And, of course, doing what libtool is doing can be harmful as your program picks up extra NEEDED entries for libraries it doesn't directly use symbols from. Hence, overlinking. So, debian's patch makes libtool skip dependency_libs when linking a program. This should be a good thing, but here it exposes what I think is a bug in ld.

2. Here dristat is using drmOpenMinor, which is a local symbol in libdrm.so. ld seems to react to this by including the entire shared object into the executable. Compare drmstat, which does not use internal symbols, to dristat:

$ nm .libs/drmstat | grep drmGetVersion
                 U drmGetVersion
$ nm .libs/dristat | grep drmGetVersion
0000000000405060 T drmGetVersion

Not such a big deal, except that then ld doesn't process the DT_NEEDED entries in libdrm.so when linking dristat. Subsequently, it fails to add librt.so.1 and then fails to resolve clock_gettime.

To work around this, we just explicitly link dristat to -lrt.
Comment 10 Dan Nicholson 2009-05-19 11:20:44 UTC
(In reply to comment #9)
> Not such a big deal, except that then ld doesn't process the DT_NEEDED entries
> in libdrm.so when linking dristat. Subsequently, it fails to add librt.so.1 and
> then fails to resolve clock_gettime.

I forgot to say that this part only happens when using --as-needed. Without --as-needed, ld does continue to process libdrm.so and its DT_NEEDED entries. So,

Also Works: gcc -o .libs/dristat dristat.o ../libdrm/.libs/libdrm.so
Comment 11 Kristian Høgsberg 2010-05-07 13:14:14 UTC
Looks like this got worked out, if not please reopen.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.