llext: xtensa: add support for local symbol relocations

Add support for relocating local symbols, as specified in the
.rela.dyn section.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2023-09-28 13:59:53 +02:00 committed by Anas Nashif
commit 03519afb84
4 changed files with 73 additions and 2 deletions

View file

@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_GDBSTUB gdbstub.c)
zephyr_library_sources_ifdef(CONFIG_XTENSA_MMU ptables.c mmu.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE userspace.S)
zephyr_library_sources_ifdef(CONFIG_XTENSA_SYSCALL_USE_HELPER syscall_helper.c)
zephyr_library_sources_ifdef(CONFIG_LLEXT elf.c)
zephyr_library_sources_ifdef(
CONFIG_KERNEL_VM_USE_CUSTOM_MEM_RANGE_CHECK

44
arch/xtensa/core/elf.c Normal file
View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2023 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/llext/elf.h>
#include <zephyr/llext/llext.h>
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(llext);
#define R_XTENSA_NONE 0
#define R_XTENSA_32 1
#define R_XTENSA_RTLD 2
#define R_XTENSA_GLOB_DAT 3
#define R_XTENSA_JMP_SLOT 4
#define R_XTENSA_RELATIVE 5
#define R_XTENSA_PLT 6
/**
* @brief Architecture specific function for relocating shared elf
*
* Elf files contain a series of relocations described in multiple sections.
* These relocation instructions are architecture specific and each architecture
* supporting modules must implement this.
*/
void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext,
elf_rela_t *rel, size_t got_offset)
{
uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
int type = ELF32_R_TYPE(rel->r_info);
if (type == R_XTENSA_RELATIVE) {
elf_word ptr_offset = *(elf_word *)(text + got_offset);
LOG_DBG("relocation type %u offset %#x value %#x",
type, got_offset, ptr_offset);
/* Relocate a local symbol: Xtensa specific */
*(elf_word *)(text + got_offset) = (elf_word)(text + ptr_offset -
ldr->sects[LLEXT_SECT_TEXT].sh_addr);
}
}

View file

@ -142,6 +142,17 @@ int llext_call_fn(struct llext *ext, const char *sym_name);
*/
void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval);
/**
* @brief Architecture specific function for updating addresses via relocation table
*
* @param[in] loader Extension loader data and context
* @param[in] ext Extension to call function in
* @param[in] rel Relocation data provided by elf
* @param[in] got_offset Offset within a relocation table
*/
void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext,
elf_rela_t *rel, size_t got_offset);
/**
* @}
*/

View file

@ -462,6 +462,11 @@ static size_t llext_file_offset(struct llext_loader *ldr, size_t offset)
return offset;
}
__weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext,
elf_rela_t *rel, size_t got_offset)
{
}
static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr)
{
unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize;
@ -514,6 +519,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
}
uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info);
uint32_t stb = ELF_ST_BIND(sym_tbl.st_info);
const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name);
/*
* Both r_offset and sh_addr are addresses for which the extension
@ -522,8 +528,14 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
size_t got_offset = llext_file_offset(ldr, rela.r_offset) -
ldr->sects[LLEXT_SECT_TEXT].sh_offset;
if (stt == STT_NOTYPE && sym_tbl.st_shndx == SHN_UNDEF && name[0] != '\0') {
const void *link_addr = llext_find_sym(NULL, name);
if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF)
continue;
const void *link_addr;
switch (stb) {
case STB_GLOBAL:
link_addr = llext_find_sym(NULL, name);
if (!link_addr) {
LOG_WRN("PLT: cannot find idx %u name %s", j, name);
@ -541,6 +553,9 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
/* Resolve the symbol */
*(const void **)(text + got_offset) = link_addr;
break;
case STB_LOCAL:
arch_elf_relocate_local(ldr, ext, &rela, got_offset);
}
}
}