363 lines
14 KiB
ReStructuredText
363 lines
14 KiB
ReStructuredText
.. _binfmt:
|
|
|
|
=============
|
|
Binary Loader
|
|
=============
|
|
|
|
The purpose of a *binary loader* is to load and
|
|
execute modules in various *binary formats* that reside in a file
|
|
system. Loading refers instantiating the binary module in some fashion,
|
|
usually copy all or some of the binary module into memory and then
|
|
linking the module with other components. In most architectures, it is
|
|
the base FLASH code that is the primary component that the binary module
|
|
must link with because that is where the RTOS and primary tasks reside.
|
|
Program modules can then be executed after they have been loaded.
|
|
|
|
**Binary Formats**. The binary loader provides generic support for
|
|
different binary formats. It supports a *registration interface* that
|
|
allows the number of support binary formats to be loaded at run time.
|
|
Each binary format provides a common, interface for use by the binary
|
|
loader. When asked to load a binary, the binary loader will query each
|
|
registered binary format, providing it with the path of the binary
|
|
object to be loaded. The binary loader will stop when first binary
|
|
format the recognizes the binary object and successfully loads it or
|
|
when all registered binary formats have attempt loading the binary
|
|
object and failed.
|
|
|
|
At present, the following binary formats are support by NuttX:
|
|
|
|
- **ELF**. Standard ELF formatted files.
|
|
- **NXFLAT**. NuttX NXFLAT formatted files. More information about the
|
|
NXFLAT binary format can be found in the :ref:`NXFLAT
|
|
documentation <nxflat>`.
|
|
|
|
**Executables and Libraries** The generic binary loader logic does not
|
|
care what it is that it being loaded. It could load an executable
|
|
program or a library. There are no strict rules, but a library will tend
|
|
to export symbols and a program will tend to import symbols: The program
|
|
will use the symbols exported by the library. However, at this point in
|
|
time, none of the supported binary formats support exporting of symbols.
|
|
|
|
**binfmt**. In the NuttX source code, the short name ``binfmt`` is used
|
|
to refer to the NuttX binary loader. This is the name of the directory
|
|
containing the binary loader and the name of the header files and
|
|
variables used by the binary loader.
|
|
|
|
The name ``binfmt`` is the same name used by the Linux binary loader.
|
|
However, the NuttX binary loader is an independent development and
|
|
shares nothing with the Linux binary loader other the same name and the
|
|
same basic functionality.
|
|
|
|
Binary Loader Interface
|
|
=======================
|
|
|
|
Header Files
|
|
------------
|
|
|
|
The interface to the binary loader is described in the header file
|
|
``include/nuttx/binfmt/binfmt.h``.
|
|
A brief summary of the data structures and interfaces prototyped in that
|
|
header file are listed below.
|
|
|
|
Data Structures
|
|
---------------
|
|
|
|
When a binary format registers with the binary loader, it provides a
|
|
pointer to a write-able instance of :c:struct:`binfmt_s`.
|
|
|
|
.. c:struct:: binfmt_s
|
|
|
|
.. code-block:: c
|
|
|
|
struct binfmt_s
|
|
{
|
|
FAR struct binfmt_s *next; /* Supports a singly-linked list */
|
|
int (*load)(FAR struct binary_s *bin); /* Verify and load binary into memory */
|
|
};
|
|
|
|
The ``load`` method is used to load the binary format into memory. It
|
|
returns either ``OK`` (0) meaning that the binary object was loaded
|
|
successfully, or a negated ``errno`` indicating why the object was not
|
|
loaded.
|
|
|
|
.. c:struct:: binary_s
|
|
|
|
The type ``struct binary_s`` is use both to (1) describe the binary
|
|
object to be loaded, and if successfully loaded, (2) to provide
|
|
information about where and how the binary object was loaded. That
|
|
structure is shown below:
|
|
|
|
.. code-block:: c
|
|
|
|
struct symtab_s;
|
|
struct binary_s
|
|
{
|
|
/* Information provided to the loader to load and bind a module */
|
|
|
|
FAR const char *filename; /* Full path to the binary to be loaded */
|
|
FAR const char **argv; /* Argument list */
|
|
FAR const struct symtab_s *exports; /* Table of exported symbols */
|
|
int nexports; /* The number of symbols in exports[] */
|
|
|
|
/* Information provided from the loader (if successful) describing the
|
|
* resources used by the loaded module.
|
|
*/
|
|
|
|
main_t entrypt; /* Entry point into a program module */
|
|
FAR void *mapped; /* Memory-mapped, address space */
|
|
FAR void *alloc[BINFMT_NALLOC]; /* Allocated address spaces */
|
|
|
|
/* Constructors/destructors */
|
|
|
|
#ifdef CONFIG_BINFMT_CONSTRUCTORS
|
|
FAR binfmt_ctor_t *ctors; /* Pointer to a list of constructors */
|
|
FAR binfmt_dtor_t *dtors; /* Pointer to a list of destructors */
|
|
uint16_t nctors; /* Number of constructors in the list */
|
|
uint16_t ndtors; /* Number of destructors in the list */
|
|
#endif
|
|
|
|
/* Address environment.
|
|
*
|
|
* addrenv - This is the handle created by up_addrenv_create() that can be
|
|
* used to manage the tasks address space.
|
|
*/
|
|
|
|
#ifdef CONFIG_ARCH_ADDRENV
|
|
arch_addrenv_t addrenv; /* Task group address environment */
|
|
#endif
|
|
|
|
size_t mapsize; /* Size of the mapped address region (needed for munmap) */
|
|
|
|
/* Start-up information that is provided by the loader, but may be modified
|
|
* by the caller between load_module() and exec_module() calls.
|
|
*/
|
|
|
|
uint8_t priority; /* Task execution priority */
|
|
size_t stacksize; /* Size of the stack in bytes (unallocated) */
|
|
#ifndef CONFIG_BUILD_KERNEL
|
|
FAR void *stackaddr; /* Task stack address */
|
|
#endif
|
|
};
|
|
|
|
Where the types ``binfmt_ctor_t`` and ``binfmt_dtor_t`` define the type
|
|
of one C++ constructor or destructor:
|
|
|
|
.. code-block:: c
|
|
|
|
typedef FAR void (*binfmt_ctor_t)(void);
|
|
typedef FAR void (*binfmt_dtor_t)(void);
|
|
|
|
Function Interfaces
|
|
-------------------
|
|
|
|
Binary format management
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. c:function:: int register_binfmt(FAR struct binfmt_s *binfmt)
|
|
|
|
Register a loader for a binary format.
|
|
|
|
:return: This is a NuttX internal function so it follows the convention
|
|
that 0 (OK) is returned on success and a negated errno is returned on
|
|
failure.
|
|
|
|
.. c:function:: int unregister_binfmt(FAR struct binfmt_s *binfmt)
|
|
|
|
Register a loader for a binary format.
|
|
|
|
:return:
|
|
This is a NuttX internal function so it follows the convention
|
|
that 0 (OK) is returned on success and a negated errno is returned on
|
|
failure.
|
|
|
|
Basic module management
|
|
~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. c:function:: int load_module(FAR struct binary_s *bin)
|
|
|
|
Load a module into memory, bind it to an exported symbol take,
|
|
and prep the module for execution.
|
|
|
|
:param bin:
|
|
The ``filename`` field will be used
|
|
in order to locate the module to be loaded from the file system.
|
|
The filename must be the full, absolute path to the file to be executed
|
|
unless ``CONFIG_LIBC_ENVPATH`` is defined. In that case, filename may be
|
|
a relative path; a set of candidate absolute paths will be generated using
|
|
the ``PATH`` environment variable and ``load_module()`` will attempt to load each
|
|
file that is found at those absolute paths.
|
|
|
|
:return:
|
|
This is a NuttX internal function so it follows the convention that 0 (``OK``)
|
|
is returned on success and a negated ``errno`` is returned on failure.
|
|
|
|
.. c:function:: int unload_module(FAR struct binary_s *bin)
|
|
|
|
Unload a (non-executing) module from memory. If the module has been started
|
|
(via :c:func:`exec_module`) and has not exited, calling this will be fatal.
|
|
|
|
However, this function must be called after the module exist. How this is
|
|
done is up to your logic. Perhaps you register it to be called by :c:func:`on_exit`?
|
|
|
|
:return:
|
|
This is a NuttX internal function so it follows the convention that 0 (``OK``)
|
|
is returned on success and a negated ``errno`` is returned on failure.
|
|
|
|
.. c:function:: int exec_module(FAR const struct binary_s *bin);
|
|
|
|
Execute a module that has been loaded into memory by :c:func:`load_module`.
|
|
|
|
:return:
|
|
This is a NuttX internal function so it follows the convention that 0 (``OK``)
|
|
is returned on success and a negated ``errno`` is returned on failure.
|
|
|
|
.. tip::
|
|
The function :c:func:`exec` is a convenience function that wraps
|
|
:c:func:`load_module` and :c:func:`exec_module` into one call.
|
|
|
|
``PATH`` traversal logic
|
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
.. c:function:: ENVPATH_HANDLE envpath_init(void);
|
|
|
|
Initialize for the traversal of each value in the ``PATH`` variable. The
|
|
usage is sequence is as follows:
|
|
|
|
#. Call :c:func:`envpath_init` to initialize for the traversal.
|
|
``envpath_init()`` will return an opaque handle that can then be
|
|
provided to :c:func:`envpath_next` and :c:func:`envpath_release`.
|
|
#. Call :c:func:`envpath_next` repeatedly to examine every file that lies in
|
|
the directories of the ``PATH`` variable.
|
|
#. Call :c:func:`envpath_release` to free resources set aside by
|
|
:c:func:`envpath_init`.
|
|
|
|
:return:
|
|
On success, :c:func:`envpath_init` return a non-``NULL``, opaque handle
|
|
that may subsequently be used in calls to :c:func:`envpath_next` and
|
|
:c:func:`envpath_release`. On error, a ``NULL`` handle value will be returned.
|
|
The most likely cause of an error would be that there is no value
|
|
associated with the ``PATH`` variable.
|
|
|
|
.. c:function:: FAR char *envpath_next(ENVPATH_HANDLE handle, FAR const char *relpath)
|
|
|
|
Traverse all possible values in the PATH variable in attempt to find the
|
|
full path to an executable file when only a relative path is provided.
|
|
|
|
:param handle: The handle value returned by :c:func:`envpath_init`.
|
|
:param relpath: The relative path to the file to be found.
|
|
|
|
:return:
|
|
On success, a non-``NULL`` pointer to a null-terminated string is provided.
|
|
This is the full path to a file that exists in the file system.
|
|
This function will verify that the file exists (but will not verify that it is marked executable).
|
|
|
|
.. note::
|
|
The string pointer return in the success case points to allocated memory.
|
|
This memory must be freed by the called by calling :c:func:`kmm_free`.
|
|
|
|
``NULL`` relpath from any absolute path in the ``PATH`` variable.
|
|
In this case, there is no point in calling :c:func:`envpath_next` further;
|
|
:c:func:`envpath_release` must be called to release resources set aside by
|
|
:c:func:`envpath_init`.
|
|
|
|
.. c:function:: void envpath_release(ENVPATH_HANDLE handle)
|
|
|
|
Release all resources set aside by envpath_init when the
|
|
handle value was created. The handle value is invalid on
|
|
return from this function. Attempts to all :c:func:`envpath_next`
|
|
or :c:func:`envpath_release` with such a stale handle will result
|
|
in undefined (i.e., not good) behavior.
|
|
|
|
:param handle: The handle value returned by :c:func:`envpath_init`.
|
|
|
|
Symbol Tables
|
|
=============
|
|
|
|
**Symbol Tables**. Symbol tables are lists of name value mappings: The
|
|
name is a string that identifies a symbol, and the value is an address
|
|
in memory where the symbol of that name has been positioned. In most
|
|
NuttX architectures symbol tables are required, as a minimum, in order
|
|
to dynamically link the loaded binary object with the base code on
|
|
FLASH. Since the binary object was separately built and separately
|
|
linked, these symbols will appear as *undefined* symbols in the binary
|
|
object. The binary loader will use the symbol table to look up the
|
|
symbol by its name and to provide the address associated with the symbol
|
|
as needed to perform the dynamic linking of the binary object to the
|
|
base FLASH code.
|
|
|
|
Some toolchains will prefix symbols with an underscore. To support these
|
|
toolchains the ``CONFIG_SYMTAB_DECORATED`` setting may be defined. This
|
|
will cause a leading underscore to be ignored on *undefined* symbols
|
|
during dynamic linking.
|
|
|
|
Symbol Table Header Files
|
|
-------------------------
|
|
|
|
The interface to the symbol table logic is described in the header file
|
|
``include/nuttx/binfmt/symtab.h``.
|
|
A brief summary of the data structurs and interfaces prototyped in that
|
|
header file are listed below.
|
|
|
|
Symbol Table Data Structures
|
|
----------------------------
|
|
|
|
.. c:struct:: symbtab_s
|
|
|
|
Describes one entry in the symbol table.
|
|
|
|
.. code-block:: c
|
|
|
|
struct symtab_s
|
|
{
|
|
FAR const char *sym_name; /* A pointer to the symbol name string */
|
|
FAR const void *sym_value; /* The value associated with the string */
|
|
};
|
|
|
|
A symbol table is a fixed size array of ``struct symtab_s``. The
|
|
information is intentionally minimal and supports only:
|
|
|
|
#. Function pointers as ``sym_values``. Of other kinds of values need to
|
|
be supported, then typing information would also need to be included
|
|
in the structure.
|
|
#. Fixed size arrays. There is no explicit provisional for dynamically
|
|
adding or removing entries from the symbol table (realloc might be
|
|
used for that purpose if needed). The intention is to support only
|
|
fixed size arrays completely defined at compilation or link time.
|
|
|
|
Symbol Table Function Interfaces
|
|
--------------------------------
|
|
|
|
.. c:function:: FAR const struct symtab_s *symtab_findbyname(FAR const struct symtab_s *symtab, FAR const char *name, int nsyms);
|
|
|
|
Find the symbol in the symbol table with the matching name.
|
|
The implementation will be linear with respect to ``nsyms`` if
|
|
``CONFIG_SYMTAB_ORDEREDBYNAME`` is not selected, and logarithmic
|
|
if it is.
|
|
|
|
:return:
|
|
A reference to the symbol table entry if an entry with
|
|
the matching name is found; NULL is returned if the entry is not found.
|
|
|
|
.. c:function:: FAR const struct symtab_s *symtab_findbyvalue(FAR const struct symtab_s *symtab, FAR void *value, int nsyms);
|
|
|
|
Find the symbol in the symbol table whose value closest
|
|
(but not greater than), the provided value. This version assumes
|
|
that table is not ordered with respect to symbol value and, hence,
|
|
access time will be linear with respect to ``nsyms``.
|
|
|
|
:return:
|
|
A reference to the symbol table entry if an entry with the matching
|
|
value is found; ``NULL`` is returned if the entry is not found.
|
|
|
|
Configuration Variables
|
|
=======================
|
|
|
|
- ``CONFIG_BINFMT_DISABLE``: By default, support for loadable binary formats is built.
|
|
This logic may be suppressed be defining this setting.
|
|
- ``CONFIG_BINFMT_CONSTRUCTORS``: Build in support for C++ constructors in loaded modules.
|
|
- ``CONFIG_SYMTAB_ORDEREDBYNAME``: Symbol tables are order by name (rather than value).
|
|
- ``CONFIG_SYMTAB_DECORATED``: Symbols will have a leading underscore in object files.
|
|
|
|
Additional configuration options may be required for the each enabled
|
|
binary format.
|