blob: 6598652840b2390210581bc75bdc498806db0b7a [file] [log] [blame]
Tom Burdick41e0a4a2023-09-27 08:10:10 -05001/*
2 * Copyright (c) 2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 */
7
8#include "zephyr/sys/__assert.h"
9#include <zephyr/sys/util.h>
10#include <zephyr/llext/elf.h>
11#include <zephyr/llext/loader.h>
12#include <zephyr/llext/llext.h>
13#include <zephyr/kernel.h>
14
15#include <zephyr/logging/log.h>
16LOG_MODULE_REGISTER(llext, CONFIG_LLEXT_LOG_LEVEL);
17
18#include <string.h>
19
20K_HEAP_DEFINE(llext_heap, CONFIG_LLEXT_HEAP_SIZE * 1024);
21
22static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'};
23
24static inline int llext_read(struct llext_loader *l, void *buf, size_t len)
25{
26 return l->read(l, buf, len);
27}
28
29static inline int llext_seek(struct llext_loader *l, size_t pos)
30{
31 return l->seek(l, pos);
32}
33
Guennadi Liakhovetskice4cdac2023-09-27 17:40:16 +020034static inline void *llext_peek(struct llext_loader *l, size_t pos)
35{
36 if (l->peek) {
37 return l->peek(l, pos);
38 }
39
40 return NULL;
41}
42
Tom Burdick41e0a4a2023-09-27 08:10:10 -050043static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list);
44
45sys_slist_t *llext_list(void)
46{
47 return &_llext_list;
48}
49
Guennadi Liakhovetskif98b8bb2023-09-22 16:15:18 +020050ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name)
51{
52 elf_shdr_t *shdr;
53 unsigned int i;
54 size_t pos;
55
56 for (i = 0, pos = ldr->hdr.e_shoff;
57 i < ldr->hdr.e_shnum;
58 i++, pos += ldr->hdr.e_shentsize) {
59 shdr = llext_peek(ldr, pos);
60 if (!shdr) {
61 /* The peek() method isn't supported */
62 return -EOPNOTSUPP;
63 }
64
65 const char *name = llext_peek(ldr,
66 ldr->sects[LLEXT_SECT_SHSTRTAB].sh_offset +
67 shdr->sh_name);
68
69 if (!strcmp(name, search_name)) {
70 return shdr->sh_offset;
71 }
72 }
73
74 return -ENOENT;
75}
76
Tom Burdick41e0a4a2023-09-27 08:10:10 -050077struct llext *llext_by_name(const char *name)
78{
79 sys_slist_t *mlist = llext_list();
80 sys_snode_t *node = sys_slist_peek_head(mlist);
81 struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list);
82
83 while (node != NULL) {
84 if (strncmp(ext->name, name, sizeof(ext->name)) == 0) {
85 return ext;
86 }
87 node = sys_slist_peek_next(node);
88 ext = CONTAINER_OF(node, struct llext, _llext_list);
89 }
90
91 return NULL;
92}
93
94const void * const llext_find_sym(const struct llext_symtable *sym_table, const char *sym_name)
95{
96 if (sym_table == NULL) {
97 /* Buildin symbol table */
98 STRUCT_SECTION_FOREACH(llext_const_symbol, sym) {
99 if (strcmp(sym->name, sym_name) == 0) {
100 return sym->addr;
101 }
102 }
103 } else {
104 /* find symbols in module */
105 for (size_t i = 0; i < sym_table->sym_cnt; i++) {
106 if (strcmp(sym_table->syms[i].name, sym_name) == 0) {
107 return sym_table->syms[i].addr;
108 }
109 }
110 }
111
112 return NULL;
113}
114
115/*
116 * Find all relevant string and symbol tables
117 */
118static int llext_find_tables(struct llext_loader *ldr)
119{
Guennadi Liakhovetski6246caa2023-11-15 10:36:47 +0100120 int sect_cnt, i, ret;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200121 size_t pos;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500122 elf_shdr_t shdr;
123
124 ldr->sects[LLEXT_SECT_SHSTRTAB] =
125 ldr->sects[LLEXT_SECT_STRTAB] =
126 ldr->sects[LLEXT_SECT_SYMTAB] = (elf_shdr_t){0};
127
128 /* Find symbol and string tables */
Guennadi Liakhovetski6246caa2023-11-15 10:36:47 +0100129 for (i = 0, sect_cnt = 0, pos = ldr->hdr.e_shoff;
130 i < ldr->hdr.e_shnum && sect_cnt < 3;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200131 i++, pos += ldr->hdr.e_shentsize) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500132 ret = llext_seek(ldr, pos);
133 if (ret != 0) {
134 LOG_ERR("failed seeking to position %u\n", pos);
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200135 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500136 }
137
138 ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t));
139 if (ret != 0) {
140 LOG_ERR("failed reading section header at position %u\n", pos);
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200141 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500142 }
143
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500144 LOG_DBG("section %d at %x: name %d, type %d, flags %x, addr %x, size %d",
145 i,
146 ldr->hdr.e_shoff + i * ldr->hdr.e_shentsize,
147 shdr.sh_name,
148 shdr.sh_type,
149 shdr.sh_flags,
150 shdr.sh_addr,
151 shdr.sh_size);
152
153 switch (shdr.sh_type) {
154 case SHT_SYMTAB:
155 case SHT_DYNSYM:
156 LOG_DBG("symtab at %d", i);
157 ldr->sects[LLEXT_SECT_SYMTAB] = shdr;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100158 ldr->sect_map[i] = LLEXT_MEM_SYMTAB;
Guennadi Liakhovetski6246caa2023-11-15 10:36:47 +0100159 sect_cnt++;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500160 break;
161 case SHT_STRTAB:
162 if (ldr->hdr.e_shstrndx == i) {
163 LOG_DBG("shstrtab at %d", i);
164 ldr->sects[LLEXT_SECT_SHSTRTAB] = shdr;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100165 ldr->sect_map[i] = LLEXT_MEM_SHSTRTAB;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500166 } else {
167 LOG_DBG("strtab at %d", i);
168 ldr->sects[LLEXT_SECT_STRTAB] = shdr;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100169 ldr->sect_map[i] = LLEXT_MEM_STRTAB;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500170 }
Guennadi Liakhovetski6246caa2023-11-15 10:36:47 +0100171 sect_cnt++;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500172 break;
173 default:
174 break;
175 }
176 }
177
178 if (!ldr->sects[LLEXT_SECT_SHSTRTAB].sh_type ||
179 !ldr->sects[LLEXT_SECT_STRTAB].sh_type ||
180 !ldr->sects[LLEXT_SECT_SYMTAB].sh_type) {
181 LOG_ERR("Some sections are missing or present multiple times!");
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200182 return -ENOENT;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500183 }
184
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200185 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500186}
187
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200188static const char *llext_string(struct llext_loader *ldr, struct llext *ext,
189 enum llext_mem mem_idx, unsigned int idx)
190{
191 return (char *)ext->mem[mem_idx] + idx;
192}
193
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500194/*
195 * Maps the section indexes and copies special section headers for easier use
196 */
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200197static int llext_map_sections(struct llext_loader *ldr, struct llext *ext)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500198{
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200199 int i, ret;
200 size_t pos;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500201 elf_shdr_t shdr;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200202 const char *name;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500203
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200204 for (i = 0, pos = ldr->hdr.e_shoff;
205 i < ldr->hdr.e_shnum;
206 i++, pos += ldr->hdr.e_shentsize) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500207 ret = llext_seek(ldr, pos);
208 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200209 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500210 }
211
212 ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t));
213 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200214 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500215 }
216
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200217 name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr.sh_name);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500218
219 LOG_DBG("section %d name %s", i, name);
220
221 enum llext_section sect_idx;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100222 enum llext_mem mem_idx;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500223
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200224 if (strcmp(name, ".text") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500225 sect_idx = LLEXT_SECT_TEXT;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100226 mem_idx = LLEXT_MEM_TEXT;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200227 } else if (strcmp(name, ".data") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500228 sect_idx = LLEXT_SECT_DATA;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100229 mem_idx = LLEXT_MEM_DATA;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200230 } else if (strcmp(name, ".rodata") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500231 sect_idx = LLEXT_SECT_RODATA;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100232 mem_idx = LLEXT_MEM_RODATA;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200233 } else if (strcmp(name, ".bss") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500234 sect_idx = LLEXT_SECT_BSS;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100235 mem_idx = LLEXT_MEM_BSS;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500236 } else {
237 LOG_DBG("Not copied section %s", name);
238 continue;
239 }
240
241 ldr->sects[sect_idx] = shdr;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100242 ldr->sect_map[i] = mem_idx;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500243 }
244
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200245 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500246}
247
Guennadi Liakhovetskifef999c2023-11-09 13:56:06 +0100248static enum llext_section llext_sect_from_mem(enum llext_mem m)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500249{
250 enum llext_section s;
251
252 switch (m) {
253 case LLEXT_MEM_BSS:
254 s = LLEXT_SECT_BSS;
255 break;
256 case LLEXT_MEM_DATA:
257 s = LLEXT_SECT_DATA;
258 break;
259 case LLEXT_MEM_RODATA:
260 s = LLEXT_SECT_RODATA;
261 break;
262 case LLEXT_MEM_TEXT:
263 s = LLEXT_SECT_TEXT;
264 break;
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100265 case LLEXT_MEM_SYMTAB:
266 s = LLEXT_SECT_SYMTAB;
267 break;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200268 case LLEXT_MEM_STRTAB:
269 s = LLEXT_SECT_STRTAB;
270 break;
271 case LLEXT_MEM_SHSTRTAB:
272 s = LLEXT_SECT_SHSTRTAB;
273 break;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500274 default:
275 CODE_UNREACHABLE;
276 }
277
278 return s;
279}
280
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200281static int llext_copy_section(struct llext_loader *ldr, struct llext *ext,
282 enum llext_mem mem_idx)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500283{
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200284 enum llext_section sect_idx = llext_sect_from_mem(mem_idx);
285 int ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500286
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200287 if (!ldr->sects[sect_idx].sh_size) {
288 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500289 }
290
Guennadi Liakhovetski0bf08e52023-10-25 17:05:38 +0200291 if (ldr->sects[sect_idx].sh_type != SHT_NOBITS) {
292 ext->mem[mem_idx] = llext_peek(ldr, ldr->sects[sect_idx].sh_offset);
293 if (ext->mem[mem_idx]) {
294 ext->mem_on_heap[mem_idx] = false;
295 return 0;
296 }
297 }
298
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200299 ext->mem[mem_idx] = k_heap_aligned_alloc(&llext_heap, sizeof(uintptr_t),
300 ldr->sects[sect_idx].sh_size,
301 K_NO_WAIT);
302 if (!ext->mem[mem_idx]) {
303 return -ENOMEM;
304 }
Tom Burdick6d651e32023-11-01 15:33:24 -0500305 ext->mem_size += ldr->sects[sect_idx].sh_size;
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200306
Guennadi Liakhovetski0bf08e52023-10-25 17:05:38 +0200307 if (ldr->sects[sect_idx].sh_type == SHT_NOBITS) {
308 memset(ext->mem[mem_idx], 0, ldr->sects[sect_idx].sh_size);
309 } else {
310 ret = llext_seek(ldr, ldr->sects[sect_idx].sh_offset);
311 if (ret != 0) {
312 goto err;
313 }
314
315 ret = llext_read(ldr, ext->mem[mem_idx], ldr->sects[sect_idx].sh_size);
316 if (ret != 0) {
317 goto err;
318 }
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200319 }
320
Guennadi Liakhovetski0bf08e52023-10-25 17:05:38 +0200321 ext->mem_on_heap[mem_idx] = true;
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200322
323 return 0;
324
325err:
326 k_heap_free(&llext_heap, ext->mem[mem_idx]);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500327 return ret;
328}
329
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200330static int llext_copy_strings(struct llext_loader *ldr, struct llext *ext)
331{
332 int ret = llext_copy_section(ldr, ext, LLEXT_MEM_SHSTRTAB);
333
334 if (!ret) {
335 ret = llext_copy_section(ldr, ext, LLEXT_MEM_STRTAB);
336 }
337
338 return ret;
339}
340
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500341static int llext_copy_sections(struct llext_loader *ldr, struct llext *ext)
342{
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500343 for (enum llext_mem mem_idx = 0; mem_idx < LLEXT_MEM_COUNT; mem_idx++) {
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200344 /* strings have already been copied */
345 if (ext->mem[mem_idx]) {
346 continue;
347 }
348
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200349 int ret = llext_copy_section(ldr, ext, mem_idx);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500350
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200351 if (ret < 0) {
352 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500353 }
354 }
355
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200356 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500357}
358
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200359static int llext_count_export_syms(struct llext_loader *ldr, struct llext *ext)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500360{
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500361 size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize;
362 size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200363 int sym_cnt = syms_size / sizeof(elf_sym_t);
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200364 const char *name;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200365 elf_sym_t sym;
366 int i, ret;
367 size_t pos;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500368
369 LOG_DBG("symbol count %u", sym_cnt);
370
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200371 for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset;
372 i < sym_cnt;
373 i++, pos += ent_size) {
Guennadi Liakhovetski68b48982023-09-07 17:38:12 +0200374 if (!i) {
375 /* A dummy entry */
376 continue;
377 }
378
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500379 ret = llext_seek(ldr, pos);
380 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200381 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500382 }
383
384 ret = llext_read(ldr, &sym, ent_size);
385 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200386 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500387 }
388
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500389 uint32_t stt = ELF_ST_TYPE(sym.st_info);
390 uint32_t stb = ELF_ST_BIND(sym.st_info);
391 uint32_t sect = sym.st_shndx;
392
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200393 name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500394
395 if (stt == STT_FUNC && stb == STB_GLOBAL) {
396 LOG_DBG("function symbol %d, name %s, type tag %d, bind %d, sect %d",
397 i, name, stt, stb, sect);
Guennadi Liakhovetskifb926362023-11-09 13:04:21 +0100398 ext->sym_tab.sym_cnt++;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500399 } else {
400 LOG_DBG("unhandled symbol %d, name %s, type tag %d, bind %d, sect %d",
401 i, name, stt, stb, sect);
402 }
403 }
404
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200405 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500406}
407
Guennadi Liakhovetskifef999c2023-11-09 13:56:06 +0100408static int llext_allocate_symtab(struct llext_loader *ldr, struct llext *ext)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500409{
Guennadi Liakhovetski60aef842023-11-09 14:06:03 +0100410 struct llext_symtable *sym_tab = &ext->sym_tab;
Guennadi Liakhovetskifb926362023-11-09 13:04:21 +0100411 size_t syms_size = sym_tab->sym_cnt * sizeof(struct llext_symbol);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500412
Guennadi Liakhovetski60aef842023-11-09 14:06:03 +0100413 sym_tab->syms = k_heap_alloc(&llext_heap, syms_size, K_NO_WAIT);
Guennadi Liakhovetskieb3071e2023-11-09 13:48:16 +0100414 if (!sym_tab->syms) {
415 return -ENOMEM;
416 }
Guennadi Liakhovetskifb926362023-11-09 13:04:21 +0100417 memset(sym_tab->syms, 0, syms_size);
Tom Burdick6d651e32023-11-01 15:33:24 -0500418 ext->mem_size += syms_size;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500419
Guennadi Liakhovetskifb926362023-11-09 13:04:21 +0100420 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500421}
422
Guennadi Liakhovetskifef999c2023-11-09 13:56:06 +0100423static int llext_copy_symbols(struct llext_loader *ldr, struct llext *ext)
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500424{
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500425 size_t ent_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_entsize;
426 size_t syms_size = ldr->sects[LLEXT_SECT_SYMTAB].sh_size;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200427 int sym_cnt = syms_size / sizeof(elf_sym_t);
Guennadi Liakhovetski60aef842023-11-09 14:06:03 +0100428 struct llext_symtable *sym_tab = &ext->sym_tab;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200429 elf_sym_t sym;
430 int i, j, ret;
431 size_t pos;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500432
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200433 for (i = 0, pos = ldr->sects[LLEXT_SECT_SYMTAB].sh_offset, j = 0;
434 i < sym_cnt;
435 i++, pos += ent_size) {
Guennadi Liakhovetski68b48982023-09-07 17:38:12 +0200436 if (!i) {
437 /* A dummy entry */
438 continue;
439 }
440
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500441 ret = llext_seek(ldr, pos);
442 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200443 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500444 }
445
446 ret = llext_read(ldr, &sym, ent_size);
447 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200448 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500449 }
450
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500451 uint32_t stt = ELF_ST_TYPE(sym.st_info);
452 uint32_t stb = ELF_ST_BIND(sym.st_info);
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100453 unsigned int sect = sym.st_shndx;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500454
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500455 if (stt == STT_FUNC && stb == STB_GLOBAL && sect != SHN_UNDEF) {
Guennadi Liakhovetski21cea072023-11-14 12:51:27 +0100456 enum llext_mem mem = ldr->sect_map[sect];
457 enum llext_section sect_idx = llext_sect_from_mem(mem);
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200458 const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
459
Guennadi Liakhovetski60aef842023-11-09 14:06:03 +0100460 __ASSERT(j <= sym_tab->sym_cnt, "Miscalculated symbol number %u\n", j);
461
462 sym_tab->syms[j].name = name;
Guennadi Liakhovetskie0ea44c2023-09-28 13:56:54 +0200463 sym_tab->syms[j].addr = (void *)((uintptr_t)ext->mem[mem] +
464 sym.st_value -
465 (ldr->hdr.e_type == ET_REL ? 0 :
466 ldr->sects[sect_idx].sh_addr));
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500467 LOG_DBG("function symbol %d name %s addr %p",
Guennadi Liakhovetski60aef842023-11-09 14:06:03 +0100468 j, name, sym_tab->syms[j].addr);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500469 j++;
470 }
471 }
472
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200473 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500474}
475
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200476/*
477 * Find the section, containing the supplied offset and return file offset for
478 * that value
479 */
480static size_t llext_file_offset(struct llext_loader *ldr, size_t offset)
481{
482 unsigned int i;
483
484 for (i = 0; i < LLEXT_SECT_COUNT; i++)
485 if (ldr->sects[i].sh_addr <= offset &&
486 ldr->sects[i].sh_addr + ldr->sects[i].sh_size > offset)
487 return offset - ldr->sects[i].sh_addr + ldr->sects[i].sh_offset;
488
489 return offset;
490}
491
Guennadi Liakhovetski03519af2023-09-28 13:59:53 +0200492__weak void arch_elf_relocate_local(struct llext_loader *ldr, struct llext *ext,
493 elf_rela_t *rel, size_t got_offset)
494{
495}
496
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200497static void llext_link_plt(struct llext_loader *ldr, struct llext *ext, elf_shdr_t *shdr)
498{
499 unsigned int sh_cnt = shdr->sh_size / shdr->sh_entsize;
500 /*
501 * CPU address where the .text section is stored, we use .text just as a
502 * reference point
503 */
504 uint8_t *text = ext->mem[LLEXT_MEM_TEXT];
505
506 LOG_DBG("Found %p in PLT %u size %u cnt %u text %p",
507 (void *)llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr->sh_name),
508 shdr->sh_type, shdr->sh_entsize, sh_cnt, (void *)text);
509
510 const elf_shdr_t *sym_shdr = ldr->sects + LLEXT_SECT_SYMTAB;
511 unsigned int sym_cnt = sym_shdr->sh_size / sym_shdr->sh_entsize;
512
513 for (unsigned int i = 0; i < sh_cnt; i++) {
514 elf_rela_t rela;
515
516 int ret = llext_seek(ldr, shdr->sh_offset + i * shdr->sh_entsize);
517
518 if (!ret) {
519 ret = llext_read(ldr, &rela, sizeof(rela));
520 }
521
522 if (ret < 0) {
523 LOG_ERR("PLT: failed to read RELA #%u, trying to continue", i);
524 continue;
525 }
526
527 /* Index in the symbol table */
528 unsigned int j = ELF32_R_SYM(rela.r_info);
529
530 if (j >= sym_cnt) {
531 LOG_WRN("PLT: idx %u >= %u", j, sym_cnt);
532 continue;
533 }
534
535 elf_sym_t sym_tbl;
536
537 ret = llext_seek(ldr, sym_shdr->sh_offset + j * sizeof(elf_sym_t));
538 if (!ret) {
539 ret = llext_read(ldr, &sym_tbl, sizeof(sym_tbl));
540 }
541
542 if (ret < 0) {
543 LOG_ERR("PLT: failed to read symbol table #%u RELA #%u, trying to continue",
544 j, i);
545 continue;
546 }
547
548 uint32_t stt = ELF_ST_TYPE(sym_tbl.st_info);
Guennadi Liakhovetski03519af2023-09-28 13:59:53 +0200549 uint32_t stb = ELF_ST_BIND(sym_tbl.st_info);
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200550 const char *name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym_tbl.st_name);
551 /*
552 * Both r_offset and sh_addr are addresses for which the extension
553 * has been built.
554 */
555 size_t got_offset = llext_file_offset(ldr, rela.r_offset) -
556 ldr->sects[LLEXT_SECT_TEXT].sh_offset;
557
Guennadi Liakhovetski03519af2023-09-28 13:59:53 +0200558 if (stt != STT_NOTYPE || sym_tbl.st_shndx != SHN_UNDEF)
559 continue;
560
561 const void *link_addr;
562
563 switch (stb) {
564 case STB_GLOBAL:
565 link_addr = llext_find_sym(NULL, name);
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200566
567 if (!link_addr) {
568 LOG_WRN("PLT: cannot find idx %u name %s", j, name);
569 continue;
570 }
571
572 if (!rela.r_offset) {
573 LOG_WRN("PLT: zero offset idx %u name %s", j, name);
574 continue;
575 }
576
577 LOG_DBG("symbol %s offset %#x r-offset %#x .text offset %#x",
578 name, got_offset,
579 rela.r_offset, ldr->sects[LLEXT_SECT_TEXT].sh_offset);
580
581 /* Resolve the symbol */
582 *(const void **)(text + got_offset) = link_addr;
Guennadi Liakhovetski03519af2023-09-28 13:59:53 +0200583 break;
584 case STB_LOCAL:
585 arch_elf_relocate_local(ldr, ext, &rela, got_offset);
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200586 }
587 }
588}
589
Guennadi Liakhovetskia9a82d52023-09-22 15:40:26 +0200590__weak void arch_elf_relocate(elf_rela_t *rel, uintptr_t opaddr, uintptr_t opval)
Guennadi Liakhovetskif0527b52023-09-07 16:51:50 +0200591{
592}
593
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500594static int llext_link(struct llext_loader *ldr, struct llext *ext)
595{
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500596 uintptr_t loc = 0;
597 elf_shdr_t shdr;
Guennadi Liakhovetskia9a82d52023-09-22 15:40:26 +0200598 elf_rela_t rel;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500599 elf_sym_t sym;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500600 elf_word rel_cnt = 0;
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200601 const char *name;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200602 int i, ret;
603 size_t pos;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500604
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200605 for (i = 0, pos = ldr->hdr.e_shoff;
606 i < ldr->hdr.e_shnum - 1;
607 i++, pos += ldr->hdr.e_shentsize) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500608 ret = llext_seek(ldr, pos);
609 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200610 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500611 }
612
613 ret = llext_read(ldr, &shdr, sizeof(elf_shdr_t));
614 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200615 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500616 }
617
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500618 /* find relocation sections */
619 if (shdr.sh_type != SHT_REL && shdr.sh_type != SHT_RELA) {
620 continue;
621 }
622
Guennadi Liakhovetski60585122023-09-22 15:35:49 +0200623 rel_cnt = shdr.sh_size / shdr.sh_entsize;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500624
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200625 name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr.sh_name);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500626
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200627 if (strcmp(name, ".rel.text") == 0 ||
628 strcmp(name, ".rela.text") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500629 loc = (uintptr_t)ext->mem[LLEXT_MEM_TEXT];
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200630 } else if (strcmp(name, ".rel.bss") == 0 ||
631 strcmp(name, ".rela.bss") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500632 loc = (uintptr_t)ext->mem[LLEXT_MEM_BSS];
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200633 } else if (strcmp(name, ".rel.rodata") == 0 ||
634 strcmp(name, ".rela.rodata") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500635 loc = (uintptr_t)ext->mem[LLEXT_MEM_RODATA];
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200636 } else if (strcmp(name, ".rel.data") == 0 ||
637 strcmp(name, ".rela.data") == 0) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500638 loc = (uintptr_t)ext->mem[LLEXT_MEM_DATA];
Guennadi Liakhovetskid6a5a6e2023-09-07 17:53:19 +0200639 } else if (strcmp(name, ".rela.plt") == 0 ||
640 strcmp(name, ".rela.dyn") == 0) {
641 llext_link_plt(ldr, ext, &shdr);
642 continue;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500643 }
644
645 LOG_DBG("relocation section %s (%d) linked to section %d has %d relocations",
646 name, i, shdr.sh_link, rel_cnt);
647
648 for (int j = 0; j < rel_cnt; j++) {
649 /* get each relocation entry */
Guennadi Liakhovetski60585122023-09-22 15:35:49 +0200650 ret = llext_seek(ldr, shdr.sh_offset + j * shdr.sh_entsize);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500651 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200652 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500653 }
654
Guennadi Liakhovetski60585122023-09-22 15:35:49 +0200655 ret = llext_read(ldr, &rel, shdr.sh_entsize);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500656 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200657 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500658 }
659
660 /* get corresponding symbol */
661 ret = llext_seek(ldr, ldr->sects[LLEXT_SECT_SYMTAB].sh_offset
662 + ELF_R_SYM(rel.r_info) * sizeof(elf_sym_t));
663 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200664 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500665 }
666
667 ret = llext_read(ldr, &sym, sizeof(elf_sym_t));
668 if (ret != 0) {
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200669 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500670 }
671
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200672 name = llext_string(ldr, ext, LLEXT_MEM_STRTAB, sym.st_name);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500673
674 LOG_DBG("relocation %d:%d info %x (type %d, sym %d) offset %d sym_name "
675 "%s sym_type %d sym_bind %d sym_ndx %d",
676 i, j, rel.r_info, ELF_R_TYPE(rel.r_info), ELF_R_SYM(rel.r_info),
677 rel.r_offset, name, ELF_ST_TYPE(sym.st_info),
678 ELF_ST_BIND(sym.st_info), sym.st_shndx);
679
Guennadi Liakhovetskidb43d352023-11-09 15:11:26 +0100680 uintptr_t link_addr, op_loc;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500681
Tom Burdickc678f252023-10-04 11:33:16 -0500682 op_loc = loc + rel.r_offset;
683
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500684 /* If symbol is undefined, then we need to look it up */
685 if (sym.st_shndx == SHN_UNDEF) {
686 link_addr = (uintptr_t)llext_find_sym(NULL, name);
687
688 if (link_addr == 0) {
689 LOG_ERR("Undefined symbol with no entry in "
690 "symbol table %s, offset %d, link section %d",
691 name, rel.r_offset, shdr.sh_link);
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200692 return -ENODATA;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500693 }
694 } else if (ELF_ST_TYPE(sym.st_info) == STT_SECTION) {
Tom Burdickc678f252023-10-04 11:33:16 -0500695 /* Current relocation location holds an offset into the section */
696 link_addr = (uintptr_t)ext->mem[ldr->sect_map[sym.st_shndx]]
697 + sym.st_value
698 + *((uintptr_t *)op_loc);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500699
700 LOG_INF("found section symbol %s addr 0x%lx", name, link_addr);
701 } else {
702 /* Nothing to relocate here */
703 continue;
704 }
705
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500706 LOG_INF("relocating (linking) symbol %s type %d binding %d ndx %d offset "
707 "%d link section %d",
708 name, ELF_ST_TYPE(sym.st_info), ELF_ST_BIND(sym.st_info),
709 sym.st_shndx, rel.r_offset, shdr.sh_link);
710
711 LOG_INF("writing relocation symbol %s type %d sym %d at addr 0x%lx "
712 "addr 0x%lx",
713 name, ELF_R_TYPE(rel.r_info), ELF_R_SYM(rel.r_info),
714 op_loc, link_addr);
715
716 /* relocation */
717 arch_elf_relocate(&rel, op_loc, link_addr);
718 }
719 }
720
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200721 return 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500722}
723
724/*
725 * Load a valid ELF as an extension
726 */
727static int do_llext_load(struct llext_loader *ldr, struct llext *ext)
728{
729 int ret = 0;
730
731 memset(ldr->sects, 0, sizeof(ldr->sects));
732 ldr->sect_cnt = 0;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500733
734 size_t sect_map_sz = ldr->hdr.e_shnum * sizeof(uint32_t);
735
736 ldr->sect_map = k_heap_alloc(&llext_heap, sect_map_sz, K_NO_WAIT);
737 if (!ldr->sect_map) {
738 LOG_ERR("Failed to allocate memory for section map, size %u", sect_map_sz);
739 ret = -ENOMEM;
740 goto out;
741 }
742 memset(ldr->sect_map, 0, ldr->hdr.e_shnum*sizeof(uint32_t));
743 ldr->sect_cnt = ldr->hdr.e_shnum;
Tom Burdick6d651e32023-11-01 15:33:24 -0500744 ext->mem_size += sect_map_sz;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500745
746 LOG_DBG("Finding ELF tables...");
747 ret = llext_find_tables(ldr);
748 if (ret != 0) {
749 LOG_ERR("Failed to find important ELF tables, ret %d", ret);
750 goto out;
751 }
752
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200753 LOG_DBG("Allocate and copy strings...");
754 ret = llext_copy_strings(ldr, ext);
755 if (ret != 0) {
756 LOG_ERR("Failed to copy ELF string sections, ret %d", ret);
757 goto out;
758 }
759
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500760 LOG_DBG("Mapping ELF sections...");
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200761 ret = llext_map_sections(ldr, ext);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500762 if (ret != 0) {
763 LOG_ERR("Failed to map ELF sections, ret %d", ret);
764 goto out;
765 }
766
Guennadi Liakhovetski23472502023-10-25 15:19:00 +0200767 LOG_DBG("Allocate and copy sections...");
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500768 ret = llext_copy_sections(ldr, ext);
769 if (ret != 0) {
770 LOG_ERR("Failed to copy ELF sections, ret %d", ret);
771 goto out;
772 }
773
774 LOG_DBG("Counting exported symbols...");
Guennadi Liakhovetski5064df02023-10-25 15:58:15 +0200775 ret = llext_count_export_syms(ldr, ext);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500776 if (ret != 0) {
777 LOG_ERR("Failed to count exported ELF symbols, ret %d", ret);
778 goto out;
779 }
780
781 LOG_DBG("Allocating memory for symbol table...");
782 ret = llext_allocate_symtab(ldr, ext);
783 if (ret != 0) {
784 LOG_ERR("Failed to allocate extension symbol table, ret %d", ret);
785 goto out;
786 }
787
788 LOG_DBG("Copying symbols...");
789 ret = llext_copy_symbols(ldr, ext);
790 if (ret != 0) {
791 LOG_ERR("Failed to copy symbols, ret %d", ret);
792 goto out;
793 }
794
795 LOG_DBG("Linking ELF...");
796 ret = llext_link(ldr, ext);
797 if (ret != 0) {
798 LOG_ERR("Failed to link, ret %d", ret);
799 goto out;
800 }
801
802out:
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200803 k_heap_free(&llext_heap, ldr->sect_map);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500804
805 if (ret != 0) {
806 LOG_DBG("Failed to load extension, freeing memory...");
807 for (enum llext_mem mem_idx = 0; mem_idx < LLEXT_MEM_COUNT; mem_idx++) {
Guennadi Liakhovetski0bf08e52023-10-25 17:05:38 +0200808 if (ext->mem_on_heap[mem_idx]) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500809 k_heap_free(&llext_heap, ext->mem[mem_idx]);
810 }
811 }
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500812 k_heap_free(&llext_heap, ext->sym_tab.syms);
813 } else {
814 LOG_DBG("loaded module, .text at %p, .rodata at %p", ext->mem[LLEXT_MEM_TEXT],
815 ext->mem[LLEXT_MEM_RODATA]);
816 }
817
818 return ret;
819}
820
821int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext)
822{
Guennadi Liakhovetskiade72c22023-09-27 17:30:59 +0200823 int ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500824 elf_ehdr_t ehdr;
825
826 ret = llext_seek(ldr, 0);
827 if (ret != 0) {
828 LOG_ERR("Failed to seek for ELF header");
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200829 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500830 }
831
832 ret = llext_read(ldr, &ehdr, sizeof(ehdr));
833 if (ret != 0) {
834 LOG_ERR("Failed to read ELF header");
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200835 return ret;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500836 }
837
838 /* check whether this is an valid elf file */
839 if (memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) {
840 LOG_HEXDUMP_ERR(ehdr.e_ident, 16, "Invalid ELF, magic does not match");
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200841 return -EINVAL;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500842 }
843
844 switch (ehdr.e_type) {
845 case ET_REL:
846 case ET_DYN:
847 LOG_DBG("Loading relocatable or shared elf");
848 *ext = k_heap_alloc(&llext_heap, sizeof(struct llext), K_NO_WAIT);
849 if (*ext == NULL) {
850 LOG_ERR("Not enough memory for extension metadata");
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200851 return -ENOMEM;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500852 }
853 memset(*ext, 0, sizeof(struct llext));
854
855 for (int i = 0; i < LLEXT_MEM_COUNT; i++) {
856 (*ext)->mem[i] = NULL;
857 }
858
859 ldr->hdr = ehdr;
860 ret = do_llext_load(ldr, *ext);
861 break;
862 default:
863 LOG_ERR("Unsupported elf file type %x", ehdr.e_type);
864 *ext = NULL;
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200865 return -EINVAL;
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500866 }
867
868 if (ret == 0) {
869 strncpy((*ext)->name, name, sizeof((*ext)->name));
870 (*ext)->name[sizeof((*ext)->name) - 1] = '\0';
871 sys_slist_append(&_llext_list, &(*ext)->_llext_list);
872 LOG_INF("Loaded extension %s", (*ext)->name);
873 }
874
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500875 return ret;
876}
877
878void llext_unload(struct llext *ext)
879{
880 __ASSERT(ext, "Expected non-null extension");
881
882 sys_slist_find_and_remove(&_llext_list, &ext->_llext_list);
883
884 for (int i = 0; i < LLEXT_MEM_COUNT; i++) {
Guennadi Liakhovetski0bf08e52023-10-25 17:05:38 +0200885 if (ext->mem_on_heap[i]) {
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500886 LOG_DBG("freeing memory region %d", i);
887 k_heap_free(&llext_heap, ext->mem[i]);
888 ext->mem[i] = NULL;
889 }
890 }
891
Guennadi Liakhovetskia88faca2023-09-28 09:43:27 +0200892 k_heap_free(&llext_heap, ext->sym_tab.syms);
Tom Burdick41e0a4a2023-09-27 08:10:10 -0500893
894 k_heap_free(&llext_heap, ext);
895}
896
897int llext_call_fn(struct llext *ext, const char *sym_name)
898{
899 void (*fn)(void);
900
901 fn = llext_find_sym(&ext->sym_tab, sym_name);
902 if (fn == NULL) {
903 return -EINVAL;
904 }
905 fn();
906
907 return 0;
908}