Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions include/zephyr/llext/llext.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg);
struct llext_load_param {
/** Should local relocation be performed */
bool relocate_local;
/**
* Use the virtual symbol addresses from the ELF, not addresses within
* the memory buffer, where the object is loaded
*/
bool pre_located;
};

#define LLEXT_LOAD_PARAM_DEFAULT {.relocate_local = true,}
Expand Down
2 changes: 1 addition & 1 deletion subsys/llext/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ config LLEXT_TYPE_ELF_OBJECT
config LLEXT_TYPE_ELF_RELOCATABLE
bool "Relocatable ELF file"
help
Build and expect relocatable (partially linked )files as the
Build and expect relocatable (partially linked) files as the
binary object type for the llext subsystem. These object files
are generated by the linker by combining multiple object files
into a single one.
Expand Down
65 changes: 51 additions & 14 deletions subsys/llext/llext.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,7 @@ static int llext_find_tables(struct llext_loader *ldr)
}

LOG_DBG("section %d at %zx: name %d, type %d, flags %zx, addr %zx, size %zd",
i,
(size_t)ldr->hdr.e_shoff + i * ldr->hdr.e_shentsize,
i, pos,
shdr.sh_name,
shdr.sh_type,
(size_t)shdr.sh_flags,
Expand Down Expand Up @@ -530,7 +529,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;
Expand Down Expand Up @@ -564,16 +564,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);
Comment on lines +612 to +613
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be:

Suggested change
sym_tab->syms[j].addr = (uint8_t *)sym.st_value +
(ldr->hdr.e_type == ET_REL ? section_addr : 0);
sym_tab->syms[j].addr = (uint8_t *)section_addr
+ sym.st_value;

because in the "pre-located" case the symbols'VMA should not be modified, so the calculation is the same regardless of dynamic or static linking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pillo79 no, the difference between ET_REL (relocatable object) and ET_DYN (shared object) remains. In the relocatable case that calculation is correct:

[  113.934401] <inf> llext: llext_copy_symbols: type: 1 sym volume_init: 0x1e8c section 0xa068a000
[  113.934410] <inf> llext: llext_copy_symbols: type: 1 sym volume_func_count: 0x24 section 0xa068e000
[  113.934420] <inf> llext: llext_copy_symbols: type: 1 sym volume_reset_state: 0xf50 section 0xa068a000

but in the shared case it's this:

[  150.092295] <inf> llext: llext_copy_symbols: type: 3 sym volume_init: 0xa068ba5c section 0xa068a000
[  150.092306] <inf> llext: llext_copy_symbols: type: 3 sym volume_func_count: 0xa068d0b0 section 0xa068d000
[  150.092318] <inf> llext: llext_copy_symbols: type: 3 sym volume_reset_state: 0xa068b510 section 0xa068a000

Copy link
Contributor

@pillo79 pillo79 May 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, that is indeed why it's subtracted in the else case!

} 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++;
Expand Down Expand Up @@ -696,11 +738,6 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext,
continue;
}

if (!rela.r_offset) {
LOG_WRN("PLT: zero offset idx %u name %s", j, name);
continue;
}

/* Resolve the symbol */
*(const void **)(text + got_offset) = link_addr;
break;
Expand Down Expand Up @@ -954,7 +991,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;
Expand Down