include/nuttx: Add link-time iterable sections infrastructure

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>
This commit is contained in:
Jorge Guzman 2026-08-21 14:24:11 -03:00 committed by Xiang Xiao
parent 71610ddac0
commit 7cd511fed2
10 changed files with 531 additions and 0 deletions

View file

@ -0,0 +1,121 @@
/****************************************************************************
* include/nuttx/iterable_sections.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* Iterable sections: link-time registration of struct instances.
*
* A struct instance defined with STRUCT_SECTION_ITERABLE() in any
* compilation unit is placed in a dedicated input section named
* "._<struct_type>.static.<varname>". The board linker script collects
* these input sections (sorted by name) into a contiguous array delimited
* by the _<struct_type>_list_start/_<struct_type>_list_end symbols by
* including <nuttx/linker/common-rom.ld> (const data, inside the .text or
* .rodata output section) and <nuttx/linker/common-ram.ld> (mutable
* initialized data, inside the .data output section, so that the startup
* FLASH-to-RAM copy initializes it).
*
* The collection is only available on architectures whose linker scripts
* are preprocessed with CPP (arm, arm64, risc-v, xtensa, x86_64, tricore)
* and on boards whose scripts include the common-*.ld fragments.
*/
#ifndef __INCLUDE_NUTTX_ITERABLE_SECTIONS_H
#define __INCLUDE_NUTTX_ITERABLE_SECTIONS_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Define a struct instance inside an iterable section. A "const"
* qualifier may be prepended at the point of use to place the instance in
* ROM. Each instance is aligned to the natural alignment of its type so
* that the collected section can be indexed as a plain C array. The
* variable name is part of the input section name so that the linker's
* SORT_BY_NAME() defines the iteration order (instances may encode
* ordering in their names).
*/
#define STRUCT_SECTION_ITERABLE(struct_type, varname) \
struct struct_type varname \
used_data \
aligned_data(__alignof__(struct struct_type)) \
locate_data("._" #struct_type ".static." #varname)
/* Start/end symbols provided by the linker script fragments */
#define STRUCT_SECTION_START(struct_type) _##struct_type##_list_start
#define STRUCT_SECTION_END(struct_type) _##struct_type##_list_end
#define STRUCT_SECTION_START_EXTERN(struct_type) \
extern struct struct_type STRUCT_SECTION_START(struct_type)[]
#define STRUCT_SECTION_END_EXTERN(struct_type) \
extern struct struct_type STRUCT_SECTION_END(struct_type)[]
/* Declare both boundary symbols of an iterable section. Place it at file
* scope (followed by a semicolon) in every file that iterates with
* STRUCT_SECTION_FOREACH.
*/
#define STRUCT_SECTION_DECLARE(struct_type) \
STRUCT_SECTION_START_EXTERN(struct_type); \
STRUCT_SECTION_END_EXTERN(struct_type)
/* Iterate over every instance of an iterable section. "iterator" is a
* pointer variable (FAR struct struct_type *) declared by the caller, as
* with list_for_every_entry(); the boundary symbols must be in scope
* (STRUCT_SECTION_DECLARE).
*/
#define STRUCT_SECTION_FOREACH(struct_type, iterator) \
for ((iterator) = STRUCT_SECTION_START(struct_type); \
(iterator) < STRUCT_SECTION_END(struct_type); \
(iterator)++)
/* Get the i-th element of an iterable section (no bounds checking) */
#define STRUCT_SECTION_GET(struct_type, i, dst) \
do \
{ \
STRUCT_SECTION_START_EXTERN(struct_type); \
*(dst) = &STRUCT_SECTION_START(struct_type)[i]; \
} \
while (0)
/* Number of elements in an iterable section */
#define STRUCT_SECTION_COUNT(struct_type, dst) \
do \
{ \
STRUCT_SECTION_START_EXTERN(struct_type); \
STRUCT_SECTION_END_EXTERN(struct_type); \
*(dst) = STRUCT_SECTION_END(struct_type) - \
STRUCT_SECTION_START(struct_type); \
} \
while (0)
#endif /* __INCLUDE_NUTTX_ITERABLE_SECTIONS_H */

View file

@ -0,0 +1,59 @@
/****************************************************************************
* include/nuttx/linker/common-insert.ld
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* Supplementary linker script for the iterable sections "zero-touch" mode
* (CONFIG_ITERABLE_SECTIONS_LINKER_INSERT): added before the board linker
* script by the build system, it supplements -- does not replace -- that
* script through the GNU ld INSERT command, so boards need no edit. The
* read-only iterable sections are collected in one output section placed
* right after .text.
*
* Subsystem blocks are added inside the output section below, each
* guarded by its Kconfig option (same layout as common-rom.ld):
*
* #ifdef CONFIG_MYSUBSYS
* ITERABLE_SECTION(mysubsys_entry)
* #endif
*
* Constraints of this mode:
* - GNU ld only (INSERT is not supported by the macOS ld64), and this
* script must come BEFORE the board script on the command line (the
* build system guarantees that ordering).
* - The board script must define an output section named ".text".
* - The ROM/flash region must be the first MEMORY region compatible
* with read-only sections: GNU ld assigns the INSERTed section to a
* region by attribute matching in declaration order, so a board that
* declares a generic rwx region at a lower address first (e.g. ITCM
* at 0x0) would pull these sections into the wrong region. Such
* boards must use the <nuttx/linker/common-rom.ld> include instead.
*/
#include <nuttx/config.h>
#include <nuttx/linker/iterable_sections.ld>
SECTIONS
{
.iterable_sections : SUBALIGN(4)
{
}
}
INSERT AFTER .text;

View file

@ -0,0 +1,43 @@
/****************************************************************************
* include/nuttx/linker/common-ram.ld
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* Mutable (initialized) iterable sections. Boards opt in by adding,
* INSIDE their .data output section (between _sdata and _edata, so the
* startup FLASH-to-RAM copy initializes the entries):
*
* #include <nuttx/linker/common-ram.ld>
*
* Every block below is guarded by its subsystem's Kconfig option, so this
* file expands to nothing on configurations that do not use iterable
* sections (zero binary impact).
*/
#include <nuttx/config.h>
#include <nuttx/linker/iterable_sections.ld>
#ifndef CONFIG_ITERABLE_SECTIONS_LINKER_INSERT
/* Extension point for subsystems that need initialized RAM iterable
* sections; blocks are added below, each guarded by its Kconfig option.
*/
#endif /* !CONFIG_ITERABLE_SECTIONS_LINKER_INSERT */

View file

@ -0,0 +1,47 @@
/****************************************************************************
* include/nuttx/linker/common-rom.ld
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* Read-only iterable sections. Boards opt in by adding, INSIDE their
* read-only output section (typically .text, before _etext):
*
* #include <nuttx/linker/common-rom.ld>
*
* Every block below is guarded by its subsystem's Kconfig option, so this
* file expands to nothing on configurations that do not use iterable
* sections (zero binary impact). In the INSERT mode
* (CONFIG_ITERABLE_SECTIONS_LINKER_INSERT) the sections are collected by
* common-insert.ld instead, so this file expands to nothing as well.
*/
#include <nuttx/config.h>
#include <nuttx/linker/iterable_sections.ld>
#ifndef CONFIG_ITERABLE_SECTIONS_LINKER_INSERT
/* Subsystem blocks are added below, each guarded by its Kconfig option:
*
* #ifdef CONFIG_MYSUBSYS
* ITERABLE_SECTION(mysubsys_entry)
* #endif
*/
#endif /* !CONFIG_ITERABLE_SECTIONS_LINKER_INSERT */

View file

@ -0,0 +1,43 @@
/****************************************************************************
* include/nuttx/linker/iterable_sections.ld
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/* CPP macro emitting the linker statements that collect one iterable
* section (see include/nuttx/iterable_sections.h). This file is meant to
* be included from linker scripts that are preprocessed with CPP (the
* ARCHSCRIPT .tmp rule).
*
* The macro must be expanded INSIDE an output section (e.g. .text or
* .data). KEEP() protects the entries from --gc-sections and
* SORT_BY_NAME() defines the iteration order.
*/
#ifndef __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD
#define __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD
#define ITERABLE_SECTION(name) \
. = ALIGN(4); \
_##name##_list_start = .; \
KEEP(*(SORT_BY_NAME(._##name.static.*))); \
_##name##_list_end = .; \
. = ALIGN(4);
#endif /* __INCLUDE_NUTTX_LINKER_ITERABLE_SECTIONS_LD */