Commit Graph

123 Commits

Author SHA1 Message Date
Guennadi Liakhovetski
cbb6199e67 LLEXT: no repeated linking with inline relocations
When linking and relocations are performed on the ELF object itself
with no copying, also global binding linking can break references.
Disable linking globally for such cases.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-20 10:17:06 +00:00
Guennadi Liakhovetski
44d96a2668 LLEXT: add llext_section_offset() to replace llext_find_section()
Now that section header cache is persistent, it can be used for
finding sections. Add a new function, similar to llext_find_section()
to use it and deprecate llext_find_section().

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
c714f0e148 LLEXT: preserve section headers
Move cached section headers to struct llext from struct llext_loader
to preserve them after llext_load() returns.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
e2d8daae16 LLEXT: Xtensa: add a Kconfig option to enable -fPIC
Currently when building LLEXT for Xtensa we use the -fPIC compiler
option, but this cannot be used when using detached sections in
extensions. Add a Kconfig option to switch between the two
compilation modes and switch -fPIC off when building relocatable
(partially linked) ELF binaries.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
4f0cb90c59 LLEXT: fix advanced uses of detached sections
When detached sections are used, STB_GLOBAL relocations also have to
be processed depending on the relocation type. This commit unified
STB_GLOBAL and STB_LOCAL flows by making them use the same relocation
type parser, adds support for R_XTENSA_GLOB_DAT and R_XTENSA_JMP_SLOT
type relocations on Xtensa and fixes STT_SECTION address calculation
for such sections.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
2b3666109e LLEXT: fix detached section cache synchronisation
Detached sections are used in situ without being copied to or
referenced from ext->mem[] LLEXT region arrays. Their caches must be
synchronised accordingly.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
ec02b815a7 LLEXT: (cosmetic) reduce the scope of a variable
Move a variable calculation inside the block, where it is actually
used.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 15:28:00 -05:00
Guennadi Liakhovetski
ae8c373314 LLEXT: fix a needless allocation
When CONFIG_LLEXT_STORAGE_WRITABLE is selected and .pre_located is
set, the BSS section is allocated by the user too, no need to
allocate it internally.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-11-16 14:56:23 -05:00
Eric Ackermann
5275d44409 llext: Add RISC-V arch-specific relocations
This commit introduces architecture-specific ELF relocations for RISC-V,
in accordance with the RISC-V PSABI specification:
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
Also, the necessary compiler configurations for compiling LLEXT
extensions on RISC-V are added, and the llext tests are executed on
RISC-V targets.
Calling llext extensions from user threads in RISC-V is still
unsupported as of this commit.

Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
2024-10-03 21:59:42 +01:00
Guennadi Liakhovetski
c6bf743df2 LLEXT: add support for detached sections
Some LLEXT objects can include sections, that should not be merged
with other sections of the same type. E.g. when such sections should
be placed into locations, other than the default. Add support for
such sections.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski
0aa6b1c9de llext: pass the whole struct llext_load_param
To simplify LLEXT loader parameter extension pass the whole
struct llext_load_param to final consumers instead of extracting
individual fields from it in the caller function.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski
f04e646af0 llext: (cosmetic) use a more common name for a variable
It's more common in the LLEXT code base to call elf_sym_t instances
"sym" and not "sym_tbl." Convert llext_link_plt() to follow this
convention.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Guennadi Liakhovetski
43a69f868b llext: make llext_loaded_sect_ptr() available to all LLEXT code
Make llext_loaded_sect_ptr() a proper function to be able to call it
from platform LLEXT code.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-29 21:21:24 +02:00
Luca Burelli
db451f2c46 llext: export DT devices to extensions
This change adds a new configuration option, LLEXT_EXPORT_DEVICES, which
enables exporting all devices defined in the device tree to llext
extensions. When enabled, all devices are made available to extensions
via the standard DT_ / DEVICE_* macros.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-25 12:59:13 +02:00
Keith Packard
88359d998c subsys/llext: Allow .exported_sym to be between other data sections
There's no reason for the .exported_sym data to always land at one end of a
data region; the order of sections depends on the whim of the compiler and
assembler.

Ignore overlaps between that region and other data regions.

Signed-off-by: Keith Packard <keithp@keithp.com>
2024-09-16 20:17:35 +02:00
Guennadi Liakhovetski
5332393066 llext: make loader parameters "const"
LLEXT loader parameters are input-only, make them "const."

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-12 13:02:59 -04:00
Adam Wojasinski
74b562569e llext: Add RELA sections processing for AARCH64
Allow to process `RELA` sections on aarch64 platform.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Adam Wojasinski
eb51529ab3 llext: Introduce AARCH64 relocation support
Adds support for all relocation type produced by GCC
on AARCH64 platform using partial linking (-r flag) or
shared link (-fpic and -shared flag).

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Adam Wojasinski
2ff71727f1 llext: Fix use of macro for relocation symbol index from r_info
Replace use of 32-bit architecture macro to macro arch agnostic that
is resolved in compilation.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-12 14:48:55 +02:00
Luca Burelli
e6b32ab681 llext: hotfix: fix function pointer logging
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>
2024-09-11 13:59:02 -04:00
Pisit Sawangvonganan
ead0dfc889 style: subsys: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-09-11 07:40:35 -04:00
Luca Burelli
af302cd5fe llext: add bringup, teardown, and bootstrap APIs
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>
2024-09-06 11:27:15 -04:00
Luca Burelli
04d7e4f490 llext: add support for ELF init/fini arrays
Load the .preinit_array, .init_array and .fini_array sections in ELF
files. These sections are arrays of function pointers that are filled by
the compiler with the addresses of functions that need to be called at
startup or termination by the loader, such as C++ constructors and
destructors.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-09-06 11:27:15 -04:00
Adam Wojasinski
420891cedb llext: Add shell command for loading LLEXT from a filesystem
This patch extends LLEXT shell commands with support for loading
LLEXT from a filesystem. Use of the command requires absolute path
to the llext file.

Example use:
`llext load_llext hello_world /lfs/hello_world.llext`

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Adam Wojasinski
fc114e85dd llext: Add filesystem based extension loader
Added loader allowing to load extensions stored in a filesystem.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Adam Wojasinski
93ffeced6a llext: Add new methods to loader API
Introducing `llext_prepare()` and `llext_finalize()` APIs
that are invoked and the beginning and the end of the `llext_load()`
function.

The purpose of these functions is to bring possibility of initializing
loader before it is used and uninitialize or clean up when
it is no longer needed. Both functions are optional.

The buffer loader has been aligned to methods introduced in the patch.

Signed-off-by: Adam Wojasinski <awojasinski@baylibre.com>
2024-09-06 11:26:09 -04:00
Nicolas Pitre
b5addc808a llext: adjust memory permissions on MMU systems
By default, normal memory is set readable+writable and not executable.
Adjust those permissions according to each region:

	LLEXT_MEM_TEXT                  --> K_MEM_PERM_EXEC
	LLEXT_MEM_DATA, LLEXT_MEM_BSS   --> K_MEM_PERM_RW
	LLEXT_MEM_RODATA                --> K_MEM_PERM_RO aka 0

This must be done only at the end of an LLEXT load operation as memory
needs to remain RW for reloc processing, etc.

And while at it, flush/invalidate the cache accordingly.

Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
2024-09-06 11:25:54 -04:00
Guennadi Liakhovetski
dd50ff5585 llext: add dependencies
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>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski
c5e305fce6 llext: fix flag evaluation for section grouping
When deciding which sections to group together, only the low 3
section attribute bits are relevant, ignore the rest.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski
fe609dd8e8 llext: look for symbols in other LLEXT objects too
LLEXT objects can also export symbols for use by other such objects.
That means, that when linking an LLEXT object we have to look for
unresolved symbols in previously loaded objects too.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Guennadi Liakhovetski
92a7c772d9 llext: remove an unused variable
Remove a loop counter, that isn't actually used for anything.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2024-09-02 12:31:52 -04:00
Tom Burdick
9dffac0107 llext: flush logging before unloading extensions
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>
2024-08-29 18:05:04 +02:00
Pisit Sawangvonganan
8f197c955d style: subsys: comply with MISRA C:2012 Rule 15.6
Add missing braces to comply with MISRA C:2012 Rule 15.6 and
also following Zephyr's style guideline.

Signed-off-by: Pisit Sawangvonganan <pisit@ndrsolution.com>
2024-08-20 10:33:51 +02:00
Luca Burelli
f257c997b5 doc: llext: improve Doxygen comments
Review and improve comments in source code to better describe the API
and the functionality provided by the llext library.

No actual code changes are performed in this commit.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-11 16:17:52 +02:00
Luca Burelli
3cc452c92f llext: consistently use "regions" for memory areas
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>
2024-07-09 19:04:06 +02:00
Luca Burelli
2e085ba29a llext: harmonize error codes
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>
2024-07-09 19:04:06 +02:00
Luca Burelli
9450240419 llext: fix table count check
llext_load() included a check to ensure that the ELF file contains all
the necessary tables, but it was not functional. Add the missing check
and rename the variable to avoid confusion with the total section count.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 19:04:06 +02:00
Luca Burelli
5ce6a750a5 llext: add explicit cast to fix Coverity CID: 392507
From https://mails.dpdk.org/archives/dev/2021-December/231212.html:

    Downcasting a void* to struct aesni_gcm_session* caused the session
    data to be treated as tainted. Removing the void* temporary variable
    and adding a cast avoids this issue.

Try the same approach here to prevent the ldr->sect_hdrs pointer from
being treated as tainted.

May fix #74817.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-07-09 11:51:29 +02:00
Luca Burelli
d4ea1da10e llext: fix llext_find_section(), remove llext_section_by_name()
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>
2024-06-25 21:25:33 -04:00
Luca Burelli
95cab98110 llext: fix section addresses at link time by using sh_info
Currently, the code uses the section name to identify the target section
of a relocation. This is not reliable, as the section name is not
guaranteed to be in a specific format. Instead, use the sh_info field of
the relocation section header to identify the target section.

This is a tricky change, as it requires a workaround for the Xtensa
port, whose code path diverges here into the `link_plt` function and
ultimately different arch-specific code. Avoiding this divergence
will require additional refactorings.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli
a1550c4db1 llext: fix llext_load() optimization
The optimization in llext_load() to avoid using the generic path for
sections that are cached in memory was broken for two reasons:
- it was comparing an ELF section index to LLEXT_MEM_BSS, which is a
  llext_mem enum, and
- it was using the wrong section address for the cached sections since
  the "merged sections" feature was introduced in 709b2e44bf.

This patch fixes both issues using the new llext_loaded_sect_ptr()
helper function.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli
ee6074a35d llext: calculate offsets for ELF sections in memory areas
The recent changes to the loader code merged related sections together,
making sure the merged sections are self-coherent. This, however, did
not take into account that the original ELF sections are now a _subset_
of the merged section - and might not start from the beginning of the
merged section.

This patch converts the `sect_map` member of `struct llext_loader` to a
structure with two fields:
- mem_idx: the memory area index where the ELF section is mapped
- offset: the offset of the ELF section inside the memory area

The offset is calculated after all sections are merged and the final
groups are defined. This will allow the loader to correctly calculate
the address of symbols and relocations in the merged sections.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli
6c5983492b llext: set proper LLEXT_STORAGE default for Xtensa
This patch sets the default value for LLEXT_STORAGE_WRITABLE to 'y' on
the Xtensa architecture. This is necessary because it does not currently
support the read-only mode for the LLEXT storage.

Make sure the default reflects this instead of asking the user to
manually set it.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-25 21:25:33 -04:00
Luca Burelli
08eb314c35 llext: refactor: use cached section headers
The section headers are now available in the loader structure, so we can
use those directly instead of reading them from the ELF file every time.

This commit contains no logic changes; it removes all copies of the
header loading code and replaces them with direct access to the cached
section headers.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli
817bbda5cc llext: read all section headers at once
This change reads all section headers at once, instead of reading them
one by one. This is more efficient and allows to further simplify the
code downstream.

The section headers are directly accessed from the file buffer if the
llext_peek() function is supported by the loader. Otherwise, they are
read into a buffer allocated on the heap and used only during the
llext_load() function.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli
a976a1a25c llext: llext_load: document memory management policy
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>
2024-06-14 11:13:44 +02:00
Luca Burelli
89e27b9312 llext: improve debug messages
The recent llext_map_sections() rework changed the way debug messages
are output so that the names of most skipped sections are not printed
at all. This makes debugging harder since the section names are useful
to identify the contents at a glance.

Also print a few additional fields from the section header, and use 0x
prefixes for hex numbers.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2024-06-14 11:13:44 +02:00
Luca Burelli
1a2f6ae381 llext: refact: move ELF loading and linking to separate files
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>
2024-06-07 18:07:53 +01:00
Luca Burelli
9c5412f79e llext: refact: move memory code to llext_mem.c
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>
2024-06-07 18:07:53 +01:00
Luca Burelli
35ef089cb1 llext: move basic ELF checks to llext_load_elf_data()
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>
2024-06-07 18:07:53 +01:00