Skip to content

Commit

Permalink
llext: add support for SLID-based linking
Browse files Browse the repository at this point in the history
This commit introduces support for an alternate linking method in the
LLEXT subsystem, called "SLID" (short for Symbol Link Identifier),
enabled by the CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID Kconfig option.

SLID-based linking uses a unique identifier (integer) to identify
exported symbols, instead of using the symbol name as done currently.
This approach provides several benefits:
 * linking is faster because the comparison operation to determine
   whether we found the correct symbol in the export table is now an
   integer compare, instead of a string compare
 * binary size is reduced as symbol names can be dropped from the binary
 * confidentiality is improved as a side-effect, as symbol names are no
   longer present in the binary

Signed-off-by: Mathieu Choplain <[email protected]>
  • Loading branch information
mathieuchopstm authored and nashif committed Jun 3, 2024
1 parent 05ad256 commit 8aa6ae4
Show file tree
Hide file tree
Showing 45 changed files with 981 additions and 7 deletions.
15 changes: 15 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,21 @@ if(CONFIG_BUILD_OUTPUT_INFO_HEADER)
)
endif()

if (CONFIG_LLEXT AND CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID)
#slidgen must be the first post-build command to be executed
#on the Zephyr ELF to ensure that all other commands, such as
#binary file generation, are operating on a preparated ELF.
list(PREPEND
post_build_commands
COMMAND ${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/build/llext_prepare_exptab.py
--elf-file ${PROJECT_BINARY_DIR}/${KERNEL_ELF_NAME}
--slid-listing ${PROJECT_BINARY_DIR}/slid_listing.txt
-vvv
)

endif()

if(NOT CMAKE_C_COMPILER_ID STREQUAL "ARMClang")
set(check_init_priorities_input
$<IF:$<TARGET_EXISTS:native_runner_executable>,${BYPRODUCT_KERNEL_EXE_NAME},${BYPRODUCT_KERNEL_ELF_NAME}>
Expand Down
4 changes: 4 additions & 0 deletions boards/qemu/x86/qemu_x86_tiny.ld
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/DISCARD/ :
{
*(.plt)
Expand Down
5 changes: 5 additions & 0 deletions cmake/llext-edk.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@

cmake_minimum_required(VERSION 3.20.0)

if (CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID)
message(FATAL_ERROR
"The LLEXT EDK is not compatible with CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID.")
endif()

set(llext_edk ${PROJECT_BINARY_DIR}/${llext_edk_name})
set(llext_edk_inc ${llext_edk}/include)

Expand Down
20 changes: 20 additions & 0 deletions cmake/modules/extensions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5431,13 +5431,31 @@ function(add_llext_target target_name)
COMMAND_EXPAND_LISTS
)

# LLEXT ELF processing for importing via SLID
#
# This command must be executed as last step of the packaging process,
# to ensure that the ELF processed for binary generation contains SLIDs.
# If executed too early, it is possible that some tools executed to modify
# the ELF file (e.g., strip) undo the work performed here.
if (CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID)
set(slid_inject_cmd
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/build/llext_inject_slids.py
--elf-file ${llext_pkg_output}
-vvv
)
else()
set(slid_inject_cmd ${CMAKE_COMMAND} -E true)
endif()

# Type-specific packaging of the built binary file into an .llext file
if(CONFIG_LLEXT_TYPE_ELF_OBJECT)

# No packaging required, simply copy the object file
add_custom_command(
OUTPUT ${llext_pkg_output}
COMMAND ${CMAKE_COMMAND} -E copy ${llext_pkg_input} ${llext_pkg_output}
COMMAND ${slid_inject_cmd}
DEPENDS ${llext_proc_target} ${llext_pkg_input}
)

Expand All @@ -5453,6 +5471,7 @@ function(add_llext_target target_name)
$<TARGET_PROPERTY:bintools,elfconvert_flag_infile>${llext_pkg_input}
$<TARGET_PROPERTY:bintools,elfconvert_flag_outfile>${llext_pkg_output}
$<TARGET_PROPERTY:bintools,elfconvert_flag_final>
COMMAND ${slid_inject_cmd}
DEPENDS ${llext_proc_target} ${llext_pkg_input}
)

Expand All @@ -5467,6 +5486,7 @@ function(add_llext_target target_name)
$<TARGET_PROPERTY:bintools,strip_flag_infile>${llext_pkg_input}
$<TARGET_PROPERTY:bintools,strip_flag_outfile>${llext_pkg_output}
$<TARGET_PROPERTY:bintools,strip_flag_final>
COMMAND ${slid_inject_cmd}
DEPENDS ${llext_proc_target} ${llext_pkg_input}
)

Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/arc/v2/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ SECTIONS {

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

GROUP_START(ROMABLE_REGION)

SECTION_PROLOGUE(_TEXT_SECTION_NAME,,ALIGN(1024)) {
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/arm/cortex_a_r/scripts/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ SECTIONS
{
#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/*
* .plt and .iplt are here according to 'arm-zephyr-elf-ld --verbose',
* before text section.
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/arm/cortex_m/scripts/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/*
* .plt and .iplt are here according to 'arm-zephyr-elf-ld --verbose',
* before text section.
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/arm64/scripts/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/*
* .plt and .iplt are here according to 'arm-zephyr-elf-ld --verbose',
* before text section.
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/mips/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

SECTION_PROLOGUE(_VECTOR_SECTION_NAME,,)
{
. = ALIGN(0x1000);
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/nios2/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/*
* .plt and .iplt are here according to
* 'nios2-zephyr-elf-ld --verbose', before text section.
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/posix/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
SECTIONS
{

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

SECTION_PROLOGUE(rom_start,,)
{
/* Located in generated directory. This file is populated by the
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/riscv/common/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/*
* The .plt and .iplt are here according to
* 'riscv32-zephyr-elf-ld --verbose', before text section.
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/sparc/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

__rom_region_start = .;

SECTION_PROLOGUE(_TEXT_SECTION_NAME,,)
Expand Down
4 changes: 4 additions & 0 deletions include/zephyr/arch/x86/ia32/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ SECTIONS

#include <zephyr/linker/rel-sections.ld>

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif

/DISCARD/ :
{
*(.plt)
Expand Down
3 changes: 3 additions & 0 deletions include/zephyr/arch/x86/intel64/linker.ld
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,7 @@ SECTIONS
.shstrtab 0 : { *(.shstrtab) }
#endif

#ifdef CONFIG_LLEXT
#include <zephyr/linker/llext-sections.ld>
#endif
}
19 changes: 19 additions & 0 deletions include/zephyr/linker/llext-sections.ld
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: Apache-2.0 */

/*
* Special section used by LLEXT if CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID
* is enabled. Declare this section to prevent it from being considered orphan.
*
* This section is used to temporarily save the exported symbols' names in the
* Zephyr ELF for post-processing, but it is not included in the final binary.
*
* NOTE: This section MUST start at address 0, as the post-processing scripts
* assume that the address of any data in this section (i.e., symbol names) is
* strictly equivalent to the offset inside the section.
*/
#ifdef CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID
SECTION_PROLOGUE(llext_exports_strtab, 0 (COPY), )
{
KEEP(*(llext_exports_strtab))
}
#endif
27 changes: 25 additions & 2 deletions include/zephyr/llext/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/toolchain.h>
#include <stddef.h>
#include <stdint.h>

#ifdef __cplusplus
extern "C" {
Expand All @@ -27,14 +28,27 @@ extern "C" {
* Symbols may be named function or global objects that have been exported
* for linking. These constant symbols are useful in the base image
* as they may be placed in ROM.
*
* @note When updating this structure, make sure to also update the
* 'scripts/build/llext_prepare_exptab.py' build script.
*/
struct llext_const_symbol {
/** Name of symbol */
const char *const name;
/** At build time, we always write to 'name'.
* At runtime, which field is used depends
* on CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID.
*/
union {
/** Name of symbol */
const char *const name;

/** Symbol Link Identifier */
const uintptr_t slid;
};

/** Address of symbol */
const void *const addr;
};
BUILD_ASSERT(sizeof(struct llext_const_symbol) == 2 * sizeof(uintptr_t));

/**
* @brief Symbols are named memory addresses
Expand Down Expand Up @@ -75,10 +89,19 @@ struct llext_symtable {
*
* @param x Symbol to export to extensions
*/
#ifdef CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID
#define EXPORT_SYMBOL(x) \
static const char Z_GENERIC_SECTION("llext_exports_strtab") __used \
x ## _sym_name[] = STRINGIFY(x); \
static const STRUCT_SECTION_ITERABLE(llext_const_symbol, x ## _sym) = { \
.name = x ## _sym_name, .addr = (const void *)&x, \
}
#else
#define EXPORT_SYMBOL(x) \
static const STRUCT_SECTION_ITERABLE(llext_const_symbol, x ## _sym) = { \
.name = STRINGIFY(x), .addr = (const void *)&x, \
}
#endif

/**
* @brief Exports a symbol from an extension to the base image
Expand Down
Loading

0 comments on commit 8aa6ae4

Please sign in to comment.