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 =>  (0x00007fff14d78000) => /lib/x86_64-linux-gnu/ (0x00007f095a16a000)
        /lib64/ (0x0000557334be6000)

We can see that our program already has 3 dependencies :,,

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.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 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

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

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

Oops, what did we do wrong?

$ ldd random =>  (0x00007ffdabf90000) => not found => /lib/x86_64-linux-gnu/ (0x00007f80708eb000)
        /lib64/ (0x0000563e30b2a000)

It seems that something is missing to tell random where to find the 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:

$ ./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.