The Mystery of Dynamically Linked or Statically Linked Executables

Hello readers, today I decided to explain a deep concept not usually discussed often because of the abstractions computer languages have created. But in the end, on a Linux/UNIX system, there is an executable binary file that can be either dynamically or statically linked. I hope this post find as many users as possible due to the fact that I could not find an easy explanation out there and i decided to write my own to share for the benefit of people that want to learn Linux/UNIX in general.

Enough, let’s dig into the subject…

In order to understand the subject we need to use a low level language like C or C++. For simplicity we are using C. If you don’t know, C and C++ are heavily used in low level program development, like the Linux Kernel.

Now, let’s first setup the environment to use a C compiler, which is required for this exercise. You are welcome to use a container for that, but for simplicity I will simply list the packages required on Ubuntu, but the same applies to all Linux distros all you have to do is install the C compiler the supported way.

In  Ubuntu you will simply run the two following commands:

sudo apt update
sudo apt install gcc

This will install gcc all the required dependencies. Now that you have the required software, we will create a directory called linking and cd into it with the following commands:

mkdir ~/linking
cd ~/linking

Now with your favorite editor create the following file named linktest.c with the following content:

#include <stdio.h>

void main() {
printf(“Hello There\n”);
}

Save the file and issue the following command to compile linktest:

gcc linktest.c -o linktest

If all goes well, the compiler produces an executable; now try to execute it with the following command:

./linktest

You should see the output of Hello There. If you reach this point everything is going according to plans, if you receive a different output of error, make sure all the steps listed above are completed without errors/compilation errors. C is very picky about syntax, so make sure you put exactly what’s listed above.

Now that we have an executable, type “ls -l” to see the properties of the file, on my system, the file is about 15k in size, relatively small. The executable, by default is compiled and dynamically linked to a set of system libraries. Let’s dig in details. Execute the following command to see all the dependent, dynamically linked libraries:

ldd linktest

Exept for the library versions, you should see an output similar to the following:

linux-vdso.so.1 (0x00007fffc4bfe000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x000072dd9707f000)
/lib64/ld-linux-x86-64.so.2 (0x000072dd972b2000)

Now, that you’ve reached this point, let’s explain dynamic linking and what it actually does. Any program in Linux is dependent on the libc, which is the standard runtime. You see it listed as libc.so.6. But you also see other files listed, in this case, I see linux-vdso because of the virtual layer I am using and ld-linux-x86 for the final kernel link.

When you execute the program, the kernel retrieves the necessary dependent executing calls to make the whole program run on the system.

Now, in order to better explain dynamic linking, let’s create the same executable with static linking. By default the compiler executed two steps, a compilation step into a .o type object and a final link step to produce the executable. In order to make a static linked executable, we have to instruct the compiler to include all the dependencies into the executable. Let’s now statically compile the executable with the following command:

gcc -static linktest.c -o static_linktest

If everything goes well, you will create an executable called static_linktest which will be bigger in size at the linktest one. Now execute ls -l to list the directory content, you should see an output similar to the following:

-rwxr-xr-x 1 devuser devgroup 15960 Jan 17 11:46 linktest
-rw-r–r– 1 devuser devgroup 63 Jan 17 11:46 linktest.c
-rwxr-xr-x 1 devuser devgroup 900352 Jan 17 11:58 static_linktest

Now, sizes will vary based on system versions, but one thing is clear, the static version is much bigger than the dynamic version. Let’s now execute the following command on the static executable:

ldd static_linktest

You should get a message that indicated that this is not a dynamic executable, which proves the point of the exercise.

A statically linked executable contains all the dependencies inside and does not require the external libraries like the dynamically linked one. Basically a portion of libc.6, ld-linux, and linux-vds0 are included (statically linked) in the file.

Now, the question should pop-up, why would I use one vs the other and when. For some of you, the answers will be self deduced, for the rest, the answers are coming in the next post…

Leave a Reply