From 7094eae11127c657246f500ef80f470dc7b2b678 Mon Sep 17 00:00:00 2001 From: Luca Burelli Date: Tue, 14 Jan 2025 19:22:36 +0100 Subject: [PATCH] llext: support multiple string and symbol tables The ELF format allows for multiple string and symbol tables with complex references between them. This is especially evident when debugging information is included. This patch fixes the issues that have been identified with multiple string tables to allow LLEXT to properly parse those files: * The symbol table used by LLEXT (LLEXT_MEM_SYMTAB) is now chosen depending on the loaded file type, and other tables are ignored. This change is also applied to the SLID injection script. * The LLEXT string table (LLEXT_MEM_SYMTAB) is now correctly identified by the symbol table reference, instead of picking the first one. * VMA range checks only make sense for allocated sections. Signed-off-by: Luca Burelli --- scripts/build/llext_inject_slids.py | 28 +++++++++++--------- subsys/llext/llext_load.c | 41 ++++++++++++++++------------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/scripts/build/llext_inject_slids.py b/scripts/build/llext_inject_slids.py index 19e87edba93..b2f42f0c813 100755 --- a/scripts/build/llext_inject_slids.py +++ b/scripts/build/llext_inject_slids.py @@ -36,20 +36,22 @@ class LLEXTSymtabPreparator(): self.elf = ELFFile(self.elf_fd) def _find_symtab(self): - supported_symtab_sections = [ - ".symtab", - ".dynsym", - ] + e_type = self.elf.header['e_type'] + if e_type == 'ET_DYN': + symtab_name = ".dynsym" + elif e_type == 'ET_REL': + symtab_name = ".symtab" + else: + self.log.error(f"unexpected ELF file type {e_type}") + return None - symtab = None - for section_name in supported_symtab_sections: - symtab = self.elf.get_section_by_name(section_name) - if not isinstance(symtab, SymbolTableSection): - self.log.debug(f"section {section_name} not found.") - else: - self.log.info(f"processing '{section_name}' symbol table...") - self.log.debug(f"(symbol table is at file offset 0x{symtab['sh_offset']:X})") - break + symtab = self.elf.get_section_by_name(symtab_name) + if not isinstance(symtab, SymbolTableSection): + self.log.debug(f"section {symtab_name} not found.") + return None + + self.log.info(f"processing symbol table from '{symtab_name}'...") + self.log.debug(f"(symbol table is at file offset 0x{symtab['sh_offset']:X})") return symtab def _find_imports_in_symtab(self, symtab): diff --git a/subsys/llext/llext_load.c b/subsys/llext/llext_load.c index 06f4b9a2f97..6f2df7a9131 100644 --- a/subsys/llext/llext_load.c +++ b/subsys/llext/llext_load.c @@ -152,6 +152,8 @@ static int llext_load_elf_data(struct llext_loader *ldr, struct llext *ext) static int llext_find_tables(struct llext_loader *ldr, struct llext *ext) { int table_cnt, i; + int shstrtab_ndx = ldr->hdr.e_shstrndx; + int strtab_ndx = -1; memset(ldr->sects, 0, sizeof(ldr->sects)); @@ -171,28 +173,28 @@ static int llext_find_tables(struct llext_loader *ldr, struct llext *ext) shdr->sh_link, shdr->sh_info); - switch (shdr->sh_type) { - case SHT_SYMTAB: - case SHT_DYNSYM: + if (shdr->sh_type == SHT_SYMTAB && ldr->hdr.e_type == ET_REL) { LOG_DBG("symtab at %d", i); ldr->sects[LLEXT_MEM_SYMTAB] = *shdr; ldr->sect_map[i].mem_idx = LLEXT_MEM_SYMTAB; + strtab_ndx = shdr->sh_link; table_cnt++; - break; - case SHT_STRTAB: - if (ldr->hdr.e_shstrndx == i) { - LOG_DBG("shstrtab at %d", i); - ldr->sects[LLEXT_MEM_SHSTRTAB] = *shdr; - ldr->sect_map[i].mem_idx = LLEXT_MEM_SHSTRTAB; - } else { - LOG_DBG("strtab at %d", i); - ldr->sects[LLEXT_MEM_STRTAB] = *shdr; - ldr->sect_map[i].mem_idx = LLEXT_MEM_STRTAB; - } + } else if (shdr->sh_type == SHT_DYNSYM && ldr->hdr.e_type == ET_DYN) { + LOG_DBG("dynsym at %d", i); + ldr->sects[LLEXT_MEM_SYMTAB] = *shdr; + ldr->sect_map[i].mem_idx = LLEXT_MEM_SYMTAB; + strtab_ndx = shdr->sh_link; + table_cnt++; + } else if (shdr->sh_type == SHT_STRTAB && i == shstrtab_ndx) { + LOG_DBG("shstrtab at %d", i); + ldr->sects[LLEXT_MEM_SHSTRTAB] = *shdr; + ldr->sect_map[i].mem_idx = LLEXT_MEM_SHSTRTAB; + table_cnt++; + } else if (shdr->sh_type == SHT_STRTAB && i == strtab_ndx) { + LOG_DBG("strtab at %d", i); + ldr->sects[LLEXT_MEM_STRTAB] = *shdr; + ldr->sect_map[i].mem_idx = LLEXT_MEM_STRTAB; table_cnt++; - break; - default: - break; } } @@ -395,9 +397,10 @@ static int llext_map_sections(struct llext_loader *ldr, struct llext *ext, continue; } - if (ldr->hdr.e_type == ET_DYN) { + if ((ldr->hdr.e_type == ET_DYN) && + (x->sh_flags & SHF_ALLOC) && (y->sh_flags & SHF_ALLOC)) { /* - * Test all merged VMA ranges for overlaps + * Test regions that have VMA ranges for overlaps */ if ((x->sh_addr <= y->sh_addr && x->sh_addr + x->sh_size > y->sh_addr) ||