Commit Graph

30 Commits

Author SHA1 Message Date
Guennadi Liakhovetski
a2a587ae20 llext: fix symbol exporting for ET_REL
When building relocatable extensions, exported symbol names might end
up in a separate section (in my case ".rodata.str1.1") for which
storage address don't match section address. To access those names
addresses have to be relalculated.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
2025-02-11 10:11:31 +01:00
Luca Burelli
f0328ddc80 llext: add option to import all global symbols
The new CONFIG_LLEXT_IMPORT_ALL_GLOBALS option allows all global symbols
from extensions to be used by the main application. This is useful to
load basic extensions that have been compiled without the full Zephyr
EDK.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2025-01-29 11:04:33 +01:00
Luca Burelli
7094eae111 llext: support multiple string and symbol tables
The ELF format allows for multiple string and symbol tables with
complex references between them. This is especially evident when
debugging information is included.

This patch fixes the issues that have been identified with multiple
string tables to allow LLEXT to properly parse those files:

* The symbol table used by LLEXT (LLEXT_MEM_SYMTAB) is now chosen
  depending on the loaded file type, and other tables are ignored.
  This change is also applied to the SLID injection script.

* The LLEXT string table (LLEXT_MEM_SYMTAB) is now correctly identified
  by the symbol table reference, instead of picking the first one.

* VMA range checks only make sense for allocated sections.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
2025-01-27 08:54:44 +01:00
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
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
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
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
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
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
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
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
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
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
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