Browse Source
Until now iterable sections APIs have been part of the toolchain (common) headers. They are not strictly related to a toolchain, they just rely on linker providing support for sections. Most files relied on indirect includes to access the API, now, it is included as needed. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>pull/58130/head
133 changed files with 599 additions and 430 deletions
@ -0,0 +1,145 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020, Intel Corporation |
||||||
|
* Copyright (C) 2023, Nordic Semiconductor ASA |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef INCLUDE_ZEPHYR_LINKER_ITERABLE_SECTIONS_H_ |
||||||
|
#define INCLUDE_ZEPHYR_LINKER_ITERABLE_SECTIONS_H_ |
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup iterable_section_apis |
||||||
|
* @{ |
||||||
|
*/ |
||||||
|
|
||||||
|
#define Z_LINK_ITERABLE(struct_type) \ |
||||||
|
_CONCAT(_##struct_type, _list_start) = .; \ |
||||||
|
KEEP(*(SORT_BY_NAME(._##struct_type.static.*))); \ |
||||||
|
_CONCAT(_##struct_type, _list_end) = . |
||||||
|
|
||||||
|
#define Z_LINK_ITERABLE_NUMERIC(struct_type) \ |
||||||
|
_CONCAT(_##struct_type, _list_start) = .; \ |
||||||
|
KEEP(*(SORT(._##struct_type.static.*_?_*))); \ |
||||||
|
KEEP(*(SORT(._##struct_type.static.*_??_*))); \ |
||||||
|
_CONCAT(_##struct_type, _list_end) = . |
||||||
|
|
||||||
|
#define Z_LINK_ITERABLE_ALIGNED(struct_type, align) \ |
||||||
|
. = ALIGN(align); \ |
||||||
|
Z_LINK_ITERABLE(struct_type); |
||||||
|
|
||||||
|
#define Z_LINK_ITERABLE_GC_ALLOWED(struct_type) \ |
||||||
|
_CONCAT(_##struct_type, _list_start) = .; \ |
||||||
|
*(SORT_BY_NAME(._##struct_type.static.*)); \ |
||||||
|
_CONCAT(_##struct_type, _list_end) = . |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a read-only iterable section output. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Define an output section which will set up an iterable area |
||||||
|
* of equally-sized data structures. For use with STRUCT_SECTION_ITERABLE(). |
||||||
|
* Input sections will be sorted by name, per ld's SORT_BY_NAME. |
||||||
|
* |
||||||
|
* This macro should be used for read-only data. |
||||||
|
* |
||||||
|
* Note that this keeps the symbols in the image even though |
||||||
|
* they are not being directly referenced. Use this when symbols |
||||||
|
* are indirectly referenced by iterating through the section. |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_ROM(struct_type, subalign) \ |
||||||
|
SECTION_PROLOGUE(struct_type##_area,,SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE(struct_type); \ |
||||||
|
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a read-only iterable section output, sorted numerically. |
||||||
|
* |
||||||
|
* This version of ITERABLE_SECTION_ROM() sorts the entries numerically, that |
||||||
|
* is, `SECNAME_10` will come after `SECNAME_2`. `_` separator is required, and |
||||||
|
* up to 2 numeric digits are handled (0-99). |
||||||
|
* |
||||||
|
* @see ITERABLE_SECTION_ROM() |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_ROM_NUMERIC(struct_type, subalign) \ |
||||||
|
SECTION_PROLOGUE(struct_type##_area, EMPTY, SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE_NUMERIC(struct_type); \ |
||||||
|
} GROUP_ROM_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a garbage collectable read-only iterable section output. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Define an output section which will set up an iterable area |
||||||
|
* of equally-sized data structures. For use with STRUCT_SECTION_ITERABLE(). |
||||||
|
* Input sections will be sorted by name, per ld's SORT_BY_NAME. |
||||||
|
* |
||||||
|
* This macro should be used for read-only data. |
||||||
|
* |
||||||
|
* Note that the symbols within the section can be garbage collected. |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_ROM_GC_ALLOWED(struct_type, subalign) \ |
||||||
|
SECTION_PROLOGUE(struct_type##_area,,SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE_GC_ALLOWED(struct_type); \ |
||||||
|
} GROUP_LINK_IN(ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a read-write iterable section output. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Define an output section which will set up an iterable area |
||||||
|
* of equally-sized data structures. For use with STRUCT_SECTION_ITERABLE(). |
||||||
|
* Input sections will be sorted by name, per ld's SORT_BY_NAME. |
||||||
|
* |
||||||
|
* This macro should be used for read-write data that is modified at runtime. |
||||||
|
* |
||||||
|
* Note that this keeps the symbols in the image even though |
||||||
|
* they are not being directly referenced. Use this when symbols |
||||||
|
* are indirectly referenced by iterating through the section. |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_RAM(struct_type, subalign) \ |
||||||
|
SECTION_DATA_PROLOGUE(struct_type##_area,,SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE(struct_type); \ |
||||||
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a read-write iterable section output, sorted numerically. |
||||||
|
* |
||||||
|
* This version of ITERABLE_SECTION_RAM() sorts the entries numerically, that |
||||||
|
* is, `SECNAME10` will come after `SECNAME2`. Up to 2 numeric digits are |
||||||
|
* handled (0-99). |
||||||
|
* |
||||||
|
* @see ITERABLE_SECTION_RAM() |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_RAM_NUMERIC(struct_type, subalign) \ |
||||||
|
SECTION_PROLOGUE(struct_type##_area, EMPTY, SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE_NUMERIC(struct_type); \ |
||||||
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Define a garbage collectable read-write iterable section output. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Define an output section which will set up an iterable area |
||||||
|
* of equally-sized data structures. For use with STRUCT_SECTION_ITERABLE(). |
||||||
|
* Input sections will be sorted by name, per ld's SORT_BY_NAME. |
||||||
|
* |
||||||
|
* This macro should be used for read-write data that is modified at runtime. |
||||||
|
* |
||||||
|
* Note that the symbols within the section can be garbage collected. |
||||||
|
*/ |
||||||
|
#define ITERABLE_SECTION_RAM_GC_ALLOWED(struct_type, subalign) \ |
||||||
|
SECTION_DATA_PROLOGUE(struct_type##_area,,SUBALIGN(subalign)) \ |
||||||
|
{ \ |
||||||
|
Z_LINK_ITERABLE_GC_ALLOWED(struct_type); \ |
||||||
|
} GROUP_DATA_LINK_IN(RAMABLE_REGION, ROMABLE_REGION) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @} |
||||||
|
*/ /* end of struct_section_apis */ |
||||||
|
|
||||||
|
#endif /* INCLUDE_ZEPHYR_LINKER_ITERABLE_SECTIONS_H_ */ |
@ -0,0 +1,291 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020, Intel Corporation |
||||||
|
* Copyright (C) 2023, Nordic Semiconductor ASA |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ |
||||||
|
#define INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ |
||||||
|
|
||||||
|
#include <zephyr/sys/__assert.h> |
||||||
|
#include <zephyr/toolchain.h> |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterable Sections APIs |
||||||
|
* @defgroup iterable_section_apis Iterable Sections APIs |
||||||
|
* @{ |
||||||
|
*/ |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines a new element for an iterable section for a generic type. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Convenience helper combining __in_section() and Z_DECL_ALIGN(). |
||||||
|
* The section name will be '.[SECNAME].static.[SECTION_POSTFIX]' |
||||||
|
* |
||||||
|
* In the linker script, create output sections for these using |
||||||
|
* ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM(). |
||||||
|
* |
||||||
|
* @note In order to store the element in ROM, a const specifier has to |
||||||
|
* be added to the declaration: const TYPE_SECTION_ITERABLE(...); |
||||||
|
* |
||||||
|
* @param[in] type data type of variable |
||||||
|
* @param[in] varname name of variable to place in section |
||||||
|
* @param[in] secname type name of iterable section. |
||||||
|
* @param[in] section_postfix postfix to use in section name |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_ITERABLE(type, varname, secname, section_postfix) \ |
||||||
|
Z_DECL_ALIGN(type) varname \ |
||||||
|
__in_section(_##secname, static, _CONCAT(section_postfix, _)) __used __noasan |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section start symbol for a generic type |
||||||
|
* |
||||||
|
* will return '_[OUT_TYPE]_list_start'. |
||||||
|
* |
||||||
|
* @param[in] secname type name of iterable section. For 'struct foobar' this |
||||||
|
* would be TYPE_SECTION_START(foobar) |
||||||
|
* |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_START(secname) _CONCAT(_##secname, _list_start) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section end symbol for a generic type |
||||||
|
* |
||||||
|
* will return '_<SECNAME>_list_end'. |
||||||
|
* |
||||||
|
* @param[in] secname type name of iterable section. For 'struct foobar' this |
||||||
|
* would be TYPE_SECTION_START(foobar) |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_END(secname) _CONCAT(_##secname, _list_end) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section extern for start symbol for a generic type |
||||||
|
* |
||||||
|
* Helper macro to give extern for start of iterable section. The macro |
||||||
|
* typically will be called TYPE_SECTION_START_EXTERN(struct foobar, foobar). |
||||||
|
* This allows the macro to hand different types as well as cases where the |
||||||
|
* type and section name may differ. |
||||||
|
* |
||||||
|
* @param[in] type data type of section |
||||||
|
* @param[in] secname name of output section |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_START_EXTERN(type, secname) \ |
||||||
|
extern type TYPE_SECTION_START(secname)[] |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section extern for end symbol for a generic type |
||||||
|
* |
||||||
|
* Helper macro to give extern for end of iterable section. The macro |
||||||
|
* typically will be called TYPE_SECTION_END_EXTERN(struct foobar, foobar). |
||||||
|
* This allows the macro to hand different types as well as cases where the |
||||||
|
* type and section name may differ. |
||||||
|
* |
||||||
|
* @param[in] type data type of section |
||||||
|
* @param[in] secname name of output section |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_END_EXTERN(type, secname) \ |
||||||
|
extern type TYPE_SECTION_END(secname)[] |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterate over a specified iterable section for a generic type |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Iterator for structure instances gathered by TYPE_SECTION_ITERABLE(). |
||||||
|
* The linker must provide a _<SECNAME>_list_start symbol and a |
||||||
|
* _<SECNAME>_list_end symbol to mark the start and the end of the |
||||||
|
* list of struct objects to iterate over. This is normally done using |
||||||
|
* ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_FOREACH(type, secname, iterator) \ |
||||||
|
TYPE_SECTION_START_EXTERN(type, secname); \ |
||||||
|
TYPE_SECTION_END_EXTERN(type, secname); \ |
||||||
|
for (type * iterator = TYPE_SECTION_START(secname); ({ \ |
||||||
|
__ASSERT(iterator <= TYPE_SECTION_END(secname),\ |
||||||
|
"unexpected list end location"); \ |
||||||
|
iterator < TYPE_SECTION_END(secname); \ |
||||||
|
}); \ |
||||||
|
iterator++) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get element from section for a generic type. |
||||||
|
* |
||||||
|
* @note There is no protection against reading beyond the section. |
||||||
|
* |
||||||
|
* @param[in] type type of element |
||||||
|
* @param[in] secname name of output section |
||||||
|
* @param[in] i Index. |
||||||
|
* @param[out] dst Pointer to location where pointer to element is written. |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_GET(type, secname, i, dst) do { \ |
||||||
|
TYPE_SECTION_START_EXTERN(type, secname); \ |
||||||
|
*(dst) = &TYPE_SECTION_START(secname)[i]; \ |
||||||
|
} while (0) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Count elements in a section for a generic type. |
||||||
|
* |
||||||
|
* @param[in] type type of element |
||||||
|
* @param[in] secname name of output section |
||||||
|
* @param[out] dst Pointer to location where result is written. |
||||||
|
*/ |
||||||
|
#define TYPE_SECTION_COUNT(type, secname, dst) do { \ |
||||||
|
TYPE_SECTION_START_EXTERN(type, secname); \ |
||||||
|
TYPE_SECTION_END_EXTERN(type, secname); \ |
||||||
|
*(dst) = ((uintptr_t)TYPE_SECTION_END(secname) - \ |
||||||
|
(uintptr_t)TYPE_SECTION_START(secname)) / sizeof(type); \ |
||||||
|
} while (0) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section start symbol for a struct type |
||||||
|
* |
||||||
|
* @param[in] struct_type data type of section |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_START(struct_type) \ |
||||||
|
TYPE_SECTION_START(struct_type) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section extern for start symbol for a struct |
||||||
|
* |
||||||
|
* Helper macro to give extern for start of iterable section. |
||||||
|
* |
||||||
|
* @param[in] struct_type data type of section |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_START_EXTERN(struct_type) \ |
||||||
|
TYPE_SECTION_START_EXTERN(struct struct_type, struct_type) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section end symbol for a struct type |
||||||
|
* |
||||||
|
* @param[in] struct_type data type of section |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_END(struct_type) \ |
||||||
|
TYPE_SECTION_END(struct_type) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief iterable section extern for end symbol for a struct |
||||||
|
* |
||||||
|
* Helper macro to give extern for end of iterable section. |
||||||
|
* |
||||||
|
* @param[in] struct_type data type of section |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_END_EXTERN(struct_type) \ |
||||||
|
TYPE_SECTION_END_EXTERN(struct struct_type, struct_type) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines a new element of alternate data type for an iterable section. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Special variant of STRUCT_SECTION_ITERABLE(), for placing alternate |
||||||
|
* data types within the iterable section of a specific data type. The |
||||||
|
* data type sizes and semantics must be equivalent! |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_ITERABLE_ALTERNATE(secname, struct_type, varname) \ |
||||||
|
TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, varname) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines an array of elements of alternate data type for an iterable |
||||||
|
* section. |
||||||
|
* |
||||||
|
* @see STRUCT_SECTION_ITERABLE_ALTERNATE |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(secname, struct_type, varname, \ |
||||||
|
size) \ |
||||||
|
TYPE_SECTION_ITERABLE(struct struct_type, varname[size], secname, \ |
||||||
|
varname) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines a new element for an iterable section. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Convenience helper combining __in_section() and Z_DECL_ALIGN(). |
||||||
|
* The section name is the struct type prepended with an underscore. |
||||||
|
* The subsection is "static" and the subsubsection is the variable name. |
||||||
|
* |
||||||
|
* In the linker script, create output sections for these using |
||||||
|
* ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM(). |
||||||
|
* |
||||||
|
* @note In order to store the element in ROM, a const specifier has to |
||||||
|
* be added to the declaration: const STRUCT_SECTION_ITERABLE(...); |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_ITERABLE(struct_type, varname) \ |
||||||
|
STRUCT_SECTION_ITERABLE_ALTERNATE(struct_type, struct_type, varname) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines an array of elements for an iterable section. |
||||||
|
* |
||||||
|
* @see STRUCT_SECTION_ITERABLE |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_ITERABLE_ARRAY(struct_type, varname, size) \ |
||||||
|
STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(struct_type, struct_type, \ |
||||||
|
varname, size) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Defines a new element for an iterable section with a custom name. |
||||||
|
* |
||||||
|
* The name can be used to customize how iterable section entries are sorted. |
||||||
|
* @see STRUCT_SECTION_ITERABLE() |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_ITERABLE_NAMED(struct_type, name, varname) \ |
||||||
|
TYPE_SECTION_ITERABLE(struct struct_type, varname, struct_type, name) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterate over a specified iterable section (alternate). |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE(). |
||||||
|
* The linker must provide a _<SECNAME>_list_start symbol and a |
||||||
|
* _<SECNAME>_list_end symbol to mark the start and the end of the |
||||||
|
* list of struct objects to iterate over. This is normally done using |
||||||
|
* ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_FOREACH_ALTERNATE(secname, struct_type, iterator) \ |
||||||
|
TYPE_SECTION_FOREACH(struct struct_type, secname, iterator) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterate over a specified iterable section. |
||||||
|
* |
||||||
|
* @details |
||||||
|
* Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE(). |
||||||
|
* The linker must provide a _<struct_type>_list_start symbol and a |
||||||
|
* _<struct_type>_list_end symbol to mark the start and the end of the |
||||||
|
* list of struct objects to iterate over. This is normally done using |
||||||
|
* ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script. |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_FOREACH(struct_type, iterator) \ |
||||||
|
STRUCT_SECTION_FOREACH_ALTERNATE(struct_type, struct_type, iterator) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get element from section. |
||||||
|
* |
||||||
|
* @note There is no protection against reading beyond the section. |
||||||
|
* |
||||||
|
* @param[in] struct_type Struct type. |
||||||
|
* @param[in] i Index. |
||||||
|
* @param[out] dst Pointer to location where pointer to element is written. |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_GET(struct_type, i, dst) \ |
||||||
|
TYPE_SECTION_GET(struct struct_type, struct_type, i, dst) |
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Count elements in a section. |
||||||
|
* |
||||||
|
* @param[in] struct_type Struct type |
||||||
|
* @param[out] dst Pointer to location where result is written. |
||||||
|
*/ |
||||||
|
#define STRUCT_SECTION_COUNT(struct_type, dst) \ |
||||||
|
TYPE_SECTION_COUNT(struct struct_type, struct_type, dst); |
||||||
|
|
||||||
|
/**
|
||||||
|
* @} |
||||||
|
*/ /* end of struct_section_apis */ |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif /* INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ */ |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue