How shared objects are used
To understand how a program makes use of shared objects, let's first see the format of an executable and then examine the steps that occur when the program starts.
Related links
- Using libraries (BlackBerry PlayBook OS Programmer's Guide)
- dladdr()
- dlclose()
- dlerror()
- dlopen()
- dlsym()
- Dynamic Linking
In a typical system, a number of programs will be running. Each program relies on a number of functions, some of which will be standard C library functions, like printf(), malloc(), write(), etc.
- ELF format
QNX Neutrino uses the ELF (Executable and Linking Format) binary format, which is currently used in SVR4 Unix systems. ELF not only simplifies the task of making shared libraries, but also enhances dynamic loading of modules at runtime.
- ELF without COFF
Most implementations of ELF loaders are derived from COFF (Common Object File Format) loaders; they use the linking view of the ELF objects at load time. This is inefficient because the program loader must load the executable using sections. A typical program could contain a large number of sections, each of which would have to be located in the program and loaded into memory separately.
- The process
The diagram below shows the memory layout of a typical process. The process load segments (corresponding to text and data in the diagram) are loaded at the process's base address. The main stack is located just below and grows downwards. Any additional threads that are created will have their own stacks, located below the main stack. Each of the stacks is separated by a guard page to detect stack overflows. The heap is located above the process and grows upwards.
- Runtime linker
The runtime linker is invoked when a program that was linked against a shared object is started or when a program requests that a shared object be dynamically loaded. The runtime linker is contained within the C runtime library.
- Loading a shared library at runtime
- Symbol name resolution
When the runtime linker loads a shared library, the symbols within that library have to be resolved. The order and the scope of the symbol resolution are important. If a shared library calls a function that happens to exist by the same name in several libraries that the program has loaded, the order in which these libraries are searched for this symbol is critical. This is why the OS defines several options that can be used when loading libraries.