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>
This commit is contained in:
parent
e5594891ac
commit
3fcd90339d
3 changed files with 18 additions and 4 deletions
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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…
Add table
Add a link
Reference in a new issue