Some function pointers were being passed via `%p` to LOG_DBG, and this
was causing the following issues in SOF CI with the `sparse` checker:
subsys/llext/llext.c: error: arithmetics on pointers to functions
subsys/llext/llext.c: error: incompatible types for operation (+)
This patch fixes the issue by casting the function pointers to void*.
Also fix a misleading error message in `llext_get_fn_table()`.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
llext_bringup() and llext_teardown() are intended to be used to call the
extension's own initialization and cleanup functions, respectively. They
are meant to be called by the developer after loading an extension and
before unloading it. The list of function pointers to be called is
obtained via the new llext_get_fn_table() syscall, so that they are
compatible with user mode.
llext_bootstrap() is intended to be used as the entry point for a thread
created to run an extension, in either user or kernel contexts. It will
call the extension's own initialization functions and then an additional
entry point in the same context (if desired). The same function can also
be called directly in the main thread, if only initialization is
required.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
When an LLEXT object uses symbols of another such object, it depends
on it. Such dependencies have to be tracked to prevent their
accidental unloading. Ideally we should be able to track arbitrary
numbers of such dependencies, but this is a bit difficult. In this
first implementation we use a fixed-size array, currently consisting
of 8 entries.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extensions could have used logging, when log processing is
deferred, the logging thread can run after the extension has
been unloaded and thereby access invalid memory addresses.
Make sure to flush all logs before unloading extensions.
Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The term "section" has a very specific meaning in the ELF file format.
After 709b2e4 ("llext: automatically merge sections by type"), some of
the code that was originally dealing with ELF sections is now handling
"memory regions" made of multiple ELF sections of the same type.
Make sure to use the term "region" consistently in the code and
log messages to avoid confusion with the original ELF sections.
Notable exception to this is the "ldr->sect" array, which is actively
used outside Zephyr and will need to be phased out in the future.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This patch changes the error codes returned by the ELF subsystem to be
more consistent with the standard error descriptions. In particular:
- issues with the ELF file are now reported as -ENOEXEC;
- valid but unsupported edge cases are reported as -ENOTSUP;
- failures in searching for an entry are reported as -ENOENT.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
The function llext_section_by_name() is used only in one place, and it
expects the caller to have the section headers cache available. This
cache is freed after the ELF file is loaded, so the function is not
usable in the context where it is called.
Remove the function and replace the call with a direct search in the
ELF file section headers array, as was done before 08eb314c35.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
The do_llext_load function is responsible for loading an extension from a
file, and for this purpose it calls a number of functions that a) allocate
memory, and b) can fail. This creates the opportunity for memory leaks if
the error paths are not handled correctly.
This commit adds a comment at the beginning of the function to document
the memory management policy that has to be followed in this file:
cleanup is not performed in the error paths, and all memory is freed at
the end of the do_llext_load() function, both in the case of error and of
successful loading.
As an improvement, the symbol table is not freed if the LLEXT log level
is set to debug, so that it can be used, for example, to inspect the
symbols of the loaded extension.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This commit moves ELF loading and linking code to separate files. This
is done to make the code more manageable and to make it easier to add
new features in the future.
No functional changes are introduced by this commit, except for a few
static functions now made public to allow this file split to occur.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
Move all memory management code to a separate file, llext_mem.c, to
allow for better separation of concerns and to make the code more
readable.
No functional changes are introduced by this commit.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This patch moves the initial checks performed on the ELF file, that were
split between llext_load() and do_llext_load(), to the newly defined
llext_load_elf_data() function.
This way:
- only one function deals with ELF internal data checks;
- do_llext_load() is reduced to a list of tasks;
- llext_load() only focuses on the extension management.
One totally misplaced line initializing the number of symbols has been
moved to llext_count_export_syms().
No functional change except that the `struct llext` allocation may be
performed unnecessarily if the ELF file is not valid.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
Add llext_alloc(), llext_aligned_alloc() and llext_free() wrapper
functions to manage memory allocation and deallocation from the llext
heap. Also add a helper to free all memory regions allocated by an
extension.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
This patch changes the way sections are mapped to memories. Instead of
looking at the section name, each section in the ELF file is mapped to
the llext_mem enum by looking at the section type and flags.
This allows for a more generic mapping that works for both the ARM and
Xtensa cases, and also allows for sections to be merged if they are
contiguous and non-overlapping in the ELF file.
This patch also fixes a number of corner cases, such as in the logging
test where a section with read-only data was being ignored (not copied
and not relinked).
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
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 <mathieu.choplain@st.com>
In the current implementation, the LLEXT linker will only apply
relocations targeting a given symbol if it has a specfic symbol type.
This is overzealous and causes issues on some platforms, as some symbols
that need to be relocated are skipped due to being of a "bad" type.
Ignore the symbol type when performing relocation to solve this problem,
but also add checks to ensure we don't attempt to relocate symbols with
an invalid section index. If such a relocation is found, return an error
instead of ignoring the relocation entry to ensure that it is impossible
to execute code from a (partially) unrelocated LLEXT.
Also remove all hacks added to circumvent this issue:
* qemu_cortex_r5 exclusion from test cases
* unnecessary exclusion of some flags when building with LLEXT EDK
Fixes#72832.
Signed-off-by: Mathieu Choplain <mathieu.choplain@st.com>
Use an existing variable instead of re-calculating and fix swapped
space and a paranthesis.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
When building partially linked / relocatable objects no ELF segments
are created and it becomes more difficult to predict which sections
the compiler will build and use. In this case a .data.rel.local
section is created by the compiler and it is needed to link .rodata
strings in a twister test. We can handle arbitrary sections at run-
time if .peek() is supported. If it isn't we need to allocate and
copy the section. For now we simply error out in such cases. Fixing
that would represent a larger change and can be done incrementally.
This also fixes the relocation calculation to point to the correct
symbol address instead of the memory location, where it's currently
residing, because that can be a temporary buffer as is the case with
SOF.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
These relocations are needed e.g. when an LLEXT is built from
multiple files and they share data objects.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Returned values are copies, so trying to "const" return values cannot
have any effect.
Fixes the following compiler warning:
```
llext.h:165: warning: type qualifiers ignored on function return type
```
Fixes commit 41e0a4a371 ("llext: Linkable loadable extensions")
Signed-off-by: Marc Herbert <marc.herbert@intel.com>
Adds support for all relocation type produced by GCC
on ARM platform using partial linking (-r flag) or
shared link (-fpic and -shared flag).
Signed-off-by: Cedric Lescop <cedric.lescop@se.com>
Some toolchains cannot create shared objects for Xtensa, with them we
have to use relocatable objects. Add support for them to llext.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
In addition to flushing the dcache, to ensure that the new code is
actually read by the CPU when loading an extension, the icache must
be invalidated as well.
Without this, some tests are failing in hardware because the CPU is
executing stale code from its instruction cache.
Fixes#70906 on arduino_giga_r1/stm32h747xx/m7.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
The opval argument of arch_elf_relocate() was modified by
adding the value stored at opaddr before passing it to
arch_elf_relocate(). This presumed that the addend would
always be stored as a raw value at opaddr, which is not the
case for all relocation types.
This PR modifies opval to be the absolute address of opval,
and moves the addition of the addend from llext_link_plt()
to the implementation of arch_elf_relocate().
Signed-off-by: Bjarki Arge Andreasen <bjarki@arge-andreasen.me>
Fixes commit a9a82d557c ("llext: use elf_rela_t instead of elf_rel_t")
Also switch sign of (unused?) `r_addend` to unsigned.
https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.reloc.html
Issue found thanks to the following warnings when compiling in 64bits:
```
/__w/zephyr/zephyr/include/zephyr/llext/elf.h:349:29: error:
right shift count >= width of type [-Werror=shift-count-overflow]
349 | #define ELF64_R_SYM(i) ((i) >> 32)
```
The name `elf64_word` was admittedly confusing.
Signed-off-by: Marc Herbert <marc.herbert@intel.com>
Note `elf64_addr` and friends are defined as uint64_t which is defined
as `long long unsigned` which is for some reason different from
`size_t`. So they all require a cast.
Signed-off-by: Marc Herbert <marc.herbert@intel.com>
Sets up memory partitions and allows for the partitions to be added to a
memory domain after loading an extension. This allows for applying
memory protection attributes to all of the needed memory regions an
extension requires to execute code correctly.
Currently only works when usermode is enabled as otherwise memory
protection APIs are unavailable.
Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
clangd like to automatically add include directives, this one slipped by
and made its way in the tree. Remove it.
Signed-off-by: Tom Burdick <thomas.burdick@intel.com>
The only difference in the two enums are some entries related to
relocation sections. However, these entries are not used in the
code, so they can be safely removed, along with the mapping function.
Use LLEXT_MEM_* to avoid confusion with low-level "section" names.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
The arch_* functions are architecture-specific and may not be defined in
all targets. Use the global alias defined in the Cache API instead.
Fixes#66382.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
On architectures that have separate data and instruction caches, such as
the Cortex-M7, it is required to flush the reloc changes to the actual RAM
storage before trying to execute any code from the newly loaded llext.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
It is not safe to assume that on entry to llext_load, *ext contains
either NULL or a previous reference to the same ext being loaded. For
example, the shell sample was passing an uninitialized value.
Initialize *ext from a search of the llext by name. If NULL, it is the
first instance of this llext (and on load error, it stays that way). If
not NULL, increment use count and return.
Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
When using the LLEXT buffer loader we now avoid copying extensions
from storage to allocated memory by pointing directly into the stored
image. We then also perform linking and relocation in that memory,
which modifies its contents. However, this is impossible if that
storage is read-only. Add a Kconfig flag to distinguish between
writable and read-only storage types. Also use that flag to decide,
whether the extension image in test_llext_simple.c should be defined
as const or not.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
a new llext object is completely initialised with zeros after
allocation, no need to additionally set members of an embedded into
it array to NULL.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
llext_list() is an exported function that returns a pointer to the
llext internal extension list. That list should only be accessible
directly inside llext, while holding a lock. Remove the function.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
The llext list should be internal to llext.c, remove its scanning
from shell.c, export a function for that instead.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Use an element size explicitly when calculating the array size and
use the calculated size for memset().
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extensions should be able to selectively export their global symbols.
Add a LL_EXTENSION_SYMBOL() macro for that. Change the present
.sym_tab to be a temporary symbol table of all global symbols in an
extensions, used only during linking for internal purposes. Add a new
.exp_tab symbol table to store symbols, exported by an extension
permanently.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
If a function fails it should release all the resources it has
managed to acquire. Fix llext_load() to free memory that it has
allocated in case of an error.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Extend the llext_load() / llext_unload() API to let it be called
repeatedly for the same extension to increment or decrement its
reference counter respectively. We use a mutex to protect the counter
and make both llext_load() and llext_unload() return the use-count to
let the caller identify when the first loading and the last unloading
took place.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Loadable modules can contain global (not "static") functions, even if
they aren't exported for use by other modules, e.g. when a module is
built from multiple .c files. Such functions are then also included
in link tables and have to be re-linked.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
llext_seek(), llext_read() and llext_peek() are needed outside of the
extension code too, move them to a header.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Some applications can decide to link their loadable objects for
exactly the same addresses, where they will be loaded. In those cases
local relocations aren't needed any more and can in fact break the
object if applied while the object is in a temporary storage. Add a
parameter to skip such local relocations.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Applications can use custom ELF sections for their own purposes, add
a function for finding them.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
Add support for relocating local symbols, as specified in the
.rela.dyn section.
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>