Skip to content

Commit 78ae035

Browse files
pillo79kartben
authored andcommitted
llext: fix link order for weak syscall symbols
The weak syscall symbols generated by gen_syscalls.py are currently compiled in the LLEXT subsystem library, which is then linked among all other Zephyr libraries in an unspecified order. This can cause the weak symbols to override the actual syscall implementations, leading to undefined behaviour. To fix this, the currently generated file is split in two elements: - syscall_exports_llext.c contains the EXPORT_SYMBOL directives for all syscalls. This part can be compiled with the LLEXT library and linked among all other Zephyr libraries, and ensures all syscalls symbols are preserved by the linker. - syscall_weakdefs_llext.c contains the weak definitions for all syscalls. This file is compiled in a separate library that is linked last, so that the weak symbols are only used if no other implementation is available. Signed-off-by: Luca Burelli <[email protected]>
1 parent bb417da commit 78ae035

File tree

3 files changed

+54
-10
lines changed

3 files changed

+54
-10
lines changed

CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -842,15 +842,21 @@ if(CONFIG_LEGACY_GENERATED_INCLUDE_PATH)
842842
${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h)
843843
endif()
844844

845-
add_custom_command(OUTPUT include/generated/zephyr/syscall_dispatch.c ${syscall_list_h}
845+
add_custom_command(
846+
OUTPUT
847+
include/generated/zephyr/syscall_dispatch.c
848+
include/generated/zephyr/syscall_exports_llext.c
849+
syscall_weakdefs_llext.c
850+
${syscall_list_h}
846851
# Also, some files are written to include/generated/zephyr/syscalls/
847852
COMMAND
848853
${PYTHON_EXECUTABLE}
849854
${ZEPHYR_BASE}/scripts/build/gen_syscalls.py
850855
--json-file ${syscalls_json} # Read this file
851856
--base-output include/generated/zephyr/syscalls # Write to this dir
852857
--syscall-dispatch include/generated/zephyr/syscall_dispatch.c # Write this file
853-
--syscall-export-llext include/generated/zephyr/syscall_export_llext.c
858+
--syscall-exports-llext include/generated/zephyr/syscall_exports_llext.c
859+
--syscall-weakdefs-llext syscall_weakdefs_llext.c # compiled in CMake library 'syscall_weakdefs'
854860
--syscall-list ${syscall_list_h}
855861
$<$<BOOL:${CONFIG_USERSPACE}>:--gen-mrsh-files>
856862
${SYSCALL_LONG_REGISTERS_ARG}
@@ -1009,6 +1015,16 @@ else()
10091015
set(NO_WHOLE_ARCHIVE_LIBS kernel)
10101016
endif()
10111017

1018+
if(CONFIG_LLEXT)
1019+
# LLEXT exports symbols for all syscalls, including unimplemented ones.
1020+
# Weak definitions for these must be added at the end of the link order
1021+
# to avoid shadowing actual implementations.
1022+
add_library(syscall_weakdefs syscall_weakdefs_llext.c)
1023+
add_dependencies(syscall_weakdefs zephyr_generated_headers)
1024+
target_link_libraries(syscall_weakdefs zephyr_interface)
1025+
list(APPEND NO_WHOLE_ARCHIVE_LIBS syscall_weakdefs)
1026+
endif()
1027+
10121028
get_property(OUTPUT_FORMAT GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT)
10131029

10141030
if (CONFIG_CODE_DATA_RELOCATION)

scripts/build/gen_syscalls.py

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,14 @@
158158
"""
159159

160160

161-
exported_template = """
161+
llext_weakdefs_template = """/* auto-generated by gen_syscalls.py, don't edit */
162+
163+
#include <zephyr/toolchain.h>
164+
#include <zephyr/llext/symbol.h>
165+
162166
/*
163167
* This symbol is placed at address 0 by llext-sections.ld. Its value and
164-
* type is not important, we are only interested in its location
168+
* type is not important, we are only interested in its location.
165169
*/
166170
static void * const no_syscall_impl Z_GENERIC_SECTION(llext_no_syscall_impl);
167171
@@ -171,6 +175,19 @@
171175
* an extension requiring them is loaded.
172176
*/
173177
%s
178+
"""
179+
180+
181+
llext_exports_template = """/* auto-generated by gen_syscalls.py, don't edit */
182+
183+
/*
184+
* Export the implementation functions of all emitted syscalls.
185+
* Only the symbol names are relevant in this file, they will be
186+
* resolved to the actual implementation functions by the linker.
187+
*/
188+
189+
/* Symbol declarations */
190+
%s
174191
175192
/* Exported symbols */
176193
%s
@@ -435,8 +452,10 @@ def parse_args():
435452
help="Indicates we are on system with 64-bit registers")
436453
parser.add_argument("--gen-mrsh-files", action="store_true",
437454
help="Generate marshalling files (*_mrsh.c)")
438-
parser.add_argument("-e", "--syscall-export-llext",
455+
parser.add_argument("-e", "--syscall-exports-llext",
439456
help="output C system call export for extensions")
457+
parser.add_argument("-w", "--syscall-weakdefs-llext",
458+
help="output C system call weak definitions")
440459
parser.add_argument("-u", "--userspace-only", action="store_true",
441460
help="Only generate the userpace path of wrappers")
442461
args = parser.parse_args()
@@ -498,14 +517,23 @@ def main():
498517
fp.write(table_template % (weak_defines,
499518
",\n\t".join(table_entries)))
500519

501-
if args.syscall_export_llext:
502-
with open(args.syscall_export_llext, "w") as fp:
503-
# Export symbols for emitted syscalls
520+
exported.sort()
521+
522+
if args.syscall_weakdefs_llext:
523+
with open(args.syscall_weakdefs_llext, "w") as fp:
524+
# Provide weak definitions for all emitted syscalls
504525
weak_refs = "\n".join("extern __weak ALIAS_OF(no_syscall_impl) void * const %s;"
505526
% e for e in exported)
527+
fp.write(llext_weakdefs_template % weak_refs)
528+
529+
if args.syscall_exports_llext:
530+
with open(args.syscall_exports_llext, "w") as fp:
531+
# Export symbols for emitted syscalls
532+
extern_refs = "\n".join("extern void * const %s;"
533+
% e for e in exported)
506534
exported_symbols = "\n".join("EXPORT_SYMBOL(%s);"
507535
% e for e in exported)
508-
fp.write(exported_template % (weak_refs, exported_symbols))
536+
fp.write(llext_exports_template % (extern_refs, exported_symbols))
509537

510538
# Listing header emitted to stdout
511539
ids_emit.sort()

subsys/llext/llext_export.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ EXPORT_SYMBOL(memcmp);
1616
EXPORT_SYMBOL(memcpy);
1717
EXPORT_SYMBOL(memset);
1818

19-
#include <zephyr/syscall_export_llext.c>
19+
#include <zephyr/syscall_exports_llext.c>

0 commit comments

Comments
 (0)