[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: fix for atexit() bug in glibc 2.2.3
From: |
Andreas Jaeger |
Subject: |
Re: fix for atexit() bug in glibc 2.2.3 |
Date: |
20 May 2001 09:52:21 +0200 |
User-agent: |
Gnus/5.090004 (Oort Gnus v0.04) XEmacs/21.1 (Channel Islands) |
Hi Mark and Franz, FYI: it seems that even gcc 2.95.3 on i686 miscompiles
weak symbols.
Andreas, this is a compiler bug you encounter. Franz has some patches
to fix this and I hope he'll point you to them, otherwise search the
GCC mailing list archives.
Andreas
Andreas Steinmetz <address@hidden> writes:
> Unfortunately applying your patch to gcc and rebuilding gcc-2.95.3, then
> glibc-2.2.3, doesn't fix the atexit() sigsegv problem for statically linked
> programs. So I started digging myself. Looking at atexit() in a statically
> linked test progam:
>
> 0x80485d0 <atexit>: sub $0xc,%esp
> 0x80485d3 <atexit+3>: mov $0x0,%edx
> 0x80485d8 <atexit+8>: mov 0x10(%esp,1),%ecx
> 0x80485dc <atexit+12>: xor %eax,%eax
> 0x80485de <atexit+14>: add $0xfffffffc,%esp
> 0x80485e1 <atexit+17>: test %edx,%edx
> 0x80485e3 <atexit+19>: cmovne 0x0,%eax <========= SIGSEGV
> 0x80485ea <atexit+26>: push %eax
> 0x80485eb <atexit+27>: push $0x0
> 0x80485ed <atexit+29>: push %ecx
> 0x80485ee <atexit+30>: call 0x80486e0 <__cxa_atexit>
> 0x80485f3 <atexit+35>: add $0x10,%esp
> 0x80485f6 <atexit+38>: add $0xc,%esp
> 0x80485f9 <atexit+41>: ret
>
> Registers at SIGSEGV time:
>
> eax 0x0 0
> ecx 0x8048210 134513168
> edx 0x0 0
> ebx 0xbffff9ac -1073743444
> esp 0xbffff910 0xbffff910
> ebp 0xbffff93c 0xbffff93c
> esi 0xbffff9a4 -1073743452
> edi 0x1 1
> eip 0x80485e3 0x80485e3
> eflags 0x10346 66374
> cs 0x23 35
> ss 0x2b 43
> ds 0x2b 43
> es 0x2b 43
> fs 0x0 0
> gs 0x0 0
> fctrl 0x37f 895
> fstat 0x0 0
> ftag 0xffff 65535
> fiseg 0x10 16
> fioff 0xc03121bf -1070521921
> foseg 0x0 0
> fooff 0x0 0
> fop 0x4f1 1265
>
> Well, I don't have an assembler manual around so I can't tell if the
> access to the source by cmovne is defined as standard or if it is just an
> unexpected speculative access (I'm running an Athlon TB900). One would expect,
> however, that a conditional move data access would only happen if the
> condition
> is met which it is not (edx=0).
>
> The same in the source (stdlib/atexit.c):
>
> /* This is defined by newer gcc version unique for each module. */
> extern void *__dso_handle __attribute__ ((__weak__));
>
>
> /* Register FUNC to be executed by `exit'. */
> int
> atexit (void (*func) (void))
> {
> return __cxa_atexit ((void (*) (void *)) func, NULL,
> &__dso_handle == NULL ? NULL : __dso_handle);
> } ^^
> ||
> This being the problem
>
>
> As it turns out a workaround is simple (de-optimization, patch below):
>
> =======snip=======
> --- stdlib/atexit.c-2.2.3 Sat May 19 20:13:37 2001
> +++ stdlib/atexit.c Sat May 19 20:48:51 2001
> @@ -28,8 +28,9 @@
> int
> atexit (void (*func) (void))
> {
> - return __cxa_atexit ((void (*) (void *)) func, NULL,
> - &__dso_handle == NULL ? NULL : __dso_handle);
> + if(&__dso_handle)return __cxa_atexit ((void (*) (void *)) func,
> + NULL,__dso_handle);
> + else return __cxa_atexit ((void (*) (void *)) func, NULL,NULL);
> }
>
> /* Hide the symbol so that no definition but the one locally in the
> ======snip========
>
> This results in the following assembler which is 'bug free':
>
> 0x80485d0 <atexit>: sub $0xc,%esp
> 0x80485d3 <atexit+3>: mov $0x0,%eax
> 0x80485d8 <atexit+8>: mov 0x10(%esp,1),%edx
> 0x80485dc <atexit+12>: test %eax,%eax
> 0x80485de <atexit+14>: je 0x80485ec <atexit+28>
> 0x80485e0 <atexit+16>: add $0xfffffffc,%esp
> 0x80485e3 <atexit+19>: mov 0x0,%eax
> 0x80485e8 <atexit+24>: push %eax
> 0x80485e9 <atexit+25>: jmp 0x80485f1 <atexit+33>
> 0x80485eb <atexit+27>: nop
> 0x80485ec <atexit+28>: add $0xfffffffc,%esp
> 0x80485ef <atexit+31>: push $0x0
> 0x80485f1 <atexit+33>: push $0x0
> 0x80485f3 <atexit+35>: push %edx
> 0x80485f4 <atexit+36>: call 0x80486e0 <__cxa_atexit>
> 0x80485f9 <atexit+41>: add $0x10,%esp
> 0x80485fc <atexit+44>: add $0xc,%esp
> 0x80485ff <atexit+47>: ret
>
> I don't really know if the actual bug is caused by glibc-2.2.3 or gcc-2.95.3.
> This problem should be solved, however, by the appropriate party (please
> forward
> this mail to the proper developers, if necessary). Furthermore '__dso_handle'
> is used in more places, especially 'malloc/mtrace.c'. So further fixes may be
> required.
>
> To better check for the problem here's the configure statement (oh, configure
> needs to be modified to be able to not build against libgd even when it is
> around, I patched that the hard way...) and the compiler flags:
>
> ../configure --prefix=/usr --enable-add-ons --disable-profile
> --enable-kernel=2.2.18 --with-headers=/usr/src/linux/include --without-gmp
> --without-gd --without-gd-include --without-gd-lib --without-cvs --with-elf
> --enable-shared
>
> CFLAGS=-O3 -fomit-frame-pointer -funroll-loops -fexpensive-optimizations
> -fschedule-insns2 -mwide-multiply -march=pentiumpro -mcpu=pentiumpro
> -malign-loops=2 -malign-jumps=2 -malign-functions=4
>
> CXXFLAGS=-O3 -fomit-frame-pointer -funroll-loops -fexpensive-optimizations
> -fschedule-insns2 -mwide-multiply -march=pentiumpro -mcpu=pentiumpro
> -malign-loops=2 -malign-jumps=2 -malign-functions=4
>
> When I'm at it: 'make check' uses somewhere a hardcoded '/bin/cat' which is
> not
> nice if cat is not in /bin. 'make install' doesn't honor a softlink for
> '/etc/ld.so.cache' but replaces the softlink with a new cache file.
>
> On 16-May-2001 Andreas Jaeger wrote:
> > Andreas Steinmetz <address@hidden> writes:
> >
> >> Hi,
> >> when building static (-static) versions of fileutils-4.1 with gcc 2.95.3
> >> the
> >> resulting binaries segfault in atexit(). Temporary fix for me is an
> >> atexit()
> >> shim diverting the call to on_exit().
> >
> > Did you apply the appended patch to GCC 2.95.3 as mentioned in the
> > release notes?
> >
> >> After the upgrade from 2.2.2 to 2.2.3 the following packages stopped
> >> working
> >> and had to be rebuilt against the new library:
> >>
> >> ypserv-1.3.12
> >> nfs-utils-0.3.1 (rpc.kstatd)
> >
> > Really?
> >> Installing glibc-2.2.3 did cause problems too:
> >>
> >> [snip]
> >>
> >> make -C linuxthreads subdir_install
> >> make[2]: Entering directory `/usr/src/glibc-2.2.3/linuxthreads'
> >> /bin/install -c -m 644 ../linuxthreads/sysdeps/pthread/pthread.h
> >> /usr/include/pt/bin/install -c -m 644 semaphore.h /usr/include/semaphore.h
> >> /bin/install -c /usr/src/glibc-2.2.3/build/linuxthreads/libpthread.so
> >> /lib/libpthread-0.9.so.new
> >> mv -f /lib/libpthread-0.9.so.new /lib/libpthread-0.9.so
> >> echo libpthread-0.9.so /lib/libpthread.so.0 >>
> >> /usr/src/glibc-2.2.3/build/elf/symlink.list
> >> rm -f /usr/lib/libpthread.so.new
> >> /bin/sh ../scripts/rellns-sh /lib/libpthread.so.0
> >> /usr/lib/libpthread.so.new
> >> mv -f /usr/lib/libpthread.so.new /usr/lib/libpthread.so
> >> /bin/install -c -m 644 /usr/src/glibc-2.2.3/build/linuxthreads/libpthread.a
> >> /usr/lib/libpthread.a
> >> : /usr/lib/libpthread.a
> >> make[2]: Leaving directory `/usr/src/glibc-2.2.3/linuxthreads'
> >> make -C resolv subdir_install
> >> make: /lib/libc.so.6: version `GLIBC_2.2.3' not found (required by
> >> /lib/libpthread.so.0)
> >> make[1]: *** [resolv/subdir_install] Error 1
> >> make[1]: Leaving directory `/usr/src/glibc-2.2.3'
> >> make: *** [install] Error 2
> >>
> >> This happens as (at least my) make (make-3.79.1) is linked against
> >> libpthread.so.0 which is installed before the symbolic link /lib/libc.so.6
> >> is
> >> set up to point to the new glibc. Workaround is to use a statically linked
> >> make
> >> during installation (if you have one available).
> >
> > I'll forward this,
> > Andreas
> >
> >
> > P.S. see http://gcc.gnu.org/ml/gcc-patches/2001-03/msg01187.html
> >
> > 2001-03-16 Jakub Jelinek <address@hidden>
> >
> > * crtstuff.c (init_dummy): Use CRT_END_INIT_DUMMY if defined.
> > Remove ia32 linux PIC kludge and move it...
> > * config/i386/linux.h (CRT_END_INIT_DUMMY): ...here.
> >
> > --- gcc/config/i386/linux.h.jj Mon Mar 12 11:45:15 2001
> > +++ gcc/config/i386/linux.h Fri Mar 16 18:52:31 2001
> > @@ -170,3 +170,21 @@ Boston, MA 02111-1307, USA. */
> > } \
> > } while (0)
> > #endif
> > +
> > +#if defined(__PIC__) && defined (USE_GNULIBC_1)
> > +/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr,
> > + __environ and atexit (). We have to make sure they are in the .dynsym
> > + section. We accomplish it by making a dummy call here. This
> > + code is never reached. */
> > +
> > +#define CRT_END_INIT_DUMMY \
> > + do \
> > + { \
> > + extern void *___brk_addr; \
> > + extern char **__environ; \
> > + \
> > + ___brk_addr = __environ; \
> > + atexit (0); \
> > + } \
> > + while (0)
> > +#endif
> > ============================================================
> > Index: gcc/crtstuff.c
> > --- gcc/crtstuff.c 1999/03/23 00:43:51 1.18
> > +++ gcc/crtstuff.c 2001/03/19 10:21:44
> > @@ -379,20 +379,8 @@
> > FORCE_INIT_SECTION_ALIGN;
> > #endif
> > asm (TEXT_SECTION_ASM_OP);
> > -
> > -/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr,
> > - __environ and atexit (). We have to make sure they are in the .dynsym
> > - section. We accomplish it by making a dummy call here. This
> > - code is never reached. */
> > -
> > -#if defined(__linux__) && defined(__PIC__) && defined(__i386__)
> > - {
> > - extern void *___brk_addr;
> > - extern char **__environ;
> > -
> > - ___brk_addr = __environ;
> > - atexit ();
> > - }
> > +#ifdef CRT_END_INIT_DUMMY
> > + CRT_END_INIT_DUMMY;
> > #endif
> > }
> >
> >
> >
> > --
> > Andreas Jaeger
> > SuSE Labs address@hidden
> > private address@hidden
> > http://www.suse.de/~aj
> >
>
> Andreas Steinmetz
> D.O.M. Datenverarbeitung GmbH
>
--
Andreas Jaeger
SuSE Labs address@hidden
private address@hidden
http://www.suse.de/~aj