Mingw-packages: Issues when building with clang (duplicate libstdc++.a symbols)

Created on 27 Aug 2016  Â·  12Comments  Â·  Source: msys2/MINGW-packages

Hello,

I am currently testing clang compilation and ran into several issues. Due to #1669 being unfixed at this moment I mostly relied on 3.8.0 win32 and 3.9.0 rc3 win32, however I tested mingw-w64-i686-clang (3.8) as well. Due to reports getting large I decided to split them.

2. A number of symbols present in libstdc++ headers are exported by libstdc++.a
The issue is pretty straight-forward. When performing optimised static linking to libstdc++.a one is likely to face multiple symbol definition issue.

Minimal sample (issue confirmed on any clang):
_clang++ -target i686-w64-mingw32 -static -std=c++11 -pthread -O1 example2.cpp_

#include <string>

int main () {
    auto s = std::string("1234");
    auto ws = std::u16string(u"1234");
    auto s1 = "#" + s;
}

This will produce the following error message:

C:\msys64\mingw32\lib\gcc\i686-w64-mingw32\6.1.0\libstdc++.a(string-inst.o):(.text$_ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_[__ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_]+0x0): multiple definition of `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > std::operator+<char, std::char_traits<char>, std::allocator<char> >(char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
C:\msys64\tmp\example2-b21e71.o:(.text[__ZStplIcSt11char_traitsIcESaIcEENSt7__cxx1112basic_stringIT_T0_T1_EEPKS5_RKS8_]+0x0): first defined here
C:\msys64\mingw32\lib\gcc\i686-w64-mingw32\6.1.0\libstdc++.a(string-inst.o):(.text$_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag[__ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag]+0x0): multiple definition of `void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char const*>(char const*, char const*, std::forward_iterator_tag)'
C:\msys64\tmp\example2-b21e71.o:(.text[__ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE12_M_constructIPKcEEvT_S8_St20forward_iterator_tag]+0x0): first defined here
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

As it can be seen from the error the bug is caused by exported symbols in libstdc++.a. I do not expect it to export any _M_construct but it does this for char-instantiated one. I.e. u16string has no this bug. One is also required to enable optimisation (e.g. -O1) to get compilation failure.

I could imagine various ways to get this fixed, for example, SFINAE. I used a force_inline attribute.

Suggested changes:
_msys64\mingw32\include\c++\6.1.0\bits\basic_string.h_

      // For forward_iterators up to random_access_iterators, used for
      // string::iterator, _CharT*, etc.
      template<typename _FwdIterator>
#ifdef __clang__
        __attribute__((always_inline))
#endif
        void
        _M_construct(_FwdIterator __beg, _FwdIterator __end,
             std::forward_iterator_tag);

and

  /**
   *  @brief  Concatenate C string and string.
   *  @param __lhs  First string.
   *  @param __rhs  Last string.
   *  @return  New string with value of @a __lhs followed by @a __rhs.
   */
  template<typename _CharT, typename _Traits, typename _Alloc>
#ifdef __clang__
    __attribute__((always_inline))
#endif
    basic_string<_CharT,_Traits,_Alloc>
    operator+(const _CharT* __lhs,
          const basic_string<_CharT,_Traits,_Alloc>& __rhs);

These methods may not be the only ones but are so far the only noticed ones by myself.

Also, I had to pass -pthread to get the sample compile without undefined pthread symbols. This feels undesired but I do not know any details about who is responsible here.

Most helpful comment

Here is a really small example of the inline function ABI incompatibility:

$ cat a.cpp
inline int foo(int a, int b) { return a + b; }
int bar(void);
int main() { return foo(1, 2) + bar(); }

$ cat b.cpp
inline int foo(int a, int b) { return a + b; }
int bar() { return foo(3, 4); }

$ gcc a.cpp -c -o a.o && clang --target=x86_64-w64-windows-gnu -c b.cpp -o b.o 

$ gcc a.o b.o -o a.exe
b.o:(.text[_Z3fooii]+0x0): multiple definition of `foo(int, int)'
a.o:a.cpp:(.text$_Z3fooii[_Z3fooii]+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

Going back to the section name .text$_Z3fooii in clang makes the problem go away.

All 12 comments

A bit more:
_msys64\mingw32\include\c++\6.1.0\bits\basic_string.h_:

      /**
       *  @brief  Construct string as copy of a range.
       *  @param  __beg  Start of range.
       *  @param  __end  End of range.
       *  @param  __a  Allocator to use (default is default allocator).
       */
#if __cplusplus >= 201103L
      template<typename _InputIterator,
           typename = std::_RequireInputIter<_InputIterator>>
#else
      template<typename _InputIterator>
#endif
#ifdef __clang__
        __attribute__((always_inline))
#endif
        basic_string(_InputIterator __beg, _InputIterator __end,
             const _Alloc& __a = _Alloc())
    : _M_dataplus(_M_local_data(), __a)
    { _M_construct(__beg, __end); }

_msys64\mingw32\include\c++\6.1.0\bits\shared_ptr_base.h_:

#ifdef __clang__
      __attribute__((always_inline))
#endif
      _M_release() noexcept
      {
        // Be race-detector-friendly.  For more info see bits/c++config.

and

      // Called when _M_weak_count drops to zero.
      virtual void
      _M_destroy() noexcept
#ifdef __clang__
      ;
#else
      { delete this; }
#endif

_msys64\mingw32\include\c++\6.1.0typeinfo_:

#ifdef __clang__
      __attribute__((always_inline))
#endif
    bool operator==(const type_info& __arg) const _GLIBCXX_NOEXCEPT

I think the question is: "Why does it work on Linux but not here?".

@mati865 the question is: "Why did it dare to link the supposedly inline functions into a static library".

Issue persists as of 3.9.1

What is that status of this? This still occurs in clang 5.0.

I have reported it some time ago to upstream but looks like we need to take
care of it ourselves...

17.09.2017 01:05 "K. S. Ernest (iFire) Lee" notifications@github.com
napisał(a):

What is that status of this? This still occurs in clang 5.0.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Alexpux/MINGW-packages/issues/1677#issuecomment-330000109,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABHsdtOlhCjFyE8ohO_pjRMZ5OUUEatxks5sjFQdgaJpZM4JuvXC
.

LINKFLAGS='-Wl,--allow-multiple-definition' This is an ugly workaround.

@fire it causes segfaults in specific cases so it's an unsafe workaround.

It happened to me, when building with clang++ -std=c++17 -static -O <two files here>

B:\msys64\mingw64\lib\gcc\x86_64-w64-mingw32\7.3.0\libstdc++.a(string-inst.o):(.text$_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_mutateEyyPKcy[_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_mutateEyyPKcy]+0x0): definiciones múltiples de `std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long long, unsigned long long, char const*, unsigned long long)'
B:\msys64\tmp\narc-5ea9c5.o:(.text[_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE9_M_mutateEyyPKcy]+0x0): primero se define aquí
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

By removing this line in my code

mNarcFiles[iFile].resize(fileSize);

the linkage error fixes.

This looks like it was probably caused by my change in r268331, which makes us emit functions into subsections called ".text" instead of subsections called ".text$_Z3foov" where _Z3foov is the symbol name. I think I didn't realize how incompatible the COFF port of ld.bfd is with the Visual C++ linker. I kind of assumed all that low-level object file stuff would be the same, since it's the most well-documented thing we have to work with. Now I'm really sad. :(

Here is a really small example of the inline function ABI incompatibility:

$ cat a.cpp
inline int foo(int a, int b) { return a + b; }
int bar(void);
int main() { return foo(1, 2) + bar(); }

$ cat b.cpp
inline int foo(int a, int b) { return a + b; }
int bar() { return foo(3, 4); }

$ gcc a.cpp -c -o a.o && clang --target=x86_64-w64-windows-gnu -c b.cpp -o b.o 

$ gcc a.o b.o -o a.exe
b.o:(.text[_Z3fooii]+0x0): multiple definition of `foo(int, int)'
a.o:a.cpp:(.text$_Z3fooii[_Z3fooii]+0x0): first defined here
collect2.exe: error: ld returned 1 exit status

Going back to the section name .text$_Z3fooii in clang makes the problem go away.

@rnk, that's quite unpleasant but at least the problem is more clear now. Will you submit a patch to clang upstream so that it could land in 7.0.0 release at least?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dgbustos picture dgbustos  Â·  5Comments

fspeech picture fspeech  Â·  6Comments

jagannatharjun picture jagannatharjun  Â·  3Comments

WuZhengqiang666 picture WuZhengqiang666  Â·  3Comments

Alex-Gamper picture Alex-Gamper  Â·  8Comments