Linking ProfileRT when using -nodefaultlibs

Hello,

I’m working on making libc++ generate code coverage data. This means that libclang_rt.profile.x86_64.a is put into the link command before ‘-lc’ and other dependencies.
I suspect this change in library order causes the linker errors I see while running the tests.

I have a couple of questions:

  • Should -ftest-coverage be passed when linking libc++?
  • Is there a way to link libclang_rt.profile.x86_64.a after the given linker flags

This file shows the ld invocation with and without -nodefaultlibs as well as the error produced when
linking tests w/ -nodefaultlibs
http://pastebin.com/QWagJpsW

Any help is appreciated

/Eric

I’m working on making libc++ generate code coverage data. This means that libclang_rt.profile.x86_64.a is put into the link command before ‘-lc’ and other dependencies.
I suspect this change in library order causes the linker errors I see while running the tests.

I forgot to mention this is because we use -nodefaultlibs when linking libc++.

Sorry for the spam
/Eric

Eric Fiselier <eric@efcs.ca> writes:

Hello,

I'm working on making libc++ generate code coverage data. This means that
libclang_rt.profile.x86_64.a is put into the link command before '-lc' and
other dependencies.
I suspect this change in library order causes the linker errors I see while
running the tests.

I have a couple of questions:
- Should -ftest-coverage be passed when linking libc++?
- Is there a way to link libclang_rt.profile.x86_64.a after the given linker
   flags

This file shows the ld invocation with and without -nodefaultlibs as well as
the error produced when
linking tests w/ -nodefaultlibs
http://pastebin.com/QWagJpsW

There's nothing there? Mailing this text directly seems simpler than a
pastebin to me.

This issue and a few other things I've seen recently make me think that
compiler-rt and -nodefaultlibs don't interact very well in general. I
guess there's work to be done in the area.

Thanks for the heads up about the dead link. I’ve attached the output to this email.

I spent some time last night trying to fix this problem in Clang but I had no luck :frowning:
Moving the compiler-rt library before the linker inputs only created more issues.

/Eric

new 2.txt (9.37 KB)

The reason we use -nodefaultlibs is to avoid linking the system’s libc++. There’s a -nostdinc++, maybe there should be a -nostdlib++? Or perhaps -stdlib=none?

That would let us stop preventing the driver from doing its job…

The reason we use -nodefaultlibs is to avoid linking the system’s libc++. There’s a -nostdinc++, maybe there should be a -nostdlib++? Or perhaps -stdlib=none?
-nostdlib already exists but it acts like -nodefaultlibs and it drops the startup files as well.
I would support -stdlib=none but I’m hesitant to start depending on Clang only flags. It would be nice to not have to special case GCC.

/Eric

Yes, that is the downside.

Has anyone actually run the tests against GCC recently? IIRC it requires some local modifications anyway.

Has anyone actually run the tests against GCC recently? IIRC it requires some local modifications anyway.

I do it occasionally. Most parts work out of the box. I haven’t tried using sanitizers with GCC though.
Don’t forget the CMake build also uses -nodefaultlibs so it’s not just the test suite that would require special handling of GCC.

/Eric

Didn’t realized we even supported using GCC to build libc++.

I thought that gcc already supported -nostdlib++ and we only had these convolutions because clang didn't...

David

Didn’t realized we even supported using GCC to build libc++.

I think we should try to support the same compilers as LLVM does (minus anything windows related).That way less problems will arise when people build LLVM w/ libc++ in tree.

However I’m not sure how feasible that is and would like some input from others.

I thought that gcc already supported -nostdlib++ and we only had these convolutions because clang didn’t…

I can’t find any documentation on that.

/Eric

Hello,

I'm working on making libc++ generate code coverage data. This means that
libclang_rt.profile.x86_64.a is put into the link command before '-lc' and
other dependencies.
I suspect this change in library order causes the linker errors I see
while running the tests.

I have a couple of questions:
  - Should -ftest-coverage be passed when linking libc++?
  - Is there a way to link libclang_rt.profile.x86_64.a after the given
linker flags

This file shows the ld invocation with and without -nodefaultlibs as well
as the error produced when
linking tests w/ -nodefaultlibs
http://pastebin.com/QWagJpsW

Hm? On the contrary, in the attached file "libclang_rt.profile.x86_64.a"
is listed *after* its dependencies, in particular, after "-lc".
I think this is wrong, and we should just fix it in the driver.
"-nodefautlibs" shouldn't be a problem here, as you seem to add "-lc",
"-lpthread"
etc. manually to your linker invocation.

Hm? On the contrary, in the attached file “libclang_rt.profile.x86_64.a” is listed after its dependencies, in particular, after “-lc”.
I think this is wrong, and we should just fix it in the driver. “-nodefautlibs” shouldn’t be a problem here, as you seem to add “-lc”, “-lpthread”
etc. manually to your linker invocation.

Yep. Sorry if I was unclear. I believe we are in agreement.
The linked libraries that come before “libclang_rt.profile.x86_64.a” are the ones libc++ manually specifies.
They actually need to appear after “libclang_rt.profile.x86_64.a” but there is no way to make that happen.
When -nodefaultlibs is not passed the linker driver automatically puts the required libraries after “libclang_rt.profile.x86_64.a” so the issues doesn’t arise.

/Eric

Ah, I see the problem here.

  1. We add profile runtime library after the linker inputs (in particular, after “-lc” provided by the user), because user-provided libraries can have references to libclang_rt.profile.a, and therefore should precede it.
  2. If -nodefautlibs is there, we never add “-lc” and friends at the very end, so some symbols in profile runtime may be left unresolved.

Interesting. This issue doesn’t arise with sanitizers, because we put sanitizer runtimes before the user inputs, and force it into the executable by wrapping it in “-whole-archive”. I wonder if
we can do the same trick for profile runtime. I don’t really know that, but it seems we have both GCDA profiling and new InstrProfiling stuff there, so pulling all of them into the executable
is not desirable, is it?

Alexey Samsonov <vonosmas@gmail.com> writes:

Ah, I see the problem here.

1) We add profile runtime library after the linker inputs (in particular,
after "-lc" provided by the user), because user-provided libraries can have
references to libclang_rt.profile.a, and therefore should precede it.
2) If -nodefautlibs is there, we never add "-lc" and friends at the very end,
so some symbols in profile runtime may be left unresolved.

Interesting. This issue doesn't arise with sanitizers, because we put
sanitizer runtimes *before* the user inputs, and force it into the executable
by wrapping it in "-whole-archive". I wonder if
we can do the same trick for profile runtime. I don't really know that, but it
seems we have both GCDA profiling and new InstrProfiling stuff there, so
pulling all of them into the executable
is not desirable, is it?

I believe -whole-archive will cause issues for the profile_rt library.
We really do only want particular symbols pulled in.

Interesting. This issue doesn’t arise with sanitizers, because we put sanitizer runtimes before the user inputs, and force it into the executable by wrapping it in “-whole-archive”. I wonder if
we can do the same trick for profile runtime. I don’t really know that, but it seems we have both GCDA profiling and new InstrProfiling stuff there, so pulling all of them into the executable
is not desirable, is it?

I can’t answer if we should do it put the profile runtime first, but I tested doing so and the change worked for me.

I believe -whole-archive will cause issues for the profile_rt library.
We really do only want particular symbols pulled in.

How would I go about looking into this?

/Eric

profile_rt.patch (1.06 KB)

>Interesting. This issue doesn't arise with sanitizers, because we put
sanitizer runtimes *before* the user inputs, and force it into the
executable by wrapping it in "-whole-archive". I wonder if
>we can do the same trick for profile runtime. I don't really know that,
but it seems we have both GCDA profiling and new InstrProfiling stuff
there, so pulling all of them into the executable
>is not desirable, is it?

I can't answer if we *should* do it put the profile runtime first, but I
tested doing so and the change worked for me.

What do you mean? We can't put it first, because user libraries depend on
it. We fail when we put it last either, because
of this specific case, where user provides "-lc" + "-nostdlib".

We can workaround this by forcing to link in libprofile deps even if
-nostdlib is specified (assuming the user passing
this weird combination knows what (s)he is doing).

Or we can design a magic flag "--profile-lib", or smth. like this, which
would be matched and replaced by the path to actual static profile runtime
in the driver. Then you'd be able
to write ("clang++ -nostdlib a.o b.o --profile-lib -lc -lpthread").

I like neither of this :frowning:

Alexey Samsonov <vonosmas@gmail.com> writes:

All compiler-rt libs are target-specific, so that would have to be
-lclang_rt.profile-x86_64.
Forcing user to write triple-dependent linker invocation is not nice...
However,
what we *might* do, is to restructure the way we layout resource directory,
and
make triple-specific folders. That is, replace this:
  lib/clang/3.6.0/lib/linux/libclang_rt.profile-x86_64.a
with this:
  lib/clang/3.6.0/lib/x86_64-linux-gnu/libclang_rt.profile.a
... and then setup correct -L flag depending on the target triple. FWIW, I
do something
similar in the internal compiler setup.
This is a rather intrusive change, though.

Also, this can work for profile or builtins runtimes, but won't work for
sanitizers,
as they require complex changes to the linker invocation.