7

I am building some code that needs to be a shared object (.so).

The problem that the libc on my building machine may be newer than the published machines, so I want to link with it statically to avoid compatibilities issues. (My program uses memcpy which is apparently a GLIBC_2.14 thing when it can go as low as 2.5).

Compiling with both -shared and -static doesn't work since crtbeginT.o wasn't compiled with -fPIC.

Edit: Probably not a duplicate of GCC linking libc static and some other library dynamically, revisited? since that question talking about the main elf linking libc statically and this is about a shared object linking libc statically.

Community
  • 1
  • 1
Eric. J. Lara
  • 203
  • 2
  • 8
  • Could you post your gcc options please. – KimKulling Mar 13 '17 at 13:25
  • 1
    It does not make sense to do what you describe, because you would end up having any application that uses your library using two different versions of glibc at the same time -- one via your library, and a different one for its own direct glibc dependencies. That presents exactly the kind of problem (I presume) you hope to avoid, so you don't gain anything by doing as you propose. – John Bollinger Mar 13 '17 at 13:27
  • 7
    From experience, you will spend, far, far less time on this by setting up e.g. a VirtualBox VM with the required old distro/version having the older glibc that matches your "publishing" machines and build your releases on that VM (you can still develop/test on your newer development distro) , than you will trying to fight glibc compatibility issues. Even more so if you are creating a shared library that contains pieces of a newer glibc that will be loaded into a process that links to an older glibc. Just don't do that. – nos Mar 13 '17 at 13:30
  • `memcpy` is a standard function since the very first version. Every C library has to provide it. Things may be different for C++, which is a different language. – too honest for this site Mar 13 '17 at 13:50
  • 1
    You don't even need a VM, you can do it in a chrooted environment (I never set it up myself though, only used pre-configured ones so not sure how much work that would be). Also should be able to set it up with Docker. – MK. Mar 13 '17 at 13:54
  • Possible duplicate of [GCC linking libc static and some other library dynamically, revisited?](http://stackoverflow.com/questions/26277283/gcc-linking-libc-static-and-some-other-library-dynamically-revisited) – Alex Lop. Mar 13 '17 at 13:58
  • If you are only concerned by `memcpy()`, just implement it yourself, its easy (if you don't need it optimized). Otherwise, you will have bad luck linking static library code to a shared library, since it is not position independent. You might rip the relevant functions from dietlibc or similar and compile it yourself as part of your shared library – Ctx Mar 13 '17 at 14:07
  • @JohnBollinger I don't mind letting the main app have its own libc, and the so having a different one. If each one uses their own libc, how could there be conflicts? – Eric. J. Lara Mar 13 '17 at 14:22
  • @nos That for me is the last ditch effort. Another reason I want to compile statically is that I may want to use newer library features, which means I will have to bundle it statically. – Eric. J. Lara Mar 13 '17 at 14:25
  • Try to create your *.so* as you did (with `-shared`) just add to it `libc.a -lc -lgcc`. Did it work? – Alex Lop. Mar 13 '17 at 14:39
  • What you should do is build and link against the oldest version of Glibc that you're willing to support. Trust me, `memcpy` wasn't introduced in version 2.14; it's been in the library since probably the beginning. – davmac Mar 13 '17 at 14:54
  • @Eric.J.Lara, there are several ways conflicts could arise, all generally involving working on the same data with different library versions. For example, suppose that there is a change from one version of glibc to another with respect to the metadata associated with dynamic memory allocation. You might then end up with memory corruption if you allocate memory with one version of glibc and free it with the other. Alternatively, you might find that some of the libraries internal structure change -- say the details of `FILE` -- with similar bad effects. – John Bollinger Mar 13 '17 at 15:20
  • I would like to further add to the complexity of the problem... What if you had multiple targets with different a libc branhd, e.g. glibc, uclibc muslibc etc... and you wanted a single shared object that is able to load on all targets without having to maintain a multitude of toolchains. – smichak May 14 '19 at 09:14

1 Answers1

8

You want to statically link glibc in your shared library.

You should not do this.

If you try, you will end up with a C++ One Definition Rule (ODR) violation. This is because some parts of glibc will be from the "old" version of your target machine, and some will be from the "new" version of your library. The result is undefined behavior.

The right solution is simple: build with an older glibc (as old as your oldest target for deployment). Or build multiple times, once for each version of glibc you need (if you truly need new glibc features). Even if you think you need a new glibc feature, consider just copy-pasting that one feature into your library under a different name to avoid collisions.

Regarding memcpy in particular, see: https://stackoverflow.com/a/8823419/4323 - and for a manual fix: https://stackoverflow.com/a/5977518/4323

Community
  • 1
  • 1
John Zwinck
  • 239,568
  • 38
  • 324
  • 436