mirror of
https://github.com/apache/nuttx.git
synced 2026-08-27 04:10:40 +00:00
Add generic support for link-time registration of struct instances, modeled after the Zephyr STRUCT_SECTION_* mechanism: - include/nuttx/iterable_sections.h: STRUCT_SECTION_ITERABLE/DECLARE/ FOREACH/GET/COUNT macros placing instances in name-sorted linker sections delimited by _<type>_list_start/_end symbols (attributes through the nuttx/compiler.h macros; FOREACH takes a caller-declared iterator, like list_for_every_entry). - include/nuttx/linker/iterable_sections.ld: ITERABLE_SECTION() macro emitting the KEEP + SORT_BY_NAME collection statements (linker scripts in ARCHSCRIPT are CPP-preprocessed). - include/nuttx/linker/common-rom.ld / common-ram.ld: central aggregators meant to be included by board linker scripts (inside .text and .data respectively); subsystems register their sections here guarded by their Kconfig options, so the fragments expand to nothing on configurations that do not use them. - CONFIG_ITERABLE_SECTIONS_LINKER_INSERT + include/nuttx/linker/ common-insert.ld (added before the board script by tools/Config.mk and by the top-level CMakeLists.txt): optional zero-touch mode that supplements the board script through GNU ld INSERT AFTER, collecting the subsystems' ITERABLE_SECTION blocks in one output section; the common-rom.ld/common-ram.ld fragments expand to nothing in that mode. See the option help for the constraints. - Documentation/components/iterable_sections.rst. First user: the Zephyr zbus message bus port (apps/system/zbus in nuttx-apps); its board integration comes in a companion PR. Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
172 lines
6.4 KiB
ReStructuredText
172 lines
6.4 KiB
ReStructuredText
=================
|
|
Iterable Sections
|
|
=================
|
|
|
|
Iterable sections provide **link-time registration** of ``struct``
|
|
instances: an instance defined with :c:macro:`STRUCT_SECTION_ITERABLE` in
|
|
any compilation unit is placed in a dedicated linker input section. The
|
|
linker collects all instances into a contiguous, name-sorted array
|
|
delimited by ``_<type>_list_start``/``_<type>_list_end`` symbols, which
|
|
the code can then iterate like a plain C array -- no runtime registration
|
|
calls, no central list to maintain.
|
|
|
|
This is the same mechanism used by the Zephyr RTOS ``STRUCT_SECTION_*``
|
|
macros. The first user of this infrastructure is the zbus message bus
|
|
port (``apps/system/zbus``, from nuttx-apps).
|
|
|
|
C API
|
|
=====
|
|
|
|
The macros are provided by ``include/nuttx/iterable_sections.h``:
|
|
|
|
.. code-block:: c
|
|
|
|
#include <nuttx/iterable_sections.h>
|
|
|
|
struct my_entry
|
|
{
|
|
const char *name;
|
|
int value;
|
|
};
|
|
|
|
/* In any .c file (const places the instance in ROM): */
|
|
|
|
const STRUCT_SECTION_ITERABLE(my_entry, entry_foo) =
|
|
{
|
|
.name = "foo",
|
|
.value = 42,
|
|
};
|
|
|
|
/* In the file that iterates: declare the section boundaries once, at
|
|
* file scope, then loop with a caller-declared pointer.
|
|
*/
|
|
|
|
STRUCT_SECTION_DECLARE(my_entry);
|
|
|
|
void print_entries(void)
|
|
{
|
|
FAR struct my_entry *entry;
|
|
|
|
STRUCT_SECTION_FOREACH(my_entry, entry)
|
|
{
|
|
printf("%s = %d\n", entry->name, entry->value);
|
|
}
|
|
}
|
|
|
|
Available macros:
|
|
|
|
* ``STRUCT_SECTION_ITERABLE(type, varname)`` -- define an instance inside
|
|
the iterable section ``._<type>.static.<varname>``. The variable name
|
|
is part of the input section name, so the linker's ``SORT_BY_NAME()``
|
|
defines the iteration order (instances may encode ordering in their
|
|
names).
|
|
* ``STRUCT_SECTION_DECLARE(type)`` -- declare the boundary symbols (file
|
|
scope), required before iterating.
|
|
* ``STRUCT_SECTION_FOREACH(type, iterator)`` -- for-loop over all
|
|
instances; ``iterator`` is a pointer declared by the caller, as with
|
|
``list_for_every_entry()``.
|
|
* ``STRUCT_SECTION_GET(type, i, dst)`` -- random access by index.
|
|
* ``STRUCT_SECTION_COUNT(type, dst)`` -- number of instances.
|
|
* ``STRUCT_SECTION_START/END/START_EXTERN/END_EXTERN`` -- direct access
|
|
to the boundary symbols.
|
|
|
|
Linker integration
|
|
==================
|
|
|
|
The collection step needs linker script support. Two mechanisms are
|
|
available; both rely on the fact that the linker scripts listed in
|
|
``ARCHSCRIPT`` are preprocessed with CPP (arm, arm64, risc-v, xtensa,
|
|
x86_64 and tricore), so ``#include`` and ``#ifdef CONFIG_*`` work inside
|
|
them.
|
|
|
|
Board script include (first-class mechanism)
|
|
--------------------------------------------
|
|
|
|
The board linker script includes the central fragments, which expand to
|
|
nothing unless a subsystem using iterable sections is enabled:
|
|
|
|
.. code-block:: text
|
|
|
|
.text :
|
|
{
|
|
...
|
|
*(.gnu.linkonce.r.*)
|
|
#include <nuttx/linker/common-rom.ld>
|
|
_etext = ABSOLUTE(.);
|
|
} > flash
|
|
|
|
.data :
|
|
{
|
|
_sdata = ABSOLUTE(.);
|
|
...
|
|
#include <nuttx/linker/common-ram.ld>
|
|
. = ALIGN(4);
|
|
_edata = ABSOLUTE(.);
|
|
} > sram AT > flash
|
|
|
|
* ``common-rom.ld`` collects the read-only (``const``) iterable sections
|
|
and must be included inside the read-only output section (typically
|
|
``.text``, before ``_etext``).
|
|
* ``common-ram.ld`` collects mutable *initialized* iterable sections and
|
|
must be included inside ``.data`` (between ``_sdata`` and ``_edata``)
|
|
so the startup FLASH-to-RAM copy initializes the entries.
|
|
* Subsystems add their sections to these central files, guarded by their
|
|
Kconfig option (see ``include/nuttx/linker/common-rom.ld`` for the zbus
|
|
example).
|
|
|
|
Supplementary INSERT script (zero-touch mode)
|
|
---------------------------------------------
|
|
|
|
With ``CONFIG_ITERABLE_SECTIONS_LINKER_INSERT`` the central script
|
|
``include/nuttx/linker/common-insert.ld`` is added before the board
|
|
script by the build system (``tools/Config.mk`` for Make, the top-level
|
|
``CMakeLists.txt`` for CMake) and supplements it through the GNU ld
|
|
``INSERT AFTER`` command, so **no board script modification is needed**.
|
|
The file defines one output section, ``.iterable_sections``, inserted
|
|
after ``.text``; subsystems add their ``ITERABLE_SECTION()`` blocks
|
|
inside it, guarded by their Kconfig option, exactly as in
|
|
``common-rom.ld`` (which expands to nothing in this mode).
|
|
|
|
This mode has constraints, discovered the hard way and worth knowing
|
|
before choosing it:
|
|
|
|
* GNU ld only (``INSERT`` is not supported by the macOS ld64).
|
|
* The INSERT script must come *before* the board script on the linker
|
|
command line. Adding it via ``ARCHSCRIPT`` from ``tools/Config.mk``
|
|
guarantees that, because ``Config.mk`` is included by the board
|
|
``Make.defs`` before it appends its own script. (The reversed order
|
|
fails with ``.text not found for insert``.)
|
|
* GNU ld assigns an INSERTed output section to a ``MEMORY`` region by
|
|
*attribute matching in declaration order*, not by inheriting the anchor
|
|
section's region. The ROM/flash region must therefore be the first
|
|
region compatible with read-only sections. Boards declaring a generic
|
|
``rwx`` region at a lower address first (e.g. an ITCM at ``0x0``) are
|
|
incompatible with this mode and must use the board script include.
|
|
* Giving the inserted section an explicit address is **not** a fix: a
|
|
section with an explicit address does not consume the memory region,
|
|
so the next region-allocated section overlaps it.
|
|
|
|
Alignment rules
|
|
===============
|
|
|
|
Instances are aligned to the natural alignment of their type
|
|
(``STRUCT_SECTION_ITERABLE`` adds ``__aligned__(__alignof__(type))``), and
|
|
``sizeof`` is always a multiple of ``alignof``, so the collected section
|
|
can be indexed as a plain array with no padding between entries from
|
|
different compilation units. The fragments additionally align the list
|
|
boundaries to 4 bytes.
|
|
|
|
Adding a new iterable type
|
|
==========================
|
|
|
|
1. Define the instances with ``STRUCT_SECTION_ITERABLE(mytype, name)``.
|
|
2. Add ``ITERABLE_SECTION(mytype)`` to
|
|
``include/nuttx/linker/common-rom.ld`` (const) or ``common-ram.ld``
|
|
(mutable initialized), guarded by the subsystem Kconfig option.
|
|
3. Iterate with ``STRUCT_SECTION_FOREACH(mytype, it)`` after
|
|
``STRUCT_SECTION_DECLARE(mytype);`` at file scope.
|
|
|
|
Caveat on generated linker scripts: the preprocessed ``.ld.tmp`` files
|
|
only depend on the board script and ``.config``; after editing the
|
|
central fragments during development, remove the ``.tmp`` files (or run
|
|
``make clean``) to force regeneration.
|