Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions include/zephyr/llext/llext.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ enum llext_mem {
struct llext_loader;
/** @endcond */

/* Maximim number of dependency LLEXTs */
#define LLEXT_MAX_DEPENDENCIES 8
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be a Kconfig, not a blocker but would be good to see a follow up for


/**
* @brief Structure describing a linkable loadable extension
*
Expand Down Expand Up @@ -111,6 +114,9 @@ struct llext {

/** Extension use counter, prevents unloading while in use */
unsigned int use_count;

/** Array of extensions, whose symbols this extension accesses */
struct llext *dependency[LLEXT_MAX_DEPENDENCIES];
Copy link
Contributor

Choose a reason for hiding this comment

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

This could use a doc string

};

/**
Expand Down
2 changes: 2 additions & 0 deletions subsys/llext/llext.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ int llext_unload(struct llext **ext)
/* FIXME: protect the global list */
sys_slist_find_and_remove(&_llext_list, &tmp->_llext_list);

llext_dependency_remove_all(tmp);

*ext = NULL;
k_mutex_unlock(&llext_lock);

Expand Down
75 changes: 73 additions & 2 deletions subsys/llext/llext_link.c
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: this sounds prone to race conditions - but the whole subsystem is, anyways, as struct llext lacks a lock... This is well outside PR scope though 😄

Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,56 @@ static size_t llext_file_offset(struct llext_loader *ldr, size_t offset)
return offset;
}

/*
* We increment use-count every time a new dependent is added, and have to
* decrement it again, when one is removed. Ideally we should be able to add
* arbitrary numbers of dependencies, but using lists for this doesn't work,
* because multiple extensions can have common dependencies. Dynamically
* allocating dependency entries would be too wasteful. In this initial
* implementation we use an array of dependencies, if at some point we run out
* of array entries, we'll implement re-allocation.
* We add dependencies incrementally as we discover them, but we only ever
* expect them to be removed all at once, when their user is removed. So the
* dependency array is always "dense" - it cannot have NULL entries between
* valid ones.
*/
static int llext_dependency_add(struct llext *ext, struct llext *dependency)
{
unsigned int i;

for (i = 0; i < ARRAY_SIZE(ext->dependency); i++) {
if (ext->dependency[i] == dependency) {
return 0;
}

if (!ext->dependency[i]) {
ext->dependency[i] = dependency;
dependency->use_count++;

return 0;
}
}

return -ENOENT;
}

void llext_dependency_remove_all(struct llext *ext)
{
unsigned int i;

for (i = 0; i < ARRAY_SIZE(ext->dependency) && ext->dependency[i]; i++) {
/*
* The use-count of dependencies is tightly bound to dependent's
* life cycle, so it shouldn't underrun.
*/
ext->dependency[i]->use_count--;
__ASSERT(ext->dependency[i]->use_count, "LLEXT dependency use-count underrun!");
/* No need to NULL-ify the pointer - ext is freed after this */
}
}

struct llext_extension_sym {
struct llext *ext;
const char *sym;
const void *addr;
};
Expand All @@ -64,17 +113,21 @@ static int llext_find_extension_sym_iterate(struct llext *ext, void *arg)

if (addr) {
se->addr = addr;
se->ext = ext;
return 1;
}

return 0;
}

static const void *llext_find_extension_sym(const char *sym_name)
static const void *llext_find_extension_sym(const char *sym_name, struct llext **ext)
{
struct llext_extension_sym se = {.sym = sym_name};

llext_iterate(llext_find_extension_sym_iterate, &se);
if (ext) {
*ext = se.ext;
}

return se.addr;
}
Expand Down Expand Up @@ -168,15 +221,23 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext,

switch (stb) {
case STB_GLOBAL:
/* First try the global symbol table */
link_addr = llext_find_sym(NULL,
SYM_NAME_OR_SLID(name, sym_tbl.st_value));

if (!link_addr) {
/* Next try internal tables */
link_addr = llext_find_sym(&ext->sym_tab, name);
}

if (!link_addr) {
link_addr = llext_find_extension_sym(name);
/* Finally try any loaded tables */
struct llext *dep;

link_addr = llext_find_extension_sym(name, &dep);
if (link_addr) {
llext_dependency_add(ext, dep);
}
}

if (!link_addr) {
Expand Down Expand Up @@ -328,6 +389,16 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local)
link_addr = (uintptr_t)llext_find_sym(NULL,
SYM_NAME_OR_SLID(name, sym.st_value));

if (link_addr == 0) {
/* Try loaded tables */
struct llext *dep;

link_addr = (uintptr_t)llext_find_extension_sym(name, &dep);
if (link_addr) {
llext_dependency_add(ext, dep);
}
}

Comment on lines +392 to +401
Copy link
Contributor

Choose a reason for hiding this comment

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

Very minor nit - if you ever have to refactor anything: this bit of code is added in the last commit, which only deals with dependency tracking. Similar to what happens for Xtensa, it could be split between the commit that introduces the actual lookup and the one adding tracking.

if (link_addr == 0) {
LOG_ERR("Undefined symbol with no entry in "
"symbol table %s, offset %zd, link section %d",
Expand Down
1 change: 1 addition & 0 deletions subsys/llext/llext_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,5 +74,6 @@ static inline const void *llext_loaded_sect_ptr(struct llext_loader *ldr, struct
*/

int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local);
void llext_dependency_remove_all(struct llext *ext);

#endif /* ZEPHYR_SUBSYS_LLEXT_PRIV_H_ */