Browse Source

llext: Add parameters to arch_elf_relocate

The RISC-V port of llext requires additional parameters for
handling non-adjacent HI20/LO12 relocations in arch_elf_relocate():
the current extension (struct llext), the current extension loader
(struct llext_loader), the current section header (elf_shdr_t) and
the current symbol (elf_sym_t).
This changes the signature of arch_elf_relocate accordingly.

Signed-off-by: Eric Ackermann <eric.ackermann@cispa.de>
pull/82776/merge
Eric Ackermann 5 months ago committed by Carles Cufí
parent
commit
3466dab804
  1. 27
      arch/arc/core/elf.c
  2. 26
      arch/arm/core/elf.c
  3. 25
      arch/arm64/core/elf.c
  4. 30
      arch/riscv/core/elf.c
  5. 13
      include/zephyr/llext/llext.h
  6. 37
      include/zephyr/llext/llext_internal.h
  7. 111
      subsys/llext/llext_link.c
  8. 6
      subsys/llext/llext_priv.h

27
arch/arc/core/elf.c

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/llext_internal.h>
#include <zephyr/llext/loader.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
@ -31,12 +32,32 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL); @@ -31,12 +32,32 @@ LOG_MODULE_REGISTER(elf, CONFIG_LLEXT_LOG_LEVEL);
* https://github.com/foss-for-synopsys-dwc-arc-processors/arc-ABI-manual/blob/master/ARCv2_ABI.pdf
* https://github.com/zephyrproject-rtos/binutils-gdb
*/
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr, const char *sym_name,
uintptr_t load_bias)
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
int ret = 0;
uint32_t insn = UNALIGNED_GET((uint32_t *)loc);
uint32_t value;
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
uint32_t insn = UNALIGNED_GET((uint32_t *)loc);
elf_sym_t sym;
uintptr_t sym_base_addr;
const char *sym_name;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
sym_base_addr += rel->r_addend;

26
arch/arm/core/elf.c

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/llext_internal.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
@ -316,11 +317,32 @@ static void thm_movs_handler(elf_word reloc_type, uint32_t loc, @@ -316,11 +317,32 @@ static void thm_movs_handler(elf_word reloc_type, uint32_t loc,
* Do NOT mix them with not 'Thumb instructions' in the below switch/case: they are not
* intended to work together.
*/
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr,
const char *sym_name, uintptr_t load_bias)
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
int ret = 0;
elf_word reloc_type = ELF32_R_TYPE(rel->r_info);
const uintptr_t load_bias = (uintptr_t)ext->mem[LLEXT_MEM_TEXT];
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
elf_sym_t sym;
uintptr_t sym_base_addr;
const char *sym_name;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
LOG_DBG("%d %lx %lx %s", reloc_type, loc, sym_base_addr, sym_name);

25
arch/arm64/core/elf.c

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/llext_internal.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>
@ -430,12 +431,32 @@ static int imm_reloc_handler(elf_rela_t *rel, elf_word reloc_type, uintptr_t loc @@ -430,12 +431,32 @@ static int imm_reloc_handler(elf_rela_t *rel, elf_word reloc_type, uintptr_t loc
* @retval -ENOTSUP Unsupported relocation
* @retval -ENOEXEC Invalid relocation
*/
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc, uintptr_t sym_base_addr, const char *sym_name,
uintptr_t load_bias)
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
int ret = 0;
bool overflow_check = true;
elf_word reloc_type = ELF_R_TYPE(rel->r_info);
const uintptr_t loc = llext_get_reloc_instruction_location(ldr, ext, shdr->sh_info, rel);
elf_sym_t sym;
uintptr_t sym_base_addr;
const char *sym_name;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
switch (reloc_type) {
case R_ARM_NONE:

30
arch/riscv/core/elf.c

@ -8,6 +8,9 @@ @@ -8,6 +8,9 @@
*/
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/llext/llext_internal.h>
#include <zephyr/llext/loader.h>
#include <zephyr/logging/log.h>
#include <zephyr/sys/util.h>
@ -68,11 +71,32 @@ static long long last_u_type_jump_target; @@ -68,11 +71,32 @@ static long long last_u_type_jump_target;
* https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc
*
*/
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc_unsigned, uintptr_t sym_base_addr_unsigned,
const char *sym_name, uintptr_t load_bias)
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
/* FIXME currently, RISC-V relocations all fit in ELF_32_R_TYPE */
elf_word reloc_type = ELF32_R_TYPE(rel->r_info);
const uintptr_t load_bias = (uintptr_t)ext->mem[LLEXT_MEM_TEXT];
const uintptr_t loc_unsigned = llext_get_reloc_instruction_location(ldr, ext,
shdr->sh_info, rel);
elf_sym_t sym;
uintptr_t sym_base_addr_unsigned;
const char *sym_name;
int ret;
ret = llext_read_symbol(ldr, ext, rel, &sym);
if (ret != 0) {
LOG_ERR("Could not read symbol from binary!");
return ret;
}
sym_name = llext_symbol_name(ldr, ext, &sym);
ret = llext_lookup_symbol(ldr, ext, &sym_base_addr_unsigned, rel, &sym, sym_name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", sym_name);
return ret;
}
/*
* The RISC-V specification uses the following symbolic names for the relocations:
*
@ -99,7 +123,7 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc_unsigned, uintptr_t sym_bas @@ -99,7 +123,7 @@ int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc_unsigned, uintptr_t sym_bas
long long original_imm8, jump_target;
int16_t compressed_imm8;
__typeof__(rel->r_addend) target_alignment = 1;
const intptr_t sym_base_addr = (intptr_t)sym_base_addr_unsigned;
intptr_t sym_base_addr = (intptr_t)sym_base_addr_unsigned;
LOG_DBG("Relocating symbol %s at %p with base address %p load address %p type %" PRIu64,
sym_name, (void *)loc, (void *)sym_base_addr, (void *)load_bias,

13
include/zephyr/llext/llext.h

@ -354,18 +354,19 @@ int llext_add_domain(struct llext *ext, struct k_mem_domain *domain); @@ -354,18 +354,19 @@ int llext_add_domain(struct llext *ext, struct k_mem_domain *domain);
* symbolic data such as a section, function, or object. These relocations
* are architecture specific and each architecture supporting LLEXT must
* implement this.
* Arguments sym_base_addr, sym_name can be computed from the sym parameter,
* but these parameters are provided redundantly to increase efficiency.
*
* @param[in] ldr Extension loader
* @param[in] ext Extension being relocated refers to
* @param[in] rel Relocation data provided by ELF
* @param[in] loc Address of opcode to rewrite
* @param[in] sym_base_addr Address of symbol referenced by relocation
* @param[in] sym_name Name of symbol referenced by relocation
* @param[in] load_bias `.text` load address
* @param[in] shdr Header of the ELF section currently being located
* @retval 0 Success
* @retval -ENOTSUP Unsupported relocation
* @retval -ENOEXEC Invalid relocation
*/
int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
uintptr_t sym_base_addr, const char *sym_name, uintptr_t load_bias);
int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr);
/**
* @brief Locates an ELF section in the file.

37
include/zephyr/llext/llext_internal.h

@ -11,6 +11,8 @@ @@ -11,6 +11,8 @@
extern "C" {
#endif
#include <zephyr/llext/llext.h>
/**
* @file
* @brief Private header for linkable loadable extensions
@ -18,8 +20,6 @@ extern "C" { @@ -18,8 +20,6 @@ extern "C" {
/** @cond ignore */
struct llext_loader;
struct llext;
struct llext_elf_sect_map {
enum llext_mem mem_idx;
@ -28,6 +28,39 @@ struct llext_elf_sect_map { @@ -28,6 +28,39 @@ struct llext_elf_sect_map {
const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct llext *ext, unsigned int sh_ndx);
static inline const char *llext_string(const struct llext_loader *ldr, const struct llext *ext,
enum llext_mem mem_idx, unsigned int idx)
{
return (const char *)ext->mem[mem_idx] + idx;
}
static inline uintptr_t llext_get_reloc_instruction_location(struct llext_loader *ldr,
struct llext *ext,
int shndx,
const elf_rela_t *rela)
{
return (uintptr_t) llext_loaded_sect_ptr(ldr, ext, shndx) + rela->r_offset;
}
static inline const char *llext_symbol_name(struct llext_loader *ldr, struct llext *ext,
const elf_sym_t *sym)
{
return llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym->st_name);
}
/*
* Determine address of a symbol.
*/
int llext_lookup_symbol(struct llext_loader *ldr, struct llext *ext, uintptr_t *link_addr,
const elf_rela_t *rel, const elf_sym_t *sym, const char *name,
const elf_shdr_t *shdr);
/*
* Read the symbol entry corresponding to a relocation from the binary.
*/
int llext_read_symbol(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
elf_sym_t *sym);
/** @endcond */
#ifdef __cplusplus

111
subsys/llext/llext_link.c

@ -26,8 +26,8 @@ LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL); @@ -26,8 +26,8 @@ LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL);
#define SYM_NAME_OR_SLID(name, slid) name
#endif
__weak int arch_elf_relocate(elf_rela_t *rel, uintptr_t loc,
uintptr_t sym_base_addr, const char *sym_name, uintptr_t load_bias)
__weak int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_rela_t *rel,
const elf_shdr_t *shdr)
{
return -ENOTSUP;
}
@ -142,22 +142,31 @@ static const void *llext_find_extension_sym(const char *sym_name, struct llext * @@ -142,22 +142,31 @@ static const void *llext_find_extension_sym(const char *sym_name, struct llext *
return se.addr;
}
/**
* @brief Determine address of a symbol.
*
* @param ext llext extension
* @param ldr llext loader
* @param link_addr (output) resolved address
* @param rel relocation entry
* @param sym symbol entry
* @param name symbol name
* @param shdr section header
*
* @return 0 for OK, negative for error
/*
* Read the symbol entry corresponding to a relocation from the binary.
*/
int llext_read_symbol(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
elf_sym_t *sym)
{
int ret;
ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset
+ ELF_R_SYM(rel->r_info) * sizeof(elf_sym_t));
if (ret != 0) {
return ret;
}
ret = llext_read(ldr, sym, sizeof(elf_sym_t));
return ret;
}
/*
* Determine address of a symbol.
*/
static int llext_lookup_symbol(struct llext *ext, struct llext_loader *ldr, uintptr_t *link_addr,
const elf_rela_t *rel, const elf_sym_t *sym, const char *name,
const elf_shdr_t *shdr)
int llext_lookup_symbol(struct llext_loader *ldr, struct llext *ext, uintptr_t *link_addr,
const elf_rela_t *rel, const elf_sym_t *sym, const char *name,
const elf_shdr_t *shdr)
{
if (ELF_R_SYM(rel->r_info) == 0) {
/*
@ -219,7 +228,6 @@ static int llext_lookup_symbol(struct llext *ext, struct llext_loader *ldr, uint @@ -219,7 +228,6 @@ static int llext_lookup_symbol(struct llext *ext, struct llext_loader *ldr, uint
return 0;
}
static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr,
const struct llext_load_param *ldr_parm, elf_shdr_t *tgt)
{
@ -359,7 +367,6 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l @@ -359,7 +367,6 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l
{
uintptr_t sect_base = 0;
elf_rela_t rel;
elf_sym_t sym;
elf_word rel_cnt = 0;
const char *name;
int i, ret;
@ -446,7 +453,7 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l @@ -446,7 +453,7 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l
return -ENOEXEC;
}
sect_base = (uintptr_t)llext_loaded_sect_ptr(ldr, ext, shdr->sh_info);
sect_base = (uintptr_t) llext_loaded_sect_ptr(ldr, ext, shdr->sh_info);
for (int j = 0; j < rel_cnt; j++) {
/* get each relocation entry */
@ -460,47 +467,49 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l @@ -460,47 +467,49 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l
return ret;
}
/* get corresponding symbol */
ret = llext_seek(ldr, ldr->sects[LLEXT_MEM_SYMTAB].sh_offset
+ ELF_R_SYM(rel.r_info) * sizeof(elf_sym_t));
if (ret != 0) {
return ret;
}
ret = llext_read(ldr, &sym, sizeof(elf_sym_t));
if (ret != 0) {
return ret;
}
#ifdef CONFIG_LLEXT_LOG_LEVEL
if (CONFIG_LLEXT_LOG_LEVEL >= LOG_LEVEL_INF) {
uintptr_t link_addr;
uintptr_t op_loc =
llext_get_reloc_instruction_location(ldr, ext,
shdr->sh_info,
&rel);
elf_sym_t sym;
name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
ret = llext_read_symbol(ldr, ext, &rel, &sym);
LOG_DBG("relocation %d:%d info 0x%zx (type %zd, sym %zd) offset %zd "
"sym_name %s sym_type %d sym_bind %d sym_ndx %d",
i, j, (size_t)rel.r_info, (size_t)ELF_R_TYPE(rel.r_info),
(size_t)ELF_R_SYM(rel.r_info), (size_t)rel.r_offset,
name, ELF_ST_TYPE(sym.st_info),
ELF_ST_BIND(sym.st_info), sym.st_shndx);
if (ret != 0) {
return ret;
}
uintptr_t link_addr, op_loc;
name = llext_symbol_name(ldr, ext, &sym);
op_loc = sect_base + rel.r_offset;
ret = llext_lookup_symbol(ldr, ext, &link_addr, &rel, &sym, name,
shdr);
ret = llext_lookup_symbol(ext, ldr, &link_addr, &rel, &sym, name, shdr);
if (ret != 0) {
LOG_ERR("Could not find symbol %s!", name);
return ret;
}
if (ret != 0) {
LOG_ERR("Failed to lookup symbol in rela section %d entry %d!", i,
j);
return ret;
LOG_DBG("relocation %d:%d info 0x%zx (type %zd, sym %zd) offset %zd"
" sym_name %s sym_type %d sym_bind %d sym_ndx %d",
i, j, (size_t)rel.r_info, (size_t)ELF_R_TYPE(rel.r_info),
(size_t)ELF_R_SYM(rel.r_info), (size_t)rel.r_offset,
name, ELF_ST_TYPE(sym.st_info),
ELF_ST_BIND(sym.st_info), sym.st_shndx);
LOG_INF("writing relocation symbol %s type %zd sym %zd at addr "
"0x%lx addr 0x%lx",
name, (size_t)ELF_R_TYPE(rel.r_info),
(size_t)ELF_R_SYM(rel.r_info),
op_loc, link_addr);
}
#endif /* CONFIG_LLEXT_LOG_LEVEL */
LOG_INF("writing relocation symbol %s type %zd sym %zd at addr 0x%lx "
"addr 0x%lx",
name, (size_t)ELF_R_TYPE(rel.r_info), (size_t)ELF_R_SYM(rel.r_info),
op_loc, link_addr);
/* relocation */
ret = arch_elf_relocate(&rel, op_loc, link_addr, name,
(uintptr_t)ext->mem[LLEXT_MEM_TEXT]);
ret = arch_elf_relocate(ldr, ext, &rel, shdr);
if (ret != 0) {
return ret;
}

6
subsys/llext/llext_priv.h

@ -49,12 +49,6 @@ static inline void llext_free(void *ptr) @@ -49,12 +49,6 @@ static inline void llext_free(void *ptr)
int do_llext_load(struct llext_loader *ldr, struct llext *ext,
const struct llext_load_param *ldr_parm);
static inline const char *llext_string(const struct llext_loader *ldr, const struct llext *ext,
enum llext_mem mem_idx, unsigned int idx)
{
return (char *)ext->mem[mem_idx] + idx;
}
/*
* Relocation (llext_link.c)
*/

Loading…
Cancel
Save