diff --git a/include/zephyr/linker/llext-sections.ld b/include/zephyr/linker/llext-sections.ld index b8cc32e3d1b..3dcfc3e8f0c 100644 --- a/include/zephyr/linker/llext-sections.ld +++ b/include/zephyr/linker/llext-sections.ld @@ -1,5 +1,17 @@ /* SPDX-License-Identifier: Apache-2.0 */ + /* + * Map the no_syscall_impl symbol in llext_export_syscalls.c to + * absolute address 0 so other weak symbols are exported as NULL. + * This section is used for mapping that symbol only and is not + * to be included in the final binary. + */ + + SECTION_PROLOGUE(llext_no_syscall_impl, 0 (COPY), ) + { + *(llext_no_syscall_impl) + } + /* * Special section used by LLEXT if CONFIG_LLEXT_EXPORT_BUILTINS_BY_SLID * is enabled. Declare this section to prevent it from being considered orphan. diff --git a/scripts/build/gen_syscalls.py b/scripts/build/gen_syscalls.py index 84f6b546bde..44e0b793a12 100755 --- a/scripts/build/gen_syscalls.py +++ b/scripts/build/gen_syscalls.py @@ -159,11 +159,16 @@ syscall_tracer_void_template = """ exported_template = """ -/* Export syscalls for extensions */ -static void * const no_handler = NULL; +/* + * This symbol is placed at address 0 by llext-sections.ld. Its value and + * type is not important, we are only interested in its location + */ +static void * const no_syscall_impl Z_GENERIC_SECTION(llext_no_syscall_impl); -/* Weak references, if something is not found by the linker, it will be NULL - * and simply fail during extension load +/* + * Weak references to all syscall implementations. Those not found by the + * linker outside this file will be exported as NULL and simply fail when + * an extension requiring them is loaded. */ %s @@ -495,7 +500,7 @@ def main(): if args.syscall_export_llext: with open(args.syscall_export_llext, "w") as fp: # Export symbols for emitted syscalls - weak_refs = "\n".join("extern __weak ALIAS_OF(no_handler) void * const %s;" + weak_refs = "\n".join("extern __weak ALIAS_OF(no_syscall_impl) void * const %s;" % e for e in exported) exported_symbols = "\n".join("EXPORT_SYMBOL(%s);" % e for e in exported) diff --git a/tests/subsys/llext/simple/src/test_llext_simple.c b/tests/subsys/llext/simple/src/test_llext_simple.c index 788c27ce2eb..6368a1b60ad 100644 --- a/tests/subsys/llext/simple/src/test_llext_simple.c +++ b/tests/subsys/llext/simple/src/test_llext_simple.c @@ -496,17 +496,16 @@ ZTEST(llext, test_printk_exported) } /* - * Ensure ext_syscall_fail is exported - as it is picked up by the syscall - * build machinery - but points to NULL as it is not implemented. + * The syscalls test above verifies that custom syscalls defined by extensions + * are properly exported. Since `ext_syscalls.h` declares ext_syscall_fail, we + * know it is picked up by the syscall build machinery, but the implementation + * for it is missing. Make sure the exported symbol for it is NULL. */ ZTEST(llext, test_ext_syscall_fail) { const void * const esf_fn = LLEXT_FIND_BUILTIN_SYM(z_impl_ext_syscall_fail); - zassert_not_null(esf_fn, "est_fn should not be NULL"); - - zassert_is_null(*(uintptr_t **)esf_fn, NULL, - "ext_syscall_fail should be NULL"); + zassert_is_null(esf_fn, "est_fn should be NULL"); } ZTEST_SUITE(llext, NULL, NULL, NULL, NULL, NULL);