mirror of
https://git.rtems.org/rtems-docs/
synced 2025-05-14 16:10:04 +08:00
user: Add a Dynamic Loader section.
This commit is contained in:
parent
789b0caad7
commit
8a73acb713
BIN
images/user/libdl-load.png
Normal file
BIN
images/user/libdl-load.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
39
images/user/libdl-load.puml
Normal file
39
images/user/libdl-load.puml
Normal file
@ -0,0 +1,39 @@
|
||||
'
|
||||
' Libdl Load Executable Object file
|
||||
'
|
||||
' Copyright (c) 2019 Chris Johns <chrisj@rtems.org>
|
||||
' All rights reserved.
|
||||
'
|
||||
@startuml
|
||||
start
|
||||
:dlopen;
|
||||
|
||||
if (check libraries ?) then (changed)
|
||||
:load libraries;
|
||||
else (no change)
|
||||
endif
|
||||
:load object;
|
||||
floating note left
|
||||
Searching of unreolved symbols
|
||||
continues until the remain symbols
|
||||
cannot be found in the global symbol
|
||||
table or libraries.
|
||||
end note
|
||||
while (unresolved symbols?) is (unresolved)
|
||||
if (search globals) then (found)
|
||||
:fix relocations;
|
||||
else (not found)
|
||||
endif
|
||||
if (search libraries ?) then (found)
|
||||
:load library object;
|
||||
floating note left
|
||||
If a symbol is found the library object file
|
||||
is load adding the symbol to the global
|
||||
symbol table and potentially adding more
|
||||
unresolved symbols.
|
||||
end note
|
||||
else (not found)
|
||||
endif
|
||||
endwhile (all searched)
|
||||
stop
|
||||
@enduml
|
42
images/user/libdl.ditaa
Normal file
42
images/user/libdl.ditaa
Normal file
@ -0,0 +1,42 @@
|
||||
'
|
||||
' Executable debugging : QEMU
|
||||
'
|
||||
' Copyright (c) 2018 Chris Johns <chrisj@rtems.org>
|
||||
' All rights reserved.
|
||||
'
|
||||
@startditaa
|
||||
|
||||
+----------------------------------------+
|
||||
/--------------------------\ | RTL (libdl) |
|
||||
| RTEMS File System | | |
|
||||
| | | +----------+ /---------------\ |
|
||||
| | /------->| archives |<--->| lib symbols | |
|
||||
| +---------------------+ | | | +----------+ \---------------/ |
|
||||
| | /etc/libdl.conf |-----+ | ^ |
|
||||
| +---------------------+ | | | | |
|
||||
| | | | | |
|
||||
| +---------------------+ | | | V |
|
||||
| | /lib/librtemscpu.a | | | | +-------------+ /-------------\ |
|
||||
| | /lib/librtemsbsp.a |-----/ /----->| link editor |<--->| symbols | |
|
||||
| | /lib/libc.a | | | | +-------------+ \-------------/ |
|
||||
| | /lib/libm.a | | | | ^ ^ |
|
||||
| | /lib/libgcc.a | | | | | | |
|
||||
| +---------------------+ | | | | V |
|
||||
| | | | | /---------------\ |
|
||||
| +---------------------+ | | | +----->| objects | |
|
||||
| | /app/foo.o |-------/ | | \---------------/ |
|
||||
| +---------------------+ | | | ^ |
|
||||
\--------------------------/ | | | |
|
||||
| | | |
|
||||
| | /------+--------\ |
|
||||
| +----->| unresolved | |
|
||||
| | | symbols | |
|
||||
| | \---------------/ |
|
||||
| | |
|
||||
+---------|------------------------------+
|
||||
|
|
||||
V
|
||||
/----------------------------------\
|
||||
| target memory |
|
||||
\----------------------------------/
|
||||
@endditaa
|
BIN
images/user/libdl.png
Normal file
BIN
images/user/libdl.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
@ -77,6 +77,8 @@ built with ``make``, ``autotools``, ``cmake``, ``waf`` and more. User should
|
||||
select a build system that meets their project, system, corporate or personal
|
||||
needs.
|
||||
|
||||
.. _MachineFlagsandABI:
|
||||
|
||||
Machine Flags and ABI
|
||||
---------------------
|
||||
.. index:: Machine flags
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
.. Copyright (C) 2018 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
.. _TargetExecution:
|
||||
|
||||
Target Execution
|
||||
================
|
||||
.. index:: Target Execution
|
||||
|
@ -11,10 +11,11 @@ Executables
|
||||
|
||||
This section discusses what an RTEMS executable is and what happens when you
|
||||
execute it in a target. The section discusses how an application executable is
|
||||
created, what happens when an executable is loaded and run as well as
|
||||
debugging an execiutable.
|
||||
created, what happens when an executable is loaded and run, debugging an
|
||||
execiutable, and creating and dynamically loading code.
|
||||
|
||||
.. include:: executables.rst
|
||||
.. include:: execution.rst
|
||||
.. include:: initialization.rst
|
||||
.. include:: debugging.rst
|
||||
.. include:: loader.rst
|
||||
|
866
user/exe/loader.rst
Normal file
866
user/exe/loader.rst
Normal file
@ -0,0 +1,866 @@
|
||||
.. SPDX-License-Identifier: CC-BY-SA-4.0
|
||||
|
||||
.. Copyright (C) 2019 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
.. index:: Dynamic Loader
|
||||
|
||||
Dynamic Loader
|
||||
==============
|
||||
.. index:: Dynamic Loader
|
||||
.. index:: Run-time Loader
|
||||
.. index:: RTL
|
||||
.. index:: Libdl
|
||||
|
||||
RTEMS supports dynamically loading of executable code and data in the form of
|
||||
object files into a running system where the run-time loaded code can be
|
||||
executed and data accessed
|
||||
|
||||
This section describes RTEMS loader, preparing and loading executable code into
|
||||
a running system, the supported architectures and any limitation that may exist
|
||||
with an architecture.
|
||||
|
||||
The RTEMS operating system contains a link editor that runs on the target. The
|
||||
link editor supports loading Extendable Linker Format (ELF) relocatable
|
||||
executable object files locating the code and data in the target's address space
|
||||
as it is loaded. An executable object file's external references to function
|
||||
identifiers and data object identifiers are resolved and any external symbols
|
||||
can be made available in the global symbol table. The executing performance of
|
||||
dynamically loaded code is similar to the same code statically linked into an
|
||||
executable. This is a core requirement of the RTEMS link editor.
|
||||
|
||||
.. _fig-dl-libdl:
|
||||
|
||||
.. figure:: ../../images/user/libdl.png
|
||||
:width: 95%
|
||||
:alt: Run Time Loader (libdl)
|
||||
:figclass: align-center
|
||||
|
||||
Run Time Loader (libdl)
|
||||
|
||||
The RTEMS operating system's dynamic loader is not the same as the dynamic
|
||||
shared library support Unix or Windows have. Those operating systems use dynamic
|
||||
loading to share code between processes and this is an important feature in
|
||||
their design. RTEMS is a single address space operating system and that means
|
||||
there is no ability to share code at run-time. As a result code is loaded in a
|
||||
similar manner to static linking removing the need for any overheads sharing
|
||||
code may have.
|
||||
|
||||
To load an executable object file it must be resident on a target and accessible
|
||||
by RTEMS's file system. The executable object file can be a single file or a
|
||||
collection in a library stored using the Unix standard archive format. The RTEMS
|
||||
loader supports the extended GNU format for long file names in archives.
|
||||
|
||||
The RTEMS developers do not see dynamically loading of code as a real-time
|
||||
activity. A system should not respond to real-time external events by loading
|
||||
code. The loading of code should happen before a system is considered available
|
||||
and the activity the system is experiencing is low and stable.
|
||||
|
||||
.. index: base image
|
||||
|
||||
The statically linked executable that is loaded and run after reset is called
|
||||
the *base image*. The *base image* contains your base application that is used
|
||||
to dynamically load code, a global symbol table, the parts of the RTEMS
|
||||
operating system code used in the base image as well as functions and data from
|
||||
the tool suite libraries and packages you are using. Only the software
|
||||
referenced is used to create the base image. The parts of the libraries not
|
||||
referenced are not part of the executable or present in the global symbol table.
|
||||
|
||||
Application software can locate a symbol by name and call the address or
|
||||
reference the data at that address. A function identifier located by a symbol
|
||||
does not have it's signatures checked, it is the responsibility of the caller to
|
||||
make sure the function is called with the correct arguments. It is the same for
|
||||
data objects, there is no type checking. Symbol versioning is not supported and
|
||||
supporting it does not make sense within the RTEMS operating system. An RTEMS
|
||||
target system is closed to normal users and software needs to be built from the
|
||||
same tool set and header files used to the build the base image.
|
||||
|
||||
An executable object file's text or code has to be built for the target's
|
||||
architecture it is loaded on and it must be built with the same ABI flags the
|
||||
base image is built with. See :ref:`MachineFlagsandABI`.
|
||||
|
||||
System Design
|
||||
-------------
|
||||
|
||||
The use of dynamic loading in a project is a system design decision. Some
|
||||
systems will have strict requirements where loading code into a live system is
|
||||
not allowed while other projects will benefit from the system level flexibility
|
||||
dynamically loading code provides.
|
||||
|
||||
Code loaded at run time needs to be resident or accessible to the target via
|
||||
RTEMS's file system. Targets that have suitable media or a network interface to
|
||||
NFS servers to hold the executable object and library files are best suited.
|
||||
|
||||
Dynamically loading code uses more memory than statically linking the same code
|
||||
into the base image. The link editor maintains symbol tables where each symbol
|
||||
is a string, an address, and some additional data. The executable object files
|
||||
resident in memory each have data to manage them, the memory they use, and any
|
||||
dependencies they might have. The link editor is designed to minimize the memory
|
||||
overheads however only statically linked executables have no memory overhead.
|
||||
|
||||
The link editor relocates the code and data into RAM fixing it to the load
|
||||
address as it is loaded. A target needs to have suitably configured memory
|
||||
available for the executable object file to reside in. The memory must be able
|
||||
to support read, write and executable type access. Fine control of the memory
|
||||
and it's modes can be supported using a customer allocator. Examples are systems
|
||||
that have a custom memory map, specialized memory for the execution of code or a
|
||||
requirement for read-only executable sections.
|
||||
|
||||
The load address of an executable object file is determined by the load order
|
||||
and the allocator used. The default allocator for the link editor is the system
|
||||
heap which means the location a specific executable object file is loaded at
|
||||
depends on the memory allocated before it is loaded and when in the load order
|
||||
it is loaded. A statically linked executable's address map is fixed and this is
|
||||
considered important in some systems. A dynamically loaded system can be loaded
|
||||
in a repeatable manner if the load order is the same and the initialization
|
||||
sequence of the system is controlled. A custom allocator may also help.
|
||||
|
||||
Management of dynamically loadable object files and libraries adds to the
|
||||
configuration management of the hosts in a project. The loadable files need to
|
||||
be released and tracked in a suitable configuration management process just like
|
||||
the base image is. Executable object files and libraries are specific to a
|
||||
version of RTEMS and cannot be mixed or moved and this needs to be carefully
|
||||
managed. Currently there are no checks an executable object file matches the
|
||||
version of the base image it is being loaded on. These extra configuration
|
||||
controlled items add to the overheads of a project and need to be considered.
|
||||
|
||||
Dynamically loadable systems have a number of features that benefit some systems
|
||||
and products. Systems can be built on a base of trusted or *golden* modules. A
|
||||
number of projects using a common base of hardware can make use of proven
|
||||
modules reducing the testing and qualification overhead for each new release. A
|
||||
tested base image with libraries for common and available boards provides a
|
||||
simple and fast way for new users to trial and use RTEMS.
|
||||
|
||||
A project can use dynamic loading during development, shipping statically linked
|
||||
executables in production. Hardware used by a development team can have more
|
||||
memory, extra media for disk drives, or a network interface.
|
||||
|
||||
Loader Interface
|
||||
----------------
|
||||
.. index:: Loader Interface
|
||||
.. index:: Loading object files
|
||||
.. index:: dlfcn.h
|
||||
|
||||
Run-time executable object file loading and management is via the standard's
|
||||
based calls provided by the header file ``<dlfcn.h>``. The details of the calls
|
||||
follow.
|
||||
|
||||
.. _dlopen:
|
||||
.. index:: dlopen
|
||||
``void* dlopen(const char* path, int mode);``
|
||||
The ``dlopen()`` function makes the symbols (function identifiers and data
|
||||
object identifiers) in the executable object file specified by `file`
|
||||
available to the calling program.
|
||||
|
||||
The executable object files eligible for this operation are in the ELF
|
||||
format.
|
||||
|
||||
The link loader may load embedded dependencies in executable object files. In
|
||||
such cases, a ``dlopen()`` operation may load those dependencies in addition
|
||||
to the executable object file specified by `file`.
|
||||
|
||||
A successful ``dlopen()`` returns a `handle` which the caller may use on
|
||||
subsequent calls to ``dlsym()``, ``dlinfo()`` and ``dlclose()``.
|
||||
|
||||
The value of the `handle` should not be interpreted in any way by the caller.
|
||||
|
||||
Subsequent calls to ``dlopen()`` for the same executable object file increases
|
||||
the references to it.
|
||||
|
||||
The `file` argument is used to construct a pathname to the executable object
|
||||
file or archive library of executable object files. If the `file` argument
|
||||
contains a colon (``:``) the name of the executable object file in the library
|
||||
follows and this file name may optionally end with ``@`` followed by a number
|
||||
which is the absolute offset in the library file where the executable object
|
||||
file starts. If an executable object file is not detected at the offset the
|
||||
archive library's file table is searched.
|
||||
|
||||
If `file` is a null pointer, ``dlopen()`` returns a global symbol table
|
||||
handle. This `handle` provides access to the global symbols from an ordered
|
||||
set of executable object files consisting of the original base image file, the
|
||||
set of executable object files loaded using ``dlopen()`` operations with the
|
||||
``RTLD_GLOBAL`` flag, and any dependencies loaded. As the latter sets of
|
||||
executable object files can change during execution, the set of symbols made
|
||||
available by this `handle` can also change dynamically.
|
||||
|
||||
Only a single copy of an executable object file is brought into the address
|
||||
space, even if ``dlopen()`` is invoked multiple times in reference to the
|
||||
executable object file, and even if different pathnames are used to reference
|
||||
the executable object file.
|
||||
|
||||
Unresolved external symbols do not cause an error to be returned allowing the
|
||||
loading of jointly dependent executable object files.
|
||||
|
||||
If ``dlopen()`` fails, it returns a null pointer, and sets an error condition
|
||||
which may be interrogated with ``dlerror()``.
|
||||
|
||||
The `mode` parameter describes how ``dlopen()`` operates upon `file` with
|
||||
respect to the processing of relocations and the scope of visibility of the
|
||||
symbols provided within `file`. When an executable object file is brought into
|
||||
the address space, it may contain references to symbols whose addresses are
|
||||
not known until the executable object file is loaded.
|
||||
|
||||
If a loaded executable object file and any dependent executable object files
|
||||
loaded with it contain any initialiser functions, they are called in the order
|
||||
loaded before ``dlopen()`` returns.
|
||||
|
||||
The modes ``RTLD_LAZY`` and ``RTLD_NOW`` do not effect the type of relocation
|
||||
performed, it is same for both modes. All relocations of an executable object
|
||||
file and any dependent executable object files loaded with it are completed
|
||||
before the ``dlopen()`` call returns. The execution performance of the code
|
||||
loaded can be considered deterministic once ``dlopen()`` has returned.
|
||||
|
||||
Any executable object file loaded by ``dlopen()`` can reference global symbols
|
||||
in the base image, any executable object files loaded included in the same
|
||||
``dlopen()`` invocation, and any executable object files that were loaded in
|
||||
any ``dlopen()`` invocation and which specified the ``RTLD_GLOBAL`` flag. To
|
||||
determine the scope of visibility for the symbols loaded with a ``dlopen()``
|
||||
invocation, the `mode` parameter should be a bitwise-inclusive ``OR`` with one
|
||||
of the following values:
|
||||
|
||||
``RTLD_GLOBAL``
|
||||
The executable object file's symbols are made available for relocation
|
||||
processing of any other executable object file. In addition, symbol lookup
|
||||
using ``dlopen(NULL,mode)`` and an associated ``dlsym()`` allows
|
||||
executable object files loaded with this mode to be searched.
|
||||
|
||||
``RTLD_LOCAL``
|
||||
The executable object file's symbols shall not be made available for
|
||||
relocation processing of any other executable object files.
|
||||
|
||||
If neither ``RTLD_GLOBAL`` nor ``RTLD_LOCAL`` is specified, the default
|
||||
behavior is unspecified.
|
||||
|
||||
If ``RTLD_GLOBAL`` has been specified, the executable object file maintains
|
||||
it's ``RTLD_GLOBAL`` status regardless of any previous or future specification
|
||||
of ``RTLD_LOCAL``, as long as the executable object file remains in the
|
||||
address space.
|
||||
|
||||
Symbols introduced through calls to ``dlopen()`` may be used in relocation
|
||||
activities. Symbols that duplicate symbols already defined by the base image
|
||||
or previous ``dlopen()`` calls are treated as an error and the object file is
|
||||
not loaded. Symbols introduced through loading dependent executable object
|
||||
files are ignored or not loaded depending on the method used to build the
|
||||
executable object files.
|
||||
|
||||
The symbols introduced by ``dlopen()`` operations and available through
|
||||
``dlsym()`` are at a minimum those which are exported as identifiers of global
|
||||
scope by the executable object file. Typically, such identifiers shall be
|
||||
those that were specified in (for example) C source code as having ``extern``
|
||||
linkage.
|
||||
|
||||
.. _dlclose:
|
||||
.. index:: dlclose
|
||||
``int dlclose(void* handle);``
|
||||
Releases a reference to the executable object file referenced by `handle`. If
|
||||
the reference count drops to ``0``, the executable object file's global symbol
|
||||
table is made unavailable. When all references to the global symbols the
|
||||
executable object file provided have been removed the object file is removed
|
||||
from the address space.
|
||||
|
||||
If the executable object being removed has any termination routines in it they
|
||||
are called.
|
||||
|
||||
.. _dlsym:
|
||||
.. index:: dlsym
|
||||
``void* dlsym(void* handle, const char* symbol);``
|
||||
The ``dlsym()`` function obtains the address of a symbol (a function identifier
|
||||
or a data object identifier) defined in the symbol table identified by the
|
||||
handle argument. The handle argument is a symbol table handle returned from a
|
||||
call to ``dlopen()`` (and which has not since been released by a call to
|
||||
``dlclose()``), and name is the symbol's name as a character string. The return
|
||||
value from ``dlsym()``, cast to a pointer to the type of the named symbol, can
|
||||
be used to call (in the case of a function) or access the contents of (in the
|
||||
case of a data object) the named symbol.
|
||||
|
||||
The ``dlsym()`` function searches for the named symbol in the symbol table
|
||||
referenced by handle and returns the address of the code or data location
|
||||
specified by the null-terminated character string symbol. Which libraries and
|
||||
objects are searched depends on the `handle` parameter.
|
||||
|
||||
Upon successful completion, if name names a function identifier, ``dlsym()``
|
||||
returns the address of the function converted from type pointer to function to
|
||||
type pointer to ``void``; otherwise, ``dlsym()`` shall return the address of
|
||||
the data object associated with the data object identifier named by name
|
||||
converted from a pointer to the type of the data object to a pointer to
|
||||
``void``. If `handle` does not refer to a valid symbol table handle or if the
|
||||
symbol named by name cannot be found in the symbol table associated with
|
||||
`handle`, ``dlsym()`` shall return a null pointer.
|
||||
|
||||
.. _dlinfo:
|
||||
.. index:: dlinfo
|
||||
``int dlinfo(void* handle, int request, void* args);``
|
||||
|
||||
The ``dlinfo()`` function provides information about dynamically loaded object.
|
||||
The action taken by ``dlinfo()`` and exact meaning and type of the argument
|
||||
`args` depend on value of the `request` argument provided by the caller.
|
||||
|
||||
``RTLD_DI_UNRESOLVED``
|
||||
Return ``1`` in an indexer value pointed to by `args` if the symbol table
|
||||
handle has unresolved relocation records to symbols. If the `handle` is the
|
||||
global symbol table handle or ``RTLD_SELF`` return ``1`` if any unresolved
|
||||
relocation records to symbols are present in any loaded executable object
|
||||
files..
|
||||
|
||||
.. _dlerror:
|
||||
.. index:: dlerror
|
||||
``const char *dlerror(void);``
|
||||
The ``dlerror()`` function returns a null-terminated character string (with no
|
||||
trailing ``<newline>``) that describes the last error that occurred during
|
||||
dynamic linking processing. If no dynamic linking errors have occurred since
|
||||
the last invocation of ``dlerror()``, ``dlerror()`` returns ``NULL``. Thus,
|
||||
invoking ``dlerror()`` a second time, immediately following a prior
|
||||
invocation, results in ``NULL`` being returned.
|
||||
|
||||
This example opens an object file, checks for any unresolved symbols the object
|
||||
file may have, locates a global symbol in the object file, calls it then closes
|
||||
the object file:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef int (*call_sig)(void);
|
||||
|
||||
bool load_object (void)
|
||||
{
|
||||
void* handle;
|
||||
call_sig call;
|
||||
int unresolved;
|
||||
|
||||
handle = dlopen ("/code.o", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle == NULL)
|
||||
{
|
||||
printf ("dlopen failed: %s\n", dlerror ());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) < 0)
|
||||
{
|
||||
printf ("dlinfo failed: %s\n", dlerror ());
|
||||
dlclose (handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unresolved != 0)
|
||||
{
|
||||
printf ("object.o has unresolved external symbols\n");
|
||||
dlclose (handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
call = dlsym (handle, "foo");
|
||||
if (call == NULL)
|
||||
{
|
||||
printf("dlsym failed: symbol 'foo' not found\n");
|
||||
dlclose (handle);
|
||||
return false;
|
||||
}
|
||||
|
||||
printf ("'foo()' returns: %i\n", call ());
|
||||
|
||||
if (dlclose (handle) < 0)
|
||||
{
|
||||
printf("dlclose failed: %s\n", dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Symbols
|
||||
-------
|
||||
.. index:: symbol
|
||||
.. index:: global symbol
|
||||
.. index:: function identifier
|
||||
.. index:: data object identifier
|
||||
|
||||
The RTEMS link editor manages the symbols for the base image and all resident
|
||||
executable object files. A symbol is an identifier string and a pointer value to
|
||||
a function identifier or a data object identifier. The symbols held in the
|
||||
symbol tables are used in the relocation of executable object files or they can
|
||||
be accessed by application code using the :ref:`dlsym() <dlsym>` call.
|
||||
|
||||
.. index:: orphaned object file
|
||||
|
||||
An executable object file's symbols are removed from the global symbol table
|
||||
when it is closed or orphaned. An executale object file cannot be unloaded if a
|
||||
symbol it provides is referenced by another object and that object is still
|
||||
resident. An executable object file that has no references to any of its symbols
|
||||
and was not explicitly loaded using the :ref:`dlopen() <dlopen>` call is
|
||||
orphaned and automatically removed from the address space.
|
||||
|
||||
Base Image Symbols
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
.. index:: base image symbols
|
||||
|
||||
The base image symbol table provides access to the function and data objects
|
||||
statically linked into the base image. Loaded executable object files can be
|
||||
directly linked to the code and data resident in the base image.
|
||||
|
||||
A statically linked RTEMS executable does not contain a symbol table, it has to
|
||||
be generated and either embedded into the executable or loaded as a specially
|
||||
created executable object file.
|
||||
|
||||
The base image symbol table is dependent on the contents of the base image and
|
||||
this is not known until it has been linked. This means the base image symbol
|
||||
table needs to be constructed after the base image executable has been linked
|
||||
and the list of global symbols is known.
|
||||
|
||||
The RTEMS Tools command :program:`rtems-syms` (see :ref:`RTEMSSymbols`) extracts
|
||||
the global and weak symbols from an RTEMS static executable file, creates a C
|
||||
file and compiles it creating a relocatable executable object file. This file
|
||||
can be linked with the static executable's object files and libraries to create
|
||||
a static executables with an embedded symbol table or the executable file can be
|
||||
loaded dynamically at run-time. The following needs to be observed:
|
||||
|
||||
#. The option ``-e`` or ``--embedded`` to :program:`rtems-syms` creates an
|
||||
executable object file to be embedded in the base image and not providing
|
||||
either of these options creates a symbols executable object file that is
|
||||
loaded at run-time. The same executable object file cannot be used to
|
||||
embedded or load.
|
||||
|
||||
#. The target C compiler and machine options need to be provided to make sure
|
||||
the correct ABI for the target is used. See :ref:`MachineFlagsandABI`.
|
||||
|
||||
.. index:: embedded symbol table
|
||||
.. _EmbbeddedSymbolTable:
|
||||
|
||||
Embedded Symbols
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
An embedded symbol table is *embedded* within the base image executable file and
|
||||
loaded when the static executable is loaded into memory by the bootloader. The
|
||||
symbol table is automatically added to the link editor's global symbol table
|
||||
when the first executable object file is loaded.
|
||||
|
||||
The process to embed the symbol table requires linking the base image twice.
|
||||
The first link is to create a static executable that collects together the
|
||||
symbols to make the symbol table. The RTEMS Tools command `rtems-syms` extracts
|
||||
the global and weak symbols from the static executable ELF file, creates a C
|
||||
file and compiles it to create an executable object file. The base image is
|
||||
linked a second time and this time the symbol table executable object file is
|
||||
added to the list of object files.
|
||||
|
||||
Embedding the symbol table means the chances of the symbol table and base image
|
||||
not matching is low, however it also means the symbol table is always present in
|
||||
the kernel image when dynamic loading may be optional. A project's build system
|
||||
is made more complex as it needs to have extra steps to link a second time.
|
||||
|
||||
This example shows creating an embedded symbol table object file and linking it
|
||||
into the base image.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ sparc-rtems5-gcc -mcpu=cypress foo.o -lrtemsbsp -lrtemscpu -o foo.pre
|
||||
$ rtems-syms -e -C sparc-rtems5-gcc -c "-mcpu=cypress" -o foo-sym.o foo.pre
|
||||
$ sparc-rtems5-gcc -mcpu=cypress foo.o foo-sym.o -lrtemsbsp -lrtemscpu -o foo.exe
|
||||
|
||||
The link command line steps in this example are not complete.
|
||||
|
||||
.. _LoadableSymbolTable:
|
||||
|
||||
Loadable Symbols
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
A run-time loaded symbol table is the default for the command
|
||||
:program:`rtems-syms`. The symbol table executable object file is packaged with
|
||||
the other files to be dynamically loaded at run-time and placed on the target's
|
||||
file system. It needs to be loaded before any other executable object file are
|
||||
loaded or unresolved symbols can occur that will not be resolved.
|
||||
|
||||
A run-time loaded symbol table does not consume any target resources until it is
|
||||
loaded. This is useful in a system that optionally needs to dynamically load
|
||||
code, for example as a development environment. The symbol table executable
|
||||
needs to exactly match the base image loading it or the behavior is
|
||||
unpredictable. No checks are made.
|
||||
|
||||
The example shows creating and loading a symbol table executable object
|
||||
file. First create the symbol table's executable object file:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ sparc-rtems5-gcc -mcpu=cypress foo.o -lrtemsbsp -lrtemscpu -o foo.exe
|
||||
$ rtems-syms -C sparc-rtems5-gcc -c "-mcpu=cypress" -o foo-sym.o foo.exe
|
||||
|
||||
The link command line steps in this example are not complete.
|
||||
|
||||
Load the symbol table:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
bool load (void)
|
||||
{
|
||||
void* handle = dlopen ("/foo-sym.o", RTLD_NOW | RTLD_GLOBAL);
|
||||
if (handle == NULL)
|
||||
{
|
||||
printf ("failed to load the symbol table: %s\n", dlerror ());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Unresolved Symbols
|
||||
------------------
|
||||
|
||||
The RTEMS link editor does not return an error when an executable object file is
|
||||
loaded with unresolved symbols. This allows dependent object files to be
|
||||
loaded. For example an executable object file :file:`foo.o` contains the
|
||||
function ``foo()`` and that function calls ``bar()`` and an executable object
|
||||
file :file:`bar.o` contains a function ``bar()`` that calls the function
|
||||
``foo()``. Either of these executable object files can be loaded first as long
|
||||
both are loaded before any symbols are accessed.
|
||||
|
||||
The link editor defers the resolution of unresolved symbols until the symbol is
|
||||
available in the global symbol table. Executing code or accessing data in a
|
||||
loaded executable object file with unresolved external symbols results in
|
||||
unpredictable behavior.
|
||||
|
||||
All unresolved symbols are checked after an executable object file has been
|
||||
loaded. If a symbol is found and resolved any relocations that reference the
|
||||
symbol are fixed. If valid library files have been configured the symbol table's
|
||||
of each library are searched and if the symbol is found the dependent executable
|
||||
object file is loaded. This process repeats until no more symbols can be
|
||||
resolved.
|
||||
|
||||
The ``dlinfo()`` call can be used to see if a loaded executable object file has
|
||||
any unresolved symbols:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
bool has_unresolved(void* handle)
|
||||
{
|
||||
int unresolved;
|
||||
if (dlinfo (handle, RTLD_DI_UNRESOLVED, &unresolved) < 0)
|
||||
{
|
||||
printf ("dlinfo failed: %s\n", dlerror ());
|
||||
return false;
|
||||
}
|
||||
return unresolved != 0;
|
||||
}
|
||||
|
||||
The handle ``RTLD_SELF`` checks for any unresolved symbols in all resident
|
||||
object files:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
if (has_unresolved(RTLD_SELF))
|
||||
printf("system has unsolved symbols\n");
|
||||
|
||||
Libraries
|
||||
---------
|
||||
|
||||
The RTEMS link editor supports loading executable object files from
|
||||
libraries. Executable object files can be explicitly loaded from a library using
|
||||
a specific path to :ref:`dlopen() <dlopen>` and treated the same as loading a
|
||||
stand alone executable object file. Libraries can be searched and an executable
|
||||
object file containing the search symbol can be loaded automatically as a
|
||||
dependent executable object file. A dependent executable object file loaded from
|
||||
a library with no symbol references to it's symbols is orphaned and
|
||||
automatically unloaded and removed from the address space.
|
||||
|
||||
.. _fig-dl-libs:
|
||||
|
||||
.. figure:: ../../images/user/libdl-load.png
|
||||
:width: 65%
|
||||
:alt: Loading Executable Object Files
|
||||
:figclass: align-center
|
||||
|
||||
Loading Executable Object Files
|
||||
|
||||
A library is an archive format file created using the RTEMS architecture
|
||||
prefixed :program:`ar` command. The RTEMS tool suite provides the :program:`ar`
|
||||
program and system libraries such as :file:`libc.a` and :file:`libm.a` for each
|
||||
architecture and ABI. Libraries used by the RTEMS link editor for searching must
|
||||
contain a symbol table created by the :program:`ranlib` program from the RTEMS
|
||||
tool suite.
|
||||
|
||||
Searching a library's symbol table and loading an executable object file
|
||||
containing the symbol is called *dependent loading*. Dependent loading provides
|
||||
a simple way to manage the dependencies when loading an executable object
|
||||
file. If code in an executable object file references functions or data objects
|
||||
that are part of a library and the symbols are not part of the base image those
|
||||
symbols will not resolve unless the library is on the target and available for
|
||||
searching and loading. Dependent loading from libraries on the target provides a
|
||||
simple and understandable way to manage the dependency issue between the base
|
||||
image, loaded code and the system libraries.
|
||||
|
||||
The RTEMS link editor checks for the configuration file :file:`/etc/libdl.conf`
|
||||
on each call to :ref:`dlopen() <dlopen>`. If the file has changed since the last
|
||||
check it is loaded again and the contents processed. The file format is:
|
||||
|
||||
#. Comments start with the ``#`` character.
|
||||
#. A line is a wildcard path of libraries to search for. The wildcard search
|
||||
uses the ``fnmatch()`` call. The ``fnmatch()`` function matches patterns
|
||||
according to the rules used by a shell.
|
||||
|
||||
Files that match the search pattern are verified as a library and if a symbol
|
||||
table is found it is loaded and the symbols it contains made search-able.
|
||||
|
||||
A call to :ref:`dlopen() <dlopen>` checks the global symbols table and any
|
||||
references to relocation symbols not found are *unresolved* and added to the
|
||||
unresolved symbol table. Once the executable object file is loaded the link
|
||||
editor attempts to resolve any unresolved symbols. The unresolved symbol
|
||||
resolver checks each unresolved symbol against the global symbol table and if
|
||||
not found the available library symbol tables are searched. If a symbol is found
|
||||
in a library the dependent executable object file is loaded. The process repeats
|
||||
until all unresolved symbols have been resolved and the remaining unresolved
|
||||
symbols are not in the global symbol table or any libraries. The loading of a
|
||||
library executable object file will resolve at least one symbol and it may add
|
||||
more unresolved symbols requiring further searching of the libraries.
|
||||
|
||||
.. index:: strip library
|
||||
|
||||
A library of executable object files built by the RTEMS Tool suite can contain
|
||||
debug information and this should be stripped before loading on to the
|
||||
target. The tool suite's command :program:`strip` can strip all the object files
|
||||
in a library with a single command.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ sparc-rtems5-strip libc.a
|
||||
|
||||
Large Memory
|
||||
------------
|
||||
|
||||
The RTEMS link editor supports large memory relocations. Some architectures have
|
||||
instructions where the relative branch or jump offset from the instruction to
|
||||
the target address is limited. These instructions provide improved performance
|
||||
because less code generated compared to larger instructions which contain full
|
||||
address space references. The compact code helps lower cache pressure as well
|
||||
and providing improved performance for localalized functions and loops. The
|
||||
compiler defaults to generating the smaller instruction and as the final address
|
||||
map not known when generating the code, linkers need to provide glue code to
|
||||
extend the small address range to the enitre address space. This is called a
|
||||
trampoline. A trampoline is transparent to the execution of the code.
|
||||
|
||||
The link editor parses an executable object file's relocation records to
|
||||
determine the number of trampolines needed. Added to this value are all
|
||||
unresolved symbols present in an executable object file after it is
|
||||
loaded. There is a slot allocated even if the symbol ends up being within range
|
||||
as there is no way to determine a symbol's address until it is loaded and the
|
||||
range calculated.
|
||||
|
||||
The trampoline table is allocated a separate block of memory to the executable
|
||||
object file's text, data and constants memory. The trampoline parsing requires
|
||||
the executable object file's instructions (text) be in memory as the
|
||||
instructions are inspected by the architecture specific relocation support to
|
||||
determine an instruction's range. As a result the allocation for the trampoline
|
||||
table has to occur after the text memory has been allocated. Most instructions
|
||||
have relative offsets and the trampoline table is allocated at one end limiting
|
||||
the size of an object to half the maximum range.
|
||||
|
||||
Trampolines support is available for the ARM and PowerPC architectures. The
|
||||
SPARC and Intel x86 architectures do not need trampolines and MIPS needs support
|
||||
added.
|
||||
|
||||
Allocator
|
||||
---------
|
||||
|
||||
The RTEMS link editor supports custom allocators. A custom allocator lets you
|
||||
manage the memory used by the RTEMS link editor as it runs. Allocators could
|
||||
provide:
|
||||
|
||||
#. Support for the various types of memory that can be allocated allowing
|
||||
specialised target support for specific use cases.
|
||||
#. Locking of read-only memory. The link editor unlocks read-only memory when it
|
||||
needs to write to it.
|
||||
#. Separation of memory holding code and data from the heap.
|
||||
|
||||
The allocator can be hooked using the ``rtems_rtl_alloc_hook`` call before any
|
||||
calls to :ref:`dlopen() <dlopen>` are made. The hook call returns the current
|
||||
allocate allowing the allocators to be chained.
|
||||
|
||||
The default allocator uses the heap.
|
||||
|
||||
.. _rtems_rtl_alloc_tags:
|
||||
.. index:: rtems_rtl_alloc_tags
|
||||
|
||||
The allocator tags specify the type of memory the allocator is handling. The tag
|
||||
used to allocate memory at an address must be used when making allocator
|
||||
calls. The ``rtems_rtl_alloc_tags`` are:
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_OBJECT
|
||||
``RTEMS_RTL_ALLOC_OBJECT``
|
||||
Allocate a generic object. The link editor uses this memory for data
|
||||
structures it uses to manage the linking process and resident executable
|
||||
object files.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_SYMBOL
|
||||
``RTEMS_RTL_ALLOC_SYMBOL``
|
||||
Allocate memory to hold symbol data.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_EXTERNAL
|
||||
``RTEMS_RTL_ALLOC_EXTERNAL``
|
||||
Allocate memory for unresolved external symbols.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_READ
|
||||
``RTEMS_RTL_ALLOC_READ``
|
||||
Allocate memory for read-only data such as constants and exception tables.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_READ_WRITE
|
||||
``RTEMS_RTL_ALLOC_READ_WRITE``
|
||||
Allocate memory for read-write data such as a initialised, uninitialized and
|
||||
common variables.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_READ_EXEC
|
||||
``RTEMS_RTL_ALLOC_READ_EXEC``
|
||||
Allocate memory for code to be executed in. The address space is configure for
|
||||
read and execute.
|
||||
|
||||
.. _rtems_rtl_alloc_cmd:
|
||||
.. index:: rtems_rtl_alloc_cmd
|
||||
|
||||
The commands are used to control the action the allocator performs. The
|
||||
``rtems_rtl_alloc_cmd`` are:
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_NEW
|
||||
``RTEMS_RTL_ALLOC_NEW``
|
||||
Allocate memory of the ``tag`` type. Returns ``NULL`` if the allocation fails.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_DEL
|
||||
``RTEMS_RTL_ALLOC_DEL``
|
||||
Delete a previous allocation freeing the memory. The ``tag`` has to match
|
||||
address of the memory being deleted.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_WR_ENABLE
|
||||
``RTEMS_RTL_ALLOC_WR_ENABLE``
|
||||
Enable writes to a region of memory previously allocated. The ``tag`` has to
|
||||
match the address of the memory being write enabled. The link editor may call
|
||||
issue this command for memory that is already write enabled.
|
||||
|
||||
.. index:: RTEMS_RTL_ALLOC_WR_DISABLE
|
||||
``RTEMS_RTL_ALLOC_WR_DISABLE``
|
||||
Disable writes to a region of memory previously allocated. The ``tag`` has to
|
||||
match address of the memory being write disabled. The link editor may call
|
||||
issue this command for memory that is writable and not to be write
|
||||
disabled. The allocator need to manage this case.
|
||||
|
||||
.. _rtems_rtl_allocator:
|
||||
.. index:: rtems_rtl_allocator
|
||||
|
||||
The allocator handler is a single call to handle all allocator requests. The
|
||||
handler called on evey allocation action made by the link editor. The type of
|
||||
the function you need is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
typedef void (*rtems_rtl_allocator)(rtems_rtl_alloc_cmd cmd,
|
||||
rtems_rtl_alloc_tag tag,
|
||||
void** address,
|
||||
size_t size);
|
||||
|
||||
|
||||
The arguments are:
|
||||
|
||||
``cmd``
|
||||
The command to action. See :ref:`_rtems_rtl_alloc_cmd`.
|
||||
|
||||
``tag``
|
||||
The type of memory the command is for. The ``tag`` must match the address for
|
||||
commands other than ``RTEMS_RTL_ALLOC_OBJECT``.
|
||||
|
||||
``address``
|
||||
Pointer to the address. This is set of the ``RTEMS_RTL_ALLOC_OBJECT`` command
|
||||
and read for the other commands. The ``tag`` must match the address for
|
||||
commands that read the address from the pointer.
|
||||
|
||||
``size``
|
||||
The size of the memory to allocate. This is only valid for the
|
||||
``RTEMS_RTL_ALLOC_OBJECT`` command.
|
||||
|
||||
The call to hook the allocator is:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
rtems_rtl_allocator rtems_rtl_alloc_hook (rtems_rtl_allocator handler);
|
||||
|
||||
The current allocator is returned. You can provide a full allocator or you can
|
||||
filter commands.
|
||||
|
||||
Languages
|
||||
---------
|
||||
|
||||
C is supported.
|
||||
|
||||
C++ is supported. Initializer functions are called when an object is loaded and
|
||||
finalizer functions are called before it is unloaded and removed. Static
|
||||
constructions are initializer functions and static destructors are finalizer
|
||||
functions.
|
||||
|
||||
C++ exceptions are handled across modules. The compiler generated exception
|
||||
tables present in an executable object file are registered with the architecture
|
||||
specific mechanism when loaded and deregistered when unloaded. An exception
|
||||
thrown in loaded code can be caught in the base image or another loaded
|
||||
module. If you are using C++ and exceptions it is recommended some exception
|
||||
code is added to the base image to place the architecture specific support in
|
||||
the base image.
|
||||
|
||||
Thread Local Storage
|
||||
--------------------
|
||||
|
||||
Thread local storage (TLS) is currenly not supported by the RTEMS link
|
||||
editor. The RTEMS executive needs to have a special allocator added to manage
|
||||
dynamically allocating TLS variables in a thread.
|
||||
|
||||
If you need TLS support in dynamically loaded code please consider the RTEMS
|
||||
support options.
|
||||
|
||||
Architectures
|
||||
-------------
|
||||
|
||||
The following architectures are supported:
|
||||
|
||||
- ARM
|
||||
- Blackfin
|
||||
- H8300
|
||||
- Intel x86 (i386)
|
||||
- LM32
|
||||
- M68K
|
||||
- MIPS
|
||||
- Moxie
|
||||
- PowerPC
|
||||
- SPARC
|
||||
- V850
|
||||
|
||||
ARM
|
||||
^^^
|
||||
|
||||
The ARM relocation backend supports veneers which is trampolines.
|
||||
|
||||
The veneer implementation is a single instruction and a 32bit target address
|
||||
making the overhead 8 bytes for each veneer. The performance overhead is a
|
||||
single instruction.
|
||||
|
||||
PowerPC
|
||||
^^^^^^^
|
||||
|
||||
The PowerPC relocation backend support trampolines and small data.
|
||||
|
||||
The trampoline is four instructions and uses register 12 which the PowerPC ABI
|
||||
reserves for scratch use. The implementation loads the counter register and
|
||||
branches to the address it contains. The trampoline size is 16 bytes. The
|
||||
performance overhead is four instructions.
|
||||
|
||||
The PowerPC relocation backend also supports small data. The sections of an
|
||||
executable object file are parsed and small data are tagged as needing
|
||||
architecture specific allocations. These sections are not allocated as part of
|
||||
the standard section allocation. Small data sections are allocated in the global
|
||||
small data region of memory. The size of this region is defined in the BSP's
|
||||
linker command file by setting ``bsp_section_small_data_area_size`` variable:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
bsp_section_small_data_area_size = 65536;
|
||||
|
||||
The maximum size of the small data region is 65536 bytes. It is recommended code
|
||||
built for loading uses the same settings for small base as the base image.
|
@ -90,6 +90,8 @@ requires:
|
||||
If you are unsure how to specify the build set for the architecture you wish to
|
||||
build, just ask the tool:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ ../source-builder/sb-set-builder --list-bsets <1>
|
||||
RTEMS Source Builder - Set Builder, v4.11.0
|
||||
Examining: config
|
||||
@ -750,4 +752,3 @@ Install the kernel to our prefix:
|
||||
make[1]: Leaving directory '/c/opt/rtems/kernel/pc686'
|
||||
/c/opt/rtems/kernel/pc686
|
||||
$
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
.. Copyright (C) 2017 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
.. _RTEMSExecutableInfomation:
|
||||
|
||||
RTEMS Executable Infomation
|
||||
===========================
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
.. Copyright (C) 2017 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
.. _RTEMSLinker:
|
||||
|
||||
RTEMS Linker
|
||||
============
|
||||
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
.. Copyright (C) 2017 Chris Johns <chrisj@rtems.org>
|
||||
|
||||
.. _RTEMSSymbols:
|
||||
|
||||
RTEMS Symbols
|
||||
=============
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user