llext: fix handling of non-standard sections in relocatable case
When building partially linked / relocatable objects no ELF segments are created and it becomes more difficult to predict which sections the compiler will build and use. In this case a .data.rel.local section is created by the compiler and it is needed to link .rodata strings in a twister test. We can handle arbitrary sections at run- time if .peek() is supported. If it isn't we need to allocate and copy the section. For now we simply error out in such cases. Fixing that would represent a larger change and can be done incrementally. This also fixes the relocation calculation to point to the correct symbol address instead of the memory location, where it's currently residing, because that can be a temporary buffer as is the case with SOF. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
parent
29026e8a89
commit
ebde53904d
2 changed files with 55 additions and 7 deletions
|
@ -530,7 +530,8 @@ static int llext_export_symbols(struct llext_loader *ldr, struct llext *ext)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext)
|
||||
static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext,
|
||||
bool pre_located)
|
||||
{
|
||||
size_t ent_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_entsize;
|
||||
size_t syms_size = ldr->sects[LLEXT_MEM_SYMTAB].sh_size;
|
||||
|
@ -564,16 +565,58 @@ static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext)
|
|||
|
||||
if ((stt == STT_FUNC || stt == STT_OBJECT) &&
|
||||
stb == STB_GLOBAL && sect != SHN_UNDEF) {
|
||||
enum llext_mem mem_idx = ldr->sect_map[sect];
|
||||
const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
|
||||
|
||||
__ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j);
|
||||
|
||||
sym_tab->syms[j].name = name;
|
||||
sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem_idx] +
|
||||
sym.st_value -
|
||||
(ldr->hdr.e_type == ET_REL ? 0 :
|
||||
ldr->sects[mem_idx].sh_addr));
|
||||
|
||||
uintptr_t section_addr;
|
||||
void *base;
|
||||
|
||||
if (sect < LLEXT_MEM_BSS) {
|
||||
/*
|
||||
* This is just a slight optimisation for cached
|
||||
* sections, we could use the generic path below
|
||||
* for all of them
|
||||
*/
|
||||
base = ext->mem[ldr->sect_map[sect]];
|
||||
section_addr = ldr->sects[ldr->sect_map[sect]].sh_addr;
|
||||
} else {
|
||||
/* Section header isn't stored, have to read it */
|
||||
size_t shdr_pos = ldr->hdr.e_shoff + sect * ldr->hdr.e_shentsize;
|
||||
elf_shdr_t shdr;
|
||||
|
||||
ret = llext_seek(ldr, shdr_pos);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("failed seeking to position %zu\n", shdr_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t));
|
||||
if (ret != 0) {
|
||||
LOG_ERR("failed reading section header at position %zu\n",
|
||||
shdr_pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
base = llext_peek(ldr, shdr.sh_offset);
|
||||
if (!base) {
|
||||
LOG_ERR("cannot handle arbitrary sections without .peek\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
section_addr = shdr.sh_addr;
|
||||
}
|
||||
|
||||
if (pre_located) {
|
||||
sym_tab->syms[j].addr = (uint8_t *)sym.st_value +
|
||||
(ldr->hdr.e_type == ET_REL ? section_addr : 0);
|
||||
} else {
|
||||
sym_tab->syms[j].addr = (uint8_t *)base + sym.st_value -
|
||||
(ldr->hdr.e_type == ET_REL ? 0 : section_addr);
|
||||
}
|
||||
|
||||
LOG_DBG("function symbol %d name %s addr %p",
|
||||
j, name, sym_tab->syms[j].addr);
|
||||
j++;
|
||||
|
@ -954,7 +997,7 @@ static int do_llext_load(struct llext_loader *ldr, struct llext *ext,
|
|||
}
|
||||
|
||||
LOG_DBG("Copying symbols...");
|
||||
ret = llext_copy_symbols(ldr, ext);
|
||||
ret = llext_copy_symbols(ldr, ext, ldr_parm ? ldr_parm->pre_located : false);
|
||||
if (ret != 0) {
|
||||
LOG_ERR("Failed to copy symbols, ret %d", ret);
|
||||
goto out;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue