Use a static version of libc from an application that uses a dynamic shared library

Viewed 106

I am trying to compile the following components:

appl - an application which links to a dynamic shared library (libwrapper.so)

libwrapper.so - A library used by appl. This library invokes functions from a libbackend archive.

libbackend.a - A static archive that uses libc functions.

I want to ensure that the libc functions invoked by libbackend always uses a fixed libc implementation. So I am also archiving the needed libc.a in libbackend, in my compilation environment.

I want to achieve that when libbackend invokes any libc function, the archived libc function from the compilation environment should be invoked, not the function from libc.so version in the target environment.

Can this be achieved? Also, can this be achieved without changing the way appl is being compiled; i.e., can be this achieved by changing makefile of only libwrapper and libbackend?

This is what I have tried so far, and does not work:

[dev-env]# ls
appl.c  backend.c  backend.h  Makefile  wrapper.c  wrapper.h

[dev-env]# cat appl.c
#include <stdio.h>
#include "wrapper.h"
void main()
{
    printf("in appl\n");
    wrapper();
}

[dev-env]# cat wrapper.h
void wrapper();

[dev-env]# cat wrapper.c
#include <stdio.h>

#include "wrapper.h"
#include "backend.h"

void wrapper()
{
    printf("In wrapper\n");
    backend();
}

[dev-env]# cat backend.h
void backend();

[dev-env]# cat backend.c
#include <stdio.h>
#include <gnu/libc-version.h>

#include "backend.h"

void backend()
{
    printf("in backend\n");
    printf("GNU libc version: %s\n", gnu_get_libc_version());
}

[dev-env]# cat Makefile
LIBC=$(shell gcc --print-file-name=libc.a)

all: libbackend.a libwrapper.so appl

libbackend.a: backend.c backend.h
        gcc -static -fPIC -c backend.c -o backend.o
        ar rcs libbackend.a $(LIBC) backend.o

libwrapper.so: wrapper.c wrapper.h libbackend.a
        gcc -c  wrapper.c
        gcc -shared -o libwrapper.so wrapper.o libbackend.a

appl: appl.c
        gcc -o appl appl.c -L . -lwrapper

clean:
        rm *.o *.a *.so appl
[dev-env]#

From compilation environment:

[dev-env]# make
gcc -static -fPIC -c backend.c -o backend.o
ar rcs libbackend.a /usr/lib/gcc/x86_64-linux-gnu/8/../../../x86_64-linux-gnu/libc.a backend.o
gcc -c  wrapper.c
gcc -shared -o libwrapper.so wrapper.o libbackend.a
gcc -o appl appl.c -L . -lwrapper

[dev-env]# export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
[dev-env]# ./appl
in appl
In wrapper
in backend
GNU libc version: 2.28

In target environment:

[target]# ./appl
in appl
In wrapper
in backend
GNU libc version: 2.30

If what I am intending works, on target I should have seen the version output as "2.28".

1 Answers

Can this be achieved?

No.

This will lead to totally unpredictable behavior on any system with a different version of libc.so.6 installed. It's not something that you should even attempt.

I want to ensure that the libc functions invoked by libbackend always uses a fixed libc implementation.

Why? What problem are you imagining this will solve?

It would not solve anything, but is guaranteed to introduce new problems.

Related