mirror of
https://github.com/apache/nuttx.git
synced 2025-01-12 22:08:35 +08:00
Doc: loading ELF program
Some checks are pending
Build Documentation / build-html (push) Waiting to run
Some checks are pending
Build Documentation / build-html (push) Waiting to run
Migrate the Updating a release System with ELF programs with child pages to official wiki
This commit is contained in:
parent
f0a3c43a54
commit
04c7391162
6 changed files with 991 additions and 1 deletions
533
Documentation/guides/fully_linked_elf.rst
Normal file
533
Documentation/guides/fully_linked_elf.rst
Normal file
|
@ -0,0 +1,533 @@
|
||||||
|
ELF Programs – No Symbol Tables
|
||||||
|
===============================
|
||||||
|
|
||||||
|
You can easily extend the firmware in your released, embedded system using ELF
|
||||||
|
programs provided via a file system (for example, an SD card or downloaded into
|
||||||
|
on-board SPI FLASH). In order to support such post-release updates, your
|
||||||
|
released firmware would have to support execution of fully linked, relocatable
|
||||||
|
ELF programs loaded into RAM (see, for example, ``apps/examples/elf``).
|
||||||
|
|
||||||
|
The files shown in this Wiki page can be downloaded `here <https://cwiki.apache.org/confluence/download/attachments/139629402/elfprog-nosymtab.tar.gz?version=1&modificationDate=1576735520000&api=v2>`_.
|
||||||
|
|
||||||
|
Alan Carvalho de Assis has also made a video based on this example in the
|
||||||
|
YouTube `NuttX Channel <https://www.youtube.com/watch?v=oL6KAgkTb8M>`_.
|
||||||
|
|
||||||
|
Creating the Export Package
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
At the time that you release the firmware, you should create and save an
|
||||||
|
export package. The export package is all that you need to create
|
||||||
|
post-release, add-on modules for your embedded system. Let's illustrate this
|
||||||
|
using the ``STM32F4-Discovery`` networking ``NSH`` configuration with the
|
||||||
|
``STM32F4DIS-BB`` baseboard. (This demonstration assumes that you also have
|
||||||
|
support for some externally modifiable media in the board configuration, such
|
||||||
|
as removable media like an SD card, or a USB FLASH stick, an internal file
|
||||||
|
system remotely accessible via USB MSC, FTP, or any remote file system (NFS).
|
||||||
|
The networking ``NSH`` configuration uses the SD card on the STM32 baseboard
|
||||||
|
for this demonstration. Other ``NSH`` configurations could be used, provided
|
||||||
|
that you supply the necessary file system support in some fashion.)
|
||||||
|
|
||||||
|
(No baseboard? You can add file system support to the basic ``STM32F4-Discovery``
|
||||||
|
board by following these instructions:
|
||||||
|
`USB FLASH drive <https://www.youtube.com/watch?v=5hB5ZXpRoS4>`_
|
||||||
|
or `SD card <https://www.youtube.com/watch?v=H28t4RbOXqI>`_.)
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make distclean
|
||||||
|
$ tools/configure.sh -c stm32f4discovery:netnsh
|
||||||
|
$ make menuconfig
|
||||||
|
|
||||||
|
Your released firmware would have to have been built with a few important
|
||||||
|
configuration settings:
|
||||||
|
|
||||||
|
1. Disable networking (Only because it is not needed in this example):
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
# CONFIG_NET is not set
|
||||||
|
|
||||||
|
2. Enable basic ELF binary support with no built-in symbol table support:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_ELF=y
|
||||||
|
CONFIG_LIBC_EXECFUNCS=y
|
||||||
|
# CONFIG_EXECFUNCS_HAVE_SYMTAB is not set
|
||||||
|
|
||||||
|
3. Enable PATH variable support:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_BINFMT_EXEPATH=y
|
||||||
|
CONFIG_PATH_INITIAL="/bin"
|
||||||
|
# CONFIG_DISABLE_ENVIRON not set
|
||||||
|
|
||||||
|
4. Enable execution of ELF files from the ``NSH`` command line:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_NSH_FILE_APPS=y
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
You must enable some application that uses ``printf()``. This is necessary
|
||||||
|
to assure that the symbol ``printf()`` is included in the base system.
|
||||||
|
Here we assume that you include the "Hello, World!" example from
|
||||||
|
``apps/examples/hello``:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_EXAMPLES_HELLO=y
|
||||||
|
|
||||||
|
Then we can build the NuttX firmware image and the export package:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make
|
||||||
|
$ make export
|
||||||
|
|
||||||
|
When ``make export`` completes, you will find a ZIP'ed package in the top-level
|
||||||
|
NuttX directory called ``nuttx-export-x.y.zip`` (for version ``x.y``). The
|
||||||
|
version is determined by the ``.version`` file in the same directory. The
|
||||||
|
content of this ZIP file is the following directory structure:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
nuttx-export-x.x
|
||||||
|
|- arch/
|
||||||
|
|- build/
|
||||||
|
|- include/
|
||||||
|
|- libs/
|
||||||
|
|- startup/
|
||||||
|
|- System.map
|
||||||
|
`- .config
|
||||||
|
|
||||||
|
The Add-On Build Directory
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
In order to create the add-on ELF program, you will need (1) the export
|
||||||
|
package, (2) the program build ``Makefile``, (3) a linker script used by the
|
||||||
|
``Makefile``, and (4) a Bash script to create a linker script. That
|
||||||
|
``Makefile`` and Bash Script are discussed in the following paragraphs.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
These example files implicitly assume a GNU tool chain is used and, in at
|
||||||
|
least one place, that the target is an ARMv7-M platform. A non-GNU tool
|
||||||
|
chain would probably require a significantly different ``Makefile`` and
|
||||||
|
linker script. There is at least one ARMv7-M specific change that would
|
||||||
|
have to be made for other platforms in the script that creates the linker
|
||||||
|
script (``mkdefines.sh``).
|
||||||
|
|
||||||
|
Hello Example
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To keep things manageable, let's use a concrete example. Suppose the ELF
|
||||||
|
program that we wish to add to the release code is the single source file
|
||||||
|
``hello.c``:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("Hello from Add-On Program!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Let's say that we have a directory called ``addon`` and it contains the
|
||||||
|
``hello.c`` source file, a ``Makefile`` that will create the ELF program, and a
|
||||||
|
Bash script called ``mkdefines.sh`` that will create a linker script.
|
||||||
|
|
||||||
|
Building the ELF Program
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The first step in creating the ELF program is to unzip the Export Package. We
|
||||||
|
start with our ``addon`` directory containing the following:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ cd addon
|
||||||
|
$ ls
|
||||||
|
gnu-elf.ld hello.c Makefile mkdefines.sh nuttx-export-7.25.zip
|
||||||
|
|
||||||
|
Where:
|
||||||
|
|
||||||
|
- ``gnu-elf.ld`` is the linker script.
|
||||||
|
- ``hello.c`` is our example source file.
|
||||||
|
- ``Makefile`` will build our ELF program and symbol table.
|
||||||
|
- ``mksymtab.h`` is the Bash script that will create the symbol table for the
|
||||||
|
ELF program.
|
||||||
|
- ``nuttx-export-7.25.zip`` is the Export Package for NuttX-7.25.
|
||||||
|
|
||||||
|
We unzip the Export Package like:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ unzip nuttx-export-7.25.zip
|
||||||
|
|
||||||
|
Then we have a new directory called ``nuttx-export-7.25`` that contains all of
|
||||||
|
the content from the released NuttX code that we need to build the ELF
|
||||||
|
program.
|
||||||
|
|
||||||
|
The Makefile
|
||||||
|
------------
|
||||||
|
|
||||||
|
The ELF program is created simply as:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make
|
||||||
|
|
||||||
|
This uses the following ``Makefile`` to generate several files:
|
||||||
|
|
||||||
|
- ``hello.o``: The compiled ``hello.c`` object.
|
||||||
|
- ``hello.r``: A "partially linked" ELF object that still has undefined
|
||||||
|
symbols.
|
||||||
|
- ``hello``: The fully linked, relocatable ELF program.
|
||||||
|
- ``linker.ld``: A linker script created by ``mkdefines.sh``.
|
||||||
|
|
||||||
|
Only the resulting ``hello`` is needed.
|
||||||
|
|
||||||
|
Below is the ``Makefile`` used to create the ELF program:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
include nuttx-export-7.25/build/Make.defs
|
||||||
|
|
||||||
|
# Long calls are need to call from RAM into FLASH
|
||||||
|
|
||||||
|
ARCHCFLAGS += -mlong-calls
|
||||||
|
ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
|
||||||
|
ARCHOPTIMIZATION = -Os -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer
|
||||||
|
ARCHINCLUDES = -I. -isystem nuttx-export-7.25/include
|
||||||
|
|
||||||
|
CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHINCLUDES) -pipe
|
||||||
|
|
||||||
|
CROSSDEV = arm-none-eabi-
|
||||||
|
CC = $(CROSSDEV)gcc
|
||||||
|
LD = $(CROSSDEV)ld
|
||||||
|
STRIP = $(CROSSDEV)strip --strip-unneeded
|
||||||
|
|
||||||
|
# Setup up linker command line options
|
||||||
|
|
||||||
|
LDRELFLAGS = -r
|
||||||
|
|
||||||
|
LDELFFLAGS = -r -e main
|
||||||
|
LDELFFLAGS += -T defines.ld -T gnu-elf.ld
|
||||||
|
|
||||||
|
# This might change in a different environment
|
||||||
|
|
||||||
|
OBJEXT ?= .o
|
||||||
|
|
||||||
|
# This is the generated ELF program
|
||||||
|
|
||||||
|
BIN = hello
|
||||||
|
REL = hello.r
|
||||||
|
|
||||||
|
# These are the sources files that we use
|
||||||
|
|
||||||
|
SRCS = hello.c
|
||||||
|
OBJS = $(SRCS:.c=$(OBJEXT))
|
||||||
|
|
||||||
|
# Build targets
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
$(OBJS): %$(OBJEXT): %.c
|
||||||
|
$(CC) -c $(CFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
System.map: nuttx-export-7.25/System.map
|
||||||
|
cat nuttx-export-7.25/System.map | sed -e "s/\r//g" >System.map
|
||||||
|
|
||||||
|
$(REL): $(OBJS)
|
||||||
|
$(LD) $(LDRELFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
defines.ld: System.map $(REL)
|
||||||
|
./mkdefines.sh System.map "$(REL)" >defines.ld
|
||||||
|
|
||||||
|
$(BIN): defines.ld $(REL)
|
||||||
|
$(LD) $(LDELFFLAGS) -o $@ $(REL)
|
||||||
|
$(STRIP) $(REL)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN)
|
||||||
|
rm -f $(REL)
|
||||||
|
rm -f defines.ld
|
||||||
|
rm -f System.map
|
||||||
|
rm -f *.o
|
||||||
|
|
||||||
|
The Linker Script
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Two linker scripts are used. One is a normal file (we'll call it the main
|
||||||
|
linker script), and the other, ``defines.ld``, is created on-the-fly as
|
||||||
|
described in the next section.
|
||||||
|
|
||||||
|
The main linker script, ``gnu-elf.ld``, contains the following:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text 0x00000000 :
|
||||||
|
{
|
||||||
|
_stext = . ;
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.stub)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.jcr)
|
||||||
|
_etext = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
_srodata = . ;
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata1)
|
||||||
|
*(.rodata.*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
_erodata = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
_sdata = . ;
|
||||||
|
*(.data)
|
||||||
|
*(.data1)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
_edata = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
_sbss = . ;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss.*)
|
||||||
|
*(.sbss)
|
||||||
|
*(.sbss.*)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(COMMON)
|
||||||
|
_ebss = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
}
|
||||||
|
|
||||||
|
Creating the ``defines.ld`` Linker Script
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
The additional linker script ``defines.ld`` is created through a three-step
|
||||||
|
process:
|
||||||
|
|
||||||
|
1. The ``Makefile`` generates a partially linked ELF object, ``hello.r``.
|
||||||
|
2. The ``Makefile`` then invokes the ``mkdefines.sh`` script, which generates
|
||||||
|
the ``defines.ld`` linker script that provides values for all of the
|
||||||
|
undefined symbols.
|
||||||
|
3. Finally, the ``Makefile`` produces the fully linked, relocatable ``hello``
|
||||||
|
ELF object using the ``defines.ld`` linker script.
|
||||||
|
|
||||||
|
Below is the version of ``mkdefines.sh`` used in this demo:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
usage="Usage: $0 <system-map> <relprog>"
|
||||||
|
|
||||||
|
# Check for the required path to the System.map file
|
||||||
|
|
||||||
|
sysmap=$1
|
||||||
|
if [ -z "$sysmap" ]; then
|
||||||
|
echo "ERROR: Missing <system-map>"
|
||||||
|
echo ""
|
||||||
|
echo $usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for the required partially linked file
|
||||||
|
|
||||||
|
relprog=$2
|
||||||
|
if [ -z "$relprog" ]; then
|
||||||
|
echo "ERROR: Missing <program-list>"
|
||||||
|
echo ""
|
||||||
|
echo $usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verify the System.map and the partially linked file
|
||||||
|
|
||||||
|
if [ ! -r "$sysmap" ]; then
|
||||||
|
echo "ERROR: $sysmap does not exist"
|
||||||
|
echo ""
|
||||||
|
echo $usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -r "$relprog" ]; then
|
||||||
|
echo "ERROR: $relprog does not exist"
|
||||||
|
echo ""
|
||||||
|
echo $usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Extract all of the undefined symbols from the partially linked file and create a
|
||||||
|
# list of sorted, unique undefined variable names.
|
||||||
|
|
||||||
|
varlist=`nm $relprog | fgrep ' U ' | sed -e "s/^[ ]*//g" | cut -d' ' -f2 | sort - | uniq`
|
||||||
|
|
||||||
|
# Now output the linker script that provides a value for all of the undefined symbols
|
||||||
|
|
||||||
|
for var in $varlist; do
|
||||||
|
map=`grep " ${var}$" ${sysmap}`
|
||||||
|
if [ -z "$map" ]; then
|
||||||
|
echo "ERROR: Variable $var not found in $sysmap"
|
||||||
|
echo ""
|
||||||
|
echo $usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
varaddr=`echo ${map} | cut -d' ' -f1`
|
||||||
|
echo "${var} = 0x${varaddr} | 0x00000001;"
|
||||||
|
done
|
||||||
|
|
||||||
|
This script uses the ``nm`` utility to find all of the undefined symbols in the
|
||||||
|
ELF object, then searches for the address of each undefined symbol in the
|
||||||
|
``System.map`` that was created when the released firmware was built. Finally,
|
||||||
|
it uses the symbol name and the symbol address to create each symbol table
|
||||||
|
entry.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
- For the ARMv7-M architecture, bit 0 of the address must be set to indicate
|
||||||
|
thumb mode. If you are using a different architecture that requires
|
||||||
|
normal aligned addresses, you will need to change the following line by
|
||||||
|
eliminating the ORed value:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
echo "${var} = 0x${varaddr} | 0x00000001;"
|
||||||
|
|
||||||
|
- If the new ELF module uses a symbol that is not provided in the base
|
||||||
|
firmware and, hence, not included in the ``System.map`` file, this script
|
||||||
|
will fail. In that case, you will need to provide the missing logic
|
||||||
|
within the ELF program itself, if possible.
|
||||||
|
|
||||||
|
- The technique as described here is only valid in the FLAT build mode. It
|
||||||
|
could probably also be extended to work in the PROTECTED mode by
|
||||||
|
substituting ``User.map`` for ``System.map``.
|
||||||
|
|
||||||
|
Here is an example ``defines.ld`` created by ``mkdefines.sh``:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
printf = 0x0800aefc | 0x00000001 ;
|
||||||
|
|
||||||
|
Replacing an NSH Built-In Function
|
||||||
|
----------------------------------
|
||||||
|
|
||||||
|
Files can be executed by ``NSH`` from the command line by simply typing the
|
||||||
|
name of the ELF program. This requires:
|
||||||
|
|
||||||
|
1. That the feature be enabled with``CONFIG_NSH_FILE_APP=y``
|
||||||
|
2. That support for the PATH variable is enabled (``CONFIG_BINFMT_EXEPATH=y`` and
|
||||||
|
``CONFIG_PATH_INITIAL`` set to the mount point of the file system that
|
||||||
|
may contain ELF programs).
|
||||||
|
|
||||||
|
Suppose, for example, I have a built-in application called ``hello``. Before
|
||||||
|
installing the new replacement ``hello`` ELF program in the file system, this
|
||||||
|
is the version of ``hello`` that ``NSH`` will execute:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
nsh> hello
|
||||||
|
Hello, World!
|
||||||
|
nsh>
|
||||||
|
|
||||||
|
In the above configuration, ``NSH`` will first attempt to run the program called
|
||||||
|
``hello`` from the file system. This will fail because we have not yet placed
|
||||||
|
our custom ``hello`` ELF program in the file system. So instead, ``NSH`` will
|
||||||
|
fall back and execute the built-in application called ``hello``.
|
||||||
|
|
||||||
|
In this way, any command known to ``NSH`` can be replaced by an ELF program
|
||||||
|
installed in a mounted file system directory that is found via the PATH
|
||||||
|
variable.
|
||||||
|
|
||||||
|
Now suppose that we do add our custom ``hello`` to the file system. When
|
||||||
|
``NSH`` attempts to run the program called ``hello`` from the file system, it
|
||||||
|
will run successfully. The built-in version will be ignored. It has been
|
||||||
|
replaced with the version in the file system:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
nsh> mount -t vfat /dev/mmcsd0 /bin
|
||||||
|
nsh> hello
|
||||||
|
Hello from Add-On Program!
|
||||||
|
nsh>
|
||||||
|
|
||||||
|
Version Dependency
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This technique generates ELF programs using fixed addresses from the
|
||||||
|
``System.map`` file of a versioned release. The generated ELF programs can
|
||||||
|
only be used with that specific firmware version. A crash will most likely
|
||||||
|
result if used with a different firmware version, because the addresses
|
||||||
|
from the ``System.map`` will not match the addresses in a different version
|
||||||
|
of the firmware.
|
||||||
|
|
||||||
|
The alternative approach using :doc:`Symbol Tables <fully_linked_elf>` is more
|
||||||
|
or less version independent.
|
||||||
|
|
||||||
|
Tightly Coupled Memories
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Most MCUs based on ARMv7-M family processors support some kind of Tightly
|
||||||
|
Coupled Memory (TCM). These TCMs have somewhat different properties for
|
||||||
|
specialized operations. Depending on the bus matrix of the processor, you may
|
||||||
|
not be able to execute programs from TCM. For instance, the ``STM32 F4``
|
||||||
|
supports Core Coupled Memory (CCM), but since it is tied directly to the D-bus,
|
||||||
|
it cannot be used to execute programs! On the other hand, the ``STM32F3`` has a
|
||||||
|
CCM that is accessible to both the D-Bus and the I-Bus, in which case it
|
||||||
|
should be possible to execute programs from this TCM.
|
||||||
|
|
||||||
|
.. image:: ./image/system_arch_stm32f42xx_and_f43xx.png
|
||||||
|
|
||||||
|
.. image:: ./image/system_arch_stm32f303xBC_and_f358xC.png
|
||||||
|
|
||||||
|
When ELF programs are loaded into memory, the memory is allocated from the
|
||||||
|
heap via a standard memory allocator. By default with the ``STM32 F4``, the
|
||||||
|
CCM is included in ``HEAP`` and will typically be allocated first. If CCM
|
||||||
|
memory is allocated to hold the ELF program, a hard-fault will occur
|
||||||
|
immediately when you try to execute the ELF program in memory.
|
||||||
|
|
||||||
|
Therefore, it is necessary on ``STM32 F4`` platforms to include the following
|
||||||
|
configuration setting:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_STM32_CCMEXCLUDE=y
|
||||||
|
|
||||||
|
With that setting, the CCM memory will be excluded from the heap, and so will
|
||||||
|
never be allocated for ELF program memory.
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
Documentation/guides/image/system_arch_stm32f42xx_and_f43xx.png
Normal file
BIN
Documentation/guides/image/system_arch_stm32f42xx_and_f43xx.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 68 KiB |
|
@ -56,4 +56,7 @@ Guides
|
||||||
signal_events_interrupt_handlers.rst
|
signal_events_interrupt_handlers.rst
|
||||||
signaling_sem_priority_inheritance.rst
|
signaling_sem_priority_inheritance.rst
|
||||||
smaller_vector_tables.rst
|
smaller_vector_tables.rst
|
||||||
port.rst
|
port.rst
|
||||||
|
updating_release_system_elf.rst
|
||||||
|
partially_linked_elf.rst
|
||||||
|
fully_linked_elf.rst
|
429
Documentation/guides/partially_linked_elf.rst
Normal file
429
Documentation/guides/partially_linked_elf.rst
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
ELF Programs – With Symbol Tables
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Updating a Release System with ELF Programs – With Symbol Tables
|
||||||
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
|
You can easily extend the firmware in your released, embedded system using
|
||||||
|
ELF programs provided via a file system. For example, an SD card or, perhaps,
|
||||||
|
downloaded into on-board SPI FLASH.
|
||||||
|
|
||||||
|
In order to support such post-release updates, your released firmware must
|
||||||
|
support execution of ELF programs loaded into RAM and symbol tables also
|
||||||
|
provided via the file system (see `apps/examples/elf`).
|
||||||
|
|
||||||
|
The files shown in this Wiki page can be downloaded
|
||||||
|
`here <https://cwiki.apache.org/confluence/download/attachments/139629402/elfprog-wsymtab.tar.gz?version=1&modificationDate=1576735523000&api=v2>`_
|
||||||
|
|
||||||
|
Creating a Symbol Table
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
There are several ways to create an application symbol table. Only two are
|
||||||
|
compatible with the example provided here:
|
||||||
|
|
||||||
|
1. **Board-specific Bring-up Logic**
|
||||||
|
Build a symbol table into the base firmware and add it to your
|
||||||
|
board-specific bring-up logic. This technique is typically used in kernel
|
||||||
|
mode with ``CONFIG_USER_INITPATH=y``.
|
||||||
|
|
||||||
|
In this setup, the system does not initialize using a standard C call like
|
||||||
|
``nsh_main()``. Instead, it starts with an ``init`` ELF program, similar to
|
||||||
|
how Linux initializes. The configuration option
|
||||||
|
``CONFIG_EXECFUNCS_SYMTAB_ARRAY`` initializes the system with a minimal set
|
||||||
|
of symbols required by the ``init`` program. Once initialized, the ``init``
|
||||||
|
program would typically call ``boardctl()`` to put the final symbol table in
|
||||||
|
place.
|
||||||
|
|
||||||
|
To enable this method, you must:
|
||||||
|
|
||||||
|
- Set ``CONFIG_EXECFUNCS_HAVE_SYMTAB=y`` in your configuration.
|
||||||
|
- Provide a symbol table with the global name ``CONFIG_EXECFUNCS_SYMTAB_ARRAY`` with the variable name ``CONFIG_EXECFUNCS_NSYMBOLS_VAR`` that holds the number of symbol entries. The default symbol table name is ``g_symtab``.
|
||||||
|
|
||||||
|
In this example, let's illustrate this using an STM32F4-Discovery
|
||||||
|
configuration. We will assume that you have modified the
|
||||||
|
``boards/arm/stm32/stm32fdiscovery/src/stm32_bringup.c`` file, adding the
|
||||||
|
following:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <nuttx/binfmt/symtab.h>
|
||||||
|
|
||||||
|
const struct symtab_s g_symtab[] = {
|
||||||
|
{"printf", (FAR void *)printf}
|
||||||
|
};
|
||||||
|
|
||||||
|
int g_nsymbols = 1;
|
||||||
|
|
||||||
|
This is a simple symbol table containing only the symbol string "printf,"
|
||||||
|
whose value is the address of the function ``printf()``.
|
||||||
|
|
||||||
|
There is, of course, a lot more that could be said about generating symbol
|
||||||
|
tables. NuttX provides specialized tools in the ``tools/`` directory and
|
||||||
|
instructions elsewhere for generating more extensive symbol tables. However,
|
||||||
|
this example keeps things simple to focus on the core functionality.
|
||||||
|
|
||||||
|
2. **Application Logic**
|
||||||
|
Alternatively, the symbol table can be provided dynamically by the
|
||||||
|
application itself, using the ``boardctl()`` system interface. The specific
|
||||||
|
``boardctl()`` command to use is ``BOARDIOC_APP_SYMTAB``. This command
|
||||||
|
provides the symbol table in the same way as the board-specific logic but
|
||||||
|
allows for application-level control.
|
||||||
|
|
||||||
|
To use this approach, you need to:
|
||||||
|
- Enable the configurations ``CONFIG_LIB_BOARDCTL=y`` and ``CONFIG_BOARDCTL_APP_SYMTAB=y``.
|
||||||
|
- Include application logic to provide the symbol table. If ``CONFIG_EXAMPLES_NSH_SYMTAB=y`` is set, NSH can handle this automatically.
|
||||||
|
|
||||||
|
Export Package
|
||||||
|
--------------
|
||||||
|
|
||||||
|
At the time of firmware release, you should create and save an export package.
|
||||||
|
This export package contains all the necessary files required to create
|
||||||
|
post-release add-on modules for your embedded system.
|
||||||
|
|
||||||
|
For demonstration purposes, we use the STM32F4-Discovery with the network NSH
|
||||||
|
configuration. This setup assumes that you have the STM32F4DIS-BB baseboard.
|
||||||
|
The demonstration also requires support for externally modifiable media, such
|
||||||
|
as:
|
||||||
|
|
||||||
|
- Removable media, like an SD card or USB flash drive.
|
||||||
|
- An internal file system remotely accessible via USB MSC, FTP, or other
|
||||||
|
protocols.
|
||||||
|
- A remote file system, such as NFS.
|
||||||
|
|
||||||
|
In this demonstration, the networking NSH configuration uses the SD card on
|
||||||
|
the STM32 baseboard. Other NSH configurations can also be used, provided they
|
||||||
|
supply the necessary file system support.
|
||||||
|
|
||||||
|
(No baseboard? You can add file system support to the basic ``STM32F4-Discovery``
|
||||||
|
board by following these instructions:
|
||||||
|
`USB FLASH drive <https://www.youtube.com/watch?v=5hB5ZXpRoS4>`_
|
||||||
|
or `SD card <https://www.youtube.com/watch?v=H28t4RbOXqI>`_.)
|
||||||
|
|
||||||
|
Example for STM32F4-Discovery:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make distclean
|
||||||
|
$ tools/configure.sh -c stm32f4discovery:netnsh
|
||||||
|
$ make menuconfig
|
||||||
|
|
||||||
|
Required configurations:
|
||||||
|
|
||||||
|
- Disable networking: ``# CONFIG_NET is not set``
|
||||||
|
- Enable ELF binary support: ``CONFIG_ELF=y``, ``CONFIG_LIBC_EXECFUNCS=y``,
|
||||||
|
``CONFIG_EXECFUNCS_HAVE_SYMTAB=y``, ``CONFIG_EXECFUNCS_SYMTAB_ARRAY="g_symtab"`` and
|
||||||
|
``CONFIG_EXECFUNCS_NSYMBOLS_VAR="g_nsymbols"``
|
||||||
|
- Enable PATH variable support: ``CONFIG_BINFMT_EXEPATH=y``,
|
||||||
|
``CONFIG_PATH_INITIAL="/bin"``
|
||||||
|
- Enable execution from NSH: ``CONFIG_NSH_FILE_APPS=y``
|
||||||
|
|
||||||
|
Then, build the NuttX firmware image and the export package:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make
|
||||||
|
$ make export
|
||||||
|
|
||||||
|
When ``make export`` completes, you will find a ZIP package in the top-level
|
||||||
|
NuttX directory called ``nuttx-export-x.y.zip`` (where x.y corresponds to the
|
||||||
|
version, determined by the .version file in the same directory). The contents
|
||||||
|
of this ZIP file are organized as follows:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
nuttx-export-x.x
|
||||||
|
|- arch/
|
||||||
|
|- build/
|
||||||
|
|- include/
|
||||||
|
|- libs/
|
||||||
|
|- startup/
|
||||||
|
|- System.map
|
||||||
|
`- .config
|
||||||
|
|
||||||
|
Add-On Build Directory
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
In order to create the add-on ELF program, you will need:
|
||||||
|
|
||||||
|
1. The export package.
|
||||||
|
2. A program build Makefile.
|
||||||
|
3. A linker script used by the Makefile.
|
||||||
|
|
||||||
|
The example Makefile discussed below assumes the use of a GNU toolchain. Note
|
||||||
|
that non-GNU toolchains would likely require a significantly different
|
||||||
|
Makefile and linker script.
|
||||||
|
|
||||||
|
Hello Example
|
||||||
|
-------------
|
||||||
|
|
||||||
|
To keep things manageable, let's use a concrete example. Suppose the ELF
|
||||||
|
program that we wish to add to the release code is the simple
|
||||||
|
source file ``hello.c``:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
printf("Hello from Add-On Program!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Let's say that we have a directory called ``addon`` that contains the following:
|
||||||
|
|
||||||
|
1. The ``hello.c`` source file.
|
||||||
|
2. A Makefile to build the ELF program.
|
||||||
|
3. A linker script called ``gnu-elf.ld`` needed by the Makefile.
|
||||||
|
4. The export package ``nuttx-export-7.25.zip``.
|
||||||
|
|
||||||
|
|
||||||
|
Building the ELF Program
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
The first step in creating the ELF program is to unzip the export
|
||||||
|
package. Starting in the ``addon`` directory:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ cd addon
|
||||||
|
$ ls
|
||||||
|
gnu-elf.ld hello.c Makefile nuttx-export-7.25.zip
|
||||||
|
|
||||||
|
Where:
|
||||||
|
- ``gnu-elf.ld`` is the linker script.
|
||||||
|
- ``hello.c`` is the example source file.
|
||||||
|
- ``Makefile`` builds the ELF program.
|
||||||
|
- ``nuttx-export-7.25.zip`` is the export package from NuttX 7.25.
|
||||||
|
|
||||||
|
Unzip the export package as follows:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ unzip nuttx-export-7.25.zip
|
||||||
|
|
||||||
|
This creates a new directory called ``nuttx-export-7.25``, containing
|
||||||
|
all the content from the released NuttX code required to build
|
||||||
|
the ELF program.
|
||||||
|
|
||||||
|
|
||||||
|
The Makefile
|
||||||
|
------------
|
||||||
|
|
||||||
|
To build the ELF program, simply run:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ make
|
||||||
|
|
||||||
|
This uses the following Makefile to generate several files:
|
||||||
|
- ``hello.o``: The compiled object file for ``hello.c``.
|
||||||
|
- ``hello``: The linked ELF program.
|
||||||
|
|
||||||
|
Only the resulting ``hello`` file is needed.
|
||||||
|
|
||||||
|
The Makefile used to create the ELF program is as follows:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
include nuttx-export-7.25/build/Make.defs
|
||||||
|
|
||||||
|
# Long calls are need to call from RAM into FLASH
|
||||||
|
|
||||||
|
ARCHCFLAGS += -mlong-calls
|
||||||
|
ARCHWARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wundef
|
||||||
|
ARCHOPTIMIZATION = -Os -fno-strict-aliasing -fno-strength-reduce -fomit-frame-pointer
|
||||||
|
ARCHINCLUDES = -I. -isystem nuttx-export-7.25/include
|
||||||
|
|
||||||
|
CFLAGS = $(ARCHCFLAGS) $(ARCHWARNINGS) $(ARCHOPTIMIZATION) $(ARCHINCLUDES) -pipe
|
||||||
|
|
||||||
|
CROSSDEV = arm-none-eabi-
|
||||||
|
CC = $(CROSSDEV)gcc
|
||||||
|
LD = $(CROSSDEV)ld
|
||||||
|
STRIP = $(CROSSDEV)strip --strip-unneeded
|
||||||
|
|
||||||
|
# Setup up linker command line options
|
||||||
|
|
||||||
|
LDELFFLAGS = -r -e main
|
||||||
|
LDELFFLAGS += -T gnu-elf.ld
|
||||||
|
|
||||||
|
# This might change in a different environment
|
||||||
|
|
||||||
|
OBJEXT ?= .o
|
||||||
|
|
||||||
|
# This is the generated ELF program
|
||||||
|
|
||||||
|
BIN = hello
|
||||||
|
|
||||||
|
# These are the sources files that we use
|
||||||
|
|
||||||
|
SRCS = hello.c
|
||||||
|
OBJS = $(SRCS:.c=$(OBJEXT))
|
||||||
|
|
||||||
|
# Build targets
|
||||||
|
|
||||||
|
all: $(BIN)
|
||||||
|
.PHONY: clean
|
||||||
|
|
||||||
|
$(OBJS): %$(OBJEXT): %.c
|
||||||
|
$(CC) -c $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
$(BIN): $(OBJS)
|
||||||
|
$(LD) $(LDELFFLAGS) -o $@ $^
|
||||||
|
$(STRIP) $(BIN)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(BIN)
|
||||||
|
rm -f *.o
|
||||||
|
|
||||||
|
The Linker Script
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The linker script that I am using in this example, gnu-elf.ld,
|
||||||
|
contains the following:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text 0x00000000 :
|
||||||
|
{
|
||||||
|
_stext = . ;
|
||||||
|
*(.text)
|
||||||
|
*(.text.*)
|
||||||
|
*(.gnu.warning)
|
||||||
|
*(.stub)
|
||||||
|
*(.glue_7)
|
||||||
|
*(.glue_7t)
|
||||||
|
*(.jcr)
|
||||||
|
_etext = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata :
|
||||||
|
{
|
||||||
|
_srodata = . ;
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata1)
|
||||||
|
*(.rodata.*)
|
||||||
|
*(.gnu.linkonce.r*)
|
||||||
|
_erodata = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
_sdata = . ;
|
||||||
|
*(.data)
|
||||||
|
*(.data1)
|
||||||
|
*(.data.*)
|
||||||
|
*(.gnu.linkonce.d*)
|
||||||
|
_edata = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
_sbss = . ;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss.*)
|
||||||
|
*(.sbss)
|
||||||
|
*(.sbss.*)
|
||||||
|
*(.gnu.linkonce.b*)
|
||||||
|
*(COMMON)
|
||||||
|
_ebss = . ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_info 0 : { *(.debug_info) }
|
||||||
|
.debug_line 0 : { *(.debug_line) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
}
|
||||||
|
|
||||||
|
Replacing NSH Built-In Functions
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Files can be executed by NSH from the command line by simply typing the name
|
||||||
|
of the ELF program. This requires (1) that the feature be enabled with
|
||||||
|
``CONFIG_NSH_FILE_APP=y`` and (2) that support for the PATH variable is
|
||||||
|
enabled with ``CONFIG_BINFMT_EXEPATH=y`` and ``CONFIG_PATH_INITIAL`` set to
|
||||||
|
the mount point of the file system that may contain ELF programs.
|
||||||
|
|
||||||
|
In this example, there is no application in the base firmware called
|
||||||
|
``hello``. So attempts to run ``hello`` will fail:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
nsh> hello
|
||||||
|
nsh: hello: command not found
|
||||||
|
nsh>
|
||||||
|
|
||||||
|
But if we mount the SD card containing the ``hello`` image that we created
|
||||||
|
above, then we can successfully execute the ``hello`` command:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
nsh> mount -t vfat /dev/mmcsd0 /bin
|
||||||
|
nsh> ls /bin
|
||||||
|
/bin:
|
||||||
|
System Volume Information/
|
||||||
|
hello
|
||||||
|
nsh> hello
|
||||||
|
Hello from Add-On Program!
|
||||||
|
nsh>
|
||||||
|
|
||||||
|
Here we showed how you can add a new command to NSH to a product without
|
||||||
|
modifying the base firmware. We can also replace or update an existing
|
||||||
|
built-in application in this way:
|
||||||
|
|
||||||
|
In the above configuration, NSH will first attempt to run the program called
|
||||||
|
``hello`` from the file system. This will fail because we have not yet put
|
||||||
|
our custom ``hello`` ELF program in the file system. So instead, NSH will
|
||||||
|
fallback and execute the built-in application called ``hello``. In this way,
|
||||||
|
any command known to NSH can be replaced from an ELF program installed in a
|
||||||
|
mounted file system directory that can be found via the PATH variable.
|
||||||
|
|
||||||
|
After we do add our custom ``hello`` to the file system, when NSH attempts to
|
||||||
|
run the program called ``hello`` from the file system it will run
|
||||||
|
successfully. The built-in version will be ignored. It has been replaced with
|
||||||
|
the version in the file system.
|
||||||
|
|
||||||
|
Tightly Coupled Memories
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Most MCUs based on ARMv7-M family processors support some kind of Tightly
|
||||||
|
Coupled Memory (TCM). These TCMs have somewhat different properties for
|
||||||
|
specialized operations. Depending on the bus matrix of the processor, you
|
||||||
|
may not be able to execute programs from the TCM. For instance, the STM32 F4
|
||||||
|
supports Core Coupled Memory (CCM), but since it is tied directly to the
|
||||||
|
D-bus, it cannot be used to execute programs! On the other hand, the STM32F3
|
||||||
|
has a CCM that is accessible to both the D-Bus and the I-Bus, in which case
|
||||||
|
it should be possible to execute programs from this TCM.
|
||||||
|
|
||||||
|
.. image:: ./image/system_arch_stm32f42xx_and_f43xx.png
|
||||||
|
|
||||||
|
.. image:: ./image/system_arch_stm32f303xBC_and_f358xC.png
|
||||||
|
|
||||||
|
When ELF programs are loaded into memory, the memory is allocated from the
|
||||||
|
heap via a standard memory allocator. By default with the STM32 F4, the CCM
|
||||||
|
is included in the heap and will typically be allocated first. If CCM memory
|
||||||
|
is allocated to hold the ELF program in memory, then a hard-fault will occur
|
||||||
|
immediately when you try to execute the ELF program in memory.
|
||||||
|
|
||||||
|
Therefore, it is necessary on STM32 F4 platforms to include the following
|
||||||
|
configuration setting:
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
CONFIG_STM32_CCMEXCLUDE=y
|
||||||
|
|
||||||
|
With that setting, the CCM memory will be excluded from the heap and so will
|
||||||
|
never be allocated for ELF program memory.
|
25
Documentation/guides/updating_release_system_elf.rst
Normal file
25
Documentation/guides/updating_release_system_elf.rst
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
Updating a Release System with ELF Programs
|
||||||
|
============================================
|
||||||
|
|
||||||
|
You can enhance the functionality of your released embedded system by adding
|
||||||
|
ELF programs, which can be loaded from a file system. These programs can be
|
||||||
|
stored on an SD card or downloaded into on-board SPI FLASH, allowing for
|
||||||
|
easy updates or extensions to the system's firmware.
|
||||||
|
|
||||||
|
There are two ways you can accomplish this:
|
||||||
|
|
||||||
|
Partially linked
|
||||||
|
----------------
|
||||||
|
This describes building the partially linked, relocatable ELF program that
|
||||||
|
depends on a symbol table provided by the base firmware in FLASH.
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
- See :doc:`Partially Linked ELF Programs <partially_linked_elf>`
|
||||||
|
|
||||||
|
Fully linked
|
||||||
|
------------
|
||||||
|
This describes building a fully linked, relocatable ELF program that does
|
||||||
|
not depend on any symbol table information.
|
||||||
|
|
||||||
|
Reference:
|
||||||
|
- See :doc:`Fully Linked ELF Programs <fully_linked_elf>`
|
Loading…
Reference in a new issue