This is an archive of the discontinued LLVM Phabricator instance.

[Compiler-RT] If unwind/c++abi is set, don't include libgcc
AbandonedPublic

Authored by rengolin on Jul 13 2015, 11:40 AM.

Details

Summary

Currently, for --rtlib=compiler-rt, when -lunwind or -lc++abi
are in the arguments list, both libgcc_s and libgcc_eh are still
added, which is wrong and duplicates symbols and may break stuff.

This patch makes sure that, when adding compiler-rt companion
libraries (unwind/c++), they haven't been added already.

Diff Detail

Event Timeline

rengolin updated this revision to Diff 29591.Jul 13 2015, 11:40 AM
rengolin retitled this revision from to [Compiler-RT] If unwind/c++abi is set, don't include libgcc.
rengolin updated this object.
rengolin added reviewers: mcrosier, logan, asl.
rengolin set the repository for this revision to rL LLVM.
rengolin added subscribers: cfe-commits, llvm-commits.
rengolin updated this revision to Diff 29657.Jul 14 2015, 3:02 AM
rengolin removed rL LLVM as the repository for this revision.

More context.

rengolin added inline comments.Jul 14 2015, 4:43 AM
test/Driver/linux-ld.c
1560

These tests pass on x86_64, ARM and AArch64, but they may not pass on others. Should I specify the target like the others above?

rengolin updated this revision to Diff 29665.Jul 14 2015, 4:53 AM

Specifically test x86_64/ARM/AArch64, to make sure we don't assume anything about any other arch.

logan edited edge metadata.Jul 14 2015, 10:16 AM

I have some concern on the design of this change. IMO, it is unintuitive that one -l option will affect the other -l options. Can't we simply rely on --rtlib=compiler-rt? Or, alternatively, can we simply emit a warning instead of changing the behavior quietly? Thanks.

I have some concern on the design of this change. IMO, it is unintuitive that one -l option will affect the other -l options. Can't we simply rely on --rtlib=compiler-rt? Or, alternatively, can we simply emit a warning instead of changing the behavior quietly? Thanks.

So, I did the original change, and that was a bad decision, which I only realised when trying to bundle RT with libc++. :)

The idea here is that we should *only* add an unwinder and a C++ library IFF there isn't one yet. This may be an overly simplistic approach, but it's better than no approach.

Since there's no way to remove libraries from the list (because the compiler adds them), there is no way a warning would be effective. Ie. the user would get a warning and would be able to do nothing.

Can't we simply rely on --rtlib=compiler-rt?

Specifically about --rtlib=compiler-rt, there are a few choices:

  1. Assume RT == unwind + c++abi. This is good for architectures where those libraries work reliably and are always available, either built in with Clang or as a package. Since it's not easy to compile libc++abi, and it requires Clang in the first place, I'd rather not have that until our build system is smart enough to do a two-stage build, like GCC.
  1. Assume RT is in a GNU system. This is what we have now, and to make debug, profile and exception code work out-of-the-box, we need the libraries. I have taken the bad choice of including both libgcc libraries.
  1. Assume RT is just part of the compiler library. This would force users to include -lgcc_s/-lunwind and/or -lgcc_eh/-lc++abi on every use of --rtlib. Clang includes gcc_s/eh already when rtlib=libgcc (obviously), and so does GCC. If we don't include some unwind/exception libraries with RT, the behaviour would be very different and make build systems a lot more complex.

This change is a preparation for a bigger one. The plan is:

Allow tools to have default libraries on different systems. Something like:

void GetCompilerLibraries() {
    // pick the defaults
    switch(OS/Env) {
        default:
            llvm_unreachable("must have a default");
        case GNU: // default GNU, --rtlib=libgcc
            RT=libgcc; UNW=libgcc_s; EH=libgcc_eh;
        case GNURT: // GNU with --rtlib=compiler-rt
            RT=compiler-rt; UNW=libgcc_s; EH=libgcc_eh;
        case FreeBSD: // BSD style
            RT=compiler-rt; UNW=libunwind; EH=libc++abi;
        case Darwin: // and so on...
            RT=...
    }
    // override with arguments
    for (lib : libArgs) {
        if (lib == libunwind) UNW=lib;
        else if (lib == libc++abi) EH=lib;
        else if (lib == libgcc_s) UNW=lib;
        else if (lib == libgcc_eh) UNW=lib;
    }
}

This way you have complete flexibility, and still produce the expected default results on all architectures.

GCC doesn't need that complexity because they're tied up with libgcc and friends.

logan added a comment.Jul 21 2015, 5:23 PM

Since there's no way to remove libraries from the list (because the compiler adds them), there is no way a warning would be effective. Ie. the user would get a warning and would be able to do nothing.

Although it is difficult to use, we can remove the default libraries with -nostdlib. This is what I am using when I am building different configurations of libc++abi and libunwind on Linux.

For your long-term plan on the default standard library, I agree that we should select the default standard library according to the environment. However, I am still concerning the overloaded meaning for -l options. For example, what will happen if the users specified -lunwind when they are mean to link with libunwind[1] from Savannah? The libunwind from Savannah does not include C++ level 1 unwinding library by default.

[1] http://www.nongnu.org/libunwind/

Although it is difficult to use, we can remove the default libraries with -nostdlib. This is what I am using when I am building different configurations of libc++abi and libunwind on Linux.

Right. In that case, I'd rather --rtlib=compiler-rt didn't include anything, and forced you to include your own libraries, instead of assuming a GNU environment.

For your long-term plan on the default standard library, I agree that we should select the default standard library according to the environment. However, I am still concerning the overloaded meaning for -l options. For example, what will happen if the users specified -lunwind when they are mean to link with libunwind[1] from Savannah? The libunwind from Savannah does not include C++ level 1 unwinding library by default.

That's a good point. That's why I didn't want to call our unwind libraries "libunwind". But that's also not an excuse to rely on string-match.

I think that removing the automatic include of libgcc is the least problematic solution.

Though it would be good to have an easier way to include unwind/eh libraries if detected, I'd rather do that on detection of presence, than on absence. This would be for another patch, of course.

Do you agree I should remove the libgcc inclusions altogether?

Would it work to always add "--as-needed -lgcc_s" and let -lunwind override the behaviour? Is that the semantics here?

Why not introduce a flag to switch between the various implementations (similar to -rt-lib=)?

Would it work to always add "--as-needed -lgcc_s" and let -lunwind override the behaviour? Is that the semantics here?

I don't think that will work. The ordering of the arguments is important. The --as-needed will apply to gcc_s.so, but because there are symbols being referenced, it will be pulled even though -lunwind comes later without --as-needed. You need to either break compilation, assume the unwinder, or provide a switch.

rengolin abandoned this revision.Jul 23 2015, 2:11 AM

Why not introduce a flag to switch between the various implementations (similar to -rt-lib=)?

I think this is the better option, and dissociated from Compiler-RT. I'll revert my original change (to add libgcc_s/eh) and work towards the unwinder/c++ in a separate thread.

cheers,
--renato