Search code examples
c++elfunresolved-externalbinutils

Unresolvable `R_X86_64_NONE` relocation


I'm using Devtoolset-7 on CentOS 7 and have built Boost 1.65.1 w/ it. But when I link my application, I've got the following:

/opt/rh/devtoolset-7/root/usr/libexec/gcc/x86_64-redhat-linux/7/ld: /opt/rh/devtoolset-7/root/usr/lib64/libboost_unit_test_framework.a(compiler_log_formatter.o)(.text._ZN5boost9unit_test5utils11string_castINS0_13basic_cstringIKcEEEESsRKT_[_ZN5boost9unit_test5utils11string_castINS0_13basic_cstringIKcEEEESsRKT_]+0x3c): unresolvable R_X86_64_NONE relocation against symbol `_ZTVSt9basic_iosIcSt11char_traitsIcEE@@GLIBCXX_3.4'
/opt/rh/devtoolset-7/root/usr/libexec/gcc/x86_64-redhat-linux/7/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

Searching more info about R_X86_64_NONE doesn't give any valuable results: mostly similar questions w/o any answer or precise explanation what is this and how to solve it.

So my questions are:

  • what is this error really means?
  • what is R_X86_64_NONE and why "nothing to relocate" (according to bintils sources) type of symbol ever exists in ELF headers?

Addendum:

  • The error happened on linking unit tests executable which is linked against my static library and Boosts' static libraries (unit tests framework)
  • All static libraries (Boost and mine one) has built with -fPIC option

PS. I really want this question to be resolved once and forever (already hit it few times, but this time update to latest binutils doesn't help). (will start a bounty on any activity on this question)


Solution

  • From the build log posted to the Red Hat Bugzilla bug:

    [19:15:01]W:     [Step 8/12] + /usr/lib/rpm/check-buildroot
    [19:15:01]W:     [Step 8/12] + /usr/lib/rpm/brp-scl-compress /opt/rh/devtoolset-7/root
    [19:15:01]W:     [Step 8/12] + /usr/lib/rpm/brp-strip-static-archive /usr/bin/strip
    [19:16:40]W:     [Step 8/12] /usr/bin/strip: /work/build/BUILDROOT/devtoolset-7-boost-1.65.1-4.el7.centos.x86_64/opt/rh/devtoolset-7/root/usr/lib64/libboost_container.a(global_resource.o): invalid relocation type 42
    [19:16:40]W:     [Step 8/12] /usr/bin/strip: BFD version 2.25.1-32.base.el7_4.2  assertion fail elf64-x86-64.c:341
    

    Note /usr/bin/strip, not /opt/rh/devtoolset-7/root/usr/bin/strip. So the system strip command is used. 42 corresponds to the R_X86_64_REX_GOTPCRELX relocation, which is generated by DTS binutils as an optimization.

    A simple way to reproduce this is with this C++ file:

    #include <iostream>
    
    void
    dot ()
    {
      std::cout << '.';
    }
    

    If compile with -O2 -fpic, it will produce an X86_64_REX_GOTPCRELX relocation for _ZNSt8ios_base4InitD1Ev. Running /usr/bin/strip -g on that will turn that into R_X86_64_NONE. This can be verified using eu-readelf -r.

    You can use RPM to tell to use the DTS strip using

    %if 0%{?scl:1}
    %define __strip %{_bindir}/strip
    %endif
    

    in the RPM spec file, or you can add

    %undefine __brp_strip_static_archive
    

    to skip stripping the static library completely (which is probably the right thing to do anyway).