Skip to content

Commit d7543bd

Browse files
committed
llext: add support for ELF init/fini arrays
Load the .preinit_array, .init_array and .fini_array sections in ELF files. These sections are arrays of function pointers that are filled by the compiler with the addresses of functions that need to be called at startup or termination by the loader, such as C++ constructors and destructors. Signed-off-by: Luca Burelli <[email protected]>
1 parent ca48767 commit d7543bd

File tree

3 files changed

+47
-1
lines changed

3 files changed

+47
-1
lines changed

include/zephyr/llext/elf.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ struct elf64_shdr {
206206
#define SHT_NOBITS 0x8 /**< Program data with no file image */
207207
#define SHT_REL 0x9 /**< Relocation entries without addends */
208208
#define SHT_DYNSYM 0xB /**< Dynamic linking symbol table */
209+
#define SHT_INIT_ARRAY 0xe /**< Array of pointers to init functions */
210+
#define SHT_FINI_ARRAY 0xf /**< Array of pointers to termination functions */
211+
#define SHT_PREINIT_ARRAY 0x10 /**< Array of pointers to early init functions */
209212

210213
/** ELF section flags */
211214
#define SHF_WRITE 0x1 /**< Section is writable */

include/zephyr/llext/llext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ enum llext_mem {
5050
LLEXT_MEM_SYMTAB, /**< Symbol table */
5151
LLEXT_MEM_STRTAB, /**< Symbol name strings */
5252
LLEXT_MEM_SHSTRTAB, /**< Section name strings */
53+
LLEXT_MEM_PREINIT, /**< Array of early setup functions */
54+
LLEXT_MEM_INIT, /**< Array of setup functions */
55+
LLEXT_MEM_FINI, /**< Array of cleanup functions */
5356

5457
LLEXT_MEM_COUNT, /**< Number of regions managed by LLEXT */
5558
};

subsys/llext/llext_load.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,12 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext)
208208

209209
name = llext_string(ldr, ext, LLEXT_MEM_SHSTRTAB, shdr->sh_name);
210210

211+
if (ldr->sect_map[i].mem_idx != LLEXT_MEM_COUNT) {
212+
LOG_DBG("section %d name %s already mapped to region %d",
213+
i, name, ldr->sect_map[i].mem_idx);
214+
continue;
215+
}
216+
211217
/* Identify the section type by its flags */
212218
enum llext_mem mem_idx;
213219

@@ -224,6 +230,15 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext)
224230
mem_idx = LLEXT_MEM_RODATA;
225231
}
226232
break;
233+
case SHT_PREINIT_ARRAY:
234+
mem_idx = LLEXT_MEM_PREINIT;
235+
break;
236+
case SHT_INIT_ARRAY:
237+
mem_idx = LLEXT_MEM_INIT;
238+
break;
239+
case SHT_FINI_ARRAY:
240+
mem_idx = LLEXT_MEM_FINI;
241+
break;
227242
default:
228243
mem_idx = LLEXT_MEM_COUNT;
229244
break;
@@ -241,6 +256,19 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext)
241256
continue;
242257
}
243258

259+
switch (mem_idx) {
260+
case LLEXT_MEM_PREINIT:
261+
case LLEXT_MEM_INIT:
262+
case LLEXT_MEM_FINI:
263+
if (shdr->sh_entsize != sizeof(void *) ||
264+
shdr->sh_size % shdr->sh_entsize != 0) {
265+
LOG_ERR("Invalid %s array in section %d", name, i);
266+
return -ENOEXEC;
267+
}
268+
default:
269+
break;
270+
}
271+
244272
LOG_DBG("section %d name %s maps to region %d", i, name, mem_idx);
245273

246274
ldr->sect_map[i].mem_idx = mem_idx;
@@ -261,14 +289,26 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext)
261289
return -ENOEXEC;
262290
}
263291

264-
if (mem_idx == LLEXT_MEM_BSS) {
292+
/* Check if this region type is extendable */
293+
switch (mem_idx) {
294+
case LLEXT_MEM_BSS:
265295
/* SHT_NOBITS sections cannot be merged properly:
266296
* as they use no space in the file, the logic
267297
* below does not work; they must be treated as
268298
* independent entities.
269299
*/
270300
LOG_ERR("Multiple SHT_NOBITS sections are not supported");
271301
return -ENOTSUP;
302+
case LLEXT_MEM_PREINIT:
303+
case LLEXT_MEM_INIT:
304+
case LLEXT_MEM_FINI:
305+
/* These regions are not extendable and must be
306+
* referenced at most once in the ELF file.
307+
*/
308+
LOG_ERR("Region %d redefined", mem_idx);
309+
return -ENOEXEC;
310+
default:
311+
break;
272312
}
273313

274314
if (ldr->hdr.e_type == ET_DYN) {

0 commit comments

Comments
 (0)