@@ -52,7 +52,56 @@ static size_t llext_file_offset(struct llext_loader *ldr, size_t offset)
5252 return offset ;
5353}
5454
55+ /*
56+ * We increment use-count every time a new dependent is added, and have to
57+ * decrement it again, when one is removed. Ideally we should be able to add
58+ * arbitrary numbers of dependencies, but using lists for this doesn't work,
59+ * because multiple extensions can have common dependencies. Dynamically
60+ * allocating dependency entries would be too wasteful. In this initial
61+ * implementation we use an array of dependencies, if at some point we run out
62+ * of array entries, we'll implement re-allocation.
63+ * We add dependencies incrementally as we discover them, but we only ever
64+ * expect them to be removed all at once, when their user is removed. So the
65+ * dependency array is always "dense" - it cannot have NULL entries between
66+ * valid ones.
67+ */
68+ static int llext_dependency_add (struct llext * ext , struct llext * dependency )
69+ {
70+ unsigned int i ;
71+
72+ for (i = 0 ; i < ARRAY_SIZE (ext -> dependency ); i ++ ) {
73+ if (ext -> dependency [i ] == dependency ) {
74+ return 0 ;
75+ }
76+
77+ if (!ext -> dependency [i ]) {
78+ ext -> dependency [i ] = dependency ;
79+ dependency -> use_count ++ ;
80+
81+ return 0 ;
82+ }
83+ }
84+
85+ return - ENOENT ;
86+ }
87+
88+ void llext_dependency_remove_all (struct llext * ext )
89+ {
90+ unsigned int i ;
91+
92+ for (i = 0 ; i < ARRAY_SIZE (ext -> dependency ) && ext -> dependency [i ]; i ++ ) {
93+ /*
94+ * The use-count of dependencies is tightly bound to dependent's
95+ * life cycle, so it shouldn't underrun.
96+ */
97+ ext -> dependency [i ]-> use_count -- ;
98+ __ASSERT (ext -> dependency [i ]-> use_count , "LLEXT dependency use-count underrun!" );
99+ /* No need to NULL-ify the pointer - ext is freed after this */
100+ }
101+ }
102+
55103struct llext_extension_sym {
104+ struct llext * ext ;
56105 const char * sym ;
57106 const void * addr ;
58107};
@@ -64,17 +113,21 @@ static int llext_find_extension_sym_iterate(struct llext *ext, void *arg)
64113
65114 if (addr ) {
66115 se -> addr = addr ;
116+ se -> ext = ext ;
67117 return 1 ;
68118 }
69119
70120 return 0 ;
71121}
72122
73- static const void * llext_find_extension_sym (const char * sym_name )
123+ static const void * llext_find_extension_sym (const char * sym_name , struct llext * * ext )
74124{
75125 struct llext_extension_sym se = {.sym = sym_name };
76126
77127 llext_iterate (llext_find_extension_sym_iterate , & se );
128+ if (ext ) {
129+ * ext = se .ext ;
130+ }
78131
79132 return se .addr ;
80133}
@@ -168,15 +221,23 @@ static void llext_link_plt(struct llext_loader *ldr, struct llext *ext,
168221
169222 switch (stb ) {
170223 case STB_GLOBAL :
224+ /* First try the global symbol table */
171225 link_addr = llext_find_sym (NULL ,
172226 SYM_NAME_OR_SLID (name , sym_tbl .st_value ));
173227
174228 if (!link_addr ) {
229+ /* Next try internal tables */
175230 link_addr = llext_find_sym (& ext -> sym_tab , name );
176231 }
177232
178233 if (!link_addr ) {
179- link_addr = llext_find_extension_sym (name );
234+ /* Finally try any loaded tables */
235+ struct llext * dep ;
236+
237+ link_addr = llext_find_extension_sym (name , & dep );
238+ if (link_addr ) {
239+ llext_dependency_add (ext , dep );
240+ }
180241 }
181242
182243 if (!link_addr ) {
@@ -328,6 +389,16 @@ int llext_link(struct llext_loader *ldr, struct llext *ext, bool do_local)
328389 link_addr = (uintptr_t )llext_find_sym (NULL ,
329390 SYM_NAME_OR_SLID (name , sym .st_value ));
330391
392+ if (link_addr == 0 ) {
393+ /* Try loaded tables */
394+ struct llext * dep ;
395+
396+ link_addr = (uintptr_t )llext_find_extension_sym (name , & dep );
397+ if (link_addr ) {
398+ llext_dependency_add (ext , dep );
399+ }
400+ }
401+
331402 if (link_addr == 0 ) {
332403 LOG_ERR ("Undefined symbol with no entry in "
333404 "symbol table %s, offset %zd, link section %d" ,
0 commit comments