Sharable libraries are files containing executable code and data. But on the contrary to ordinary executables, they are not to be run on their own; they are to be mapped in into a running program, which can then call functions from that library.
Let's follow in some detail what really happens when you want to make your very latest "Hello World" program.
Example: we'll write a minimalist "Hello World" in C, and compile it with gcc. The file hello_world.c contains:
Example: The temporary file hello_world.cpp, can be generated with the incantation
gcc -E -o hello_world.cpp hello_world.cThe resulting file hello_world.cpp then contains 2185 lines (on the alpha platform). The first few lines and look like this (interspersed with lots of empty lines)
Example: The temporary file hello_world.cpp, can be generated with the following incantation. Note that the last argument is the source file; so any previous steps are done here too.
gcc -S -O3 -o hello_world.s hello_world.cThe resulting file hello_world.s then contains 32 lines (on the alpha platform).
Example:
gcc -c -O3 -o hello_world.o hello_world.c file hello_world.o hello_world.o: COFF format alpha executable or object module not stripped - version 3.11-10File hello_world.o is 1448 bytes long.
Linking against a static library is nothing else than extracting the needed objects from the library, putting them next to the other object files, and replacing the symbolic references with addresses. Note that an object extracted from a library can itself need other objects, from the same or other libraries. That is the reason why objects must sorted inside each archive (either using ranlib on ancient systems, or using the -s flag for the archiver). That is also the reason why the order of the libraries on you command line is important.
Example: static loading of hello_world. Note that libc.a does not show up on the command line, because it is one of the few libraries gcc automatically adds for C program files.
gcc -static -o hello_world hello_world.cThe resulting executable (which runs by the way!) is 122880 bytes long, which is rather large for such a minimal program; this is of course because an important part of libc.a is included. You can reduces the size of the executable somewhat by stripping it; this is removing unneeded parts (like debugging symbols etc.) In this example, the size reduces to 90112 bytes. For static linking, the story ends here.
Linking against a shared library is a two step process. The first step happens only once, when you generate your executable. This step is very similar to the static loading process, except that the needed objects are not copied from the library. Only their existence is checked.
Example: dynamic loading of hello_world. Note that libc.so does not show up on the command line.
gcc -o hello_world hello_world.cThe resulting executable is of course much smaller: 24576 bytes. After stripping only 16384 bytes remain. But this executable cannot run on its own as it is incomplete. Therefore, its first action is to call the run-time loader. This is the second load step, and is performed each time the executable is run. The run-time loader now resolves any unsatisfied references against the shared libraries that were specified during link time. If that does not work, because shared libraries are no longer where they were originally, or if versions don't match, or if a library is erroneous, a run time link error occurs.
Advantages of shared libraries:
There are some disadvantages too:
Executables linked against shared libraries need to be linked further at run time. This means that those libraries need to be found at run time too. There are several mechanisms to obtain this behavior.
Conclusion: unless you know what you're doing, don't use LD_LIBRARY_PATH
For /freeware, it is recommended to:
No special options are needed since position independent code is the default.
-shared
Generate shared objects.
-x
Strip unneeded symbols.
-rpath <directory_of_sharable>
Set rpath to the place where the sharable will end up.
-no_excpt
Don't generate unneeded exception sections.
-expect_unresolved '*'
Ignore unresolved symbols in the shared object.
-allConvert a whole archive at once.
Use the archiver flags -crsvf if you use the GNU archiver. This is because the native ld does not recognize filenames longer than 14 characters in the archives index.
This can be done with the following type of script:
#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 ld -O3 -x -no_excpt -expect_unresolved '*' -rpath /freeware/gcc/alpha/lib -shared -o ${shared_library:-${static_library%%a}so} -all $1
No special options are needed since normal Mips code is position independent.
-shared
Generate shared objects.
-x
Strip unneeded symbols.
-rpath <directory_of_sharable>
Set rpath to the place where the sharable will end up.
-rdata_shared
Share readonly data among processes.
-allow_r5k_jump_at_eop -allow_jump_at_eop
Don't enable workarounds for certain processor problems, as we don't have these types at ESAT.
-n32
Set the ABI to -n32. This is very important!
-woff <list_of_numbers>
Switch off some irrelevant warnings.
-all
Convert a whole archive at once.
When the so_locations file is on a remote NFS mounted filesystem, and the remote machine is HPUX ld will hang indefinitely, due to a NFS locking problem. The only solution is to have so_locations locally, or otherwise link it to /dev/null.
This can be done with the following type of script:
#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 ld -x -allow_r5k_jump_at_eop -allow_jump_at_eop -n32 -woff 13 -rdata_shared -rpath /freeware/gcc/sgiN32/lib -shared -o ${shared_library:-${static_library%%a}so} -all $1
Usually, nothing is needed. If you want to be sure, add -pic
-shared
Generate shared objects.
-s
Strip unneeded symbols.
-rpath <directory_of_sharable>
Set rpath to the place where the sharable will end up.
-whole-archive
Convert a whole archive at once.
This can be done with the following type of script:
#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 ld -s -rpath /freeware/gcc/sol2/lib -shared -o ${shared_library:-${static_library%%a}so} -all $1
Usually, nothing is needed. If you want to be sure, add -pic
-shared
Generate shared objects.
-s
Strip unneeded symbols.
-rpath <directory_of_sharable>
Set rpath to the place where the sharable will end up.
-whole-archive
Convert a whole archive at once.
This can be done with the following type of script:
#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 ld -s -rpath /freeware/gcc/linux-i386/lib -shared -o ${shared_library:-${static_library%%a}so} -all $1
Usually, nothing is needed. If you want to be sure, add -pic
-shared
Generate shared objects.
-s
Strip unneeded symbols.
-rpath <directory_of_sharable>
Set rpath to the place where the sharable will end up.
-whole-archive
Convert a whole archive at once.
This can be done with the following type of script:
#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 ld -s -rpath /freeware/gcc/linux-sparc/lib -shared -o ${shared_library:-${static_library%%a}so} -all $1
-fPIC is needed
-b
Generate shared objects.
-s
Strip unneeded symbols.
+h <name_of_sharable>
Register the library.
This can be done with the following type of script:
Note that a workaround is needed, as the loader cannot convert static to shared libraries.#! /usr/bin/ksh # # Makes a shared library from a static one # static_library=$1; shared_library=$2 shared_library=${shared_library:-${static_library%%a}sl} mkdir -p o; cd o; ar -x ../$1; cd .. gcc -Wl,-b,-s,+h,/freeware/gcc/hppa/$shared_library -nostartfiles -nostdlib -o $shared_library ./o/*.o rm -rf o
Ultrix never had (and will never have) shared libraries, because it does not have a mmap() capable of mapping files.
On all Linux architectures, shared libs are pretty much the same as on Intel.
On BSD type platforms, the GNU loader is used. Take a look at the Linux-intel description above. On NetBSD-mips on particular, shared libraries are fully supported.
On WinNT/W2k, under Cygwin, shared libraries (the infamous DLL's) are fully supported. Use the GNU loader to create them. Not that windows DLL's are severely crippled, as the cannot contain static data. Windows does not know of any library paths neither, making it virtually impossible to maintain several versions of a library at the same time.
There is no clean platform independent way. You can try strings <executable> | grep lib.
On alpha and sgi you should do odump -Dl.
On sol2 and linux-* you should try ldd.
On hppa, use chatr.
Runtime loaders are complex things. Usually, you can pass options to it, by setting a shell variable (usually called _RLD_ARGS). Be careful, because these flags affect all processes you will create (including ls, less etc.); moreover, most options generate enormous amounts of output, directed straight to your /dev/tty, not standard output. If you need details, read the man page of the run-time loader.
The info files of gcc will tell you all about compilation options. The info files on ld will give you details on loader options, but remember that the GNU loader is not supported on all platforms.