Question about libc++ basic_string methods, inline, and LTO linking in 3.5 vs 3.6

Hi all,

I hope someone could shed some light on the following.

Some basic_string methods have “_LIBCPP_INLINE_VISIBILITY” in the header, while others are not. Where can I look up the rules for which should be inline and which should not?

Perhaps that is not the right question to ask, but it is related to a problem I’m seeing in LTO linking with LLVM/Clang/libc++ 3.5 vs 3.6. The string headers have not changed much so I’m thinking the relevant change is in LLVM or Clang.

For PNaCl, we do linking in this manner:

Step (1) LTO link of bitcode using gold, and the gold plugin.

gold -plugin LLVMgold.so -plugin-opt=emit-llvm -o merged.bc bc.o bc2.o … -lapp_native1.a -lapp_native2.a … -lc++ -lm …

For various reasons, the setup is such that bc{1,2,…}.o are bitcode, libc++ and libm are bitcode, and the libapp_native{1,2,…}.a are x86.

Step (2) compile the merged.bc to x86 (as merged.o).

Step (3) link native code: gold -o a.out merged.o -lapp_native1.a -lapp_native2.a …

Note that there is no native version of libc++ and libm, so they are absent in this step.

In LLVM 3.5, step (1) would produce a merged.bc where “ZNSt3__1plIcNS_11char_traitsIcEENS_9allocatorIcEEEENS_12basic_stringIT_T0_T1_EEPKS6_RKS9” (an operator+ variant) is defined, but in 3.6 it is just a declaration.

If I use the linker “-y _ZNSt3…” option in step (1), it explains that there are a few references to operator+ from within libc++, but no references from any of the bc.o, bc2.o. It is not defined in any of the bc.o, bc2.o either, but it is defined in libapp_native1.a and libc++. This is the same in 3.5 and 3.6.

Since the operator+ variant is not in merged.bc w/ 3.6, step (3) ends up pulling the definition from a libapp_native1.a member. However, that member depends on libm for log/exp. For some reason, step (1) does not pull log/exp into merged.bc from the bitcode libm. So in the end, linking in step (3) fails with undefined references to log/exp. In 3.5, step 3 never needed to pull in that member of libapp_native1.a.

If the operator+ variant was marked inline, then it would end up in merged.bc and there is no need to worry about log/exp either. That is why I ask about the “inline” rules.

Otherwise, I’m wondering if it is a bug that, for reasons besides inline, step (1) did not end up with the operator+ definition in merged.bc. Or, is entirely reasonable for merged.bc to not have the definition of operator+ (deferring to libapp_native1), and the bug is that merged.bc doesn’t end up with the definition of log/exp? Maybe a problem is that the member thought to have supplied operator+ from libapp_native1.a in step (1) is one that doesn’t depend on log/exp, but the one ultimately chosen in step (3) is one that does depend on log/exp .

Or, is this whole setup of (1), (2), (3) unusual and not expected to work well?

Thanks in advance,

  • Jan

Some basic_string methods have "_LIBCPP_INLINE_VISIBILITY" in the <string> header, while others are not. Where can I look up the rules for which should be inline and which should not?

I'm not sure if there are rules. Ones that are not marked
_LIBCPP_INLINE_VISIBILITY should be externally instantiated in the
dynlib.

I'll look into what we are doing with operator+