'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 |
