How can a shared object be statically linked

72 Views Asked by At

I have a shared object where file indicates it is a shared object, and it is used and behaves as a shared object.

% file libirc.so
libirc.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=9d54bda46b31ae048aae323dfd809f9ae6c8c55c, not stripped
%

But the ldd command indicates it is statically linked.

% ldd libirc.so
    statically linked
%

When I run an executable, ./Solver, that uses this libirc.so it runs as expected. But when I run the same with LD_PRELOAD="io_functions.so" the run time linker, /lib64/ld-linux-x86-64.so.2, segfaults just after issuing the error message:

./Solver: Relink `./lib/libirc.so' with `/lib64/libc.so.6' for IFUNC symbol `memmove'

I can make the run using LD_PRELOAD work by also including libirc.so on the LD_PRELOAD. I don't have source for libirc.so so I can't figure out much on that end. I suspect that the troubles are centered on libirc.so being statically linked. It should not matter what code is in io_functions.so because ld.so doesn't even get to the point of calling the init functions as ld.so is segfaulting while binding symbols.

I have done a bit of investigating using LD_DEBUG. When I run with LD_PRELOAD=irc/libirc.so ld.so needs to find memmove for libstdc++ , and uses memmove [GLIBC_2.2.5] from /lib64/libc.so.6. Later ld.so needs to find memmove for libirc.so and also uses memmove from libc.so.6.

LD_DEBUG output from successfull run with LD_PRELOAD=irc/libirc.so
3677171:     binding file /lib64/libstdc++.so.6 [0] to /lib64/libc.so.6 [0]: normal symbol `memmove' [GLIBC_2.2.5]
.
.
.
3677171:     binding file irc/libirc.so [0] to /lib64/libc.so.6 [0]: normal symbol 'memmove'

When I run the failing job (without LD_PRELOAD=irc/libirc.so), ld.so first needs to find memmove for libirc.so and finds it in libc.so.6. ld.so then prints out the Relink message, followed by a segfault. Why does running this way cause the Relink message and segfault, even though its finding memmove for libirc.so in the same place ( libc.so.6 ) as the above successful run?

The last LD_DEBUG line for this process, followed by the print
3676728:     binding file irc/libirc.so [0] to /lib64/libc.so.6 [0]: normal symbol `memmove'
./bin/SMAEqsDirSolverSymmetric: Relink `irc/libirc.so' with `/lib64/libc.so.6' for IFUNC symbol `memmove'
1

There are 1 best solutions below

0
Mike Kinghan On

There is nothing inherently crooked about a DSO that ldd reports as statically linked. In that case ldd is just telling you that the DSO has no dynamic dependencies itself.

Here comes one such:

$ gcc --version
gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0

This compiler emits PIC code by default.

$ cat hello.c
#include <stdio.h>

void hello(void)
{
    puts("Hello World");
}

$ gcc -shared -o libhello-musl.so hello.c -L/usr/lib/x86_64-linux-musl/ -l:libc.a

The stock muscl static libc built for and by my compiler contains PIC object files, so it harbours no relocation errors.

$ file libhello-musl.so
libhello-musl.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=015152e75131cd274f08fa16447ff926b7c6d85d, not stripped

and:

$ ldd libhello-musl.so 
statically linked

even though I did not attempt to link -shared -static (which would fail). ldd says that because there is no dynamic section in the shared library:

$ readelf --dynamic libhello-musl.so | grep NEEDED; echo Done
Done

Because it doesn't need one. Whereas:

$ gcc -shared -o libhello-gnu.so hello.c

$ readelf --dynamic libhello-gnu.so | grep NEEDED; echo Done
0x0000000000000001 (NEEDED)             Shared library [libc.so.6]
Done

 
$ ldd libhello-gnu.so 
    linux-vdso.so.1 (0x00007ffc4f5ce000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000079377ee00000)
    /lib64/ld-linux-x86-64.so.2 (0x000079377f104000)

libhello-musl.so is fit for purpose.

$ cat main.c
#include <stdio.h>

extern void hello(void);

int main(void)
{
    hello();
    return 0;
}

$ gcc -o hello main.c -L. -lhello-musl -Wl,-rpath=$(pwd)
$ ./hello
Hello World

$ ltrace -l libhello-musl.so ./hello
hello->hello(1, 0x7ffd219317d8, 0x7ffd219317e8, 0x5c2dd535bda0 <unfinished ...>
libhello-musl.so->puts("Hello World" <unfinished ...>
libhello-musl.so->fputs("Hello World", 0x78c0473fe060 <unfinished ...>
libhello-musl.so->strlen("Hello World")                                                                                                 = 11
libhello-musl.so->fwrite("Hello World", 1, 11, 0x78c0473fe060 <unfinished ...>
libhello-musl.so->memcpy(0x78c0473fe188, "Hello World", 11)                                                                             = 0x78c0473fe188
<... fwrite resumed> )                                                                                                                  = 11
<... fputs resumed> )                                                                                                                   = 0
Hello World
<... puts resumed> )                                                                                                                    = 0
<... hello resumed> )                                                                                                                   = 0
+++ exited (status 0) +++

In this light:

I suspect that the troubles are centered on libirc.so being statically linked.

seems to be a misplaced suspicion.

The internet throws up other examples of the same class of

Relink `/path/to/libsome.so' with `/path/to/libc.so.6' for IFUNC symbol `symbol'

error, in which the observation that libsome.so is statically linked does not appear.

These include:

in which as it happens the libsome.so = /usr/lib/libgcc_s.so.1 transpires to have been linked against libc.musl-x86_64.so.1 .

and:

which is identical to your error modulo paths.

and:

which implicates glibc patch:

committed Oct. 21st 2021.

In this light, like @n. m. could be an AI, I suggest that the version of [g]libc that your libirc.so has been statically linked with is unaligned with the one that your ./Solver is linked with. The likeliest remedy - as usual? - is to obey the diagnostic: get a new libirc.so that you know has been linked with libc.so.6 (or a static PIC version of same). If that's difficult just getting the latest version of libirc.so from wherever you got it may be a fix.