This is the mail archive of the
libc-alpha@sources.redhat.com
mailing list for the glibc project.
shared lib problem with atexit
- To: libc-alpha at sources dot redhat dot com
- Subject: shared lib problem with atexit
- From: Bruno Haible <haible at ilog dot fr>
- Date: Tue, 8 May 2001 15:41:32 +0200 (CEST)
Hi, ELF experts,
With recent glibc, I'm getting a link error when trying to build applications
using libqt. I don't understand where the problem lies - in libc or in the
linker.
$ gcc hello.c -lqt
/packages/gnu/XFree86/lib/libX11.so.6: undefined reference to `atexit'
collect2: ld returned 1 exit status
where hello.c is a trivial C hello-world program.
The situation:
- CPU is i686,
- gcc is gcc-2.95.3.
- binutils (as, ld, ...) are binutils-2.10.0.18 and identify themselves as
"GNU ld 2.10.90".
- /usr/lib/libqt.so.1 and /usr/lib/libqt.so.2 are from SuSE 7.0.
- on 2001-04-12, I installed glibc-2001-03-15 from sources, with
--prefix=/usr,
- on 2001-04-21, I installed XFree86-4.0.99.2 from sources, with
--prefix=/packages/gnu/XFree86
- now I installed glibc-2001-04-30 from sources, with --prefix=/usr.
The source:
====================== hello.c ===========================
#include <stdio.h>
main ()
{
printf("Hello, world.\n");
return 0;
}
==========================================================
The link error occurs when I have set LD_LIBRARY_PATH.
Without LD_LIBRARY_PATH:
$ gcc hello.c -lqt
OK
With LD_LIBRARY_PATH:
$ LD_LIBRARY_PATH=/packages/gnu/XFree86/lib \
gcc hello.c -lqt
/packages/gnu/XFree86/lib/libX11.so.6: undefined reference to `atexit'
collect2: ld returned 1 exit status
Calling collect2 directly:
$ LD_LIBRARY_PATH=/packages/gnu/XFree86/lib \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/collect2 -m elf_i386 \
-dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtbegin.o \
-L/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3 -L/usr/local/lib \
hello.o -lqt \
-lgcc -lc -lgcc \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtend.o /usr/lib/crtn.o
/packages/gnu/XFree86/lib/libX11.so.6: undefined reference to `atexit'
collect2: ld returned 1 exit status
Same with "-lqt" replaced by "/usr/lib/libqt.so.1" or "/usr/lib/libqt.so.2".
libX11 comes in as a dependency from libqt.
$ ldd /usr/lib/libqt.so.1
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x401f7000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x402c7000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x402d5000)
libc.so.6 => /lib/libc.so.6 (0x402f4000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)
$ LD_LIBRARY_PATH=/packages/gnu/XFree86/lib \
ldd /usr/lib/libqt.so.1
libX11.so.6 => /packages/gnu/XFree86/lib/libX11.so.6 (0x401eb000)
libXext.so.6 => /packages/gnu/XFree86/lib/libXext.so.6 (0x402cb000)
libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x402e5000)
libc.so.6 => /lib/libc.so.6 (0x40304000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)
How do these libraries refer to 'atexit'?
$ nm /usr/lib/libqt.so.1 | grep atexit
U atexit@@GLIBC_2.0
$ nm /usr/lib/libqt.so.2 | grep atexit
U atexit@@GLIBC_2.0
$ nm /usr/X11R6/lib/libX11.so.6 | grep atexit
U atexit@@GLIBC_2.0
$ nm /packages/gnu/XFree86/lib/libX11.so.6 | grep atexit
U atexit
So the difference between without/with LD_LIBRARY_PATH is that the libX11
it uses refers to a qualified/unqualified 'atexit' symbol.
Another strange behaviour is that when I explicitly insert the libX11
that causes the error into the link command line, the error goes away!
$ LD_LIBRARY_PATH=/packages/gnu/XFree86/lib \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/collect2 -m elf_i386 \
-dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtbegin.o \
-L/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3 -L/usr/local/lib \
hello.o /usr/lib/libqt.so.1 /packages/gnu/XFree86/lib/libX11.so.6 \
-lgcc -lc -lgcc \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtend.o /usr/lib/crtn.o
OK!!
Or when /usr/lib/libqt.so.1 is dropped and only libX11.so.6 is referred to,
the error goes away as well.
$ LD_LIBRARY_PATH=/packages/gnu/XFree86/lib \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/collect2 -m elf_i386 \
-dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtbegin.o \
-L/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3 -L/usr/local/lib \
hello.o /packages/gnu/XFree86/lib/libX11.so.6 \
-lgcc -lc -lgcc \
/packages/gnu/lib/gcc-lib/i686-pc-linux-gnu/2.95.3/crtend.o /usr/lib/crtn.o
OK!!
Another strange point is the list of undefined symbols of the two libraries:
$ diff <(nm /usr/X11R6/lib/libX11.so.6 | grep ' U ') \
<(nm /packages/gnu/XFree86/lib/libX11.so.6 | grep ' U ')
...
15c16
< U atexit@@GLIBC_2.0
---
> U atexit
...
$ nm /usr/X11R6/lib/libX11.so.6 | grep ' U '
U _IO_getc@@GLIBC_2.0
U _IO_putc@@GLIBC_2.0
U ___brk_addr@@GLIBC_2.0
U __ctype_b@@GLIBC_2.0
U __ctype_get_mb_cur_max@@GLIBC_2.0
U __ctype_tolower@@GLIBC_2.0
U __ctype_toupper@@GLIBC_2.0
U __curbrk@@GLIBC_2.0
U __environ@@GLIBC_2.0
U __errno_location@@GLIBC_2.0
U __fxstat@@GLIBC_2.0
U __strtol_internal@@GLIBC_2.0
U __xstat@@GLIBC_2.0
U access@@GLIBC_2.0
U atexit@@GLIBC_2.0
U calloc@@GLIBC_2.0
U close@@GLIBC_2.0
U connect@@GLIBC_2.0
U exit@@GLIBC_2.0
U fclose@@GLIBC_2.1
U fcntl@@GLIBC_2.0
U ferror@@GLIBC_2.0
U fflush@@GLIBC_2.0
U fgets@@GLIBC_2.0
U fileno@@GLIBC_2.0
U fopen@@GLIBC_2.1
U fprintf@@GLIBC_2.0
U fputs@@GLIBC_2.0
U fread@@GLIBC_2.0
U free@@GLIBC_2.0
U fwrite@@GLIBC_2.0
U getenv@@GLIBC_2.0
U gethostbyname@@GLIBC_2.0
U getpeername@@GLIBC_2.0
U getpid@@GLIBC_2.0
U getpwnam_r@@GLIBC_2.0
U getpwuid_r@@GLIBC_2.0
U getservbyname@@GLIBC_2.0
U getsockname@@GLIBC_2.0
U getuid@@GLIBC_2.0
U inet_addr@@GLIBC_2.0
U ioctl@@GLIBC_2.0
U malloc@@GLIBC_2.0
U mblen@@GLIBC_2.0
U mbtowc@@GLIBC_2.0
U memcpy@@GLIBC_2.0
U memmove@@GLIBC_2.0
U memset@@GLIBC_2.0
U open@@GLIBC_2.0
U pthread_cond_broadcast@@GLIBC_2.0
U pthread_cond_destroy@@GLIBC_2.0
U pthread_cond_init@@GLIBC_2.0
U pthread_cond_signal@@GLIBC_2.0
U pthread_cond_wait@@GLIBC_2.0
U pthread_equal@@GLIBC_2.0
U pthread_mutex_destroy@@GLIBC_2.0
U pthread_mutex_init@@GLIBC_2.0
U pthread_mutex_lock@@GLIBC_2.0
U pthread_mutex_unlock@@GLIBC_2.0
U pthread_self@@GLIBC_2.0
U qsort@@GLIBC_2.0
U read@@GLIBC_2.0
U readv@@GLIBC_2.0
U realloc@@GLIBC_2.0
U rewind@@GLIBC_2.0
U select@@GLIBC_2.0
U setlocale@@GLIBC_2.0
U setsockopt@@GLIBC_2.0
U shutdown@@GLIBC_2.0
U sleep@@GLIBC_2.0
U socket@@GLIBC_2.0
U sprintf@@GLIBC_2.0
U sscanf@@GLIBC_2.0
U stderr@@GLIBC_2.0
U strcat@@GLIBC_2.0
U strchr@@GLIBC_2.0
U strcmp@@GLIBC_2.0
U strcpy@@GLIBC_2.0
U strerror@@GLIBC_2.0
U strncmp@@GLIBC_2.0
U strncpy@@GLIBC_2.0
U strrchr@@GLIBC_2.0
U time@@GLIBC_2.0
U uname@@GLIBC_2.0
U ungetc@@GLIBC_2.0
U unlink@@GLIBC_2.0
U wctomb@@GLIBC_2.0
U write@@GLIBC_2.0
U writev@@GLIBC_2.0
$ nm /packages/gnu/XFree86/lib/libX11.so.6 | grep ' U '
U _IO_getc@@GLIBC_2.0
U _IO_putc@@GLIBC_2.0
U ___brk_addr@@GLIBC_2.0
U __ctype_b@@GLIBC_2.0
U __ctype_get_mb_cur_max@@GLIBC_2.0
U __ctype_tolower@@GLIBC_2.0
U __ctype_toupper@@GLIBC_2.0
U __curbrk@@GLIBC_2.0
U __environ@@GLIBC_2.0
U __errno_location@@GLIBC_2.0
U __fxstat@@GLIBC_2.0
U __strtol_internal@@GLIBC_2.0
U __xstat@@GLIBC_2.0
U abort@@GLIBC_2.0
U access@@GLIBC_2.0
U atexit
U calloc@@GLIBC_2.0
U close@@GLIBC_2.0
U connect@@GLIBC_2.0
U exit@@GLIBC_2.0
U fclose@@GLIBC_2.1
U fcntl@@GLIBC_2.0
U ferror@@GLIBC_2.0
U fflush@@GLIBC_2.0
U fgets@@GLIBC_2.0
U fileno@@GLIBC_2.0
U fopen@@GLIBC_2.1
U fprintf@@GLIBC_2.0
U fputs@@GLIBC_2.0
U fread@@GLIBC_2.0
U free@@GLIBC_2.0
U fwrite@@GLIBC_2.0
U getenv@@GLIBC_2.0
U gethostbyname@@GLIBC_2.0
U getpeername@@GLIBC_2.0
U getpwnam_r@@GLIBC_2.1.2
U getpwuid_r@@GLIBC_2.1.2
U getservbyname@@GLIBC_2.0
U getsockname@@GLIBC_2.0
U getuid@@GLIBC_2.0
U inet_addr@@GLIBC_2.0
U ioctl@@GLIBC_2.0
U malloc@@GLIBC_2.0
U mblen@@GLIBC_2.0
U mbtowc@@GLIBC_2.0
U memcpy@@GLIBC_2.0
U memmove@@GLIBC_2.0
U memset@@GLIBC_2.0
U open@@GLIBC_2.0
U pthread_cond_broadcast@@GLIBC_2.0
U pthread_cond_destroy@@GLIBC_2.0
U pthread_cond_init@@GLIBC_2.0
U pthread_cond_signal@@GLIBC_2.0
U pthread_cond_wait@@GLIBC_2.0
U pthread_equal@@GLIBC_2.0
U pthread_mutex_destroy@@GLIBC_2.0
U pthread_mutex_init@@GLIBC_2.0
U pthread_mutex_lock@@GLIBC_2.0
U pthread_mutex_unlock@@GLIBC_2.0
U pthread_self@@GLIBC_2.0
U qsort@@GLIBC_2.0
U read@@GLIBC_2.0
U readv@@GLIBC_2.0
U realloc@@GLIBC_2.0
U rewind@@GLIBC_2.0
U select@@GLIBC_2.0
U setlocale@@GLIBC_2.0
U setsockopt@@GLIBC_2.0
U shmat@@GLIBC_2.0
U shmctl@@GLIBC_2.2
U shmdt@@GLIBC_2.0
U shutdown@@GLIBC_2.0
U sleep@@GLIBC_2.0
U socket@@GLIBC_2.0
U sprintf@@GLIBC_2.0
U sscanf@@GLIBC_2.0
U stderr@@GLIBC_2.0
U strcat@@GLIBC_2.0
U strchr@@GLIBC_2.0
U strcmp@@GLIBC_2.0
U strcpy@@GLIBC_2.0
U strerror@@GLIBC_2.0
U strncmp@@GLIBC_2.0
U strncpy@@GLIBC_2.0
U strpbrk@@GLIBC_2.0
U strrchr@@GLIBC_2.0
U strstr@@GLIBC_2.0
U uname@@GLIBC_2.0
U ungetc@@GLIBC_2.0
U unlink@@GLIBC_2.0
U wctomb@@GLIBC_2.0
U write@@GLIBC_2.0
U writev@@GLIBC_2.0
Why does _only_ 'atexit' refer to a symbol without version?
Bruno