diff --git a/include/zephyr/llext/llext.h b/include/zephyr/llext/llext.h index 96bd64d2854..5376e2cf13a 100644 --- a/include/zephyr/llext/llext.h +++ b/include/zephyr/llext/llext.h @@ -78,6 +78,19 @@ sys_slist_t *llext_list(void); */ struct llext *llext_by_name(const char *name); +/** + * @brief llext loader parameters + * + * These are parameters, not saved in the permanent llext context, needed only + * for the loader + */ +struct llext_load_param { + /** Should local relocation be performed */ + bool relocate_local; +}; + +#define LLEXT_LOAD_PARAM_DEFAULT {.relocate_local = true,} + /** * @brief Load and link an extension * @@ -88,12 +101,14 @@ struct llext *llext_by_name(const char *name); * @param[in] loader An extension loader that provides input data and context * @param[in] name A string identifier for the extension * @param[out] ext A pointer to a statically allocated llext struct + * @param[in] ldr_parm Loader parameters * * @retval 0 Success * @retval -ENOMEM Not enough memory * @retval -EINVAL Invalid ELF stream */ -int llext_load(struct llext_loader *loader, const char *name, struct llext **ext); +int llext_load(struct llext_loader *loader, const char *name, struct llext **ext, + struct llext_load_param *ldr_parm); /** * @brief Unload an extension diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index 6598652840b..d71f2a2a102 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -494,7 +494,8 @@ __weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, { } -static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr) +static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, + elf_shdr_t *shdr, bool do_local) { unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; /* @@ -547,6 +548,11 @@ 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); + + if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF) { + continue; + } + 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 @@ -555,9 +561,6 @@ 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) - continue; - const void *link_addr; switch (stb) { @@ -574,16 +577,18 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr continue; } - LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x", - name, got_offset, - rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset); - /* Resolve the symbol */ *(const void **)(text + got_offset) = link_addr; break; case STB_LOCAL: - arch_elf_relocate_local(ldr, ext, &rela, got_offset); + if (do_local) { + arch_elf_relocate_local(ldr, ext, &rela, got_offset); + } } + + LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x stb %u", + name, got_offset, + rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset, stb); } } @@ -591,7 +596,7 @@ __weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval { } -static int llext_link(struct llext_loader *ldr, struct llext *ext) +static int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local) { uintptr_t loc = 0; elf_shdr_t shdr; @@ -638,7 +643,7 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA]; } else if (strcmp(name, ".rela.plt") == 0 || strcmp(name, ".rela.dyn") == 0) { - llext_link_plt(ldr, ext, &shdr); + llext_link_plt(ldr, ext, &shdr, do_local); continue; } @@ -724,7 +729,8 @@ static int llext_link(struct llext_loader *ldr, struct llext *ext) /* * Load a valid ELF as an extension */ -static int do_llext_load(struct llext_loader *ldr, struct llext *ext) +static int do_llext_load(struct llext_loader *ldr, struct llext *ext, + struct llext_load_param *ldr_parm) { int ret = 0; @@ -793,7 +799,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext) } LOG_DBG("Linking ELF..."); - ret = llext_link(ldr, ext); + ret = llext_link(ldr, ext, ldr_parm ? ldr_parm->relocate_local : true); if (ret != 0) { LOG_ERR("Failed to link, ret %d", ret); goto out; @@ -818,7 +824,8 @@ out: return ret; } -int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) +int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, + struct llext_load_param *ldr_parm) { int ret; elf_ehdr_t ehdr; @@ -857,7 +864,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext) } ldr->hdr = ehdr; - ret = do_llext_load(ldr, *ext); + ret = do_llext_load(ldr, *ext, ldr_parm); break; default: LOG_ERR("Unsupported elf file type %x", ehdr.e_type); diff --git a/subsys/llext/shell.c b/subsys/llext/shell.c index b9a4121acc6..289ebaa4d35 100644 --- a/subsys/llext/shell.c +++ b/subsys/llext/shell.c @@ -117,8 +117,9 @@ static int cmd_llext_load_hex(const struct shell *sh, size_t argc, char *argv[]) hex_len, CONFIG_LLEXT_SHELL_MAX_SIZE, llext_buf_len); LOG_HEXDUMP_DBG(llext_buf, 4, "4 byte MAGIC"); + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; struct llext *ext; - int res = llext_load(ldr, name, &ext); + int res = llext_load(ldr, name, &ext, &ldr_parm); if (res == 0) { shell_print(sh, "Successfully loaded extension %s, addr %p\n", ext->name, ext); diff --git a/tests/subsys/llext/src/test_llext_simple.c b/tests/subsys/llext/src/test_llext_simple.c index ef0e62b93b5..0b002c79e71 100644 --- a/tests/subsys/llext/src/test_llext_simple.c +++ b/tests/subsys/llext/src/test_llext_simple.c @@ -28,12 +28,13 @@ ZTEST(llext, test_llext_simple) struct llext_buf_loader buf_loader = LLEXT_BUF_LOADER(hello_world_elf, ARRAY_SIZE(hello_world_elf)); struct llext_loader *loader = &buf_loader.loader; + struct llext_load_param ldr_parm = LLEXT_LOAD_PARAM_DEFAULT; struct llext *ext; const void * const printk_fn = llext_find_sym(NULL, "printk"); zassert_equal(printk_fn, printk, "printk should be an exported symbol"); - int res = llext_load(loader, name, &ext); + int res = llext_load(loader, name, &ext, &ldr_parm); zassert_ok(res, "load should succeed");