Created attachment 22457 [details] main prog C++ source As discussed in http://gcc.gnu.org/ml/gcc-help/2010-11/msg00198.html, the G++ driver does not link with -lgcc when creating a shared lib. This is a problem when the shared lib references some symbols which are only present in libgcc.a (such as __sync_fetch_and_add and all __sync*). This is the case for instance on ARM. I have attached atomic.cxx (shared lib) and atomain.cxx (main prog) to be compiled with: $ arm-linux-g++ atomic.cxx -fPIC -shared -o libatomic.so $ arm-linux-g++ atomain.cxx -o atomain -L. -latomic .../ld: atomain: hidden symbol `__sync_fetch_and_add_4' in /.../libgcc.a(linux-atomic.o) is referenced by DSO As a fix I can suggest to patch gcc.c:init_gcc_specs() and to add static_name next to shared_name when expanding the specs. diff -up gcc.c gcc.c.patch --- gcc.c 2010-02-25 17:20:51.831150000 +0100 +++ gcc.c.patch 2010-11-19 17:02:37.141674000 +0100 @@ -1722,7 +1722,7 @@ init_gcc_specs (struct obstack *obstack, static_name, " --as-needed ", shared_name, " --no-as-needed" "}" "%{shared-libgcc:", - shared_name, "%{!shared: ", static_name, "}" + shared_name, " ", static_name, "%{!shared: ", static_name, "}" "}" #else "%{!shared:" @@ -1731,11 +1731,11 @@ init_gcc_specs (struct obstack *obstack, "}" #ifdef LINK_EH_SPEC "%{shared:" - "%{shared-libgcc:", shared_name, "}" + "%{shared-libgcc:", shared_name, " ", static_name"}" "%{!shared-libgcc:", static_name, "}" "}" #else - "%{shared:", shared_name, "}" + "%{shared:", shared_name, " ", static_name"}" #endif #endif "}}", NULL);
Created attachment 22458 [details] shared lib C++ source
If you try linking with "-lgcc_s -lgcc", does everything then work?
Yes. I did find this workaround myself, but I was very surprised I had to do it manually. (As I said, the problem arised when building QT, and I guess I'm not the first one to build QT for ARM, so probably every other person have applied that workaround in the QT sources without contributing back ;-)
(In reply to comment #0) > Created attachment 22457 [details] > main prog C++ source > > As discussed in http://gcc.gnu.org/ml/gcc-help/2010-11/msg00198.html, the G++ > driver does not link with -lgcc when creating a shared lib. The example in the link above works for me with my native arm-linux-gnueabi toolchain. Did you forget to install the libgcc_s.so linker script? The very purpose of that script is to make -lgcc_s suck in both the dynamic and the static libgcc, since (as you've noticed) some symbols are only defined in the static libgcc.
I am not sure what you mean about "libgcc_s.so linker script". But I think the difference is that I am cross-compiling.
I am cross-compiling too. Try this: $ cat /home/aph/x-arm/install/arm-linux-gnueabi/lib/libgcc_s.so /* GNU ld script Use the shared library, but some functions are only in the static library. */ GROUP ( libgcc_s.so.1 libgcc.a )
The example works for me also with a cross built from gcc-4.5.1 with --enable-shared --enable-languages=c,c++. > armv5tel-unknown-linux-gnueabi-g++ atomic.cxx -fPIC -shared -o libatomic.so > armv5tel-unknown-linux-gnueabi-g++ atomain.cxx -o atomain -L. -latomic 'make install' automatically installed the linker script in $PREFIX/armv5tel-unknown-linux-gnueabi/lib/libgcc_s.so I don't see "-gnueabi" in your compile command. Is it an OABI toolchain?
Yes, it is a gnueabi; -v says: Configured with: ../configure --target=arm-cortex-linux-gnueabi --program-prefix=arm-linux- --enable-languages=c,c++ --enable-threads=posix --disable-multilib --enable-nls --enable-c99 --enable-long-long --with-system-zlib --enable-shared --enable-symvers=gnu --enable-__cxa_atexit --with-float=hard --with-fp --enable-cxx-flags=-mhard-float --with-cpu=cortex-a9 But libgcc_s.so is an ELF file in my install. I will check if the build script has a hack to modify libgcc_s.so.
Indeed the build script explicitly removes libgcc_s.so and replaces it with a symlink to libgcc_s.so.1 I am going to have a discussion with the colleague who originally wrote the script :-) Thanks a lot!
However, I'd like to ask a question: why use a link script in libgcc_s.so, rather than having the driver link with -lgcc?
You see how hard it is to help people with problems like this: we just don't know what weird things they may be doing that we don't know about! I's a script because otherwise we'd have to find everywhere -lgcc_s was used and replace it with -lgcc_s -lgcc. It's simpler just to fix it in one place.
Yes, I appreciate your help very much (and I spent quite some time investigating on my own before deciding to bother you). Now, I am sorry to insist, but it's still unclear to me why GCC and G++ behave differently, and why there is a link script rather than a fix in the driver. I have compile & link the code attached as atomic.cxx in C mode, I can see some differences wrt the case where I do the same thing with G++ (invoking with -v): - g++ has -shared-libgcc in COLLECT_GCC_OPTIONS - g++ links with lstdc++ -lm -lgcc_s -lc -lgcc_s - gcc links with -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed So, the very same code, when compiled & linked in C mode, is linked against -lgcc, but not in C++ mode; that's why I proposed a changed in the driver (to adjust the specs for -shared-libgcc)
Sure, but not everyone uses the driver, some use ld directly. I might as well ask: why not? libc is linked this way on GNU/Linux systems too. It's easy and convenient. I don't know why C and C++ are treated differently. I suspect it's just a historical accident, but it doesn't matter because it doesn't break anything.