Bug 46563 - link with -lgcc when creating a shared lib
Summary: link with -lgcc when creating a shared lib
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: driver (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-11-19 16:04 UTC by christophe.lyon
Modified: 2010-11-22 10:12 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
main prog C++ source (95 bytes, application/octet-stream)
2010-11-19 16:04 UTC, christophe.lyon
Details
shared lib C++ source (91 bytes, application/octet-stream)
2010-11-19 16:05 UTC, christophe.lyon
Details

Note You need to log in before you can comment on or make changes to this bug.
Description christophe.lyon 2010-11-19 16:04:21 UTC
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);
Comment 1 christophe.lyon 2010-11-19 16:05:16 UTC
Created attachment 22458 [details]
shared lib C++ source
Comment 2 Andrew Haley 2010-11-19 16:09:00 UTC
If you try linking with "-lgcc_s -lgcc", does everything then work?
Comment 3 christophe.lyon 2010-11-19 16:12:11 UTC
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 ;-)
Comment 4 Mikael Pettersson 2010-11-19 16:45:51 UTC
(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.
Comment 5 christophe.lyon 2010-11-19 16:49:05 UTC
I am not sure what you mean about "libgcc_s.so linker script".

But I think the difference is that I am cross-compiling.
Comment 6 Andrew Haley 2010-11-19 17:30:35 UTC
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 )
Comment 7 Mikael Pettersson 2010-11-19 17:38:35 UTC
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?
Comment 8 christophe.lyon 2010-11-22 08:39:45 UTC
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.
Comment 9 christophe.lyon 2010-11-22 08:50:20 UTC
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!
Comment 10 christophe.lyon 2010-11-22 09:01:19 UTC
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?
Comment 11 Andrew Haley 2010-11-22 09:47:52 UTC
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.
Comment 12 christophe.lyon 2010-11-22 10:06:07 UTC
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)
Comment 13 Andrew Haley 2010-11-22 10:12:04 UTC
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.