Static vs Dynamic: The fight of the libraries.

Checha Giudice
8 min readDec 15, 2020

“This is what happens when an unstoppable force meets an immovable object”. Joker.

You can see by the subtitle of this article that I’m a huge Batman fan. And this quote from the Joker (The Dark Knight, 2008, great film, please watch it) reminded me of the topic I will talk about today: Static vs Dynamic libraries, both of which are C (programming languaje) libraries.

What are C libraries?

If I have to explain what a C library is to my 98-year-old grandfather, I probably would explain it like this:

Grampa, C libraries are like cellphones. They look small and useless to you but they hold my whole life inside it.

Kind of dramatic, but, why?

A library is a file containing several object files, that can be used as a single entity in a linking phase of a program (for more information about linking and compilation process please visit: Is compilation easy?). And they are organized as your regular-real-life library: they are (usually) indexed.

Oh! So that’s why they call it libraries, go figure.

With this amazing discovery, let’s imagine these so called files as actual libraries. I’m imagining mine as the one from Beauty and the Beast (because, why not?). Imagine yourself entering this library and you want to find something, let’s say a function, how would I search for it? As I explained it before, C libraries work the same as regular-real-life libraries, so they are indexed, better to find anything if its organized.

But why are libraries so important? They make the compilation process faster (I know you haven’t read my article, so here it is: AGAIN). Also, when using a library, we have fewer files to look for and open, which even further speeds up linking. Think of it as trying to move a wall of bricks, it would be faster and safer to move one brick at a time, that to move the hole wall.

Unix systems allow us to create and use two kinds of libraries — static libraries and dynamic (or shared) libraries.

Static and Dynamic.

Static libraries are just collections of object files that are linked into the program during the linking phase of compilation, and are not relevant during runtime. Only the program’s executable file is needed in order to run the program.

Dynamic (or shared) libraries are linked into the program in two stages. First, during compile time, the linker checks that variables, functions, etc., required by the program are either linked into the program, or in one of its shared libraries, but the object files from the dynamic library are not actually inserted into the executable file. Instead, when the program is started, a program in the system (called a dynamic loader) checks out which shared libraries were linked with the program, loads them to memory, and attaches them to the copy of the program in memory.

This may seem to slow down the launching process, and it does a little bit, but the reward for your patience will be worth it: if a second program linked with the same shared library is executed, it can use the same copy of the shared library, thus saving a lot of memory.

You may have heard about the Standard library (<stdio.h>): it’s usually a shared library, used by every C program but only one copy of the library is stored in memory at any given time (saving a lot of memory in the process, just as I said before).

Basically, and continuing with the example of the real life library, imagine you are reading your favorite book/novel. Usually when an author describes a character, s/he does it only once, when said character is introduced to the story. If you wanted to remember how that character looked like when s/he first showed up, you just go back on your book. That’s a dynamic library.

The static library version of this example would be that the author would describe each character every single time they are appear on scene. Tedious, but it would do the job, nevertheless.

Anyway…

You are probably saying: Ok, now I want one of those, how can I get them?

Create them!

Creating your C static library: a tutorial.

With the sole purpose of teaching how to create a static library (and later on, a dynamic library), I already have a folder with some files created previously.

Now open your favorite editor, and start creating!

The basic tool used to create static libraries is a program called 'ar', for 'archiver'. This program can be used to create static libraries (which are actually archive files), modify object files in the static library, list the names of object files in the library, and so on. In order to create a static library, we can use a command like this:

ar rc statlib.a functions1.o functions2.o functions3.o

Lets run that command:

This command creates a static library named ‘statlib.a’ and puts copies of the object files “functions1.o”, “functions2.o” and “functions3.o” in it. If the library file already exists, it has the object files added to it, or replaced, if they are newer than those inside the library. The 'r' flag tells it to replace older object files in the library, with the new object files.

Let’s ignore the fact that it seems the command didn’t do anything. Keep reading.

After an archive is created, or modified, there is a need to index it, as we said before. This index is later used by the compiler to make sure that the order of the symbols in the library won’t matter during compilation, as well as speeding up said process. The command used to create or update the index is called 'ranlib', and is invoked as follows:

ranlib statlib.a (write this on your text editor).

Ok, now we have our new static library, yay!

Creating your C dynamic library: another tutorial.

This tutorial might be a little bit familiar to you because it involves a lot of the above process (Oh, no, why?). Both dynamic and static are created in a similar way, that’s not an opinion, but a fact.

Compile a list of object files, then insert them all into a shared library file.

Simple but, there are two major differences:

  • Shared libraries work with memory. When the object files are generated, we have no idea where in memory they will be inserted in a program that will use them. We need that all jump calls and subroutine calls will use relative addresses, and not absolute addresses (because everyone using the same library problably won’t have the same memory address, duh). Plus, compiler flag that will cause this type of code to be generated: '-fPIC' or '-fpic'.
  • Unlike a static library, a shared library is not an archive file (say, what?). It has a format that is specific to the architecture for which it is being created and we need to use the compiler to generate the library, and tell it that it should create a shared library, not a final program file. This is done by using the '-G' flag with some compilers, or the '-shared' flag with other compilers.

Finally, or what I should have started in the first place: how to actually create it.

gcc -fPIC -c functions1.c
gcc -fPIC -c functions2.c
gcc -fPIC -c functions3.c
gcc -shared dynlib.so functions1.o functions2.o functions3.o

The first three commands compile the source files with the PIC option, so they will be suitable for use in a shared library . The last command asks the compiler to generate a shared library.

Now you need toexport LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATHfor your program to know where to look for those library files adding then that location to your environment variable LD_LIBRARY_PATH.

That should do the trick.

Now I have them, how do I use them?

Stacic Library.

Simply, by adding the library’s name to the list of object file names given to the linker, using a special flag, normally '-l'.

gcc main.c -L. -lstatlib -o prog

This will create a program using object file “main.o”, and any symbols it requires from the “statlib” static library.

Note the usage of the '-L' flag - this flag tells the linker that libraries might be found in the given directory ('.', refering to the current directory), in addition to the standard locations where the compiler looks for system libraries.

Dynamic Library.

In order to open and load the shared library, one should use the dlopen() function. It is used this way:

#include <dlfcn.h> / * define dlopen (), etc. * /
.
.
void * lib_handle; / * open library handle * /
lib_handle = dlopen ("/ full / path / to / library", RTLD_LAZY);
if (! lib_handle) {
fprintf (stderr, "Error during dlopen ():% s \ n", dlerror ());
output (1);
}

The dlopen() function gets two parameters. One is the full path to the shared library. The other is a flag defining whether all symbols refered to by the library need to be checked immediatly, or only when used. In our case, we may use the lazy approach (RTLD_LAZY) of checking only when used. The function returns a pointer to the loaded library, that may later be used to reference symbols in the library. It will return NULL in case an error occured. In that case, we may use the dlerror() function to print out a human-readable error message, as we did here.

After we have a handle to a loaded shared library, we can find symbols in it, of both functions and variables. We need to define their types properly, and we need to make sure we made no mistakes. The compiler won’t be able to check those declarations, so we should be extra carefull when typing them.

The final step is to close down the library, to free the memory it occupies. This should only be done if we are not intending to use it soon. If we do — it is better to leave it open, since library loading takes time. To close down the library, we use something like this:

dlclose(lib_handle);

This will free down all resources taken by the library (in particular, the memory its executable code takes up).

Finally, the dynamic loading library gives us the option of defining two special functions in each library, namely _init and _fini. The _init function, if found, is invoked automatically when the library is opened, and before dlopen() returns. It may be used to invoke some startup code needed to initialize data structures used by the library, read configuration files, and so on.

Now you’ve got too much on your plate about C libraries, haven’t you?.

Hope it did you well and see you soon!

--

--