spdlog icon indicating copy to clipboard operation
spdlog copied to clipboard

1.14.1 unresolvable R_X86_64_TPOFF32 relocation

Open Oipo opened this issue 1 year ago • 8 comments

Updating spdlog to 1.14.1, I get the following linker error:

/usr/bin/c++ -Wno-maybe-uninitialized  -ggdb -O3 -DNDEBUG -pie -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--no-copy-dt-needed-entries test/CMakeFiles/EtcdTests.dir/EtcdTests.cpp.o -o /opt/ichor/src/bin/EtcdTests  /opt/ichor/src/bin/libichor.a  /opt/ichor/src/bin/libCatch2Main.a  -lsystemd  /usr/lib/libboost_coroutine.a  /usr/lib/libboost_fiber.a  /usr/lib/libboost_context.a  /usr/lib/libboost_filesystem.a  /usr/lib/libssl.a  /usr/lib/libcrypto.a  -ldl  -lhiredis  -ldl  -lrt  /opt/ichor/src/bin/libCatch2.a && :
/usr/bin/ld: /opt/ichor/src/bin/libichor.a(async.cpp.o)(.text+0x266e): unresolvable R_X86_64_TPOFF32 relocation against symbol `_ZSt15__once_callable@@GLIBCXX_3.4.11'

This doesn't happen with 1.13.0, or when ftls-model=local-exec is removed from the compiler flags.

Compiler: gcc 12.3.0 Linux: Ubuntu Jammy cxxflags: -O2 -std=c++20 -fpie -fstack-protector-strong -fcf-protection -fstack-clash-protection -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3 -D_GLIBCXX_ASSERTIONS -D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST -ftls-model=local-exec linkflags: -ggdb -O3 -DNDEBUG -pie -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -Wl,--no-copy-dt-needed-entries

Oipo avatar Oct 16 '24 22:10 Oipo

It doesn't look like the spdlog symbol, maybe you should ask the question in the GCC or Ubuntu community.

tt4g avatar Oct 16 '24 22:10 tt4g

Maybe duplicate #1405

tt4g avatar Oct 17 '24 03:10 tt4g

It doesn't look like the spdlog symbol, maybe you should ask the question in the GCC or Ubuntu community.

once_callable is likely a thread_local related symbol, which glibc uses. The error shows that this happens in async.cpp, which includes a bunch of spdlog related files.

Maybe duplicate #1405

-fPIC didn't change anything, which is because I'm not creating or linking into a shared library. Instead, I'm making a PIE executable with the PIE static library. Regardless, I'll bisect it later.

Oipo avatar Oct 17 '24 07:10 Oipo

-fPIC didn't change anything, which is because I'm not creating or linking into a shared library. Instead, I'm making a PIE executable with the PIE static library. Regardless, I'll bisect it later.

As far as I know, the -fPIC option causes relocation problems when using the static library: c++ - "relocation R_X86_64_32S against " linking Error - Stack Overflow

tt4g avatar Oct 17 '24 11:10 tt4g

As far as I know, the -fPIC option causes relocation problems when using the static library: c++ - "relocation R_X86_64_32S against " linking Error - Stack Overflow

Your linked stackoverflow is saying the same thing as I am. As long as the end result is a dynamic library (either directly, or by first creating a static library which is then linked into a dynamic library), -fPIC is useful. This can also be gleaned from the gcc manual:

Generate position-independent code (PIC) suitable for use in a shared library ...

However, I am not creating a shared library anywhere in my workflow. I make a static library and link it directly into an executable. Therefore, I use -fpie (since my GOT tables aren't too big to need to use -fPIE) and -fPIC has no effect on the problem at hand. I know, because I've added it to the compiler flags and it resulted in the same error I mentioned above.

I have bisected the problem to 6725584e27ca93f50527165696d7cf34e3978373. And specifically, the call to set_value() in thread_pool-inl.h:115.

promise<>::set_value() ends up calling std::call_once, which requires thread local storage and GCC requires the glibcxx once_callable symbol (which is probably some pthread_once alias). ftls-model=local-exec disables the usage of thread_local storage which has not been defined inside the executable itself. And the once_callable symbol resides in libc.so.6.

On top of that, unfortunately, gcc has had a pretty bad bug with std::call_once and exceptions since gcc 5.x, making it impossible to support handling exceptions during a std::call_once call on musl and other non-glibc, non-x86 targets. Not the case here, but certainly something to consider.

The options I see are as follows:

  • Change compiler flags to ftls-model=initial-exec, losing some performance whenever I access thread_local variables
  • Refactor the std::promise/std::future to a std::function of sorts.
  • Patch out the specific commit in my own fork

Oipo avatar Oct 17 '24 20:10 Oipo

Thanks for the accurate investigation. I had never heard of the std::call_once bug in GCC. It would be helpful if you could send the PR.

tt4g avatar Oct 17 '24 21:10 tt4g

Sure, I'll take a stab when I have some free time. It would likely be a backwards incompatible change though. Or should I put in a #ifdef to control the function signature?

Oipo avatar Oct 19 '24 19:10 Oipo

Personally, I think it is a bug and should be fixed even if it is not compatible. However, I am not this repository maintainer, so the final decision is up to @gabime.

tt4g avatar Oct 19 '24 21:10 tt4g