'g++ lto optimization breaking symbols in shared libraries

I have run into a problem when compiling with -flto in that I run into a problem where a symbol appears to disappear in a shared library which causes an undefined symbol error when attempting to dlopen another shared library. This only happens when -flto is defined and happens with g++ 7.5 and 11.2.

When I look at the shared library which contains the C++ template that's failing with lto with readelf -Ws, I see some curious differences.

Without LTO, I see these two entries, indicating a weak function:

  3805: 0000000000334a70  1843 FUNC    WEAK   DEFAULT   13 _ZN13VirtualMapper13stage2_lookupILb0EEEN3vms15lookup_result_tEimbN6sysreg9ESR_ELX_tENS_8Access_tEb
  2660: 0000000000334a70  1843 FUNC    WEAK   DEFAULT   13 _ZN13VirtualMapper13stage2_lookupILb0EEEN3vms15lookup_result_tEimbN6sysreg9ESR_ELX_tENS_8Access_tEb

I am not sure why the function is being marked as weak since the attribute isn't being specified in the code.

However, with -flto enabled, I instead see the following:

   728: 000000000007e4d2  1422 FUNC    LOCAL  DEFAULT   13 
_ZN13VirtualMapper13stage2_lookupILb0EEEN3vms15lookup_result_tEimbN6sysreg9ESR_ELX_tENS_8Access_tEb.cold
  1308: 0000000000303430  7449 FUNC    LOCAL  DEFAULT   13 _ZN13VirtualMapper13stage2_lookupILb0EEEN3vms15lookup_result_tEimbN6sysreg9ESR_ELX_tENS_8Access_tEb

In this case, instead of being marked as weak, it has ".cold" appended to it.

Furthermore, when I attempt to dump using objdump -T -w, in the working case without lto I see:

0000000000334a70  w   DF .text  0000000000000733  Base        _ZN13VirtualMapper13stage2_lookupILb0EEEN3vms15lookup_result_tEimbN6sysreg9ESR_ELX_tENS_8Access_tEb

However, with lto enabled, this symbol is not present when listed with objdump.

I cannot provide source since it is from a very large proprietary c++ project, unfortunately. It is compiled using -fPIC -shared -rdynamic -mcx16 -march=native (on AMD Threadripper) along with the proper rpath assigned.

As for the CPPFLAGS, -O3, -march=native -fPIC -mno-red-zone -std=gnu++11 and various parameters to enable various warnings. I had to compile with -fPIC instead of -fpic due to the compiler complaining. Note that this is also with clean builds as well.

This is with OpenSUSE 15.3 with libc 2.31 and libstdc++ 6.0.29. This happens with both g++ 7.5 and 11.2. Everything works fine when lto is not enabled.

Any idea on what could be going on? To me this looks like a bug in the lto optimizer. Symbols should not disappear in shared libraries when lto is enabled.



Solution 1:[1]

The problem turned out that the template needed to be explicitely instantiated in the .cpp file where it was defined. Without that, the compiler appears to have attempted to inline it and not make it externally visible. The other option is to add attribute((externally_visible)) to the template definition in the header file.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Aaron Williams