Browse Source

llext: optimize allocations for read-only sections

When loading an extension, read-only sections that do not have
relocations and whose data is accessible from the ELF buffer can be
directly mapped as-is in the extension memory. This avoids the need to
allocate and copy unmodified data from the ELF buffer to the LLEXT heap.

Signed-off-by: Luca Burelli <l.burelli@arduino.cc>
pull/87372/head
Luca Burelli 4 months ago committed by Anas Nashif
parent
commit
3fcd90339d
  1. 8
      include/zephyr/llext/elf.h
  2. 9
      subsys/llext/llext_load.c
  3. 5
      subsys/llext/llext_mem.c

8
include/zephyr/llext/elf.h

@ -211,9 +211,11 @@ struct elf64_shdr {
#define SHT_PREINIT_ARRAY 0x10 /**< Array of pointers to early init functions */ #define SHT_PREINIT_ARRAY 0x10 /**< Array of pointers to early init functions */
/** ELF section flags */ /** ELF section flags */
#define SHF_WRITE 0x1 /**< Section is writable */ #define SHF_WRITE 0x1 /**< Section is writable */
#define SHF_ALLOC 0x2 /**< Section is present in memory */ #define SHF_ALLOC 0x2 /**< Section is present in memory */
#define SHF_EXECINSTR 0x4 /**< Section contains executable instructions */ #define SHF_EXECINSTR 0x4 /**< Section contains executable instructions */
#define SHF_MASKOS 0x0ff00000 /**< OS specific flags */
#define SHF_LLEXT_HAS_RELOCS 0x00100000 /**< Section is a target for relocations */
#define SHF_BASIC_TYPE_MASK (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR) #define SHF_BASIC_TYPE_MASK (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR)

9
subsys/llext/llext_load.c

@ -494,11 +494,20 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext,
/* /*
* Calculate each ELF section's offset inside its memory region. This * Calculate each ELF section's offset inside its memory region. This
* is done as a separate pass so the final regions are already defined. * is done as a separate pass so the final regions are already defined.
* Also mark the regions that include relocation targets.
*/ */
for (i = 0; i < ext->sect_cnt; ++i) { for (i = 0; i < ext->sect_cnt; ++i) {
elf_shdr_t *shdr = ext->sect_hdrs + i; elf_shdr_t *shdr = ext->sect_hdrs + i;
enum llext_mem mem_idx = ldr->sect_map[i].mem_idx; enum llext_mem mem_idx = ldr->sect_map[i].mem_idx;
if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) {
enum llext_mem target_region = ldr->sect_map[shdr->sh_info].mem_idx;
if (target_region != LLEXT_MEM_COUNT) {
ldr->sects[target_region].sh_flags |= SHF_LLEXT_HAS_RELOCS;
}
}
if (mem_idx != LLEXT_MEM_COUNT) { if (mem_idx != LLEXT_MEM_COUNT) {
ldr->sect_map[i].offset = shdr->sh_offset - ldr->sects[mem_idx].sh_offset; ldr->sect_map[i].offset = shdr->sh_offset - ldr->sects[mem_idx].sh_offset;
} }

5
subsys/llext/llext_mem.c

@ -95,7 +95,10 @@ static int llext_copy_region(struct llext_loader *ldr, struct llext *ext,
} }
} }
if (ldr->storage == LLEXT_STORAGE_WRITABLE) { if (ldr->storage == LLEXT_STORAGE_WRITABLE || /* writable storage */
(ldr->storage == LLEXT_STORAGE_PERSISTENT && /* || persistent storage */
!(region->sh_flags & SHF_WRITE) && /* && read-only region */
!(region->sh_flags & SHF_LLEXT_HAS_RELOCS))) { /* && no relocs to apply */
/* /*
* Try to reuse data areas from the ELF buffer, if possible. * Try to reuse data areas from the ELF buffer, if possible.
* If any of the following tests fail, a normal allocation * If any of the following tests fail, a normal allocation

Loading…
Cancel
Save