From 03519afb841f30cb9743c271050ce69245fe4210 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 28 Sep 2023 13:59:53 +0200 Subject: [PATCH] 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 --- arch/xtensa/core/CMakeLists.txt | 1 + arch/xtensa/core/elf.c | 44 +++++++++++++++++++++++++++++++++ include/zephyr/llext/llext.h | 11 +++++++++ subsys/llext/llext.c | 19 ++++++++++++-- 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 arch/xtensa/core/elf.c diff --git a/arch/xtensa/core/CMakeLists.txt b/arch/xtensa/core/CMakeLists.txt index f3122c1a550..b415aec2e9c 100644 --- a/arch/xtensa/core/CMakeLists.txt +++ b/arch/xtensa/core/CMakeLists.txt @@ -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 diff --git a/arch/xtensa/core/elf.c b/arch/xtensa/core/elf.c new file mode 100644 index 00000000000..959f374888c --- /dev/null +++ b/arch/xtensa/core/elf.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +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); + } +} diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index a4458a05468..60ce1cae47a 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -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); + /** * @} */ diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 7b8099a9190..57e8fb2e828 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -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); } } }