From 2be816e69622872f198ccb66297512ef00939cf9 Mon Sep 17 00:00:00 2001 From: dongjiuzhu1 Date: Wed, 29 Nov 2023 22:25:47 +0800 Subject: [PATCH 1/3] binfmt/modlib: support loading each sections to different memory for Relocate object The feature depends on ARCH_USE_SEPARATED_SECTION the different memory area has different access speed and cache capability, so the arch can custom allocate them based on section names to achieve performance optimization test: sim:elf sim:sotest Signed-off-by: dongjiuzhu1 --- arch/Kconfig | 8 + arch/sim/src/Makefile | 2 +- arch/sim/src/sim/CMakeLists.txt | 2 +- .../sim/{sim_textheap.c => sim_sectionheap.c} | 60 +++++++- binfmt/binfmt_unloadmodule.c | 33 ++++ binfmt/elf.c | 16 ++ binfmt/libelf/libelf_addrenv.c | 62 ++++++-- binfmt/libelf/libelf_bind.c | 24 ++- binfmt/libelf/libelf_load.c | 105 ++++++++++++- include/nuttx/arch.h | 14 +- include/nuttx/binfmt/binfmt.h | 4 + include/nuttx/binfmt/elf.h | 4 + include/nuttx/lib/modlib.h | 4 + libs/libc/dlfcn/lib_dlopen.c | 8 + libs/libc/modlib/modlib_bind.c | 24 ++- libs/libc/modlib/modlib_load.c | 145 +++++++++++++++--- libs/libc/modlib/modlib_unload.c | 28 ++++ sched/module/mod_insmod.c | 8 + 18 files changed, 505 insertions(+), 46 deletions(-) rename arch/sim/src/sim/{sim_textheap.c => sim_sectionheap.c} (63%) diff --git a/arch/Kconfig b/arch/Kconfig index c4c095ddcc9ae..4d94cbf40ac1b 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -671,6 +671,14 @@ config ARCH_USE_DATA_HEAP This option enables architecture-specific memory allocator for dynamic data loading. +config ARCH_USE_SEPARATED_SECTION + bool "Enable separate section allocation for dynamic loading" + default n + depends on ARCH_USE_TEXT_HEAP || ARCH_USE_DATA_HEAP + ---help--- + This option enables loading different sections into different + memory areas, allowing for different speeds. + menuconfig ARCH_ADDRENV bool "Address environments" default n diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index a2632b38e2fd4..2f25984ed4051 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -81,7 +81,7 @@ CSRCS = sim_initialize.c sim_idle.c sim_doirq.c sim_initialstate.c CSRCS += sim_createstack.c sim_usestack.c sim_releasestack.c sim_stackframe.c CSRCS += sim_exit.c sim_schedulesigaction.c sim_switchcontext.c sim_heap.c CSRCS += sim_uart.c sim_copyfullstate.c sim_sigdeliver.c sim_tcbinfo.c sim_cpuinfo.c -CSRCS += sim_registerdump.c sim_saveusercontext.c sim_textheap.c +CSRCS += sim_registerdump.c sim_saveusercontext.c sim_sectionheap.c CSRCS += sim_checkhostfstypes.c ifeq ($(CONFIG_SCHED_BACKTRACE),y) diff --git a/arch/sim/src/sim/CMakeLists.txt b/arch/sim/src/sim/CMakeLists.txt index ccd91cfc9b11d..a4e114b14771c 100644 --- a/arch/sim/src/sim/CMakeLists.txt +++ b/arch/sim/src/sim/CMakeLists.txt @@ -57,7 +57,7 @@ list( sim_registerdump.c sim_saveusercontext.c sim_tcbinfo.c - sim_textheap.c + sim_sectionheap.c sim_checkhostfstypes.c) if(CONFIG_HOST_X86_64) diff --git a/arch/sim/src/sim/sim_textheap.c b/arch/sim/src/sim/sim_sectionheap.c similarity index 63% rename from arch/sim/src/sim/sim_textheap.c rename to arch/sim/src/sim/sim_sectionheap.c index 6fa233201e600..411190b51b352 100644 --- a/arch/sim/src/sim/sim_textheap.c +++ b/arch/sim/src/sim/sim_sectionheap.c @@ -1,5 +1,5 @@ /**************************************************************************** - * arch/sim/src/sim/sim_textheap.c + * arch/sim/src/sim/sim_sectionheap.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -32,6 +32,7 @@ ****************************************************************************/ static struct mm_heap_s *g_textheap; +static struct mm_heap_s *g_dataheap; /**************************************************************************** * Public Functions @@ -45,7 +46,11 @@ static struct mm_heap_s *g_textheap; * ****************************************************************************/ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +void *up_textheap_memalign(const char *sectname, size_t align, size_t size) +#else void *up_textheap_memalign(size_t align, size_t size) +#endif { if (g_textheap == NULL) { @@ -85,3 +90,56 @@ bool up_textheap_heapmember(void *p) { return g_textheap != NULL && mm_heapmember(g_textheap, p); } + +/**************************************************************************** + * Name: up_dataheap_memalign + * + * Description: + * Allocate memory for data sections with the specified alignment. + * + ****************************************************************************/ + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +void *up_dataheap_memalign(const char *sectname, size_t align, size_t size) +#else +void *up_dataheap_memalign(size_t align, size_t size) +#endif +{ + if (g_dataheap == NULL) + { + g_dataheap = mm_initialize("dataheap", + host_allocheap(SIM_HEAP_SIZE, true), + SIM_HEAP_SIZE); + } + + return mm_memalign(g_dataheap, align, size); +} + +/**************************************************************************** + * Name: up_dataheap_free + * + * Description: + * Free memory allocated for data sections. + * + ****************************************************************************/ + +void up_dataheap_free(void *p) +{ + if (g_dataheap != NULL) + { + mm_free(g_dataheap, p); + } +} + +/**************************************************************************** + * Name: up_dataheap_heapmember + * + * Description: + * Test if memory is from data heap. + * + ****************************************************************************/ + +bool up_dataheap_heapmember(void *p) +{ + return g_dataheap != NULL && mm_heapmember(g_dataheap, p); +} diff --git a/binfmt/binfmt_unloadmodule.c b/binfmt/binfmt_unloadmodule.c index b15fc4c69c8de..bc5effded8fd7 100644 --- a/binfmt/binfmt_unloadmodule.c +++ b/binfmt/binfmt_unloadmodule.c @@ -161,6 +161,32 @@ int unload_module(FAR struct binary_s *binp) file_munmap(binp->mapped, binp->mapsize); } +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(binp->sectalloc[i])) + { + up_textheap_free(binp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(binp->sectalloc[i])) + { + up_dataheap_free(binp->sectalloc[i]); + continue; + } +# endif + + kumm_free(binp->sectalloc[i]); + } + + binp->alloc[0] = NULL; + binp->alloc[1] = NULL; +#endif + /* Free allocated address spaces */ for (i = 0; i < BINFMT_NALLOC; i++) @@ -174,6 +200,13 @@ int unload_module(FAR struct binary_s *binp) up_textheap_free(binp->alloc[i]); } else +#endif +#if defined(CONFIG_ARCH_USE_DATA_HEAP) + if (i == 1) + { + up_dataheap_free(binp->alloc[i]); + } + else #endif { kumm_free(binp->alloc[i]); diff --git a/binfmt/elf.c b/binfmt/elf.c index 5e3ed98380b54..1ea77cea3f5d3 100644 --- a/binfmt/elf.c +++ b/binfmt/elf.c @@ -164,6 +164,14 @@ static void elf_dumploadinfo(FAR struct elf_loadinfo_s *loadinfo) for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo("Sections %d:\n", i); binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); @@ -317,6 +325,14 @@ static int elf_loadbinary(FAR struct binary_s *binp, binp->addrenv = loadinfo.addrenv; #else +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo.ehdr.e_type == ET_REL) + { + binp->sectalloc = (FAR void *)loadinfo.sectalloc; + binp->nsect = loadinfo.ehdr.e_shnum; + } +# endif + binp->alloc[0] = (FAR void *)loadinfo.textalloc; binp->alloc[1] = (FAR void *)loadinfo.dataalloc; # ifdef CONFIG_BINFMT_CONSTRUCTORS diff --git a/binfmt/libelf/libelf_addrenv.c b/binfmt/libelf/libelf_addrenv.c index 944981b408fb6..3f2ebe3b66bd0 100644 --- a/binfmt/libelf/libelf_addrenv.c +++ b/binfmt/libelf/libelf_addrenv.c @@ -146,13 +146,15 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, /* Allocate memory to hold the ELF image */ -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# ifndef CONFIG_ARCH_USE_SEPARATED_SECTION +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) loadinfo->textalloc = (uintptr_t) - up_textheap_memalign(loadinfo->textalign, textsize); -# else + up_textheap_memalign(loadinfo->textalign, + textsize); +# else loadinfo->textalloc = (uintptr_t) kumm_memalign(loadinfo->textalign, textsize); -# endif +# endif if (!loadinfo->textalloc) { @@ -161,19 +163,20 @@ int elf_addrenv_alloc(FAR struct elf_loadinfo_s *loadinfo, size_t textsize, if (loadinfo->datasize > 0) { -# if defined(CONFIG_ARCH_USE_DATA_HEAP) +# ifdef CONFIG_ARCH_USE_DATA_HEAP loadinfo->dataalloc = (uintptr_t) up_dataheap_memalign(loadinfo->dataalign, datasize); -# else +# else loadinfo->dataalloc = (uintptr_t) kumm_memalign(loadinfo->dataalign, datasize); -# endif +# endif if (!loadinfo->dataalloc) { return -ENOMEM; } } +# endif return OK; #endif @@ -290,23 +293,56 @@ void elf_addrenv_free(FAR struct elf_loadinfo_s *loadinfo) addrenv_drop(loadinfo->addrenv, false); #else +# ifndef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->textalloc != 0) { -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) up_textheap_free((FAR void *)loadinfo->textalloc); -# else +# else kumm_free((FAR void *)loadinfo->textalloc); -# endif +# endif } if (loadinfo->dataalloc != 0) { -# if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)loadinfo->dataalloc); -# else +# else kumm_free((FAR void *)loadinfo->dataalloc); -# endif +# endif + } +# else + int i; + + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + if ((loadinfo->shdr[i].sh_flags & SHF_WRITE) != 0) + { +# if defined(CONFIG_ARCH_USE_DATA_HEAP) + up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); +# else + kumm_free((FAR void *)loadinfo->sectalloc[i]); +# endif + } + else + { +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) + up_textheap_free((FAR void *)loadinfo->sectalloc[i]); +# else + kumm_free((FAR void *)loadinfo->sectalloc[i]); +# endif + } } + + kmm_free(loadinfo->sectalloc); + loadinfo->sectalloc = 0; +# endif #endif /* Clear out all indications of the allocated address environment */ diff --git a/binfmt/libelf/libelf_bind.c b/binfmt/libelf/libelf_bind.c index bd6830df92885..57ec52dcb2895 100644 --- a/binfmt/libelf/libelf_bind.c +++ b/binfmt/libelf/libelf_bind.c @@ -674,8 +674,28 @@ int elf_bind(FAR struct elf_loadinfo_s *loadinfo, * contents to memory and invalidating the I cache). */ - up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); - up_coherent_dcache(loadinfo->dataalloc, loadinfo->datasize); + if (loadinfo->textsize > 0) + { + up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); + } + + if (loadinfo->datasize > 0) + { + up_coherent_dcache(loadinfo->dataalloc, loadinfo->datasize); + } + +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + up_coherent_dcache(loadinfo->sectalloc[i], loadinfo->shdr[i].sh_size); + } +# endif #endif diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index 408fba0991f01..a3d1b0d1c7e99 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -64,6 +64,69 @@ * Private Functions ****************************************************************************/ +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) +static int elf_section_alloc(FAR struct elf_loadinfo_s *loadinfo, + FAR Elf_Shdr *shdr, uint8_t idx) +{ + if (loadinfo->ehdr.e_type != ET_REL) + { + return -EINVAL; + } + + if (loadinfo->sectalloc == NULL) + { + /* Allocate memory info for all sections */ + + loadinfo->sectalloc = kmm_zalloc(sizeof(uintptr_t) * + loadinfo->ehdr.e_shnum); + if (loadinfo->sectalloc == NULL) + { + return -ENOMEM; + } + } + + elf_sectname(loadinfo, shdr); + if ((shdr->sh_flags & SHF_WRITE) != 0) + { +# ifdef CONFIG_ARCH_USE_DATA_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_dataheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)kumm_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->dataalloc == 0) + { + loadinfo->dataalloc = loadinfo->sectalloc[idx]; + } + } + else + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_textheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)kumm_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->textalloc == 0) + { + loadinfo->textalloc = loadinfo->sectalloc[idx]; + } + } + + return OK; +} +#endif + /**************************************************************************** * Name: elf_elfsize * @@ -104,6 +167,13 @@ static void elf_elfsize(FAR struct elf_loadinfo_s *loadinfo) #endif ) { +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) + if (elf_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + datasize = _ALIGN_UP(datasize, shdr->sh_addralign); datasize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->dataalign < shdr->sh_addralign) @@ -113,6 +183,13 @@ static void elf_elfsize(FAR struct elf_loadinfo_s *loadinfo) } else { +#if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) && !defined(CONFIG_ARCH_ADDRENV) + if (elf_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + textsize = _ALIGN_UP(textsize, shdr->sh_addralign); textsize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->textalign < shdr->sh_addralign) @@ -181,7 +258,7 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR uint8_t *text = (FAR uint8_t *)loadinfo->textalloc; FAR uint8_t *data = (FAR uint8_t *)loadinfo->dataalloc; - FAR uint8_t **pptr; + FAR uint8_t **pptr = NULL; int ret; int i; @@ -193,6 +270,23 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + /* SHF_ALLOC indicates that the section requires memory during + * execution. + */ + + if ((shdr->sh_flags & SHF_ALLOC) == 0) + { + continue; + } + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + pptr = (FAR uint8_t **)&loadinfo->sectalloc[i]; + } + else +#endif + /* SHF_WRITE indicates that the section address space is write- * able */ @@ -262,7 +356,9 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) continue; } +#ifndef CONFIG_ARCH_USE_SEPARATED_SECTION *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, shdr->sh_addralign); +#endif /* SHT_NOBITS indicates that there is no data in the file for the * section. @@ -296,9 +392,16 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) shdr->sh_addr = (uintptr_t)*pptr; +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type != ET_REL) + { + *pptr += ELF_ALIGNUP(shdr->sh_size); + } +#else /* Setup the memory pointer for the next time through the loop */ *pptr += ELF_ALIGNUP(shdr->sh_size); +#endif } return OK; diff --git a/include/nuttx/arch.h b/include/nuttx/arch.h index 25171be094e39..184cfaebc8dc6 100644 --- a/include/nuttx/arch.h +++ b/include/nuttx/arch.h @@ -771,12 +771,17 @@ void up_extraheaps_init(void); * Name: up_textheap_memalign * * Description: - * Allocate memory for text sections with the specified alignment. + * Allocate memory for text with the specified alignment and sectname. * ****************************************************************************/ #if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) +FAR void *up_textheap_memalign(FAR const char *sectname, + size_t align, size_t size); +# else FAR void *up_textheap_memalign(size_t align, size_t size); +# endif #endif /**************************************************************************** @@ -851,12 +856,17 @@ void up_textheap_data_sync(void); * Name: up_dataheap_memalign * * Description: - * Allocate memory for data sections with the specified alignment. + * Allocate memory for data with the specified alignment and sectname. * ****************************************************************************/ #if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_SEPARATED_SECTION) +FAR void *up_dataheap_memalign(FAR const char *sectname, + size_t align, size_t size); +# else FAR void *up_dataheap_memalign(size_t align, size_t size); +# endif #endif /**************************************************************************** diff --git a/include/nuttx/binfmt/binfmt.h b/include/nuttx/binfmt/binfmt.h index 9fe9c47ed5c2c..118c483627206 100644 --- a/include/nuttx/binfmt/binfmt.h +++ b/include/nuttx/binfmt/binfmt.h @@ -69,6 +69,10 @@ struct binary_s main_t entrypt; /* Entry point into a program module */ FAR void *mapped; /* Memory-mapped, address space */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + FAR void **sectalloc; /* All sections memory allocated */ + uint16_t nsect; /* Number of sections */ +#endif FAR void *alloc[BINFMT_NALLOC]; /* Allocated address spaces */ #ifdef CONFIG_BINFMT_CONSTRUCTORS diff --git a/include/nuttx/binfmt/elf.h b/include/nuttx/binfmt/elf.h index 7c32f5ff1235d..0dea9ae448afd 100644 --- a/include/nuttx/binfmt/elf.h +++ b/include/nuttx/binfmt/elf.h @@ -79,6 +79,10 @@ struct elf_loadinfo_s * after the ELF module has been loaded. */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + FAR uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ +#endif + uintptr_t textalloc; /* .text memory allocated when ELF file was loaded */ uintptr_t dataalloc; /* .bss/.data memory allocated when ELF file was loaded */ size_t textsize; /* Size of the ELF .text memory allocation */ diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index aa35b260887b3..8ca35e84ae558 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -191,6 +191,10 @@ struct mod_loadinfo_s * after the module has been loaded. */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ +#endif + uintptr_t textalloc; /* .text memory allocated when module was loaded */ uintptr_t datastart; /* Start of.bss/.data memory in .text allocation */ size_t textsize; /* Size of the module .text memory allocation */ diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index 357271ff8097c..a9921ccdf9e62 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -89,6 +89,14 @@ static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); binfo(" sh_flags: %08x\n", shdr->sh_flags); diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index b7202d8490562..89443250e4939 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -964,8 +964,28 @@ int modlib_bind(FAR struct module_s *modp, * contents to memory and invalidating the I cache). */ - up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); - up_coherent_dcache(loadinfo->datastart, loadinfo->datasize); + if (loadinfo->textsize > 0) + { + up_coherent_dcache(loadinfo->textalloc, loadinfo->textsize); + } + + if (loadinfo->datasize > 0) + { + up_coherent_dcache(loadinfo->datastart, loadinfo->datasize); + } + +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + for (i = 0; loadinfo->ehdr.e_type == ET_REL && i < loadinfo->ehdr.e_shnum; + i++) + { + if (loadinfo->sectalloc[i] == 0) + { + continue; + } + + up_coherent_dcache(loadinfo->sectalloc[i], loadinfo->shdr[i].sh_size); + } +#endif return ret; } diff --git a/libs/libc/modlib/modlib_load.c b/libs/libc/modlib/modlib_load.c index 8e1200863f70a..26748ed2ae188 100644 --- a/libs/libc/modlib/modlib_load.c +++ b/libs/libc/modlib/modlib_load.c @@ -56,6 +56,69 @@ * Private Functions ****************************************************************************/ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION +static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, + FAR Elf_Shdr *shdr, uint8_t idx) +{ + if (loadinfo->ehdr.e_type != ET_REL) + { + return -EINVAL; + } + + if (loadinfo->sectalloc == NULL) + { + /* Allocate memory info for all sections */ + + loadinfo->sectalloc = lib_zalloc(sizeof(uintptr_t) * + loadinfo->ehdr.e_shnum); + if (loadinfo->sectalloc == NULL) + { + return -ENOMEM; + } + } + + modlib_sectname(loadinfo, shdr); + if ((shdr->sh_flags & SHF_WRITE) != 0) + { +# ifdef CONFIG_ARCH_USE_DATA_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_dataheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)lib_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->datastart == 0) + { + loadinfo->datastart = loadinfo->sectalloc[idx]; + } + } + else + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + loadinfo->sectalloc[idx] = (uintptr_t) + up_textheap_memalign( + (FAR const char *)loadinfo->iobuffer, + shdr->sh_addralign, + shdr->sh_size); +# else + loadinfo->sectalloc[idx] = (uintptr_t)lib_memalign(shdr->sh_addralign, + shdr->sh_size); +# endif + + if (loadinfo->textalloc == 0) + { + loadinfo->textalloc = loadinfo->sectalloc[idx]; + } + } + + return 0; +} +#endif + /**************************************************************************** * Name: modlib_elfsize * @@ -70,7 +133,10 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) size_t datasize = 0; int i; - /* Accumulate the size each section into memory that is marked SHF_ALLOC */ + /* Accumulate the size each section into memory that is marked SHF_ALLOC + * if CONFIG_ARCH_USE_SEPARATED_SECTION is enabled, allocate + * (and zero) memory for the each section. + */ if (loadinfo->ehdr.e_phnum > 0) { @@ -118,6 +184,13 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) #endif ) { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (modlib_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + datasize = _ALIGN_UP(datasize, shdr->sh_addralign); datasize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->dataalign < shdr->sh_addralign) @@ -127,6 +200,13 @@ static void modlib_elfsize(FAR struct mod_loadinfo_s *loadinfo) } else { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (modlib_section_alloc(loadinfo, shdr, i) >= 0) + { + continue; + } +#endif + textsize = _ALIGN_UP(textsize, shdr->sh_addralign); textsize += ELF_ALIGNUP(shdr->sh_size); if (loadinfo->textalign < shdr->sh_addralign) @@ -161,7 +241,6 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) { FAR uint8_t *text = (FAR uint8_t *)loadinfo->textalloc; FAR uint8_t *data = (FAR uint8_t *)loadinfo->datastart; - FAR uint8_t **pptr; int ret; int i; @@ -204,6 +283,7 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) for (i = 0; i < loadinfo->ehdr.e_shnum; i++) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + FAR uint8_t **pptr = NULL; /* SHF_ALLOC indicates that the section requires memory during * execution @@ -214,25 +294,35 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) continue; } - /* SHF_WRITE indicates that the section address space is write- - * able - */ - - if ((shdr->sh_flags & SHF_WRITE) != 0 -#ifdef CONFIG_ARCH_HAVE_TEXT_HEAP_WORD_ALIGNED_READ - || (shdr->sh_flags & SHF_EXECINSTR) == 0 -#endif - ) +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) { - pptr = &data; + pptr = (FAR uint8_t **)&loadinfo->sectalloc[i]; } - else +#endif + + if (pptr == NULL) { - pptr = &text; - } + /* SHF_WRITE indicates that the section address space is + * writeable + */ - *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, - shdr->sh_addralign); + if ((shdr->sh_flags & SHF_WRITE) != 0 +#ifdef CONFIG_ARCH_HAVE_TEXT_HEAP_WORD_ALIGNED_READ + || (shdr->sh_flags & SHF_EXECINSTR) == 0 +#endif + ) + { + pptr = &data; + } + else + { + pptr = &text; + } + + *pptr = (FAR uint8_t *)_ALIGN_UP((uintptr_t)*pptr, + shdr->sh_addralign); + } /* SHT_NOBITS indicates that there is no data in the file for the * section. @@ -267,9 +357,16 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo) shdr->sh_addr = (uintptr_t)*pptr; +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type != ET_REL) + { + *pptr += ELF_ALIGNUP(shdr->sh_size); + } +#else /* Setup the memory pointer for the next time through the loop */ *pptr += ELF_ALIGNUP(shdr->sh_size); +#endif } } @@ -324,18 +421,19 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->ehdr.e_type == ET_REL) { +#ifndef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->textsize > 0) { -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# ifdef CONFIG_ARCH_USE_TEXT_HEAP loadinfo->textalloc = (uintptr_t) up_textheap_memalign(loadinfo->textalign, loadinfo->textsize + loadinfo->segpad); -#else +# else loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign, loadinfo->textsize + loadinfo->segpad); -#endif +# endif if (!loadinfo->textalloc) { berr("ERROR: Failed to allocate memory for the module text\n"); @@ -346,14 +444,14 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->datasize > 0) { -#if defined(CONFIG_ARCH_USE_DATA_HEAP) +# ifdef CONFIG_ARCH_USE_DATA_HEAP loadinfo->datastart = (uintptr_t) up_dataheap_memalign(loadinfo->dataalign, loadinfo->datasize); -#else +# else loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign, loadinfo->datasize); -#endif +# endif if (!loadinfo->datastart) { berr("ERROR: Failed to allocate memory for the module data\n"); @@ -361,6 +459,7 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo) goto errout_with_buffers; } } +#endif } else { diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index ebd88404de9e0..02c86468559fe 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -62,6 +62,33 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) if (loadinfo->ehdr.e_type != ET_DYN) { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; loadinfo->sectalloc[i] != 0 && + i < loadinfo->ehdr.e_shnum; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember((FAR void *)loadinfo->sectalloc[i])) + { + up_textheap_free((FAR void *)loadinfo->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember((FAR void *)loadinfo->sectalloc[i])) + { + up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); + continue; + } +# endif + + lib_free((FAR void *)loadinfo->sectalloc[i]); + } + + lib_free(loadinfo->sectalloc); +#else if (loadinfo->textalloc != 0) { #if defined(CONFIG_ARCH_USE_TEXT_HEAP) @@ -79,6 +106,7 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) lib_free((FAR void *)loadinfo->datastart); #endif } +#endif } else { diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index 25539f381b80c..a020089450172 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -90,6 +90,14 @@ static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + binfo(" sh_name: %08x\n", shdr->sh_name); binfo(" sh_type: %08x\n", shdr->sh_type); binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags); From c5ed6238b5543f7c44903f1a862bebf625e755e1 Mon Sep 17 00:00:00 2001 From: dongjiuzhu1 Date: Wed, 21 Feb 2024 15:58:02 +0800 Subject: [PATCH 2/3] libc/modlib: free memory resource when rmmod elf Signed-off-by: dongjiuzhu1 --- include/nuttx/lib/modlib.h | 4 ++++ libs/libc/dlfcn/lib_dlclose.c | 33 +++++++++++++++++++++++++++ libs/libc/dlfcn/lib_dlopen.c | 5 ++++ libs/libc/modlib/modlib_unload.c | 2 +- sched/module/mod_rmmod.c | 39 ++++++++++++++++++++++++++++---- 5 files changed, 77 insertions(+), 6 deletions(-) diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index 8ca35e84ae558..cb6f5a178a2e8 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -159,6 +159,10 @@ struct module_s struct mod_info_s modinfo; /* Module information */ FAR void *textalloc; /* Allocated kernel text memory */ FAR void *dataalloc; /* Allocated kernel memory */ +#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 */ +#endif int dynamic; /* Module is a dynamic shared object */ #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) size_t textsize; /* Size of the kernel .text memory allocation */ diff --git a/libs/libc/dlfcn/lib_dlclose.c b/libs/libc/dlfcn/lib_dlclose.c index 335d7fb77cca0..e50055ea71daf 100644 --- a/libs/libc/dlfcn/lib_dlclose.c +++ b/libs/libc/dlfcn/lib_dlclose.c @@ -132,6 +132,34 @@ static inline int dlremove(FAR void *handle) if (!modp->dynamic) { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(modp->sectalloc[i])) + { + up_textheap_free(modp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(modp->sectalloc[i])) + { + up_dataheap_free(modp->sectalloc[i]); + continue; + } +# endif + + lib_free(modp->sectalloc[i]); + } + + lib_free(modp->sectalloc); + modp->sectalloc = NULL; + modp->nsect = 0; +#else if (modp->textalloc != NULL) { /* Free the module memory */ @@ -147,8 +175,13 @@ static inline int dlremove(FAR void *handle) { /* Free the module memory */ +#if defined(CONFIG_ARCH_USE_DATA_HEAP) + up_dataheap_free((FAR void *)modp->dataalloc); +#else lib_free((FAR void *)modp->dataalloc); +#endif } +#endif } else { diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index a9921ccdf9e62..89e4874d6db45 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -238,6 +238,11 @@ static inline FAR void *dlinsert(FAR const char *filename) /* Save the load information */ +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + modp->sectalloc = (FAR void *)loadinfo.sectalloc; + modp->nsect = loadinfo.ehdr.e_shnum; +#endif + modp->textalloc = (FAR void *)loadinfo.textalloc; modp->dataalloc = (FAR void *)loadinfo.datastart; modp->dynamic = (loadinfo.ehdr.e_type == ET_DYN); diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index 02c86468559fe..12cdb813f4cf2 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -87,7 +87,7 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) lib_free((FAR void *)loadinfo->sectalloc[i]); } - lib_free(loadinfo->sectalloc); + lib_free(loadinfo->sectalloc); #else if (loadinfo->textalloc != 0) { diff --git a/sched/module/mod_rmmod.c b/sched/module/mod_rmmod.c index 885d2cfcd85d7..bc1470d456b7f 100644 --- a/sched/module/mod_rmmod.c +++ b/sched/module/mod_rmmod.c @@ -127,15 +127,44 @@ int rmmod(FAR void *handle) if (!modp->dynamic) { -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(modp->sectalloc[i])) + { + up_textheap_free(modp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(modp->sectalloc[i])) + { + up_dataheap_free(modp->sectalloc[i]); + continue; + } +# endif + + kmm_free(modp->sectalloc[i]); + } + + kmm_free(modp->sectalloc); + modp->sectalloc = NULL; + modp->nsect = 0; #else +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) + up_textheap_free((FAR void *)modp->textalloc); +# else kmm_free((FAR void *)modp->textalloc); -#endif -#if defined(CONFIG_ARCH_USE_DATA_HEAP) +# endif +# if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)modp->dataalloc); -#else +# else kmm_free((FAR void *)modp->dataalloc); +# endif #endif } else From b545c1abf9f9355e1760170ead0a45a69ad5fbcd Mon Sep 17 00:00:00 2001 From: anjiahao Date: Mon, 29 Apr 2024 19:59:34 +0800 Subject: [PATCH 3/3] modlib/dlfcn:unify same code Signed-off-by: anjiahao --- binfmt/binfmt_unloadmodule.c | 35 ++-- binfmt/libelf/libelf_load.c | 9 - include/nuttx/lib/modlib.h | 104 +++++++++- libs/libc/dlfcn/lib_dlclose.c | 210 +------------------ libs/libc/dlfcn/lib_dlopen.c | 266 +------------------------ libs/libc/dlfcn/lib_dlsym.c | 86 +------- libs/libc/modlib/CMakeLists.txt | 6 +- libs/libc/modlib/Make.defs | 2 + libs/libc/modlib/modlib_gethandle.c | 80 ++++++++ libs/libc/modlib/modlib_getsymbol.c | 116 +++++++++++ libs/libc/modlib/modlib_insert.c | 299 ++++++++++++++++++++++++++++ libs/libc/modlib/modlib_load.c | 2 +- libs/libc/modlib/modlib_remove.c | 203 +++++++++++++++++++ libs/libc/modlib/modlib_unload.c | 21 +- sched/module/mod_insmod.c | 241 +--------------------- sched/module/mod_modhandle.c | 25 +-- sched/module/mod_modsym.c | 52 +---- sched/module/mod_rmmod.c | 155 +------------- 18 files changed, 860 insertions(+), 1052 deletions(-) create mode 100644 libs/libc/modlib/modlib_gethandle.c create mode 100644 libs/libc/modlib/modlib_getsymbol.c create mode 100644 libs/libc/modlib/modlib_insert.c create mode 100644 libs/libc/modlib/modlib_remove.c diff --git a/binfmt/binfmt_unloadmodule.c b/binfmt/binfmt_unloadmodule.c index bc5effded8fd7..0f0b246deebc4 100644 --- a/binfmt/binfmt_unloadmodule.c +++ b/binfmt/binfmt_unloadmodule.c @@ -162,29 +162,30 @@ int unload_module(FAR struct binary_s *binp) } #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++) - { -# ifdef CONFIG_ARCH_USE_TEXT_HEAP - if (up_textheap_heapmember(binp->sectalloc[i])) + for (i = 0; binp->sectalloc[i] != NULL && i < binp->nsect; i++) { - up_textheap_free(binp->sectalloc[i]); - continue; - } +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(binp->sectalloc[i])) + { + up_textheap_free(binp->sectalloc[i]); + } + else # endif # ifdef CONFIG_ARCH_USE_DATA_HEAP - if (up_dataheap_heapmember(binp->sectalloc[i])) - { - up_dataheap_free(binp->sectalloc[i]); - continue; - } + if (up_dataheap_heapmember(binp->sectalloc[i])) + { + up_dataheap_free(binp->sectalloc[i]); + } + else # endif + { + kumm_free(binp->sectalloc[i]); + } + } - kumm_free(binp->sectalloc[i]); - } - - binp->alloc[0] = NULL; - binp->alloc[1] = NULL; + binp->alloc[0] = NULL; + binp->alloc[1] = NULL; #endif /* Free allocated address spaces */ diff --git a/binfmt/libelf/libelf_load.c b/binfmt/libelf/libelf_load.c index a3d1b0d1c7e99..1ffade84e27ad 100644 --- a/binfmt/libelf/libelf_load.c +++ b/binfmt/libelf/libelf_load.c @@ -270,15 +270,6 @@ static inline int elf_loadfile(FAR struct elf_loadinfo_s *loadinfo) { FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - /* SHF_ALLOC indicates that the section requires memory during - * execution. - */ - - if ((shdr->sh_flags & SHF_ALLOC) == 0) - { - continue; - } - #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION if (loadinfo->ehdr.e_type == ET_REL) { diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index cb6f5a178a2e8..e198b2c1c22fa 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -196,7 +196,7 @@ struct mod_loadinfo_s */ #ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ + FAR uintptr_t *sectalloc; /* All sections memory allocated when ELF file was loaded */ #endif uintptr_t textalloc; /* .text memory allocated when module was loaded */ @@ -563,4 +563,106 @@ int modlib_registry_foreach(mod_callback_t callback, FAR void *arg); void modlib_freesymtab(FAR struct module_s *modp); +/**************************************************************************** + * Name: modlib_insert + * + * Description: + * Verify that the file is an ELF module binary and, if so, load the + * module into kernel memory and initialize it for use. + * + * NOTE: modlib_setsymtab() had to have been called in board-specific OS + * logic prior to calling this function from application logic (perhaps via + * boardctl(BOARDIOC_OS_SYMTAB). Otherwise, insmod will be unable to + * resolve symbols in the OS module. + * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modname - The name that can be used to refer to the module after + * it has been loaded. + * + * Returned Value: + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If modlib_insert() was + * unable to load the module modlib_insert() will return a NULL handle + * and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modlib_insert(FAR const char *filename, FAR const char *modname); + +/**************************************************************************** + * Name: modlib_getsymbol + * + * Description: + * modlib_getsymbol() returns the address of a symbol defined within the + * object that was previously made accessible through a modlib_getsymbol() + * call. handle is the value returned from a call to modlib_insert() (and + * which has not since been released via a call to modlib_remove()), + * name is the symbol's name as a character string. + * + * The returned symbol address will remain valid until modlib_remove() is + * called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to modlib_insert(). + * name - A pointer to the symbol name string. + * + * Returned Value: + * The address associated with the symbol is returned on success. + * If handle does not refer to a valid module opened by modlib_insert(), + * or if the named modlib_symbol cannot be found within any of the objects + * associated with handle, modlib_getsymbol() will return NULL and the + * errno variable will be set appropriately. + * + * NOTE: This means that the address zero can never be a valid return + * value. + * + ****************************************************************************/ + +FAR const void *modlib_getsymbol(FAR void *handle, FAR const char *name); + +/**************************************************************************** + * Name: modlib_remove + * + * Description: + * Remove a previously installed module from memory. + * + * Input Parameters: + * handle - The module handler previously returned by modlib_insert(). + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * + ****************************************************************************/ + +int modlib_remove(FAR void *handle); + +/**************************************************************************** + * Name: modlib_modhandle + * + * Description: + * modlib_modhandle() returns the module handle for the installed + * module with the provided name. A secondary use of this function is to + * determine if a module has been loaded or not. + * + * Input Parameters: + * name - A pointer to the module name string. + * + * Returned Value: + * The non-NULL module handle previously returned by modlib_insert() is + * returned on success. If no module with that name is installed, + * modlib_modhandle() will return a NULL handle and the errno variable + * will be set appropriately. + * + ****************************************************************************/ + +#ifdef HAVE_MODLIB_NAMES +FAR void *modlib_gethandle(FAR const char *name); +#else +# define modlib_gethandle(n) NULL +#endif + #endif /* __INCLUDE_NUTTX_LIB_MODLIB_H */ diff --git a/libs/libc/dlfcn/lib_dlclose.c b/libs/libc/dlfcn/lib_dlclose.c index e50055ea71daf..aff1a7bf9a6ea 100644 --- a/libs/libc/dlfcn/lib_dlclose.c +++ b/libs/libc/dlfcn/lib_dlclose.c @@ -25,211 +25,13 @@ #include #include -#include -#include -#include -#include #include -#include "libc.h" - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dlremove - * - * Description: - * Remove a previously installed shared library from memory. - * - * Input Parameters: - * handle - The shared library handle previously returned by dlopen(). - * - * Returned Value: - * Zero (OK) on success. On any failure, -1 (ERROR) is returned the - * errno value is set appropriately. - * - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -static inline int dlremove(FAR void *handle) -{ - FAR struct module_s *modp = (FAR struct module_s *)handle; - void (**array)(void); - int ret; - int i; - - DEBUGASSERT(modp != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Verify that the module is in the registry */ - - ret = modlib_registry_verify(modp); - if (ret < 0) - { - serr("ERROR: Failed to verify module: %d\n", ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Refuse to remove any module that other modules may depend upon. */ - - if (modp->dependents > 0) - { - serr("ERROR: Module has dependents: %d\n", modp->dependents); - ret = -EBUSY; - goto errout_with_lock; - } -#endif - - /* Is there an uninitializer? */ - - if (modp->modinfo.uninitializer != NULL) - { - /* Try to uninitialize the module */ - - ret = modp->modinfo.uninitializer(modp->modinfo.arg); - - /* Did the module successfully uninitialize? */ - - if (ret < 0) - { - serr("ERROR: Failed to uninitialize the module: %d\n", ret); - goto errout_with_lock; - } - - /* Nullify so that the uninitializer cannot be called again */ - - modp->modinfo.uninitializer = NULL; - - /* Call any .fini_array entries in reverse order */ - - array = (void (**)(void))modp->finiarr; - for (i = (modp->nfini - 1); i >= 0; i--) - { - array[i](); - } - -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = NULL; - modp->modinfo.arg = NULL; - modp->modinfo.exports = NULL; - modp->modinfo.nexports = 0; -#endif - } - - /* Release resources held by the module */ - - /* Dynamic shared objects have text and data allocated in one - * operation to keep the relative positions between the two - * areas relative otherwise references to the GOT will fail - */ - - if (!modp->dynamic) - { -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - int i; - - for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) - { -# ifdef CONFIG_ARCH_USE_TEXT_HEAP - if (up_textheap_heapmember(modp->sectalloc[i])) - { - up_textheap_free(modp->sectalloc[i]); - continue; - } -# endif - -# ifdef CONFIG_ARCH_USE_DATA_HEAP - if (up_dataheap_heapmember(modp->sectalloc[i])) - { - up_dataheap_free(modp->sectalloc[i]); - continue; - } -# endif - - lib_free(modp->sectalloc[i]); - } - - lib_free(modp->sectalloc); - modp->sectalloc = NULL; - modp->nsect = 0; -#else - if (modp->textalloc != NULL) - { - /* Free the module memory */ - -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); -#else - lib_free((FAR void *)modp->textalloc); -#endif - } - - if (modp->dataalloc != NULL) - { - /* Free the module memory */ - -#if defined(CONFIG_ARCH_USE_DATA_HEAP) - up_dataheap_free((FAR void *)modp->dataalloc); -#else - lib_free((FAR void *)modp->dataalloc); -#endif - } -#endif - } - else - { - lib_free((FAR void *)modp->textalloc); - } - - /* Nullify so that the memory cannot be freed again */ - - modp->textalloc = NULL; - modp->dataalloc = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = 0; - modp->datasize = 0; -#endif - - /* Free the modules exported symmbols table */ - - modlib_freesymtab(modp); - - /* Remove the module from the registry */ - - ret = modlib_registry_del(modp); - if (ret < 0) - { - serr("ERROR: Failed to remove the module from the registry: %d\n", - ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Eliminate any dependencies that this module has on other modules */ - - modlib_undepend(modp); -#endif - modlib_registry_unlock(); - - /* And free the registry entry */ - - lib_free(modp); - return OK; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return ERROR; -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -277,15 +79,11 @@ static inline int dlremove(FAR void *handle) int dlclose(FAR void *handle) { -#if defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. - */ - - return rmmod(handle); - -#elif defined(CONFIG_BUILD_PROTECTED) - /* The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there * must be two copies of the module logic: One residing in kernel * space and using the kernel symbol table and one residing in user space * using the user space symbol table. @@ -293,7 +91,7 @@ int dlclose(FAR void *handle) * dlremove() is essentially a clone of rmmod(). */ - return dlremove(handle); + return modlib_remove(handle); #else /* if defined(CONFIG_BUILD_KERNEL) */ /* The KERNEL build is considerably more complex: In order to be shared, diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index 89e4874d6db45..b0fbc3db650f7 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -24,129 +24,17 @@ #include -#include -#include #include #include -#include -#include -#include -#include -#include #include -#include #include - -#include "libc.h" -#include "debug.h" +#include /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dldump_loadinfo - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -# if defined(CONFIG_DEBUG_INFO) && defined(CONFIG_DEBUG_BINFMT) -static void dldump_loadinfo(FAR struct mod_loadinfo_s *loadinfo) -{ - int i; - - binfo("LOAD_INFO:\n"); - binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); - binfo(" datastart: %08lx\n", (long)loadinfo->datastart); - binfo(" textsize: %ld\n", (long)loadinfo->textsize); - binfo(" datasize: %ld\n", (long)loadinfo->datasize); - binfo(" filelen: %ld\n", (long)loadinfo->filelen); - binfo(" filfd: %d\n", loadinfo->filfd); - binfo(" symtabidx: %d\n", loadinfo->symtabidx); - binfo(" strtabidx: %d\n", loadinfo->strtabidx); - - binfo("ELF Header:\n"); - binfo(" e_ident: %02x %02x %02x %02x\n", - loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], - loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); - binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); - binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); - binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); - binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); - binfo(" e_phoff: %d\n", loadinfo->ehdr.e_phoff); - binfo(" e_shoff: %d\n", loadinfo->ehdr.e_shoff); - binfo(" e_flags: %08x\n" , loadinfo->ehdr.e_flags); - binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); - binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); - binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); - binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); - binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); - binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); - - if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_shnum; i++) - { - FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - binfo("Sections %d:\n", i); -# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - if (loadinfo->ehdr.e_type == ET_REL) - { - binfo(" sh_alloc: %08jx\n", - (uintmax_t)loadinfo->sectalloc[i]); - } -# endif - - binfo(" sh_name: %08x\n", shdr->sh_name); - binfo(" sh_type: %08x\n", shdr->sh_type); - binfo(" sh_flags: %08x\n", shdr->sh_flags); - binfo(" sh_addr: %08x\n", shdr->sh_addr); - binfo(" sh_offset: %d\n", shdr->sh_offset); - binfo(" sh_size: %d\n", shdr->sh_size); - binfo(" sh_link: %d\n", shdr->sh_link); - binfo(" sh_info: %d\n", shdr->sh_info); - binfo(" sh_addralign: %d\n", shdr->sh_addralign); - binfo(" sh_entsize: %d\n", shdr->sh_entsize); - } - } - - if (loadinfo->phdr && loadinfo->ehdr.e_phnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_phnum; i++) - { - FAR Elf32_Phdr *phdr = &loadinfo->phdr[i]; - binfo("Program Header %d:\n", i); - binfo(" p_type: %08x\n", phdr->p_type); - binfo(" p_offset: %08x\n", phdr->p_offset); - binfo(" p_vaddr: %08x\n", phdr->p_vaddr); - binfo(" p_paddr: %08x\n", phdr->p_paddr); - binfo(" p_filesz: %08x\n", phdr->p_filesz); - binfo(" p_memsz: %08x\n", phdr->p_memsz); - binfo(" p_flags: %08x\n", phdr->p_flags); - binfo(" p_align: %08x\n", phdr->p_align); - } - } -} -# else -# define dldump_loadinfo(i) -# endif -#endif - -/**************************************************************************** - * Name: dldump_initializer - ****************************************************************************/ - -#if defined(CONFIG_BUILD_PROTECTED) && defined(CONFIG_MODLIB_DUMPBUFFER) -static void dldump_initializer(mod_initializer_t initializer, - FAR struct mod_loadinfo_s *loadinfo) -{ - modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, - MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); -} -#else -# define dldump_initializer(b,l) -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -173,148 +61,7 @@ static void dldump_initializer(mod_initializer_t initializer, * ****************************************************************************/ -#ifdef CONFIG_BUILD_PROTECTED -/* The PROTECTED build is equivalent to the FLAT build EXCEPT that there - * must be two copies of the module logic: One residing in kernel - * space and using the kernel symbol table and one residing in user space - * using the user space symbol table. - * - * dlinsert() is essentially a clone of insmod(). - */ - -static inline FAR void *dlinsert(FAR const char *filename) -{ - struct mod_loadinfo_s loadinfo; - FAR struct module_s *modp; - mod_initializer_t initializer; - void (**array)(void); - int ret; - int i; - - binfo("Loading file: %s\n", filename); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Initialize the ELF library to load the program binary. */ - - ret = modlib_initialize(filename, &loadinfo); - dldump_loadinfo(&loadinfo); - if (ret != 0) - { - serr("ERROR: Failed to initialize to load module: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Allocate a module registry entry to hold the module data */ - - modp = (FAR struct module_s *)lib_zalloc(sizeof(struct module_s)); - if (modp == NULL) - { - ret = -ENOMEM; - binfo("Failed to initialize for load of ELF program: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Load the program binary */ - - ret = modlib_load(&loadinfo); - dldump_loadinfo(&loadinfo); - if (ret != 0) - { - binfo("Failed to load ELF program binary: %d\n", ret); - goto errout_with_registry_entry; - } - - /* Bind the program to the kernel symbol table */ - - ret = modlib_bind(modp, &loadinfo); - if (ret != 0) - { - binfo("Failed to bind symbols program binary: %d\n", ret); - goto errout_with_load; - } - - /* Save the load information */ - -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - modp->sectalloc = (FAR void *)loadinfo.sectalloc; - modp->nsect = loadinfo.ehdr.e_shnum; -#endif - - modp->textalloc = (FAR void *)loadinfo.textalloc; - modp->dataalloc = (FAR void *)loadinfo.datastart; - modp->dynamic = (loadinfo.ehdr.e_type == ET_DYN); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = loadinfo.textsize; - modp->datasize = loadinfo.datasize; -#endif - - /* Get the module initializer entry point */ - - initializer = (mod_initializer_t)(loadinfo.textalloc + - loadinfo.ehdr.e_entry); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = initializer; -#endif - dldump_initializer(initializer, &loadinfo); - - /* Call the module initializer */ - - switch (loadinfo.ehdr.e_type) - { - case ET_REL : - ret = initializer(&modp->modinfo); - if (ret < 0) - { - binfo("Failed to initialize the module: %d\n", ret); - goto errout_with_load; - } - break; - case ET_DYN : - - /* Process any preinit_array entries */ - - array = (void (**)(void)) loadinfo.preiarr; - for (i = 0; i < loadinfo.nprei; i++) - { - array[i](); - } - - /* Process any init_array entries */ - - array = (void (**)(void)) loadinfo.initarr; - for (i = 0; i < loadinfo.ninit; i++) - { - array[i](); - } - - modp->finiarr = loadinfo.finiarr; - modp->nfini = loadinfo.nfini; - break; - } - - /* Add the new module entry to the registry */ - - modlib_registry_add(modp); - - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - return modp; - -errout_with_load: - modlib_unload(&loadinfo); - modlib_undepend(modp); -errout_with_registry_entry: - lib_free(modp); -errout_with_loadinfo: - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - set_errno(-ret); - return NULL; -} -#elif defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. * @@ -322,6 +69,13 @@ static inline FAR void *dlinsert(FAR const char *filename) * - No automatic binding of symbols * - No dependencies * - mode is ignored. + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * must be two copies of the module logic: One residing in kernel + * space and using the kernel symbol table and one residing in user space + * using the user space symbol table. + * + * dlinsert() is essentially a clone of insmod(). */ static inline FAR void *dlinsert(FAR const char *filename) @@ -341,7 +95,7 @@ static inline FAR void *dlinsert(FAR const char *filename) * name. */ - handle = insmod(filename, basename(name)); + handle = modlib_insert(filename, basename(name)); lib_free(name); return handle; } diff --git a/libs/libc/dlfcn/lib_dlsym.c b/libs/libc/dlfcn/lib_dlsym.c index 66fa6af077ebc..5308e6c699cf8 100644 --- a/libs/libc/dlfcn/lib_dlsym.c +++ b/libs/libc/dlfcn/lib_dlsym.c @@ -25,87 +25,13 @@ #include #include -#include -#include -#include -#include -#include #include /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: dlgetsym - * - * Description: - * dlgetsym() implements dlsym() for the PROTECTED build. - * - * Input Parameters: - * handle - The opaque, non-NULL value returned by a previous successful - * call to insmod(). - * name - A pointer to the symbol name string. - * - * Returned Value: - * See dlsym(). - * - ****************************************************************************/ - -#ifdef CONFIG_BUILD_PROTECTED -static inline FAR const void *dlgetsym(FAR void *handle, - FAR const char *name) -{ - FAR struct module_s *modp = (FAR struct module_s *)handle; - FAR const struct symtab_s *symbol; - int err; - int ret; - - /* Verify that the module is in the registry */ - - modlib_registry_lock(); - ret = modlib_registry_verify(modp); - if (ret < 0) - { - serr("ERROR: Failed to verify module: %d\n", ret); - err = -ret; - goto errout_with_lock; - } - - /* Does the module have a symbol table? */ - - if (modp->modinfo.exports == NULL || modp->modinfo.nexports == 0) - { - serr("ERROR: Module has no symbol table\n"); - err = ENOENT; - goto errout_with_lock; - } - - /* Search the symbol table for the matching symbol */ - - symbol = symtab_findbyname(modp->modinfo.exports, name, - modp->modinfo.nexports); - if (symbol == NULL) - { - serr("ERROR: Failed to find symbol in symbol \"%s\" in table\n", name); - err = ENOENT; - goto errout_with_lock; - } - - /* Return the address within the module associated with the symbol */ - - modlib_registry_unlock(); - DEBUGASSERT(symbol->sym_value != NULL); - return symbol->sym_value; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(err); - return NULL; -} -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -143,15 +69,11 @@ static inline FAR const void *dlgetsym(FAR void *handle, FAR void *dlsym(FAR void *handle, FAR const char *name) { -#if defined(CONFIG_BUILD_FLAT) +#if defined(CONFIG_BUILD_FLAT) || defined(CONFIG_BUILD_PROTECTED) /* In the FLAT build, a shared library is essentially the same as a kernel * module. - */ - - return (FAR void *)modsym(handle, name); - -#elif defined(CONFIG_BUILD_PROTECTED) - /* The PROTECTED build is equivalent to the FLAT build EXCEPT that there + * + * The PROTECTED build is equivalent to the FLAT build EXCEPT that there * must be two copies of the module logic: One residing in kernel * space and using the kernel symbol table and one residing in user space * using the user space symbol table. @@ -159,7 +81,7 @@ FAR void *dlsym(FAR void *handle, FAR const char *name) * dlgetsem() is essentially a clone of modsym(). */ - return (FAR void *)dlgetsym(handle, name); + return (FAR void *)modlib_getsymbol(handle, name); #else /* if defined(CONFIG_BUILD_KERNEL) */ /* The KERNEL build is considerably more complex: In order to be shared, diff --git a/libs/libc/modlib/CMakeLists.txt b/libs/libc/modlib/CMakeLists.txt index 741f37abf94d3..e1606b6772c0a 100644 --- a/libs/libc/modlib/CMakeLists.txt +++ b/libs/libc/modlib/CMakeLists.txt @@ -36,7 +36,11 @@ if(CONFIG_LIBC_MODLIB) modlib_symtab.c modlib_uninit.c modlib_unload.c - modlib_verify.c) + modlib_verify.c + modlib_gethandle.c + modlib_getsymbol.c + modlib_insert.c + modlib_remove.c) list(APPEND SRCS modlib_globals.S) diff --git a/libs/libc/modlib/Make.defs b/libs/libc/modlib/Make.defs index f9cd0a3e335fa..8b6f1d010090b 100644 --- a/libs/libc/modlib/Make.defs +++ b/libs/libc/modlib/Make.defs @@ -26,6 +26,8 @@ CSRCS += modlib_bind.c modlib_depend.c modlib_init.c modlib_iobuffer.c CSRCS += modlib_load.c modlib_loadhdrs.c modlib_verify.c CSRCS += modlib_read.c modlib_registry.c modlib_sections.c CSRCS += modlib_symbols.c modlib_symtab.c modlib_uninit.c modlib_unload.c +CSRCS += modlib_gethandle.c modlib_getsymbol.c modlib_insert.c +CSRCS += modlib_remove.c # Add the modlib directory to the build diff --git a/libs/libc/modlib/modlib_gethandle.c b/libs/libc/modlib/modlib_gethandle.c new file mode 100644 index 0000000000000..ddd7303df35e4 --- /dev/null +++ b/libs/libc/modlib/modlib_gethandle.c @@ -0,0 +1,80 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_gethandle.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_modhandle + * + * Description: + * modlib_modhandle() returns the module handle for the installed + * module with the provided name. A secondary use of this function is to + * determine if a module has been loaded or not. + * + * Input Parameters: + * name - A pointer to the module name string. + * + * Returned Value: + * The non-NULL module handle previously returned by modlib_insert() is + * returned on success. If no module with that name is installed, + * modlib_modhandle() will return a NULL handle and the errno variable + * will be set appropriately. + * + ****************************************************************************/ + +#ifdef HAVE_MODLIB_NAMES + +FAR void *modlib_gethandle(FAR const char *name) +{ + FAR struct module_s *modp; + + DEBUGASSERT(name != NULL); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Find the module entry for this name in the registry */ + + modp = modlib_registry_find(name); + if (modp == NULL) + { + berr("ERROR: Failed to find module %s\n", name); + set_errno(ENOENT); + } + + modlib_registry_unlock(); + return modp; +} + +#endif /* HAVE_MODLIB_NAMES */ diff --git a/libs/libc/modlib/modlib_getsymbol.c b/libs/libc/modlib/modlib_getsymbol.c new file mode 100644 index 0000000000000..c73a454a109ba --- /dev/null +++ b/libs/libc/modlib/modlib_getsymbol.c @@ -0,0 +1,116 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_getsymbol.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_getsymbol + * + * Description: + * modlib_getsymbol() returns the address of a symbol defined within the + * object that was previously made accessible through a modlib_getsymbol() + * call. handle is the value returned from a call to modlib_insert() (and + * which has not since been released via a call to modlib_remove()), + * name is the symbol's name as a character string. + * + * The returned symbol address will remain valid until modlib_remove() is + * called. + * + * Input Parameters: + * handle - The opaque, non-NULL value returned by a previous successful + * call to modlib_insert(). + * name - A pointer to the symbol name string. + * + * Returned Value: + * The address associated with the symbol is returned on success. + * If handle does not refer to a valid module opened by modlib_insert(), + * or if the named modlib_symbol cannot be found within any of the objects + * associated with handle, modlib_getsymbol() will return NULL and the + * errno variable will be set appropriately. + * + * NOTE: This means that the address zero can never be a valid return + * value. + * + ****************************************************************************/ + +FAR const void *modlib_getsymbol(FAR void *handle, FAR const char *name) +{ + FAR struct module_s *modp = handle; + FAR const struct symtab_s *symbol; + int err; + int ret; + + /* Verify that the module is in the registry */ + + modlib_registry_lock(); + ret = modlib_registry_verify(modp); + if (ret < 0) + { + berr("ERROR: Failed to verify module: %d\n", ret); + err = -ret; + goto errout_with_lock; + } + + /* Does the module have a symbol table? */ + + if (modp->modinfo.exports == NULL || modp->modinfo.nexports == 0) + { + berr("ERROR: Module has no symbol table\n"); + err = ENOENT; + goto errout_with_lock; + } + + /* Search the symbol table for the matching symbol */ + + symbol = symtab_findbyname(modp->modinfo.exports, name, + modp->modinfo.nexports); + + modlib_registry_unlock(); + if (symbol == NULL) + { + berr("ERROR: Failed to find symbol in symbol \"%s\" in table\n", name); + set_errno(ENOENT); + return NULL; + } + + /* Return the address within the module associated with the symbol */ + + DEBUGASSERT(symbol->sym_value != NULL); + return symbol->sym_value; + +errout_with_lock: + modlib_registry_unlock(); + set_errno(err); + return NULL; +} diff --git a/libs/libc/modlib/modlib_insert.c b/libs/libc/modlib/modlib_insert.c new file mode 100644 index 0000000000000..ec3098db440c2 --- /dev/null +++ b/libs/libc/modlib/modlib_insert.c @@ -0,0 +1,299 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_insert.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_dumploadinfo + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_BINFMT_INFO +static void modlib_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) +{ + int i; + + binfo("LOAD_INFO:\n"); + binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); + binfo(" datastart: %08lx\n", (long)loadinfo->datastart); + binfo(" textsize: %ld\n", (long)loadinfo->textsize); + binfo(" datasize: %ld\n", (long)loadinfo->datasize); + binfo(" textalign: %zu\n", loadinfo->textalign); + binfo(" dataalign: %zu\n", loadinfo->dataalign); + binfo(" filelen: %ld\n", (long)loadinfo->filelen); + binfo(" filfd: %d\n", loadinfo->filfd); + binfo(" symtabidx: %d\n", loadinfo->symtabidx); + binfo(" strtabidx: %d\n", loadinfo->strtabidx); + + binfo("ELF Header:\n"); + binfo(" e_ident: %02x %02x %02x %02x\n", + loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], + loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); + binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); + binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); + binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); + binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); + binfo(" e_phoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_phoff); + binfo(" e_shoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_shoff); + binfo(" e_flags: %08x\n", loadinfo->ehdr.e_flags); + binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); + binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); + binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); + binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); + binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); + binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); + + if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) + { + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + binfo("Sections %d:\n", i); +# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + if (loadinfo->ehdr.e_type == ET_REL) + { + binfo(" sh_alloc: %08jx\n", + (uintmax_t)loadinfo->sectalloc[i]); + } +# endif + + binfo(" sh_name: %08x\n", shdr->sh_name); + binfo(" sh_type: %08x\n", shdr->sh_type); + binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags); + binfo(" sh_addr: %08jx\n", (uintmax_t)shdr->sh_addr); + binfo(" sh_offset: %ju\n", (uintmax_t)shdr->sh_offset); + binfo(" sh_size: %ju\n", (uintmax_t)shdr->sh_size); + binfo(" sh_link: %d\n", shdr->sh_link); + binfo(" sh_info: %d\n", shdr->sh_info); + binfo(" sh_addralign: %ju\n", (uintmax_t)shdr->sh_addralign); + binfo(" sh_entsize: %ju\n", (uintmax_t)shdr->sh_entsize); + } + } +} +#else +# define modlib_dumploadinfo(i) +#endif + +/**************************************************************************** + * Name: modlib_dumpinitializer + ****************************************************************************/ + +#ifdef CONFIG_MODLIB_DUMPBUFFER +static void modlib_dumpinitializer(mod_initializer_t initializer, + FAR struct mod_loadinfo_s *loadinfo) +{ + modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, + MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); +} +#else +# define modlib_dumpinitializer(b,l) +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_insert + * + * Description: + * Verify that the file is an ELF module binary and, if so, load the + * module into kernel memory and initialize it for use. + * + * NOTE: modlib_setsymtab() had to have been called in board-specific OS + * logic prior to calling this function from application logic (perhaps via + * boardctl(BOARDIOC_OS_SYMTAB). Otherwise, insmod will be unable to + * resolve symbols in the OS module. + * + * Input Parameters: + * + * filename - Full path to the module binary to be loaded + * modname - The name that can be used to refer to the module after + * it has been loaded. + * + * Returned Value: + * A non-NULL module handle that can be used on subsequent calls to other + * module interfaces is returned on success. If modlib_insert() was + * unable to load the module modlib_insert() will return a NULL handle + * and the errno variable will be set appropriately. + * + ****************************************************************************/ + +FAR void *modlib_insert(FAR const char *filename, FAR const char *modname) +{ + struct mod_loadinfo_s loadinfo; + FAR struct module_s *modp; + mod_initializer_t initializer; + FAR void (**array)(void); + int ret; + int i; + + DEBUGASSERT(filename != NULL && modname != NULL); + binfo("Loading file: %s\n", filename); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Check if this module is already installed */ + +#ifdef HAVE_MODLIB_NAMES + if (modlib_registry_find(modname) != NULL) + { + modlib_registry_unlock(); + set_errno(EEXIST); + return NULL; + } +#endif + + /* Initialize the ELF library to load the program binary. */ + + ret = modlib_initialize(filename, &loadinfo); + modlib_dumploadinfo(&loadinfo); + if (ret != 0) + { + berr("ERROR: Failed to initialize to load module: %d\n", ret); + goto errout_with_loadinfo; + } + + /* Allocate a module registry entry to hold the module data */ + + modp = lib_zalloc(sizeof(struct module_s)); + if (modp == NULL) + { + berr("Failed to allocate struct module_s\n"); + ret = -ENOMEM; + goto errout_with_loadinfo; + } + +#ifdef HAVE_MODLIB_NAMES + /* Save the module name in the registry entry */ + + strlcpy(modp->modname, modname, sizeof(modp->modname)); +#endif + + /* Load the program binary */ + + ret = modlib_load(&loadinfo); + modlib_dumploadinfo(&loadinfo); + if (ret != 0) + { + binfo("Failed to load ELF program binary: %d\n", ret); + goto errout_with_registry_entry; + } + + /* Bind the program to the kernel symbol table */ + + ret = modlib_bind(modp, &loadinfo); + if (ret != 0) + { + binfo("Failed to bind symbols program binary: %d\n", ret); + goto errout_with_load; + } + + /* Save the load information */ + + modp->textalloc = (FAR void *)loadinfo.textalloc; + modp->dataalloc = (FAR void *)loadinfo.datastart; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->textsize = loadinfo.textsize; + modp->datasize = loadinfo.datasize; +#endif + + /* Get the module initializer entry point */ + + initializer = (mod_initializer_t)(loadinfo.textalloc + + loadinfo.ehdr.e_entry); +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->initializer = initializer; +#endif + modlib_dumpinitializer(initializer, &loadinfo); + + /* Call the module initializer */ + + switch (loadinfo.ehdr.e_type) + { + case ET_REL : + ret = initializer(&modp->modinfo); + if (ret < 0) + { + binfo("Failed to initialize the module: %d\n", ret); + goto errout_with_load; + } + break; + case ET_DYN : + + /* Process any preinit_array entries */ + + array = (FAR void (**)(void))loadinfo.preiarr; + for (i = 0; i < loadinfo.nprei; i++) + { + array[i](); + } + + /* Process any init_array entries */ + + array = (FAR void (**)(void))loadinfo.initarr; + for (i = 0; i < loadinfo.ninit; i++) + { + array[i](); + } + + modp->finiarr = loadinfo.finiarr; + modp->nfini = loadinfo.nfini; + break; + } + + /* Add the new module entry to the registry */ + + modlib_registry_add(modp); + + modlib_uninitialize(&loadinfo); + modlib_registry_unlock(); + return modp; + +errout_with_load: + modlib_unload(&loadinfo); +#if CONFIG_MODLIB_MAXDEPEND > 0 + modlib_undepend(modp); +#endif +errout_with_registry_entry: + lib_free(modp); +errout_with_loadinfo: + modlib_uninitialize(&loadinfo); + modlib_registry_unlock(); + set_errno(-ret); + return NULL; +} + diff --git a/libs/libc/modlib/modlib_load.c b/libs/libc/modlib/modlib_load.c index 26748ed2ae188..4aaae3a1b9384 100644 --- a/libs/libc/modlib/modlib_load.c +++ b/libs/libc/modlib/modlib_load.c @@ -70,7 +70,7 @@ static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo, /* Allocate memory info for all sections */ loadinfo->sectalloc = lib_zalloc(sizeof(uintptr_t) * - loadinfo->ehdr.e_shnum); + loadinfo->ehdr.e_shnum); if (loadinfo->sectalloc == NULL) { return -ENOMEM; diff --git a/libs/libc/modlib/modlib_remove.c b/libs/libc/modlib/modlib_remove.c new file mode 100644 index 0000000000000..a645c689866de --- /dev/null +++ b/libs/libc/modlib/modlib_remove.c @@ -0,0 +1,203 @@ +/**************************************************************************** + * libs/libc/modlib/modlib_remove.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: modlib_remove + * + * Description: + * Remove a previously installed module from memory. + * + * Input Parameters: + * handle - The module handler previously returned by modlib_insert(). + * + * Returned Value: + * Zero (OK) on success. On any failure, -1 (ERROR) is returned the + * errno value is set appropriately. + * + ****************************************************************************/ + +int modlib_remove(FAR void *handle) +{ + FAR struct module_s *modp = (FAR struct module_s *)handle; + int ret; + + DEBUGASSERT(modp != NULL); + + /* Get exclusive access to the module registry */ + + modlib_registry_lock(); + + /* Verify that the module is in the registry */ + + ret = modlib_registry_verify(modp); + if (ret < 0) + { + berr("ERROR: Failed to verify module: %d\n", ret); + goto errout_with_lock; + } + +#if CONFIG_MODLIB_MAXDEPEND > 0 + /* Refuse to remove any module that other modules may depend upon. */ + + if (modp->dependents > 0) + { + berr("ERROR: Module has dependents: %d\n", modp->dependents); + ret = -EBUSY; + goto errout_with_lock; + } +#endif + + /* Is there an uninitializer? */ + + if (modp->modinfo.uninitializer != NULL) + { + /* Try to uninitialize the module */ + + ret = modp->modinfo.uninitializer(modp->modinfo.arg); + + /* Did the module successfully uninitialize? */ + + if (ret < 0) + { + berr("ERROR: Failed to uninitialize the module: %d\n", ret); + goto errout_with_lock; + } + + /* Nullify so that the uninitializer cannot be called again */ + + modp->modinfo.uninitializer = NULL; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->initializer = NULL; + modp->modinfo.arg = NULL; + modp->modinfo.exports = NULL; + modp->modinfo.nexports = 0; +#endif + } + + /* Release resources held by the module */ + + if (modp->textalloc != NULL || modp->dataalloc != NULL) + { + /* Free the module memory and nullify so that the memory cannot + * be freed again + * + * NOTE: For dynamic shared objects there is only a single + * allocation: the text/data were allocated in one operation + */ + + if (!modp->dynamic) + { +#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION + int i; + + for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) + { +# ifdef CONFIG_ARCH_USE_TEXT_HEAP + if (up_textheap_heapmember(modp->sectalloc[i])) + { + up_textheap_free(modp->sectalloc[i]); + continue; + } +# endif + +# ifdef CONFIG_ARCH_USE_DATA_HEAP + if (up_dataheap_heapmember(modp->sectalloc[i])) + { + up_dataheap_free(modp->sectalloc[i]); + continue; + } +# endif + + lib_free(modp->sectalloc[i]); + } + + lib_free(modp->sectalloc); + modp->sectalloc = NULL; + modp->nsect = 0; +#else +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) + up_textheap_free((FAR void *)modp->textalloc); +# else + lib_free((FAR void *)modp->textalloc); +# endif +# if defined(CONFIG_ARCH_USE_DATA_HEAP) + up_dataheap_free((FAR void *)modp->dataalloc); +# else + lib_free((FAR void *)modp->dataalloc); +# endif +#endif + } + else + { + lib_free((FAR void *)modp->textalloc); + } + + modp->textalloc = NULL; + modp->dataalloc = NULL; +#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) + modp->textsize = 0; + modp->datasize = 0; +#endif + } + + /* Remove the module from the registry */ + + ret = modlib_registry_del(modp); + if (ret < 0) + { + berr("ERROR: Failed to remove the module from the registry: %d\n", + ret); + goto errout_with_lock; + } + +#if CONFIG_MODLIB_MAXDEPEND > 0 + /* Eliminate any dependencies that this module has on other modules */ + + modlib_undepend(modp); +#endif + modlib_registry_unlock(); + + /* And free the registry entry */ + + lib_free(modp); + return OK; + +errout_with_lock: + modlib_registry_unlock(); + set_errno(-ret); + return ERROR; +} diff --git a/libs/libc/modlib/modlib_unload.c b/libs/libc/modlib/modlib_unload.c index 12cdb813f4cf2..981e2a8fd1e79 100644 --- a/libs/libc/modlib/modlib_unload.c +++ b/libs/libc/modlib/modlib_unload.c @@ -72,39 +72,40 @@ int modlib_unload(FAR struct mod_loadinfo_s *loadinfo) if (up_textheap_heapmember((FAR void *)loadinfo->sectalloc[i])) { up_textheap_free((FAR void *)loadinfo->sectalloc[i]); - continue; } + else # endif # ifdef CONFIG_ARCH_USE_DATA_HEAP if (up_dataheap_heapmember((FAR void *)loadinfo->sectalloc[i])) { up_dataheap_free((FAR void *)loadinfo->sectalloc[i]); - continue; } + else # endif - - lib_free((FAR void *)loadinfo->sectalloc[i]); + { + lib_free((FAR void *)loadinfo->sectalloc[i]); + } } lib_free(loadinfo->sectalloc); #else if (loadinfo->textalloc != 0) { -#if defined(CONFIG_ARCH_USE_TEXT_HEAP) +# if defined(CONFIG_ARCH_USE_TEXT_HEAP) up_textheap_free((FAR void *)loadinfo->textalloc); -#else +# else lib_free((FAR void *)loadinfo->textalloc); -#endif +# endif } if (loadinfo->datastart != 0) { -#if defined(CONFIG_ARCH_USE_DATA_HEAP) +# if defined(CONFIG_ARCH_USE_DATA_HEAP) up_dataheap_free((FAR void *)loadinfo->datastart); -#else +# else lib_free((FAR void *)loadinfo->datastart); -#endif +# endif } #endif } diff --git a/sched/module/mod_insmod.c b/sched/module/mod_insmod.c index a020089450172..ab17c38ba88d9 100644 --- a/sched/module/mod_insmod.c +++ b/sched/module/mod_insmod.c @@ -26,110 +26,11 @@ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include #include #include #ifdef CONFIG_MODULE -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mod_dumploadinfo - ****************************************************************************/ - -#ifdef CONFIG_DEBUG_BINFMT_INFO -static void mod_dumploadinfo(FAR struct mod_loadinfo_s *loadinfo) -{ - int i; - - binfo("LOAD_INFO:\n"); - binfo(" textalloc: %08lx\n", (long)loadinfo->textalloc); - binfo(" datastart: %08lx\n", (long)loadinfo->datastart); - binfo(" textsize: %ld\n", (long)loadinfo->textsize); - binfo(" datasize: %ld\n", (long)loadinfo->datasize); - binfo(" textalign: %zu\n", loadinfo->textalign); - binfo(" dataalign: %zu\n", loadinfo->dataalign); - binfo(" filelen: %ld\n", (long)loadinfo->filelen); - binfo(" filfd: %d\n", loadinfo->filfd); - binfo(" symtabidx: %d\n", loadinfo->symtabidx); - binfo(" strtabidx: %d\n", loadinfo->strtabidx); - - binfo("ELF Header:\n"); - binfo(" e_ident: %02x %02x %02x %02x\n", - loadinfo->ehdr.e_ident[0], loadinfo->ehdr.e_ident[1], - loadinfo->ehdr.e_ident[2], loadinfo->ehdr.e_ident[3]); - binfo(" e_type: %04x\n", loadinfo->ehdr.e_type); - binfo(" e_machine: %04x\n", loadinfo->ehdr.e_machine); - binfo(" e_version: %08x\n", loadinfo->ehdr.e_version); - binfo(" e_entry: %08lx\n", (long)loadinfo->ehdr.e_entry); - binfo(" e_phoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_phoff); - binfo(" e_shoff: %ju\n", (uintmax_t)loadinfo->ehdr.e_shoff); - binfo(" e_flags: %08x\n", loadinfo->ehdr.e_flags); - binfo(" e_ehsize: %d\n", loadinfo->ehdr.e_ehsize); - binfo(" e_phentsize: %d\n", loadinfo->ehdr.e_phentsize); - binfo(" e_phnum: %d\n", loadinfo->ehdr.e_phnum); - binfo(" e_shentsize: %d\n", loadinfo->ehdr.e_shentsize); - binfo(" e_shnum: %d\n", loadinfo->ehdr.e_shnum); - binfo(" e_shstrndx: %d\n", loadinfo->ehdr.e_shstrndx); - - if (loadinfo->shdr && loadinfo->ehdr.e_shnum > 0) - { - for (i = 0; i < loadinfo->ehdr.e_shnum; i++) - { - FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; - binfo("Sections %d:\n", i); -# ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - if (loadinfo->ehdr.e_type == ET_REL) - { - binfo(" sh_alloc: %08jx\n", - (uintmax_t)loadinfo->sectalloc[i]); - } -# endif - - binfo(" sh_name: %08x\n", shdr->sh_name); - binfo(" sh_type: %08x\n", shdr->sh_type); - binfo(" sh_flags: %08jx\n", (uintmax_t)shdr->sh_flags); - binfo(" sh_addr: %08jx\n", (uintmax_t)shdr->sh_addr); - binfo(" sh_offset: %ju\n", (uintmax_t)shdr->sh_offset); - binfo(" sh_size: %ju\n", (uintmax_t)shdr->sh_size); - binfo(" sh_link: %d\n", shdr->sh_link); - binfo(" sh_info: %d\n", shdr->sh_info); - binfo(" sh_addralign: %ju\n", (uintmax_t)shdr->sh_addralign); - binfo(" sh_entsize: %ju\n", (uintmax_t)shdr->sh_entsize); - } - } -} -#else -# define mod_dumploadinfo(i) -#endif - -/**************************************************************************** - * Name: mod_dumpinitializer - ****************************************************************************/ - -#ifdef CONFIG_MODLIB_DUMPBUFFER -static void mod_dumpinitializer(mod_initializer_t initializer, - FAR struct mod_loadinfo_s *loadinfo) -{ - modlib_dumpbuffer("Initializer code", (FAR const uint8_t *)initializer, - MIN(loadinfo->textsize - loadinfo->ehdr.e_entry, 512)); -} -#else -# define mod_dumpinitializer(b,l) -#endif - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -162,147 +63,7 @@ static void mod_dumpinitializer(mod_initializer_t initializer, FAR void *insmod(FAR const char *filename, FAR const char *modname) { - struct mod_loadinfo_s loadinfo; - FAR struct module_s *modp; - mod_initializer_t initializer; - FAR void (**array)(void); - int ret; - int i; - - DEBUGASSERT(filename != NULL && modname != NULL); - binfo("Loading file: %s\n", filename); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Check if this module is already installed */ - - if (modlib_registry_find(modname) != NULL) - { - ret = -EEXIST; - goto errout_with_lock; - } - - /* Initialize the ELF library to load the program binary. */ - - ret = modlib_initialize(filename, &loadinfo); - mod_dumploadinfo(&loadinfo); - if (ret != 0) - { - berr("ERROR: Failed to initialize to load module: %d\n", ret); - goto errout_with_loadinfo; - } - - /* Allocate a module registry entry to hold the module data */ - - modp = kmm_zalloc(sizeof(struct module_s)); - if (modp == NULL) - { - berr("Failed to allocate struct module_s\n"); - ret = -ENOMEM; - goto errout_with_loadinfo; - } - -#ifdef HAVE_MODLIB_NAMES - /* Save the module name in the registry entry */ - - strlcpy(modp->modname, modname, sizeof(modp->modname)); -#endif - - /* Load the program binary */ - - ret = modlib_load(&loadinfo); - mod_dumploadinfo(&loadinfo); - if (ret != 0) - { - binfo("Failed to load ELF program binary: %d\n", ret); - goto errout_with_registry_entry; - } - - /* Bind the program to the kernel symbol table */ - - ret = modlib_bind(modp, &loadinfo); - if (ret != 0) - { - binfo("Failed to bind symbols program binary: %d\n", ret); - goto errout_with_load; - } - - /* Save the load information */ - - modp->textalloc = (FAR void *)loadinfo.textalloc; - modp->dataalloc = (FAR void *)loadinfo.datastart; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = loadinfo.textsize; - modp->datasize = loadinfo.datasize; -#endif - - /* Get the module initializer entry point */ - - initializer = (mod_initializer_t)(loadinfo.textalloc + - loadinfo.ehdr.e_entry); -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = initializer; -#endif - mod_dumpinitializer(initializer, &loadinfo); - - /* Call the module initializer */ - - switch (loadinfo.ehdr.e_type) - { - case ET_REL : - ret = initializer(&modp->modinfo); - if (ret < 0) - { - binfo("Failed to initialize the module: %d\n", ret); - goto errout_with_load; - } - break; - case ET_DYN : - - /* Process any preinit_array entries */ - - array = (FAR void (**)(void))loadinfo.preiarr; - for (i = 0; i < loadinfo.nprei; i++) - { - array[i](); - } - - /* Process any init_array entries */ - - array = (FAR void (**)(void))loadinfo.initarr; - for (i = 0; i < loadinfo.ninit; i++) - { - array[i](); - } - - modp->finiarr = loadinfo.finiarr; - modp->nfini = loadinfo.nfini; - break; - } - - /* Add the new module entry to the registry */ - - modlib_registry_add(modp); - - modlib_uninitialize(&loadinfo); - modlib_registry_unlock(); - return modp; - -errout_with_load: - modlib_unload(&loadinfo); -#if CONFIG_MODLIB_MAXDEPEND > 0 - modlib_undepend(modp); -#endif -errout_with_registry_entry: - kmm_free(modp); -errout_with_loadinfo: - modlib_uninitialize(&loadinfo); -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return NULL; + return modlib_insert(filename, modname); } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modhandle.c b/sched/module/mod_modhandle.c index 13e7c55133cb8..006593feacd9d 100644 --- a/sched/module/mod_modhandle.c +++ b/sched/module/mod_modhandle.c @@ -26,11 +26,6 @@ #include -#include -#include -#include -#include - #include #include @@ -60,25 +55,7 @@ FAR void *modhandle(FAR const char *name) { - FAR struct module_s *modp; - - DEBUGASSERT(name != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Find the module entry for this name in the registry */ - - modp = modlib_registry_find(name); - if (modp == NULL) - { - berr("ERROR: Failed to find module %s\n", name); - set_errno(ENOENT); - } - - modlib_registry_unlock(); - return modp; + return modlib_gethandle(name); } #endif /* CONFIG_MODULE */ diff --git a/sched/module/mod_modsym.c b/sched/module/mod_modsym.c index f5afc7e9dcdd1..3a839a2615329 100644 --- a/sched/module/mod_modsym.c +++ b/sched/module/mod_modsym.c @@ -26,11 +26,6 @@ #include -#include -#include -#include - -#include #include #include @@ -69,50 +64,5 @@ FAR const void *modsym(FAR void *handle, FAR const char *name) { - FAR struct module_s *modp = (FAR struct module_s *)handle; - FAR const struct symtab_s *symbol; - int err; - int ret; - - /* Verify that the module is in the registry */ - - modlib_registry_lock(); - ret = modlib_registry_verify(modp); - if (ret < 0) - { - berr("ERROR: Failed to verify module: %d\n", ret); - err = -ret; - goto errout_with_lock; - } - - /* Does the module have a symbol table? */ - - if (modp->modinfo.exports == NULL || modp->modinfo.nexports == 0) - { - berr("ERROR: Module has no symbol table\n"); - err = ENOENT; - goto errout_with_lock; - } - - /* Search the symbol table for the matching symbol */ - - symbol = symtab_findbyname(modp->modinfo.exports, name, - modp->modinfo.nexports); - if (symbol == NULL) - { - berr("ERROR: Failed to find symbol in symbol \"%s\" in table\n", name); - err = ENOENT; - goto errout_with_lock; - } - - /* Return the address within the module associated with the symbol */ - - modlib_registry_unlock(); - DEBUGASSERT(symbol->sym_value != NULL); - return symbol->sym_value; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(err); - return NULL; + return modlib_getsymbol(handle, name); } diff --git a/sched/module/mod_rmmod.c b/sched/module/mod_rmmod.c index bc1470d456b7f..933ac1a15c11b 100644 --- a/sched/module/mod_rmmod.c +++ b/sched/module/mod_rmmod.c @@ -26,12 +26,6 @@ #include -#include -#include -#include -#include - -#include #include #include @@ -58,154 +52,7 @@ int rmmod(FAR void *handle) { - FAR struct module_s *modp = (FAR struct module_s *)handle; - int ret; - - DEBUGASSERT(modp != NULL); - - /* Get exclusive access to the module registry */ - - modlib_registry_lock(); - - /* Verify that the module is in the registry */ - - ret = modlib_registry_verify(modp); - if (ret < 0) - { - berr("ERROR: Failed to verify module: %d\n", ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Refuse to remove any module that other modules may depend upon. */ - - if (modp->dependents > 0) - { - berr("ERROR: Module has dependents: %d\n", modp->dependents); - ret = -EBUSY; - goto errout_with_lock; - } -#endif - - /* Is there an uninitializer? */ - - if (modp->modinfo.uninitializer != NULL) - { - /* Try to uninitialize the module */ - - ret = modp->modinfo.uninitializer(modp->modinfo.arg); - - /* Did the module successfully uninitialize? */ - - if (ret < 0) - { - berr("ERROR: Failed to uninitialize the module: %d\n", ret); - goto errout_with_lock; - } - - /* Nullify so that the uninitializer cannot be called again */ - - modp->modinfo.uninitializer = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->initializer = NULL; - modp->modinfo.arg = NULL; - modp->modinfo.exports = NULL; - modp->modinfo.nexports = 0; -#endif - } - - /* Release resources held by the module */ - - if (modp->textalloc != NULL || modp->dataalloc != NULL) - { - /* Free the module memory and nullify so that the memory cannot - * be freed again - * - * NOTE: For dynamic shared objects there is only a single - * allocation: the text/data were allocated in one operation - */ - - if (!modp->dynamic) - { -#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION - int i; - - for (i = 0; i < modp->nsect && modp->sectalloc[i] != NULL; i++) - { -# ifdef CONFIG_ARCH_USE_TEXT_HEAP - if (up_textheap_heapmember(modp->sectalloc[i])) - { - up_textheap_free(modp->sectalloc[i]); - continue; - } -# endif - -# ifdef CONFIG_ARCH_USE_DATA_HEAP - if (up_dataheap_heapmember(modp->sectalloc[i])) - { - up_dataheap_free(modp->sectalloc[i]); - continue; - } -# endif - - kmm_free(modp->sectalloc[i]); - } - - kmm_free(modp->sectalloc); - modp->sectalloc = NULL; - modp->nsect = 0; -#else -# if defined(CONFIG_ARCH_USE_TEXT_HEAP) - up_textheap_free((FAR void *)modp->textalloc); -# else - kmm_free((FAR void *)modp->textalloc); -# endif -# if defined(CONFIG_ARCH_USE_DATA_HEAP) - up_dataheap_free((FAR void *)modp->dataalloc); -# else - kmm_free((FAR void *)modp->dataalloc); -# endif -#endif - } - else - { - kmm_free((FAR void *)modp->textalloc); - } - - modp->textalloc = NULL; - modp->dataalloc = NULL; -#if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE) - modp->textsize = 0; - modp->datasize = 0; -#endif - } - - /* Remove the module from the registry */ - - ret = modlib_registry_del(modp); - if (ret < 0) - { - berr("ERROR: Failed to remove the module from the registry: %d\n", - ret); - goto errout_with_lock; - } - -#if CONFIG_MODLIB_MAXDEPEND > 0 - /* Eliminate any dependencies that this module has on other modules */ - - modlib_undepend(modp); -#endif - modlib_registry_unlock(); - - /* And free the registry entry */ - - kmm_free(modp); - return OK; - -errout_with_lock: - modlib_registry_unlock(); - set_errno(-ret); - return ERROR; + return modlib_remove(handle); } #endif /* CONFIG_MODULE */