Loading and Linking Shared Libraries from Applications
Up to this point, we have discussed the scenario in which the dynamic linker loads and links shared libraries when an application is loaded, just before it executes. However, it is also possible for an application to request the dynamic linker to load and link arbitrary shared libraries while the application is running, without having to link in the applications against those libraries at compile time.
Examples of Dynamic linking:
(1) Distributing software.
(2) Building high-performance Web servers.
Early Web servers generated dynamic content by using fork and execve to create a child process and run a “CGI program” in the context of the child.
However, modern high-performance Web servers can generate dynamic content using a more efficient and sophisticated approach based on dynamic linking.
The idea is to package each function that generates dynamic content in a shared library.
When a request arrives from a Web browser, the server dynamically loads and links the appropriate function and then calls it directly.
The function remains cached in the server’s address space, so subsequent requests can be handled at the cost of a simple function call.
This can have a significant impact on the throughput of a busy site.
Further, existing functions can be updated and new functions can be added at run time, without stopping the server.
Linux systems provide a simple interface to the dynamic linker that allows appli- cation programs to load and link shared libraries at run time.
related functions:
The dlopen function loads and links the shared library filename.
The external symbols in filename are resolved using libraries previously opened with the RTLD_ GLOBAL flag.
If the current executable was compiled with the -rdynamic flag, then its global symbols are also available for symbol resolution.
The flag argument must include either RTLD_NOW, which tells the linker to resolve references to external symbols immediately,
or the RTLD_LAZY flag, which instructs the linker to defer symbol resolution until code from the library is executed.
Either of these values can be or’d with the RTLD_GLOBAL flag.
The dlsym function takes a handle to a previously opened shared library and a symbol name, and returns the address of the symbol,
if it exists, or NULL otherwise.
The dlclose function unloads the shared library if no other shared libraries are still using it.
Figure 7.16 shows how we would use this interface to dynamically link our libvector.so shared library (Figure 7.5), and then invoke its addvec routine.
To compile the program, we would invoke gcc in the following way:
unix> gcc -rdynamic -O2 -o p3 dll.c -ldl
Shared libraries and the Java Native Interface
Java defines a standard calling convention called Java Native Interface (JNI) that allows “native” C and C++ functions to be called from Java programs.
The basic idea of JNI is to compile the native C function, say, foo, into a shared library, say foo.so.
When a running Java program attempts to invoke function foo, the Java interpreter uses the dlopen interface (or something like it) to dynamically link and load foo.so, and then call foo.
PIC (TODO)
summary
Linking can be performed at compile time by static linkers, and at load time and run time by dynamic linkers.
Linkers manipulate binary files called object files, which come in three different forms: relocatable, executable, and shared.
Relocatable object files are combined by static linkers into an executable object file that can be loaded into memory and executed.
Shared object files (shared libraries) are linked and loaded by dynamic linkers at run time,
either implicitly when the calling program is loaded and begins executing,
or on demand, when the program calls functions from the dlopen library.
The two main tasks of linkers are symbol resolution, where each global symbol in an object file is bound to a unique definition,
and relocation, where the ultimate memory address for each symbol is determined and where references to those objects are modified.
Static linkers are invoked by compiler drivers such as gcc.
They combine multiple relocatable object files into a single executable object file.
Multiple object files can define the same symbol, and the rules that linkers use for silently resolving these multiple definitions can introduce subtle bugs in user programs.
Multiple object files can be concatenated(fasten) in a single static library.
Linkers use libraries to resolve symbol references in other object modules.
The left-to- right sequential scan that many linkers use to resolve symbol references is another source of confusing link-time errors.
Loaders map the contents of executable files into memory and run the pro- gram.
Linkers can also produce partially linked executable object files with un- resolved references to the routines and data defined in a shared library.
At load time, the loader maps the partially linked executable into memory and then calls a dynamic linker, which completes the linking task by loading the shared library and relocating the references in the program.
Shared libraries that are compiled as position-independent code can be loaded anywhere and shared at run time by multiple processes.
Applications can also use the dynamic linker at run time in order to load, link, and access the functions and data in shared libraries.