Linked Libraries and their Functions
Lets start with a simple Hello World
#include <stdio.h>
int main(void)
{
printf("Hello, World!\n");
return 0;
}
To compile and execute from the shell
1
2
3
$ gcc -g hello.c -o hello
$ ./hello
Hello, World!
Now we all know that
- executing this program means the kernel loads this program, then executes in in the given context. But how is it able to do this?
printfis the function call that sends the string to thestdout. But we have included just the headerstdio.h, then where is the actual implementation ofprintf?
For these and more, we rely on libraries that have been created already. To find out which libraries are linked to an executable, we use the ldd command.
1
2
3
4
$ ldd ./hello
linux-vdso.so.1 (0x00007fffc7f24000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f259c820000)
/lib64/ld-linux-x86-64.so.2 (0x00007f259ca32000)
Lets look at what each of these shared objects are doing one by one
- linux-vdso
- libc
- ld-linux-x86-64
And to help us, lets take a look at the strace output of the hello program
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ strace ./hello
execve("./hello", ["./hello"], 0x7fffe8d00b60 /* 21 vars */) = 0
brk(NULL) = 0x7fffdd8c3000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffe60351d0) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=32952, ...}) = 0
mmap(NULL, 32952, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fb6df9c7000
close(3) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\360q\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
fstat(3, {st_mode=S_IFREG|0755, st_size=2029224, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fb6dfa00000
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32, 848) = 32
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0\t\233\222%\274\260\320\31\331\326\10\204\276X>\263"..., 68, 880) = 68
mmap(NULL, 2036952, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fb6df7d0000
mprotect(0x7fb6df7f5000, 1847296, PROT_NONE) = 0
mmap(0x7fb6df7f5000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fb6df7f5000
mmap(0x7fb6df96d000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7fb6df96d000
mmap(0x7fb6df9b8000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7fb6df9b8000
mmap(0x7fb6df9be000, 13528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fb6df9be000
close(3) = 0
arch_prctl(ARCH_SET_FS, 0x7fb6dfa01340) = 0
mprotect(0x7fb6df9b8000, 12288, PROT_READ) = 0
mprotect(0x7fb6dfa0b000, 4096, PROT_READ) = 0
mprotect(0x7fb6df9fd000, 4096, PROT_READ) = 0
munmap(0x7fb6df9c7000, 32952) = 0
fstat(1, {st_mode=S_IFCHR|0660, st_rdev=makedev(0x4, 0x2), ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
brk(NULL) = 0x7fffdd8c3000
brk(0x7fffdd8e4000) = 0x7fffdd8e4000
write(1, "Hello, World!\n", 14Hello, World!
) = 14
exit_group(0) = ?
+++ exited with 0 +++