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>
This commit is contained in:
parent
7293f59a05
commit
3466dab804
8 changed files with 206 additions and 81 deletions
|
@ -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);
|
|||
* 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;
|
||||
|
||||
|
|
|
@ -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,
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -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
|
|||
* @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:
|
||||
|
|
|
@ -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;
|
|||
* 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
|
|||
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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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" {
|
|||
|
||||
/** @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 {
|
|||
|
||||
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
|
||||
|
|
|
@ -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 *
|
|||
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.
|
||||
*/
|
||||
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_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.
|
||||
*/
|
||||
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
|
|||
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
|
|||
{
|
||||
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
|
|||
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
|
|||
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;
|
||||
#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;
|
||||
|
||||
ret = llext_read_symbol(ldr, ext, &rel, &sym);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
name = llext_symbol_name(ldr, ext, &sym);
|
||||
|
||||
ret = llext_lookup_symbol(ldr, ext, &link_addr, &rel, &sym, name,
|
||||
shdr);
|
||||
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Could not find symbol %s!", name);
|
||||
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 */
|
||||
|
||||
ret = llext_read(ldr, &sym, sizeof(elf_sym_t));
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
|
||||
|
||||
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);
|
||||
|
||||
uintptr_t link_addr, op_loc;
|
||||
|
||||
op_loc = sect_base + rel.r_offset;
|
||||
|
||||
ret = llext_lookup_symbol(ext, ldr, &link_addr, &rel, &sym, name, shdr);
|
||||
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to lookup symbol in rela section %d entry %d!", i,
|
||||
j);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue