From 435b72dc18c8f959163e38d87ba133d7a4c17d1b Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Wed, 29 May 2024 17:40:27 +0200 Subject: [PATCH] llext: add a test for the pre_located feature This test checks that the pre_located feature works as expected. It creates a new extension that is manually relocated to a specific address via the add_llext_command() CMake function invoking a custom linker command. The test then loads the extension setting the pre_located option and checks that the symbol is resolved properly. Signed-off-by: Luca Burelli --- tests/subsys/llext/simple/CMakeLists.txt | 25 ++++++++++------- .../subsys/llext/simple/src/pre_located_ext.c | 19 +++++++++++++ .../llext/simple/src/test_llext_simple.c | 27 +++++++++++++++++++ 3 files changed, 62 insertions(+), 9 deletions(-) create mode 100644 tests/subsys/llext/simple/src/pre_located_ext.c diff --git a/tests/subsys/llext/simple/CMakeLists.txt b/tests/subsys/llext/simple/CMakeLists.txt index 2a677470f66..2337b3a80c9 100644 --- a/tests/subsys/llext/simple/CMakeLists.txt +++ b/tests/subsys/llext/simple/CMakeLists.txt @@ -23,6 +23,10 @@ if(CONFIG_ARM) endif() endif() +if (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE AND CONFIG_XTENSA) + list(APPEND ext_names pre_located) +endif() + # generate extension targets foreach extension given by 'ext_names' foreach(ext_name ${ext_names}) set(ext_src ${PROJECT_SOURCE_DIR}/src/${ext_name}_ext.c) @@ -45,12 +49,15 @@ if(NOT CONFIG_LLEXT_TYPE_ELF_OBJECT) ) endif() -# Add a dummy custom processing command to test add_llext_command -get_target_property(proc_in_file hello_world_ext lib_output) -get_target_property(proc_out_file hello_world_ext pkg_input) -add_llext_command( - TARGET hello_world_ext - POST_BUILD - COMMAND echo "dummy patching ${proc_in_file} to create ${proc_out_file}" - COMMAND ${CMAKE_COMMAND} -E copy ${proc_in_file} ${proc_out_file} -) +if (CONFIG_LLEXT_TYPE_ELF_RELOCATABLE AND CONFIG_XTENSA) + # Manually fix the pre_located extension's text address at a multiple of 4 + get_target_property(pre_located_target pre_located_ext lib_target) + get_target_property(pre_located_file pre_located_ext pkg_input) + add_llext_command( + TARGET pre_located_ext + POST_BUILD + COMMAND ${CMAKE_C_COMPILER} + -Wl,-r -Wl,-Ttext=0xbada110c -nostdlib -nodefaultlibs -nostartfiles + $ -o ${pre_located_file} + ) +endif() diff --git a/tests/subsys/llext/simple/src/pre_located_ext.c b/tests/subsys/llext/simple/src/pre_located_ext.c new file mode 100644 index 00000000000..1308c8d662f --- /dev/null +++ b/tests/subsys/llext/simple/src/pre_located_ext.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Arduino SA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/* + * This file contains a simple test extension that defines an entry point + * in the .text section. The entry point is never called, but the symbol + * address is fixed via a linker call and then checked by the test. + */ + +#include + +void test_entry(void) +{ + /* This function is never called */ +} +LL_EXTENSION_SYMBOL(test_entry); diff --git a/tests/subsys/llext/simple/src/test_llext_simple.c b/tests/subsys/llext/simple/src/test_llext_simple.c index 2552844946e..68b318f5e1c 100644 --- a/tests/subsys/llext/simple/src/test_llext_simple.c +++ b/tests/subsys/llext/simple/src/test_llext_simple.c @@ -237,6 +237,33 @@ static LLEXT_CONST uint8_t multi_file_ext[] __aligned(4) = { LLEXT_LOAD_UNLOAD(multi_file, true, NULL) #endif +#if defined(CONFIG_LLEXT_TYPE_ELF_RELOCATABLE) && defined(CONFIG_XTENSA) +static LLEXT_CONST uint8_t pre_located_ext[] __aligned(4) = { + #include "pre_located.inc" +}; + +ZTEST(llext, test_pre_located) +{ + struct llext_buf_loader buf_loader = + LLEXT_BUF_LOADER(pre_located_ext, ARRAY_SIZE(pre_located_ext)); + struct llext_loader *loader = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; + struct llext *ext = NULL; + const void *test_entry_fn; + int res; + + /* load the extension trying to respect the addresses in the ELF */ + ldr_parm.pre_located = true; + res = llext_load(loader, "pre_located", &ext, &ldr_parm); + zassert_ok(res, "load should succeed"); + + /* check the function address is the expected one */ + test_entry_fn = llext_find_sym(&ext->exp_tab, "test_entry"); + zassert_equal(test_entry_fn, (void *)0xbada110c, "test_entry should be at 0xbada110c"); + + llext_unload(&ext); +} +#endif /* * Ensure that EXPORT_SYMBOL does indeed provide a symbol and a valid address