C6000 Dynamic Linking

From Texas Instruments Wiki
Jump to: navigation, search


The C6000 Code Generation Tools support dynamic linking, provided you build with EABI. If you are not already familiar with the limitations of EABI support in the C6000 compiler, please see EABI Support in C6000 Compiler.


Motivation and Background

Static vs. Dynamic Linking

Static linking is the traditional process of combining relocatable object files and static libraries into a static link unit: either an ELF executable file (.exe) or an ELF shared object (.so). Within this article, we use the term object to refer generically to either.

Code Size Reduction

A program consists of exactly one executable file (also commonly known as a client application) and any additional shared objects (aka libraries) that it depends on to satisfy any undefined references. If multiple executables depend on the same library, they can share a single copy of its code (hence the “shared” in “shared object”), thereby significantly reducing the memory requirements of the system.

A dynamic shared object, as the name implies, can be shared among several applications that may be running one-at-a-time in a single threaded environment, or at the same time in a multi-threaded environment. Rather than making a separate copy of the dynamic shared object code in memory for each application that needs to use it, a single version of the code can reside in one location (like ROM) where references to its functions can be resolved as the executables and other dynamic shared objects that use it are loaded and dynamically linked.

Binding Time

In a conventionally linked static executable, symbols are bound to addresses and library code is bound to the executable at link-time, so the library that the executable is bound to at link-time is the one that it will always use, regardless of changes or defect fixes that are made to the library.

In a static shared library, symbols are still bound to addresses at link-time, but the library code is not bound to the executable that uses the library until run-time.

With a dynamic shared library, decisions about binding library symbols to addresses and resolving symbol references between a dynamic shared library and the other objects that use it (or are used by it): these decisions are delayed until actual load-time. This allows the user to load a shared library when its services are needed, and unload it when its services are not needed. Thus, making more effective use of limited target memory space.

Modular Development

Dynamically linking encourages modular development. The interface for a dynamic shared object is explicitly defined via the importing and exporting of global symbols. A cleanly defined interface for a dynamic shared object will tend to improve the cohesion of the code that implements the services provided by a given DLL.

Recommended Reading

For a more detailed discussion of the benefits and disadvantages of using dynamic executables and dynamic shared objects, please refer to available literature on the subject, including John R. Levine's excellent book Linkers & Loaders (ISBN-13: 978-1-55860-496-4).

Dynamic Linking with the C6000 Code Generation Tools

The C6000 Compiler Tools provide support for two dynamic linking models: the Linux Dynamic Linking Model, and the Lightweight (Bare Metal) Dynamic Linking Model.

Embedded Application Binary Interface (EABI) Required

Please be aware that all software components in a system that uses the Lightweight Dynamic Linking Model or the Linux Dynamic Linking Model must use the EABI Runtime Model. The EABI Runtime Model can be specified using the --abi=eabi option.

%> cl6x --abi=eabi ... 

The compiler will generate obejct files in ELF object file format when EABI is specified. The C6000 CGT makes use of the industry-standard dynamic linking mechanisms that are detailed in the ELF Specification (Tool Interface Standard).

Specifically, for OMAP developers that are using devices with ROMed code, you must be sure that the ROMed code has been built using the EABI model. Similarly, if your application uses BIOS, you need to ensure that the BIOS version that you are using has been built using the EABI model. Finally, for developers that are relying on Code Composer Studio (CCS) to run and/or debug their application, you must use CCS version 4 or later (CCS ELF support begins in CCS version 4).


In the following sections, we will take up each dynamic linking model in some detail, explaining what situation(s) it is designed to support and how it can be used.

Lightweight (Bare Metal) Dynamic Linking Model

The Lightweight Dynamic Linking Model is intended to support an application environment in which a Real Time Operating System (RTOS) is loaded and running on a DSP processor.

Consider a Static DSP Application

First, consider an example of the Bare Metal Runtime Model. If the RTOS and the applications that use it are built as a single static executable, the resulting system will look something like this:

RTOS example.jpg

In this scenario, the DSP application is a single static executable file that contains:

  • the RTOS,
  • any required driver functions, and
  • all tasks that the application needs to carry out

All of the addresses in the static executable are bound at link-time, they cannot be relocated at load-time. Execution of the DSP application will proceed from the application's entry point.

Make it Dynamic

In a dynamic linking system the user can build dynamic modules that are loaded and relocated by a dynamic loader at run time. The dynamic loader can also perform dynamic symbol resolution: resolving symbol references from dynamic modules with the symbol definitions from other dynamic modules.

The Lightweight Dynamic Linking Model supports the creation of such dynamic modules. In particular, it supports creating dynamic executables and dynamic libraries.

  • A Dynamic Executable:
  • Will have a dynamic segment
  • Can export/import symbols
  • Is optionally relocatable (Can contain dynamic relocations)
  • Must have an entry point
  • Can be created using -c/-cr compiler options
  • Must use far DP or absolute addressing to access imported data, but can use near DP addressing to access its own data
  • A Dynamic Library:
  • Will have a dynamic segment
  • Can export/import symbols
  • Is relocatable
  • Does not require an entry point
  • Cannot be created using -c/-cr compiler option
  • Must use far DP or absolute addressing to access its own data as well as data that it imports from other modules

GPPwRIDLplusDSPdlapp.jpg

If we convert the earlier RTOS example into a lightweight dynamic system, the RTOS part of the system is still built like an executable and is assumed to be loaded by traditional means (bootstrap loader) and set running on the DSP by a host application.

Application tasks can be built as Dynamically Linked Libraries (DLLs) that can then be loaded by the dynamic loader and linked against the RTOS that is already loaded and running on the DSP. In this scenario, the RTOS is a bare metal dynamic executable and is also sometimes referred to as the "base image". The DLL is a dynamic library that is dynamically linked against the RTOS base image at load time.

In the above scenario, the dynamic loader is running on a General Purpose Processor (GPP) and is able to interact with the user to load and unload DLL components onto the DSP as needed. Another scenario is to load the dynamic loader as part of the RTOS "base image" executable:

DSPwRIDLexe.jpg

An example of this scenario is the reference implementation of the C6000 dynamic loader which you can download from the TI Gforge site. It is written to be built and run as a dynamic executable base image itself. It contains an interactive user interface which allows the user to identify their own base image, load and link dynamic libraries against that base image, and then execute a function that is defined in the dynamic library. For more details about the reference implementation of the dynamic loader, please see the Dynamic Loader wiki article.

Symbol Resolution

A DLL in a lightweight dynamic DSP application can utilize services that are provided by the RTOS. These functions in the RTOS that are callable from a DLL must be "exported" when the RTOS is built. Similarly, a DLL must "import" any function or data object symbols that are part of the RTOS when the DLL is built.

Exported symbols in a dynamic object, 'dynA', are available for use by any other dynamic object that links with 'dynA'. When a dynamic object "imports" a symbol, it is asserting that when the object is loaded, the definition of that symbol must be contained in a dynamic object that is already loaded or one that is required to be loaded. The symbol importing and exporting mechanisms lie at the core of how dynamic objects are designed to interact with each other. This subject is explored in more detail in the Symbol Import/Export section below.


So now that we know what a lightweight dynamic DSP application looks like, how do we build one?

Building a Dynamic Executable

A dynamic executable is essentially a statically linked executable file that contains extra information in the form of a dynamic segment that can be used when a dynamic library is loaded and needs symbols that are defined in the dynamic executable.

In the sample system described here, the reference implementation of the dynamic loader (dl6x.6x) is built as a base image. This base image also contains the basic I/O functions and some runtime support (RTS) functions. The base image should export these I/O and RTS functions. These symbols will then become available to a dynamic library when it is dynamically loaded and linked against the dynamic executable.

Exporting Symbols

To accomplish exporting of symbols, there are two methods available:

  • Recommended: Declare exported symbols explicitly in the source of the dynamic executable using "__declspec(dllexport)".
For example, if you want to export "exp_func" from the dynamic executable, you can declare it in your source as follows:
__declspec(dllexport) int exp_func();
  • Use "--export" option at link time. You can specify one or more symbols to be exported with "--export=<symbol>" on the linker command line or in a linker command file.
For example, you could export exp_func() at link time with:
%> cl6x --abi=elfabi ... -z --dynamic=exe --export=exp_func ...
In general, to build a dynamic executable, you must specify "--dynamic=exe" or "--dynamic" on the linker command line or in a linker command file (LCF).
Consider the build of the dl6x.6x file described in the Dynamic Loader wiki article as an example of how to build a dynamic executable or "base image":
%> cl6x --abi=elfabi ... -z *.obj ... --dynamic --export=printf ...
In this example, the --dynamic option indicates that the result of the link is going to be a dynamic executable. The --export=printf indicates that the printf() RTS function is exported by the dynamic executable and, if imported by a dynamic library, can be called at run-time by the functions defined in the dynamic library.

Building a Dynamic Library

A dynamic library is a shared object that contains dynamic information in the form of a dynamic segment. It is relocatable and can import symbols from other ELF dynamic objects that it links against and it can also export symbols that it defines itself.

Importing / Exporting Symbols

Importing and exporting of symbols can be accomplished in two ways, similarly to how it can be done in dynamic executables:

  • Recommended: Declare exported and/or imported symbols explicitly in the source code of the dynamic library using "__declspec(dllexport)" for exported symbols and "__declspec(dllimport)" for imported symbols.
For example, if I want to export a function, red_fish(), and import another function, blue_fish(), I could specify this in a source file as follows:
__declspec(dllexport) long red_fish();
__declspec(dllimport) int blue_fish();
  • You can also specify symbols to be imported or exported on the linker command line (or in a linker command file) using "--import=<symbol>" or "--export=<symbol>".
So at link time, you might say:
%> cl6x --abi=elfabi ... -z --dynamic=lib --export=red_fish --import=blue_fish blue.dll -o red.dll
This informs the linker that the definition of red_fish() will be in the red.dll dynamic library and that we can find and use the definition of blue_fish() in blue.dll.

In general, to build a dynamic library, you must specify "--dynamic=lib" on the linker command line or in a linker command file (LCF). In addition, if any symbols are imported from other dynamic objects, then those dynamic objects must be specified on the linker command line when the dynamic library is built. This is sometimes referred to as static binding.

A Simple Example - hello.dll

This section describes a simple walk-through of the process used to build, load, and run a function that is defined in a dynamic library.

  • First compile this simple "Hello World" source:
hello.c:

#include <stdio.h>
__declspec(dllexport) int start();
int start()
{
   printf("Hello World\n");
   return 0;
}
  • Then build a dynamic library called "hello.dll":
%> cl6x -mv6400+ --abi=elfabi hello.c -z --import=printf --dynamic=lib -o hello.dll dl6x.6x -e start
  • Now, load the dynamic loader using a loader that supports C6x ELF executable object files. Then start the dynamic loader running. You will see the "RIDL" prompt come up and then you need to issue the following commands:
RIDL> base_image dl6x.6x
RIDL> load hello.dll
RIDL> execute

You should see the "Hello World" message displayed and then control will return to the "RIDL" prompt. To terminate the dynamic loader you can enter the "exit" command from the "RIDL" prompt.

Summary of Compiler and Linker Options

This is a brief summary of the compiler and linker options that are related to support for the Lightweight Dynamic Linking Model in the C6000 CGT.


Compiler Options:

  • --abi=eabi - specifies that EABI runtime model is to be used.
  • --visibility=<default visibility> - specifies a default visibility to be assumed for global symbols. Please see Symbol Import/Export section for more details.
  • --import_undef - specifies that all global symbol references that are not defined in a module are imported.
  • --import_helper_functions - specifies that all compiler generated calls to RTS functions are treated as calls to imported functions. Please see Symbol Import/Export section for more details.


Linker Options:

  • --dynamic[=exe] - specifies that the result of a link will be a lightweight dynamic executable.
  • --dynamic=lib - specifies that the result of a link will be a dynamic library.
  • --export=<symbol> - specifies that <symbol> is exported by the ELF object that is generated for this link.
  • --fini=<sym> - specifies the symbol name of the termination code for the output file currently being linked.
  • --import=<symbol> - specifies that <symbol> is imported by the ELF object that is generated for this link.
  • --init=<sym - specifies the symbol name of the initialization code for the output file currently being linked.
  • --rpath=<dir> - will add a directory to the beginning of the dynamic library search path.
  • --runpath=<dir> - will add a directory to the end of the dynamic library search path.
  • --soname=<string> - specifies shared object name to be used to identify this ELF object to the any downstream ELF object consumers.

Linux Dynamic Linking Model

The Linux Dynamic Linking Model supported in the C6000 CGT constitutes full-fledged dynamic linking capability. It provides mechanisms for building dynamic shared objects that can be shared in a multi-threaded environment by two or more applications.

LinuxonDSP.jpg

In the example above, you can see that the code for libc.so resides in Read-Only (RO) memory, but it can be run by either application. However, each application must create and maintain its own copy of the Read/Write (RW) data from libc.so.

In terms of underlying mechanisms, the major difference between the Lightweight Dynamic Linking model and the Linux Dynamic Linking model is that the Linux Dynamic Linking model provides a means of managing multiple data segment base pointers (DPs). It is this mechanism that allows a Linux DSO to be shared between multiple Linux applications that may be running at the same time.

Building a C6x Linux Executable

To build a C6x Linux executable, the source code should be compiled using the --linux compiler option and linked using the --sysv linker option:

%> cl6x --abi=eabi --linux <src_files>.c
%> cl6x -z <src_files>.obj <libs>.lib --sysv -o a.out

The resulting a.out file will be a C6x Linux executable.

Building a C6x Linux DSO

To build a C6x Linux DSO, the source should be compiled using the following compiler options:

  • --linux - generate code for linux
  • --pic - generate position independent code

and linked using the following linker options:

  • --sysv - generate SysV ELF output file
  • --shared - generate a dynamically shared object

For example:

%> cl6x --abi=eabi --linux --pic <src_files>.c
%> cl6x -z <src_files>.obj <libs>.lib --sysv -o codec.so

The resulting object file, codec.so, will be a C6x Linux Dynamic Shared Object.


Summary of Compiler and Linker Options

This is a brief summary of the compiler and linker options that are related to support for the Linux Dynamic Linking Model in the C6000 CGT.

Compiler Options:

  • --abi=eabi - specifies that EABI runtime model is to be used.
  • --linux - when specified, this option will set all necessary options to build a module for Linux.
  • --pic[={near|far}] - specifies that the compiler will generate position independent code for use in a shared library. Such code will access all constant addresses through a Global Offset Table (GOT).
  • --dsbt - specifies that compiler will assume the presence of a Data Segment Base Table (DSBT) and will load the DP from the DSBT table for every function that is marked exported.
  • --visibility=<default visibility> - specifies a default visibility to be assumed for global symbols. Please see Symbol Import/Export section for more details.
  • --import_undef - specifies that all global symbol references that are not defined in a module are imported.
  • --import_helper_functions - specifies that all compiler generated calls to RTS functions are treated as calls to imported functions. Please see Symbol Import/Export section for more details.


Linker Options:

  • --dsbt_index=<int> - request a specific Data Segment Base Table (DSBT) index to be associated with the current output file. If the DSBT model is being used, and the user does not request a specific DSBT index for the output file, then a DSBT index will be assigned to the module at load time.
  • --dsbt_size=<int> - specifies the size of the Data Segment Base Table (DSBT) for the current output file, in words. If the DSBT model is being used, this option can be used to override the default DSBT size (8 words).
  • --export=<symbol> - specifies that <symbol> is exported by the ELF object that is generated for this link.
  • --fini=<sym> - specifies the symbol name of the termination code for the output file currently being linked.
  • --import=<symbol> - specifies that <symbol> is imported by the ELF object that is generated for this link.
  • --init=<sym - specifies the symbol name of the initialization code for the output file currently being linked.
  • --rpath=<dir> - will add a directory to the beginning of the dynamic library search path.
  • --runpath=<dir> - will add a directory to the end of the dynamic library search path.
  • --shared - generate an ELF dynamic shared object (DSO).
  • --soname=<string> - specifies shared object name to be used to identify this ELF object to the any downstream ELF object consumers.
  • --sysv - specifies that the linker will produce a SysV ELF output file.

Symbol Import/Export

In a dynamic linking system the user can build dynamic modules that are loaded and relocated by a dynamic loader at run time. The dynamic loader can also perform dynamic symbol resolution: resolve references from dynamic modules with the definitions from other dynamic modules.

Only symbols explicitly imported or exported have dynamic linkage and participate in dynamic linking. Normal global symbols don't participate in dynamic symbol resolution. A symbol is exported if it is visible from a module during dynamic symbol resolution. A dynamic object is a dynamic library (DLL or DSO) or a dynamic executable. The dynamic object is also called a module in this readme. Such a dynamic object imports a symbol when its symbol references are resolved by definitions from another dynamic object. The dynamic object that has the definition and makes it visible is said to export the symbol.

First, let's have a look at ELF symbols and see how the symbol attributes are used to control importing and exporting global symbols.

ELF Symbols

ELF symbols have two attributes that contribute to static and dynamic symbol binding:

  • Symbol Binding - symbol’s scope with respect to other files
  • Symbol Visibility - Symbol’s scope with respect to other run-time components (EXE/DLL/DSO etc)

A more detailed discussion of the symbol binding and visibility characteristics, provided below, can be found in the ELF Specification (Tool Interface Standard).

Symbol Binding Attribute Values

  • STB_LOCAL
    • Indicates that a symbol is not visible outside the module where it is defined
    • Any local references to the symbol will be resolved by the definition in the current module
  • STB_GLOBAL
    • Indicates that a symbol is visible to all files being combined during the link step
    • Any references to a global symbol that are left unresolved will result in a link-time error
  • STB_WEAK
    • Indicates that a symbol is visible to all files being combined during a link step
    • Global symbol definition takes precedence over corresponding weak symbol def

ELF Symbol Visibility

GLOBAL/WEAK symbols can have any of the following visibility attributes:

  • STV_DEFAULT
    • Symbol definition is visible outside the defining component
    • Symbol definition can be preempted
    • Symbol references can be resolved by definition outside the referenced component
  • STV_PROTECTED
    • Symbol definition is visible outside the defining component
    • Symbol definition cannot be preempted
    • Symbol reference must be resolved by a definition in the same component
  • STV_HIDDEN
    • Symbol definition is not visible outside its own component
    • Symbol reference must be resolved by a definition in the same component

Controlling Import/Export of Symbols

Symbols can be imported/exported by using:

  • Source Code Annotations
  • ELF Linkage Macros
  • Compiler Options
  • Linker Options

Source Code Annotations (Recommended)

A global symbol can be imported or exported by adding a __declspec() symbol annotation to the source file.

  • Export Using __declspec(dllexport)
 __declspec(dllexport) int foo() { }
  • __declspec(dllexport) can be applied to both symbol declarations and symbol definitions
  • Import Using __declspec(dllimport)
 __declspec(dllimport) int bar();
  • __declspec(dllimport) can be applied to a symbol declaration
  • The compiler will generate a warning if __declspec(dllimport) is applied to a symbol definition
  • Typically an API is exported by a module and is imported by another module. __declspec() can be added to the API header file
  • The linker uses the most restrictive visibility for symbols.
For example, consider the following:
  • if foo() is declared with __declspec(dllimport) in a.c, and
  • if foo() is declared plain (no __declspec()) in b.c, and
  • if a.c and b.c are compiled into ab.dll
Then, the symbol, foo, will not be imported in ab.dll and the linker will report an error indicating that the reference to foo() is unresolved.
  • Use __declspec() in header files to avoid link time errors
  • Some of the benefits of using the __declspec() approach include:
  • It enables the compiler to generate more optimal code
  • The optimizer will not optimize out exported symbols
  • The source code becomes a self-documenting in specifying the API for a given module, making it easier to read and maintain.
  • It can be used in both the Linux Dynamic Linking Model and the Lightweight (Bare Metal) Dynamic Linking Model

Import/Export Using ELF Linkage Macros (elf_linkage.h)

The C6000 compiler now provides a header file, elf_linkage.h in the include sub-directory of the installed toolset, which defines several macros that can be used to control symbol visibility:

  • TI_IMPORT <symbol declaration>
This macro imports the declared symbol. The TI_IMPORT macro cannot be applied to symbol definitions.
TI_IMPORT int foo(void);
extern TI_IMPORT long global_variable;
  • TI_EXPORT <symbol definition>|<symbol declaration>
This macro exports the symbol that is being declared or defined. The source module that makes use of this macro must contain a definition of the symbol.
TI_EXPORT int foo(void);
TI_EXPORT long global_variable;
  • TI_PATCHABLE <symbol definition>
This macro makes the definition of the symbol visible outside of the source module that uses it. Other modules can import the defined symbol. Also, a reference to the symbol can be patched (or re-directed) to a different definition of the symbol if needed. The compiler will generate an indirect call to a function that has been marked as patchable. This technique is also sometimes called symbol preemption.
TI_PATCHABLE int foo(void);
TI_PATCHABLE long global_variable;
  • TI_DEFAULT <symbol definition>|<symbol declaration>
This macro specifies that the symbol in question can be either imported or exported. The definition of the symbol is visible outside the module. Other modules can import the symbol definition. Any references to the symbol can also be patched.
  • TI_PROTECTED <symbol definition>|<symbol declaration>
This macro specifies that the qymbol in question is visible outside of the module. Other modules can import the symbol definition. However, a reference to the symbol can never be patched (symbol is non-preemptable).
  • TI_HIDDEN <symbol definition>|<symbol declaration>
The definition of the symbol is not visible outside the module that defines it.

Import/Export Using Compiler Options

The following compiler options can be used to control the symbol visibility of global symbols. The symbols using source code annotations to control the visibility are not affected by these compiler options.

  • --visibility=<default visibility> option
The --visibility option can be used to specify the default visibility for global symbols. This option does not affect the the visibility of symbols that use the __declspec() or TI_xxx macros to specify a visibility in the source code.
The <default visibility> is one of the following:
  • hidden - Global symbols are not imported or exported. This is the default compiler behavior.
  • fhidden - All function definitions are hidden. All other kinds of global symbols are imported or exported.
  • default - All global symbols are imported, exported, and patchable.
  • protected - All global symbols are exported
  • --import_undef option
The --import_undef option makes all of the global symbol references imported. This option can be combined with the --visibility option. For example, the following option combination will make all definitions exported and all references imported:
--import_undef --visibility=protected
Note that --import_undef takes precedence over the --visibility option.
  • --import_helper_functions option
The compiler will generate calls to functions that are defined in the RTS library. For example, to perfomr unsigned long division in user code, the compiler generates a call to __c6xabi_divul (_divul in COFF ABI). Since there is no declaration and the user does not call these functions directly, the __declspec() annotation cannot be used. This prevents the user from importing such functions from the RTS library that is built as a dynamic library. To address this issue, the compiler supports the --import_helper_functions option. When specified on the compiler command line, for each RTS function that is called by the compiler, that function symbol will be imported.

Import / Export Using Linker Options

To import or export a symbol when the source code can not be updated with a __declspec() annotation, the following linker options can be used:

  • --import=<symbol> option
This option will add <symbol> to the dynamic symbol table as an imported reference. At link-time, the static linker will search through any object libraries that are included in the link to make sure that a definition of <symbol> is available.
If a definition of <symbol> is included in the current link, then the --import option is ignored with a warning.
  • --export=<symbol> option
This option will add <symbol> to the dynamic symbol table as an exported definition. At link-time, if the are any objects that contain an unresolved external reference to <symbol> when the object that exports <symbol> is encountered, then the object that contains the exported definition is included in the link.
If the --export=<symbol> option is used on the compile of an object that does not have a definition of <symbol> in it, then the copmiler will generate an error.

NOTE: The --import and --export options are only available under the lightweight dynamic linking model. They cannot be used when building a Linux executable or DSO.

Symbol Preemption

Symbol preemption is the act of overriding a symbol definition in a dynamic module using a definition of the symbol from a different module.

When the runtime loader loads a component, all symbols within the component that have default visibility are subject to preemption by symbols of the same name in components that are already loaded. Since the main program image is always loaded first, none of the symbols it defines will be preempted.


Consider an example:

  • Initially cd.dll calls its own version of foo()

LightweightPreemption1.jpg


  • Even if a dynamic executable uses ab.dll and cd.dll:
%> cl6x --abi=eabi <exe_sources> -z --dynamic ab.dll cd.dll -o my.exe
cd.dll will still call its own definition of foo()

LightweightPreemption2.jpg


  • If we declare cd.dll's foo() to be patchable, then it will call ab.dll's version of foo()

LightweightPreemption3.jpg

We say that the definition of foo() in ab.dll preempts the definition of foo() in cd.dll for the call to foo() in cd.dll.

FAQ: Dynamic Linking

What is the DSBT model and how is it used?

DSBT stands for Data Segment Base Table. It is a mechanism for managing the content of the static base pointer (also commonly known as the DP) during execution of a dynamic application. The Linux dynamic linking model relies on the DSBT mechanism to facilitate sharing of dynamic shared objects in a dynamic system.

A Linux dynamic system can include multiple dynamic processes or applications. A dynamic shared object (DSO) can be shared among some proper subset of the dynamic processes that are executing at a given time. There is only one copy of the DSO's code which is loaded into RO memory. Each application that uses a DSO makes its own copy of the DSO's RW data segment.

Physically, the DSBT is an array of pointers. The size of the array is determined at static link time. The DSBT must be large enough to store a static base pointer for one dynamic executable and as many dynamic shared objects as there are in the dynamic system. Each DSO in the system is assigned to a specific array element in the DSBT.

When a dynamic executable calls a function that has been imported from a dynamic shared object, the static base pointer must be managed. At the call site in the dynamic executable, the DP register contains the static base pointer for the dynamic executable, but when the call reaches its destination, the called function must transition the content of the DP register so that the dynamic executable's static base pointer is preserved during the execution of the imported function, but it must also load the DSO's static base pointer into the DP register. This action is performed on arrival into the DSO function:

 push DP          ; save static base pointer of caller
 load DSO's static base ptr value from DSBT, DP
 <function body>
 pop  DP          ; restore static base pointer of caller

This mechanism allows each dynamic application in the system to keep its own version of the data that belongs to a shared DSO.

Related Topics, Articles, and Links

For more detailed background on topics that are closely related to the dynamic linging support in the C6000 CGT, please consult the following articles, documents, and/or web links:

  • C6000 EABI Specification
  • ELF Specification (Tool Interface Standard) - provides details about the ELF object file format and industry-standard mechanisms in ELF that support dynamic linking.
  • C6000 Dynamic Loader - a wiki article about the reference implementation of the dynamic loader.
  • Data Segment Base Table (DSBT) - a forthcoming wiki article that takes a closer look at the underlying mechanisms that allow management of multiple data segment base pointers (DPs) in a multi-threaded environment. Not yet available!
  • DSO Initialization and Termination - a forthcoming wiki article that describes initialization and termination of global objects in a dynamic C++ application. Not yet available! Many of these details are already available in the System V Application Binary Interface.
  • Linkers & Loaders by John R. Levine - this book contains useful background about some of the mechanisms used to implement the dynamic linking support in the C6000 CGT, including:
  • Global Offset Table
  • Procedure Linkage Table
  • Position Independent Code