2

We have a given set of legacy C++ libraries compiled on an old release system with the very old compiler gcc 3.2 using libstdc++.so.5.0.0. An up-to-date CentOS7 will run an executable compiled on the old OS using the compatibility library libstdc++.so.5.0.7, while the current C++ version with a different library ABI is libstdc++.so.6.

Our new version of the executable is built on the new OS and cannot be built on the old platform any more. But currently recompiling the legacy libs on CentOS7 is also not an option: the numerical results will be slightly different. So I would like to use them as they are with their libstdc++.so.5, while the rest of my binary uses c++ version 6.

this post suggest using a wrapper c-interface library which is linked with the static version libstdc++.a.5.

this post mainly suggests the same.

This method seems possible in our case since the interface is only C-style and does not use C++ objects. And the C-ABI seems to work as a kind of barrier between the two versions of the c++ lib.

However, I have yet to find someone providing the static C++.5 libs. Also I think I have once heard talk about using two shared lib versions of libstdc++ in parallel, in one application. So is there also a solution keeping the shared C++.5 libs? I have some weak memory that they also used a C-library as border. Would it also work with dlopen()?

My current situation is like this:

Compiled on old OS with old gcc-3.2, libstdc++.so.5, 32-bit mode:

  • libA1.so using C++
  • libA2.so calling libB.so, both use C++, libA2 explicitely linked against libstdc++ with linker option -lstdc++, libB not but probably it gets its symbols from libA
  • libwrapper.so only using C not C++, linked with/using libA1 and libA2.

Compiled on new OS with new gcc-4.8.5:

  • executable (32-bit) calling libwrapper.so by using dlopen() system call, so indirectly calling C++ libs libA1.so and libA2.
  • executable also uses a shared C++ lib libC.so (but interface is C style)
  • executable also uses a shared C++ lib libB.so (but interface is C style), which is also needed by libA1 and libA2.

So the executable must use the new libstdc++.so.6 for libC, but will indirectly call libA1, libA2, libB which must use the old libstdc++.so.5.

Do I have to limit the symbols exported by the wrapper lib exactly to my API, not exposing any c++ symbols like in pobedims comment in 1, using a version-script flag for the linker ?

Or maybe I just link the legacy lib on the old OS not with -lstdc++, but with the full name /usr/lib/libstdc++.so.5 ? And libB will continue to get the correct symbols from libA2 ?

My executable links/depends on ...

  1. libB.so (C++)
  2. libC.so (C++) which needs libstdc++.6
  3. libwrapper.so (with C interface), which is loaded using the dynamic load dlopen(), and which itself is linked to the "worker" libA1 and libA2 (which also present a C interface):
    • libA1.so using C++.5
    • libA2.so using C++.5
      • libB.so using C++.5

The executable is linked with -rdynamic, maybe that is a problem? How can I be sure that no symbols in libA1, A2, B are resolved using symbols from the executable with same name?

Edit later / Resolution: Note1: Trying on the old platform to link using archive version libstdc++.a.5 leads to an error which is only fixed in later version of gcc >= 3.4:
Error: ld: libwrapper.so: undefined versioned symbol name _ZSt10time_put_w@@GLIBCPP_3.2
ld: failed to set dynamic section sizes: Bad value

so this is not an option.

Note2: LibB was a problem since it is expected by the working libs and by the executable itself. If the executable uses the new version of libB it introduces libstdc++.so.6, of which the symbols are passed to the worker libs, which crash upon start. I have changed the version of libB used to the one compiled on the old system, simply by exchanging it on the runtime system. This is possible because of the simple C interface being binary compatible. Thus my executable (via libB) and the worker libs libA1 and libA2 all use the same libstdc++.so.5. My (C) executable is built directly linking libstdc++.so.5. Now my executable can be started and works.

Note3: I found some numerical differences between the reference results and the new result. Using LD_PRELOAD mechanism has worked to resolve these: LD_PRELOAD=libstdc++.so.5 my_executable

This seems to work nicely. I think by using LD_PRELOAD I make sure that libstdc++.so.5 has precendence in supplying the symbols resolved from libstdc++. What I did not mention before: we used the Intel compiler on the old platform, and I used the math lib libimf.so from it like this: LD_PRELOAD="libimf.so libstdc++.so.5" to provide both libs. As a result the numerical differences vanished, which seem to be caused by the implementation of common math functions.

karsten
  • 639
  • 5
  • 13
  • 2
    Sounds to me like the most fruitful path in the long run would be to just bite the bullet and fix your libraries to work correctly with the modern libc. Continuing to use the old stuff is just going to get harder and harder and more painful and error prone as the years go by. Just fix it and bring it up-to-date already. – Jesper Juhl Jun 01 '18 at 16:28
  • 1
    Maybe you are right. But the old libs are government certified, and any replacement must reproduce exactly the same result, or a new certification process is necessary for each released version. But maybe it would be possible to recompile using a slightly newer compiler gcc-3.4 on the old platform, having the new ABI. – karsten Jun 01 '18 at 16:44
  • Why don't you install the 32bit `libstdc++.so.5` ? ... `# yum install compat-libstdc++-33.i686` ... No problem having both. They are available for a reason http://mirror.centos.org/centos/7.5.1804/os/x86_64/Packages/ – Knud Larsen Jun 01 '18 at 18:24
  • @KnudLarsen It is already installed, the problem is that usually you are not supposed to have two versions of libstdc++.so, i.e. 5 and 6, in use both in the SAME executable. – karsten Jun 01 '18 at 18:35
  • 1
    technically, there is `dlmopen` which may allow to solve conflicts , but you would have load entire tree of dependencies separately.. GL at trying. – Swift - Friday Pie Jun 01 '18 at 19:53
  • @Swift Thanks, I did not know this gnu extension although it is available since 2004! – karsten Jun 01 '18 at 20:52
  • @Swift Thank How would this work? I would have to include all the standard headers in advance from a central header, and put it into a namespace. How could I make sure that noone includes a different header? Also I would have to recompile all sources. – karsten Jun 04 '18 at 09:12
  • News: * dlmopen is not available with gcc-3.2 * static linkage with libstdc++.a.5 is not possible, needs gcc-3.4 ("undefined versioned symbol name _ZSt10time_put_w@@GLIBCPP_3.2") * works: use version of libC compiled on old machine, so that all need the same version of libstdc++. Then link executable directly against /lib/libstdc++.so.5 from compat-libstdc++ package. – karsten Jun 06 '18 at 12:30

0 Answers0