Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ cxxflags.txt
includes.txt
syms-dynamic.ld
syms-static.ld
tls-syms.S
5 changes: 5 additions & 0 deletions cores/arduino/llext_wrappers.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
__real_##name(a); \
}

#ifdef CONFIG_ARM
/* ARM EABI thread pointer access */
W0(size_t, __aeabi_read_tp)
#endif

/* string.h */
W3(void *, memcpy, void *, const void *, size_t)
W3(void *, memmove, void *, const void *, size_t)
Expand Down
1 change: 1 addition & 0 deletions extra/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ cp ${BUILD_DIR}/zephyr/.config firmwares/zephyr-$variant.config

# Generate the provides.ld file for linked builds
echo "Generating exported symbol scripts"
extra/gen_provides.py "${BUILD_DIR}/zephyr/zephyr.elf" -T > ${VARIANT_DIR}/tls-syms.S
extra/gen_provides.py "${BUILD_DIR}/zephyr/zephyr.elf" -L > ${VARIANT_DIR}/syms-dynamic.ld
extra/gen_provides.py "${BUILD_DIR}/zephyr/zephyr.elf" -LF \
"+kheap_llext_heap" \
Expand Down
70 changes: 57 additions & 13 deletions extra/gen_provides.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,29 @@ def main():
argparser.add_argument('-F', '--funcs',
action='store_true',
help='Extract all public functions')
argparser.add_argument('-T', '--tls-defs',
action='store_true',
help='Extract TLS symbol offsets to a .S file')
argparser.add_argument('file',
help='ELF file to parse')
argparser.add_argument('syms', nargs='*',
help='Symbols to export')

args = argparser.parse_intermixed_args()

wants_provides = bool(args.syms or args.funcs or args.llext)
if wants_provides and args.tls_defs:
sys.stderr.write("Cannot generate TLS defs when also generating PROVIDEs.\n")
sys.exit(1)
elif not wants_provides and not args.tls_defs:
sys.stderr.write("Nothing specified for export.\n")
sys.exit(1)

exact_syms = set()
regex_syms = set()
deref_syms = set()
sized_syms = set()
tls_syms = set() # tuple of (name, value, size)
rename_map = {}
for sym in args.syms:
sym_class = None
Expand Down Expand Up @@ -184,6 +196,11 @@ def main():
fail = False

for name, sym in all_syms.items():
if sym['st_info']['type'] == 'STT_TLS':
# Collect TLS symbol information, ignore for PROVIDEs
tls_syms.add((name, sym['st_value'], sym['st_size']))
continue

value = None
comment = []
if name in exact_syms or any(re.match(r, name) for r in regex_syms):
Expand Down Expand Up @@ -220,10 +237,6 @@ def main():
if name in sized_syms:
out_syms[name + "_size"] = (sym['st_size'], [f"size of {name}"])

if not out_syms:
sys.stderr.write("No symbols found matching the criteria.\n")
fail = True

if fail:
sys.exit(1)

Expand All @@ -235,16 +248,47 @@ def main():
* SHA256: {elf_sha}
*/
""")
sym_comment = nul_comment = ""
for name, (value, comments) in sorted(out_syms.items(), key=lambda x: x[0]):
if args.verbose:
comment = ', '.join(sorted(comments))
sym_comment = f"/* {comment} */"
nul_comment = f" ({comment})"
if value:
print(f"PROVIDE({name} = {value:#010x});{sym_comment}")

if wants_provides:
if not out_syms:
print("/* No symbols found matching the criteria */")
sys.stderr.write("warning: no symbols found matching the criteria.\n")
else:
print(f"/* NULL {name}{nul_comment} */")
sym_comment = nul_comment = ""
for name, (value, comments) in sorted(out_syms.items(), key=lambda x: x[0]):
if args.verbose:
comment = ', '.join(sorted(comments))
sym_comment = f"/* {comment} */"
nul_comment = f" ({comment})"
if value:
print(f"PROVIDE({name} = {value:#010x});{sym_comment}")
else:
print(f"/* NULL {name}{nul_comment} */")

if args.tls_defs:
# ARM and AArch64 use '@' as a line-comment character in GAS, so the
# assembler requires '%' as the type prefix there. All other targets use '@'.
prefix = '%' if elf['e_machine'] in ('EM_ARM', 'EM_AARCH64') else '@'

# The TLS Variant 1 layout (used by ARM/AArch64) places a Thread
# Control Block (TCB) before the TLS data. The thread pointer
# returned by __aeabi_read_tp() points to the TCB, so the actual
# runtime address of a TLS variable must be offset by that size.
#
# TCB is 2 pointers: 8 bytes on 32-bit, 16 bytes on 64-bit.
# See zephyr/arch/arm/core/tls.c: arch_tls_stack_setup().
tcb_size = (elf.elfclass // 8) * 2
print(f"/* Offsets include {tcb_size} bytes for TCB data */")

# Sort by offset first, then size
for name, offset, size in sorted(tls_syms, key=lambda x: (x[1], x[2])):
offset += tcb_size
print(
f"\n/* TLS offset {offset:#x}: {name} ({size} bytes) */\n"
f".global {name}\n"
f".type {name}, {prefix}tls_object\n"
f".set {name}, {offset}"
)

#-------------------------------------------------------------------------------
if __name__ == '__main__':
Expand Down
5 changes: 5 additions & 0 deletions loader/llext_exports.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,10 @@ EXPORT_SYMBOL(ring_buf_area_finish);
#endif

EXPORT_SYMBOL(sys_clock_cycle_get_32);

#if defined(CONFIG_ARM)
extern uint32_t __aeabi_read_tp(void);
EXPORT_LIBC_SYM(__aeabi_read_tp);
FORCE_EXPORT_SYM(__aeabi_dcmpun);
FORCE_EXPORT_SYM(__aeabi_dcmple);
FORCE_EXPORT_SYM(__aeabi_d2lz);
Expand Down Expand Up @@ -318,6 +322,7 @@ FORCE_EXPORT_SYM(__aeabi_idivmod);
FORCE_EXPORT_SYM(__aeabi_ldivmod);
FORCE_EXPORT_SYM(__aeabi_ul2f);
FORCE_EXPORT_SYM(__aeabi_dcmpge);
#endif

#if defined (CONFIG_CPP)
FORCE_EXPORT_SYM(__cxa_pure_virtual);
Expand Down
Loading