Introduction

Anyone who has any experience in programming is used to call procedures that have been implemented elsewhere. For instance in Python we could import a bar function from a module named foo by writing something like from foo import bar. We are then able to call the procedure by typing something like bar().

We would like to have something similar but at object level.

Linking Objects

Objects are binary files intended for the machine. They are usually produced as the result of compilation by the compiler. For instance if we deal with Assembly source code, the compiler will get a .asm file with human readable information and will convert it into an object file made by binaries.

With the process of linking two object files we could create a relation within their binaries. For instance assume that we have two objects, namely objectA and objectB If we use a pseudo instruction like link objectA, objectB we are telling the linker to look at the objects and fill in the necessary dependencies. For instance in objectA we could have something that reads as “if you want to know what to do here go to objectB”. When this is found by the linker, this will go to objectB and take the necessary binaries. Therefore the output of the linker will be an object that has the binaries of objectA but with “go to this X object” replaced with the actual binaries found there. The result of objects linking is an executable file. Like objects also executable files are bunch of binaries intended for the machine.

Libraries

Now that linking of two objects has been touched, lets dive into the actual concepts of static and dynamic libraries. Those are nothing more then particular objects (actually indexed concatenation of objects) to be linked. From here on-wards read to libraries as binary files.

A Use case for libraries

To understand them better lets consider a potential use case. Suppose you ask a programmer to write a procedure for you to be used in your program. Such a programmer is willing to accept your request but only upon the payment of a little price. Furthermore she does not want to share the source code of the procedure. How can she do that?

She will give you the compiled object of its own procedure and you will call it as a kind of “service”. She will write her procedure in her desired programming language. Once done she will create from that a library .lib file (made of binaries) that she will hand to you.

You then write your program calling her procedure but without providing any other information on the actual inner working of the function. We just say to the compiler: “ I know I am calling something I did not define but be aware that the linker will receive an object with instructions on how to execute this procedure”. Therefore the compiler will create an object leaving a space that will be filled later by the linker.

Filling the void with libraries

Assume we are dealing with an Assembly .asm program. Suppose also that, during the compiling stage, the compiler finds some procedures that, although declared and called, have never been defined(implemented) into the program itself. For the sake of our argument, refer to them as “external procedures”.

As previously said creating the object file, the compiler will leave a space for the binaries that will have instructions on how the external procedures work. Once the object file (binaries) is created there is a space that has been left to be filled by the linker. The latter has two ways to fill such a space, namely: i) use all the binaries that define the behavior of the procedure ii) use a reduced number of binaries that contain just instructions on where to go to find the desired binaries for the actual execution of the procedure

The previous two alternatives represent respectively the concepts of static and dynamic libraries.

Static means that the object will be complemented with all the necessary binaries resulting in a standalone executable. On the other hand with dynamic libraries the executable created cannot be used as a standalone file as it depends on some other sources where the instructions for the procedures are going to be found.

Suppose we have a program myProg.asm with a structure like the following:

declare the signature of the EXTERNAL_PROCEDURE
_____ other code ____
call EXTERNAL_PROCEDURE
_____ other code ____

where we declare and call a procedure named EXTERNAL_PROCEDURE without never defining it.

Lets investigate the two ways to have a full program that is able to use such external procedure.

Static library (steps)

Assume we have a static library named myStaticLibrary.lib that holds all the binaries necessary to execute the procedure that we want to import into the object file created by myProg.asm. In order to inject the code into our program we link the compiled object with the static library. All the steps can be summarized as it follows.

1) Compile myProgram.asm into an object file

The compiler will see that inside the program there are external procedures not defined locally. The compiler leaves the space into the created object, say myProgram.obj, for later filling it with the necessary binaries.

2) Create the myStaticLibrary.lib file

Write a program with procedures that are going to be imported by other objects and create a library file out of it.

3) Link myProgram.obj with myStaticLibrary.lib to create a final executable myProgram.exe

The process of linking the .obj with a static library results into the creation of a standalone executable. This means that the space for the missing binaries that the compiler was not able to produce is filled with those found into the library. The output of the linker is in this case a .exe file that has all the information it needs to run the procedures embedded into it.

Dynamic libraries (steps)

In dynamic libraries the process is similar but conceptually different.

Suppose we have three files here, namely myProg.asm, myDynamicLibrary.lib and myDynamicLibrary.dll.

Note that also here we have a .lib file. But compared to the previous case these files have a conceptual difference. While in the static case it held all the binaries for the procedure, now its content is just informative of where to find the actual binary implementation of the procedure. Such a place holding the operational binaries of the procedure is myDynamicLibrary.dll.

Indeed, when using dynamic libraries the .lib file is used to tell just where to find the procedure rather then how to execute as in the static case.

The steps when using dynamic libraries are the followings:

1) Compile myProgram.asm into an object file

As in the static case. The compiler is not able, out of myProgram.asm alone, to create all the actual binaries needed to execute all the code. Inside the resulting object a to be filled later space is placed.

2) Create the myDynamicLibrary.lib and myDynamicLibrary.dll files

Here the .lib file is not as heavy as in the static case. Indeed, instead of having the procedure’s binaries, the .lib acts as a pointer to the .dll. It is the .dll that holds the binaries needed to execute the procedure.

3) Link myProgram.obj with myDynamicLibrary.lib to create a final executable myProgram.exe

In the linker stage we link the object file previously created with the .lib file. Note that no .dll is used in the linker stage. Having been said that in this case the .lib does not hold the binaries to execute the procedure we should not expect to have a final standalone executable file out of this process. This means that myProgram.exe needs to be able to access to myDynamicLibrary.dll while executing.

Conclusion

To conclude, we can say that with static libraries we insert the code at compile time while for dynamic libraries the necessary code is injected at runtime.

For the creation of a static library and its usage check the post here.