Browse Source

llext: make unresolved symbol errors fatal

With experience it becomes clear, that failing to resolve symbols
during the linking process is likely fatal for the module loading and
a simple warning isn't enough. Fail loading instead.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
pull/91566/head
Guennadi Liakhovetski 4 weeks ago committed by Henrik Brix Andersen
parent
commit
53a179ac4e
  1. 34
      arch/xtensa/core/elf.c
  2. 12
      include/zephyr/llext/llext.h
  3. 46
      subsys/llext/llext_link.c

34
arch/xtensa/core/elf.c

@ -32,10 +32,10 @@ LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL);
#define R_XTENSA_ASM_EXPAND 11 #define R_XTENSA_ASM_EXPAND 11
#define R_XTENSA_SLOT0_OP 20 #define R_XTENSA_SLOT0_OP 20
static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext, static int xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,
const elf_rela_t *rel, uintptr_t addr, const elf_rela_t *rel, uintptr_t addr,
uint8_t *loc, int type, uint32_t stb, uint8_t *loc, int type, uint32_t stb,
const struct llext_load_param *ldr_parm) const struct llext_load_param *ldr_parm)
{ {
elf_word *got_entry = (elf_word *)loc; elf_word *got_entry = (elf_word *)loc;
@ -59,7 +59,7 @@ static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,
if (sh_ndx == ext->sect_cnt) { if (sh_ndx == ext->sect_cnt) {
LOG_ERR("%#x not found in any of the sections", *got_entry); LOG_ERR("%#x not found in any of the sections", *got_entry);
return; return -ENOENT;
} }
*got_entry += (uintptr_t)llext_loaded_sect_ptr(ldr, ext, sh_ndx) - *got_entry += (uintptr_t)llext_loaded_sect_ptr(ldr, ext, sh_ndx) -
@ -87,7 +87,7 @@ static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,
} }
if (ret) { if (ret) {
LOG_ERR("Failed to read a symbol table entry, LLEXT linking might fail."); LOG_ERR("Failed to read a symbol table entry, LLEXT linking might fail.");
return; return ret;
} }
/* /*
@ -124,19 +124,21 @@ static void xtensa_elf_relocate(struct llext_loader *ldr, struct llext *ext,
default: default:
LOG_DBG("Unsupported relocation type %u", type); LOG_DBG("Unsupported relocation type %u", type);
return; return 0;
} }
LOG_DBG("Applied relocation to %#x type %u at %p", LOG_DBG("Applied relocation to %#x type %u at %p",
*(uint32_t *)((uintptr_t)got_entry & ~3), type, (void *)got_entry); *(uint32_t *)((uintptr_t)got_entry & ~3), type, (void *)got_entry);
return 0;
} }
/** /**
* @brief Architecture specific function for STB_LOCAL ELF relocations * @brief Architecture specific function for STB_LOCAL ELF relocations
*/ */
void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel, int arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, uint8_t *rel_addr, const elf_sym_t *sym, uint8_t *rel_addr,
const struct llext_load_param *ldr_parm) const struct llext_load_param *ldr_parm)
{ {
int type = ELF32_R_TYPE(rel->r_info); int type = ELF32_R_TYPE(rel->r_info);
uintptr_t sh_addr; uintptr_t sh_addr;
@ -152,15 +154,15 @@ void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, const
sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr; sh_addr = ldr->sects[LLEXT_MEM_TEXT].sh_addr;
} }
xtensa_elf_relocate(ldr, ext, rel, sh_addr, rel_addr, type, ELF_ST_BIND(sym->st_info), return xtensa_elf_relocate(ldr, ext, rel, sh_addr, rel_addr, type,
ldr_parm); ELF_ST_BIND(sym->st_info), ldr_parm);
} }
/** /**
* @brief Architecture specific function for STB_GLOBAL ELF relocations * @brief Architecture specific function for STB_GLOBAL ELF relocations
*/ */
void arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel, int arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, uint8_t *rel_addr, const void *link_addr) const elf_sym_t *sym, uint8_t *rel_addr, const void *link_addr)
{ {
int type = ELF32_R_TYPE(rel->r_info); int type = ELF32_R_TYPE(rel->r_info);
@ -169,6 +171,6 @@ void arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext, const
LOG_WRN("global: non-zero relative value %#x", *(elf_word *)rel_addr); LOG_WRN("global: non-zero relative value %#x", *(elf_word *)rel_addr);
} }
xtensa_elf_relocate(ldr, ext, rel, (uintptr_t)link_addr, rel_addr, type, return xtensa_elf_relocate(ldr, ext, rel, (uintptr_t)link_addr, rel_addr, type,
ELF_ST_BIND(sym->st_info), NULL); ELF_ST_BIND(sym->st_info), NULL);
} }

12
include/zephyr/llext/llext.h

@ -409,10 +409,11 @@ int llext_get_section_header(struct llext_loader *loader, struct llext *ext,
* @param[in] sym Corresponding symbol table entry * @param[in] sym Corresponding symbol table entry
* @param[in] rel_addr Address where relocation should be performed * @param[in] rel_addr Address where relocation should be performed
* @param[in] ldr_parm Loader parameters * @param[in] ldr_parm Loader parameters
* @returns 0 on success or a negative error code
*/ */
void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel, int arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, uint8_t *rel_addr, const elf_sym_t *sym, uint8_t *rel_addr,
const struct llext_load_param *ldr_parm); const struct llext_load_param *ldr_parm);
/** /**
* @brief Architecture specific function for global binding relocations * @brief Architecture specific function for global binding relocations
@ -423,9 +424,10 @@ void arch_elf_relocate_local(struct llext_loader *loader, struct llext *ext, con
* @param[in] sym Corresponding symbol table entry * @param[in] sym Corresponding symbol table entry
* @param[in] rel_addr Address where relocation should be performed * @param[in] rel_addr Address where relocation should be performed
* @param[in] link_addr target address for table-based relocations * @param[in] link_addr target address for table-based relocations
* @returns 0 on success or a negative error code
*/ */
void arch_elf_relocate_global(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel, int arch_elf_relocate_global(struct llext_loader *loader, struct llext *ext, const elf_rela_t *rel,
const elf_sym_t *sym, uint8_t *rel_addr, const void *link_addr); const elf_sym_t *sym, uint8_t *rel_addr, const void *link_addr);
/** /**
* @brief Initialize LLEXT heap dynamically * @brief Initialize LLEXT heap dynamically

46
subsys/llext/llext_link.c

@ -32,16 +32,18 @@ __weak int arch_elf_relocate(struct llext_loader *ldr, struct llext *ext, elf_re
return -ENOTSUP; return -ENOTSUP;
} }
__weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext, __weak int arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext,
const elf_rela_t *rel, const elf_sym_t *sym, uint8_t *rel_addr, const elf_rela_t *rel, const elf_sym_t *sym, uint8_t *rel_addr,
const struct llext_load_param *ldr_parm) const struct llext_load_param *ldr_parm)
{ {
return -ENOTSUP;
} }
__weak void arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext, __weak int arch_elf_relocate_global(struct llext_loader *ldr, struct llext *ext,
const elf_rela_t *rel, const elf_sym_t *sym, uint8_t *rel_addr, const elf_rela_t *rel, const elf_sym_t *sym, uint8_t *rel_addr,
const void *link_addr) const void *link_addr)
{ {
return -ENOTSUP;
} }
/* /*
@ -246,8 +248,8 @@ int llext_lookup_symbol(struct llext_loader *ldr, struct llext *ext, uintptr_t *
return 0; return 0;
} }
static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr, static int 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) const struct llext_load_param *ldr_parm, elf_shdr_t *tgt)
{ {
unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize; unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize;
/* /*
@ -255,6 +257,7 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
* reference point * reference point
*/ */
uint8_t *text = ext->mem[LLEXT_MEM_TEXT]; uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
int link_err = 0;
LOG_DBG("Found %p in PLT %u size %zu cnt %u text %p", LOG_DBG("Found %p in PLT %u size %zu cnt %u text %p",
(void *)llext_section_name(ldr, ext, shdr), (void *)llext_section_name(ldr, ext, shdr),
@ -370,20 +373,34 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr
if (!link_addr) { if (!link_addr) {
LOG_WRN("PLT: cannot find idx %u name %s", j, name); LOG_WRN("PLT: cannot find idx %u name %s", j, name);
continue; /* Will fail after reporting all missing symbols */
if (!link_err) {
link_err = -ENOENT;
}
break;
} }
/* Resolve the symbol */ /* Resolve the symbol */
arch_elf_relocate_global(ldr, ext, &rela, &sym, rel_addr, link_addr); ret = arch_elf_relocate_global(ldr, ext, &rela, &sym, rel_addr, link_addr);
if (!link_err) {
link_err = ret;
}
break; break;
case STB_LOCAL: case STB_LOCAL:
arch_elf_relocate_local(ldr, ext, &rela, &sym, rel_addr, ldr_parm); ret = arch_elf_relocate_local(ldr, ext, &rela, &sym, rel_addr, ldr_parm);
if (!link_err) {
link_err = ret;
}
} }
LOG_DBG("symbol %s relocation @%p r-offset %#zx .text offset %#zx stb %u", if (!link_err) {
name, (void *)rel_addr, LOG_DBG("symbol %s relocation @%p r-offset %#zx .text offset %#zx stb %u",
(size_t)rela.r_offset, (size_t)ldr->sects[LLEXT_MEM_TEXT].sh_offset, stb); name, (void *)rel_addr, (size_t)rela.r_offset,
(size_t)ldr->sects[LLEXT_MEM_TEXT].sh_offset, stb);
}
} }
return link_err;
} }
int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_load_param *ldr_parm) int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_load_param *ldr_parm)
@ -457,7 +474,10 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, const struct llext_l
tgt = ext->sect_hdrs + shdr->sh_info; tgt = ext->sect_hdrs + shdr->sh_info;
} }
llext_link_plt(ldr, ext, shdr, ldr_parm, tgt); ret = llext_link_plt(ldr, ext, shdr, ldr_parm, tgt);
if (ret < 0) {
return ret;
}
continue; continue;
} }

Loading…
Cancel
Save