Create a simple shared library in C

mar. 29 août 2017 by Mick Cherry

In this post we will see how to create a (very) simple shared library in C.

A shared library is a set of compiled code that can be used by an application without embedding the whole library code inside the final application.

Shared libraries used in a "Hello World!" linux application

A simple C application on Linux uses some shared libraries provided by the os. Let's compile a hello world and check its dependencies to shared objects:

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

int main(void)
{
  printf("Hello world!\n");
  return 0;
}
$ gcc hello.c 
$ ./a.out 
Hello world!
$ ldd a.out 
        linux-vdso.so.1 =>  (0x00007fff14d78000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f095a16a000)
        /lib64/ld-linux-x86-64.so.2 (0x0000557334be6000)

We can see that our program already has 3 dependencies : linux-vdso.so.1, libc.so.6, ld-linux-x86-64.so.2.

The first is a shared libray that handles fast system calls, the second is the C standard library, and the third one is the dynamic linker/loader.

Create a shared library

We create a library with a single function in it:

$ cat lib_random.c
int getRandomNumber(void)
{
  return 4;
}
$ cat lib_random.h
int getRandomNumber(void);

We compile the source file lib_random.c with -shared and -fPIC:

$ gcc -shared -fPIC -o lib_random.so lib_random.c

The -shared option tells gcc to produce a shared object that can be linked to other objects.

The -fPIC option produces position-independent code suitable for dynamic linking (when the linking is not done at compile time, but at runtime).

Compile the application

We want to call the shared library lib_random.so from an application that will not embed the library in its binary.

$ cat random.c 
#include <stdio.h>
#include "lib_random.h"

int main(void)
{
  int x;
  x = getRandomNumber();
  printf("A random number is %d\n", x);
  return 0;
}

We compile the application against the shared library:

$ gcc -o random random.c -L. -l_random

The -L. options tells gcc to look in the current folder for libraries. The -l_random option tells gcc to look for libraries names lib_random.

We can check that the resulting binary does not contain the getRandomNumber function, since it will be dynamically linked during runtime:

$ objdump -S random | grep "^\S* <getRandomNumber>" | wc -l
0

Finally, when we try to run our home-made application, it fails:

$ ./random 
./random: error while loading shared libraries: lib_random.so: cannot open shared object file: No such file or directory

Oops, what did we do wrong?

$ ldd random
        linux-vdso.so.1 =>  (0x00007ffdabf90000)
        lib_random.so => not found
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f80708eb000)
        /lib64/ld-linux-x86-64.so.2 (0x0000563e30b2a000)

It seems that something is missing to tell random where to find the lib_random.so file.

The dynamic linker does not know where our lib resides, so we need to tell him where to look. This is done through LD_LIBRARY_PATH environment variable:

$ export LD_LIBRARY_PATH=$(pwd):$LD_LIBRARY_PATH
$ ./random 
A random number is 4

And finally it works! We built a small shared library that was dynamically linked and loaded at runtime.

Sources: this, this and that.