The program we will examine here is simple - it writes the characters hello world to the screen and exits. The regular program, helloworld-nolib. s, looks like this:
#PURPOSE: This program writes the message "hello world" and # exits # .include "linux.s" .section .data helloworld: .ascii "hello world\n" helloworld_end: .equ helloworld_len, helloworld_end - helloworld .section .text .globl _start _start: movl $STDOUT, %ebx movl $helloworld, %ecx movl $helloworld_len, %edx movl $SYS_WRITE, %eax int $LINUX_SYSCALL movl $0, %ebx movl $SYS_EXIT, %eax int $LINUX_SYSCALL
That's not too long. However, take a look at how short helloworld-lib is which uses a library:
#PURPOSE: This program writes the message "hello world" and # exits # .section .data helloworld: .ascii "hello world\n\0" .section .text .globl _start _start: pushl $helloworld call printf pushl $0 call exit
It's even shorter!
Now, building programs which use dynamic libraries is a little different than normal. You can build the first program normally by doing this:
as helloworld-nolib.s -o helloworld-nolib.o ld helloworld-nolib.o -o helloworld-nolib
However, in order to build the second program, you have to do this:
as helloworld-lib.s -o helloworld-lib.o ld -dynamic-linker /lib/ld-linux.so.2 \ -o helloworld-lib helloworld-lib.o -1c
Remember, the backslash in the first line simply means that the command continues on the next line. The option -dynamic-linker /lib/ld-linux.so.2 allows our program to be linked to libraries. This builds the executable so that before executing, the operating system will load the program /lib/ld-linux.so.2 to load in external libraries and link them with the program. This program is known as a dynamic linker.
The -lc option says to link to the c library, named libc.so on GNU/Linux systems. Given a library name, c in this case (usually library names are longer than a single letter), the GNU/Linux linker prepends the string lib to the beginning of the library name and appends .so to the end of it to form the library's filename. This library contains many functions to automate all types of tasks. The two we are using are printf, which prints strings, and exit, which exits the program.
Notice that the symbols printf and exit are simply referred to by name within the program. In previous chapters, the linker would resolve all of the names to physical memory addresses, and the names would be thrown away. When using dynamic linking, the name itself resides within the executable, and is resolved by the dynamic linker when it is run. When the program is run by the user, the dynamic linker loads the dynamic libraries listed in our link statement, and then finds all of the function and variable names that were named by our program but not found at link time, and matches them up with corresponding entries in the shared libraries it loads. It then replaces all of the names with the addresses which they are loaded at. This sounds time-consuming. It is to a small degree, but it only happens once - at program startup time.