From a72e9e5621273d73685240024fe7adfbbeecf422 Mon Sep 17 00:00:00 2001 From: anjiahao Date: Wed, 3 Jul 2024 19:45:27 +0800 Subject: [PATCH] modlib:if elf in romfs/tmpfs, try use xipbase Signed-off-by: anjiahao --- include/nuttx/lib/modlib.h | 8 +++++ libs/libc/modlib/modlib_bind.c | 2 ++ libs/libc/modlib/modlib_load.c | 52 ++++++++++++++++++++++++++++---- libs/libc/modlib/modlib_remove.c | 8 +++-- libs/libc/modlib/modlib_unload.c | 2 +- 5 files changed, 63 insertions(+), 9 deletions(-) diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index 6e406fcb8cf..b8cc0d1263c 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -160,6 +160,10 @@ struct module_s struct mod_info_s modinfo; /* Module information */ FAR void *textalloc; /* Allocated kernel text memory */ FAR void *dataalloc; /* Allocated kernel memory */ + uintptr_t xipbase; /* if elf is position independent, and use + * romfs/tmps, we can try get xipbase, + * skip the copy. + */ #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION FAR void **sectalloc; /* All sections memory allocated when ELF file was loaded */ uint16_t nsect; /* Number of entries in sectalloc array */ @@ -232,6 +236,10 @@ struct mod_loadinfo_s int filfd; /* Descriptor for the file being loaded */ int nexports; /* ET_DYN - Number of symbols exported */ int gotindex; /* Index to the GOT section */ + uintptr_t xipbase; /* if elf is position independent, and use + * romfs/tmps, we can try get xipbase, + * skip the copy. + */ /* Address environment. * diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index 2dc3d36add6..8ae64a71382 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -1045,6 +1045,8 @@ int modlib_bind(FAR struct module_s *modp, } } + modp->xipbase = loadinfo->xipbase; + /* Ensure that the I and D caches are coherent before starting the newly * loaded module by cleaning the D cache (i.e., flushing the D cache * contents to memory and invalidating the I cache). diff --git a/libs/libc/modlib/modlib_load.c b/libs/libc/modlib/modlib_load.c index 1baeb66e735..25308cd3e08 100644 --- a/libs/libc/modlib/modlib_load.c +++ b/libs/libc/modlib/modlib_load.c @@ -32,12 +32,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include "libc.h" #include "modlib/modlib.h" @@ -62,7 +64,7 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, FAR Elf_Shdr *shdr, uint8_t idx) { - if (loadinfo->ehdr.e_type != ET_DYN) + if (loadinfo->ehdr.e_type == ET_DYN) { return -EINVAL; } @@ -98,6 +100,14 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, loadinfo->datastart = loadinfo->sectalloc[idx]; } } + else if (loadinfo->xipbase != 0) + { + loadinfo->sectalloc[idx] = loadinfo->xipbase + shdr->sh_offset; + if (loadinfo->textalloc == 0) + { + loadinfo->textalloc = loadinfo->sectalloc[idx]; + } + } else { # ifdef CONFIG_ARCH_USE_TEXT_HEAP @@ -107,8 +117,9 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, shdr->sh_addralign, shdr->sh_size); # else - loadinfo->sectalloc[idx] = (uintptr_t)lib_memalign(shdr->sh_addralign, - shdr->sh_size); + loadinfo->sectalloc[idx] = (uintptr_t) + lib_memalign(shdr->sh_addralign, + shdr->sh_size); # endif if (loadinfo->textalloc == 0) @@ -365,8 +376,20 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) pptr = &text; } - *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, - shdr->sh_addralign); + if (loadinfo->xipbase == 0) + { + /* If xipbase is not set, align the address + * xipbase is set, the address can't be aligned + */ + + *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, + shdr->sh_addralign); + } + } + + if ((shdr->sh_flags & SHF_WRITE) == 0 && loadinfo->xipbase != 0) + { + goto skipload; } /* SHT_NOBITS indicates that there is no data in the file for the @@ -406,6 +429,8 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) } #endif +skipload: + /* Update sh_addr to point to copy in memory */ binfo("%d. %08lx->%08lx\n", i, @@ -497,6 +522,11 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->gotindex >= 0) { binfo("GOT section found! index %d\n", loadinfo->gotindex); + if (ioctl(loadinfo->filfd, FIOC_XIPBASE, + (unsigned long)&loadinfo->xipbase) >= 0) + { + binfo("can use xipbase %zu\n", loadinfo->xipbase); + } } /* Determine total size to allocate */ @@ -517,7 +547,12 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->ehdr.e_type == ET_REL || loadinfo->ehdr.e_type == ET_EXEC) { # ifndef CONFIG_ARCH_USE_SEPARATED_SECTION - if (loadinfo->textsize > 0) + if (loadinfo->xipbase != 0) + { + loadinfo->textalloc = loadinfo->xipbase + + loadinfo->shdr[1].sh_offset; + } + else if (loadinfo->textsize > 0) { # ifdef CONFIG_ARCH_USE_TEXT_HEAP loadinfo->textalloc = (uintptr_t) @@ -643,6 +678,11 @@ int modlib_load_with_addrenv(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->gotindex >= 0) { binfo("GOT section found! index %d\n", loadinfo->gotindex); + if (ioctl(loadinfo->filfd, FIOC_XIPBASE, + (unsigned long)&loadinfo->xipbase) >= 0) + { + binfo("can use xipbase %zu\n", loadinfo->xipbase); + } } /* Determine total size to allocate */ diff --git a/libs/libc/modlib/modlib_remove.c b/libs/libc/modlib/modlib_remove.c index 844f031d5ff..10db0de4198 100644 --- a/libs/libc/modlib/modlib_remove.c +++ b/libs/libc/modlib/modlib_remove.c @@ -132,11 +132,15 @@ int modlib_uninit(FAR struct module_s *modp) modp->sectalloc = NULL; modp->nsect = 0; #else + if (modp->xipbase == 0) + { # if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); + up_textheap_free((FAR void *)modp->textalloc); # else - lib_free((FAR void *)modp->textalloc); + lib_free((FAR void *)modp->textalloc); # endif + } + # if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)modp->dataalloc); # else diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index 5fde605d2b0..dd1c913c936 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -99,7 +99,7 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) lib_free(loadinfo->sectalloc); #else - if (loadinfo->textalloc != 0) + if (loadinfo->textalloc != 0 && loadinfo->xipbase == 0) { # if defined(CONFIG_ARCH_USE_TEXT_HEAP) up_textheap_free((FAR void *)loadinfo->textalloc);