Linux Shared Libraries

While writing applications in linux , the developer can use tons of libraries. Each library can packs functions, classes and variables and it is very  important to understand how to create and work with it.

Lets start with simple example: Implicit link

To compile the library we use:

Here we use -g3 to add debugging information , -shared to specify that we build a shared object and -fPIC to specify that this build a position independent code (we don’t know where in the memory the shared library will be loaded)

Using the library:

To build the application we need to use -l with the library name and -L to specify the library location. If we put the library in one of the lib directories (/lib , /usr/lib) we don’t need to specify the location using -L flag but usually we want to put our code in a separate place

Here we use -L with the current directory. note that don’t write the lib prefix and the extension so any library should named libXXX.so and to link with it we specify -lXXX

To run the app we need to put the library in one of the path locations or specify the library path use LD_LIBRARY_PATH environment variable:

 

Explicit link

What if we don’t know on build time the name of the loaded library ? For example we want to build an app that support plugins – for each plugin the user should implement 2 functions that we specify the prototype for. In this case we can use dlopen(3)

We build the library the same way , the different is the application using it:

To compile it use:

We need to add -ldl to use dlopen.

Note about C++ libraries

Note that we are using the symbol name. In C the function name is also the symbol name but if we compile it to c++ as a result of function overloading the symbol name is different. To see the symbols , use the nm utility:

As you can see in the last 2 lines the symbol names are different because the compiler decode also the function prototype so if we want to use the above example with this library we need to use the correct symbol name:

Another option is to add extern “C” on the library functions prototype to make the compiler use the name as a symbol name.

If we can’t find the function name we can ask nm to display the functions prototype using -C :

Now we can see the functions, using their address we can find the symbol name

Global Variables

One basic concept of any general purpose operating system is the private process address space – means each process has its on private memory space and the system maps pages from the physical address space to virtual for every process. Shared libraries are code sharing mechanism and not data means that every process has its own copy for example if we add a global variable to our library:

and we use it by 2 separate processes :

If you run simp.c and wait until it gets to sleep so global=200 and then run simp2.c you will get global = 100

To create a shared data we need to use shared memory (shm_open)

First we define a structure to hold our data – Do Not Use Pointers !!! :

Then we create a shared memory on library load (note the constructor attribute to declare a function as initializer)

Now if we create 2 or more processes accessing global , the data will be shared

This example is for learning purpose just to show a simple way to share data, If you do that for real application it will be better to hide the structure, define a set of getters/setters and check on init if this is the first process loading to library so we can initialize the data.

To initialize the shared memory on the first instance creating it use O_EXCL flag in shm_open

If we want to delete the shared memory while no process is mapped we can also implement destructor add add a reference count + mutex in the shared  memory

 

Tagged ,

1 thought on “Linux Shared Libraries

  1. […] can build the fault handler into a shared library and use the constructor to set it. Then you can inject the library to any process using […]

Leave a Reply

Your email address will not be published. Required fields are marked *