diff --git a/include/elf.h b/include/elf.h index ca982c2b18..570b2d328b 100644 --- a/include/elf.h +++ b/include/elf.h @@ -175,6 +175,9 @@ #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 +#define SHT_INIT_ARRAY 14 +#define SHT_FINI_ARRAY 15 +#define SHT_PREINIT_ARRAY 16 #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7fffffff #define SHT_LOUSER 0x80000000 diff --git a/include/elf32.h b/include/elf32.h index 1bfcb920e0..5ba13771f1 100644 --- a/include/elf32.h +++ b/include/elf32.h @@ -40,6 +40,11 @@ #define ELF32_ST_TYPE(i) ((i) & 0xf) #define ELF32_ST_INFO(b,t) (((b) << 4) | ((t) & 0xf)) +/* Generic macro to abstract ELF32/ELF64 type/bind */ + +#define ELF_ST_TYPE(a) ELF32_ST_TYPE(a) +#define ELF_ST_BIND(a) ELF32_ST_BIND(a) + /* Definitions for Elf32_Rel*::r_info */ #define ELF32_R_SYM(i) ((i) >> 8) diff --git a/include/elf64.h b/include/elf64.h index a8fb3b8abc..58dc673cb7 100644 --- a/include/elf64.h +++ b/include/elf64.h @@ -38,14 +38,23 @@ /* See ELF-64 Object File Format: Version 1.5 Draft 2 */ +#define ELF64_ST_BIND(i) ((i) >> 4) +#define ELF64_ST_TYPE(i) ((i) & 0xf) +#define ELF64_ST_INFO(b,t) (((b) << 4) | ((t) & 0xf)) + +/* Generic macro to abstract ELF32/ELF64 type/bind */ + +#define ELF_ST_TYPE(a) ELF64_ST_TYPE(a) +#define ELF_ST_BIND(a) ELF64_ST_BIND(a) + /* Definitions for Elf64_Rel*::r_info */ -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffffL) -#define ELF64_R_INFO(s,t) (((s)<< 32) + ((t) & 0xffffffffL)) +#define ELF64_R_SYM(i) ((i) >> 32) +#define ELF64_R_TYPE(i) ((i) & 0xffffffffL) +#define ELF64_R_INFO(s,t) (((s)<< 32) + ((t) & 0xffffffffL)) -#define ELF_R_SYM(i) ELF64_R_SYM(i) -#define ELF_R_TYPE(i) ELF64_R_TYPE(i) +#define ELF_R_SYM(i) ELF64_R_SYM(i) +#define ELF_R_TYPE(i) ELF64_R_TYPE(i) /**************************************************************************** * Public Type Definitions diff --git a/include/nuttx/lib/modlib.h b/include/nuttx/lib/modlib.h index 03e2f6dacf..60384e40e8 100644 --- a/include/nuttx/lib/modlib.h +++ b/include/nuttx/lib/modlib.h @@ -173,6 +173,8 @@ struct module_s FAR struct module_s *dependencies[CONFIG_MODLIB_MAXDEPEND]; #endif + uintptr_t finiarr; /* .fini_array */ + uint16_t nfini; /* Number of entries in .fini_array */ }; /* This struct provides a description of the currently loaded instantiation @@ -202,6 +204,12 @@ struct mod_loadinfo_s uint8_t *iobuffer; /* File I/O buffer */ uintptr_t datasec; /* ET_DYN - data area start from Phdr */ uintptr_t segpad; /* Padding between text and data */ + uintptr_t initarr; /* .init_array */ + uintptr_t finiarr; /* .fini_array */ + uintptr_t preiarr; /* .preinit_array */ + uint16_t ninit; /* Number of .init_array entries */ + uint16_t nfini; /* Number of .fini_array entries */ + uint16_t nprei; /* Number of .preinit_array entries */ uint16_t symtabidx; /* Symbol table section index */ uint16_t strtabidx; /* String table section index */ uint16_t dsymtabidx; /* Dynamic symbol table section index */ diff --git a/libs/libc/dlfcn/lib_dlclose.c b/libs/libc/dlfcn/lib_dlclose.c index 8a803bf116..28d139aa2c 100644 --- a/libs/libc/dlfcn/lib_dlclose.c +++ b/libs/libc/dlfcn/lib_dlclose.c @@ -57,7 +57,9 @@ 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); @@ -104,6 +106,15 @@ static inline int dlremove(FAR void *handle) /* 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; diff --git a/libs/libc/dlfcn/lib_dlopen.c b/libs/libc/dlfcn/lib_dlopen.c index e5d43b550d..d38c9f3054 100644 --- a/libs/libc/dlfcn/lib_dlopen.c +++ b/libs/libc/dlfcn/lib_dlopen.c @@ -181,7 +181,9 @@ 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); @@ -249,14 +251,37 @@ static inline FAR void *dlinsert(FAR const char *filename) /* Call the module initializer */ - if (loadinfo.ehdr.e_type == ET_REL) + switch (loadinfo.ehdr.e_type) { - ret = initializer(&modp->modinfo); - if (ret < 0) - { - binfo("Failed to initialize the module: %d\n", ret); - goto errout_with_load; - } + 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 */ diff --git a/libs/libc/modlib/modlib_bind.c b/libs/libc/modlib/modlib_bind.c index ff1efc2274..06317a29ad 100644 --- a/libs/libc/modlib/modlib_bind.c +++ b/libs/libc/modlib/modlib_bind.c @@ -591,7 +591,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp, for (i = 0; dyn[i].d_tag != DT_NULL; i++) { switch (dyn[i].d_tag) - { + { case DT_REL : relData.relOff[I_REL] = dyn[i].d_un.d_val; break; @@ -601,18 +601,18 @@ static int modlib_relocatedyn(FAR struct module_s *modp, case DT_RELENT : relData.relEntSz = dyn[i].d_un.d_val; break; - case DT_SYMTAB : - relData.symOff = dyn[i].d_un.d_val; - break; - case DT_STRTAB : - relData.strOff = dyn[i].d_un.d_val; - break; - case DT_JMPREL : - relData.relOff[I_PLT] = dyn[i].d_un.d_val; - break; - case DT_PLTRELSZ : - relData.relSz[I_PLT] = dyn[i].d_un.d_val; - break; + case DT_SYMTAB : + relData.symOff = dyn[i].d_un.d_val; + break; + case DT_STRTAB : + relData.strOff = dyn[i].d_un.d_val; + break; + case DT_JMPREL : + relData.relOff[I_PLT] = dyn[i].d_un.d_val; + break; + case DT_PLTRELSZ : + relData.relSz[I_PLT] = dyn[i].d_un.d_val; + break; } } @@ -658,10 +658,19 @@ static int modlib_relocatedyn(FAR struct module_s *modp, if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT)) { + size_t relSize = (sizeof(Elf_Rel) * + CONFIG_MODLIB_RELOCATION_BUFFERCOUNT); + + if (relData.relSz[idx_rel] < relSize) + { + relSize = relData.relSz[idx_rel]; + } + ret = modlib_read(loadinfo, (FAR uint8_t *) rels, - sizeof(Elf_Rel) * CONFIG_MODLIB_RELOCATION_BUFFERCOUNT, + relSize, relData.relOff[idx_rel] + i * sizeof(Elf_Rel)); + if (ret < 0) { berr("ERROR: Section %d reloc %d:" @@ -689,13 +698,14 @@ static int modlib_relocatedyn(FAR struct module_s *modp, if ((idx_sym = ELF_R_SYM(rel->r_info)) != 0) { - if (sym[idx_sym].st_shndx == SHN_UNDEF) /* We have an external reference */ + if (sym[idx_sym].st_shndx == SHN_UNDEF) /* We have an external reference */ { void *ep; ep = modlib_findglobal(modp, loadinfo, symhdr, &sym[idx_sym]); - if (ep == NULL) + if ((ep == NULL) && (ELF_ST_BIND(sym[idx_sym].st_info) + != STB_WEAK)) { berr("ERROR: Unable to resolve addr of ext ref %s\n", loadinfo->iobuffer); @@ -707,7 +717,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp, } addr = rel->r_offset + loadinfo->textalloc; - *(uintptr_t *)addr = (uintptr_t)ep; + *(uintptr_t *)addr = (uintptr_t)ep; } } else @@ -834,6 +844,27 @@ int modlib_bind(FAR struct module_s *modp, case SHT_DYNSYM : loadinfo->dsymtabidx = i; break; + case SHT_INIT_ARRAY : + loadinfo->initarr = loadinfo->shdr[i].sh_addr - + loadinfo->datasec + + loadinfo->datastart; + loadinfo->ninit = loadinfo->shdr[i].sh_size / + sizeof(uintptr_t); + break; + case SHT_FINI_ARRAY : + loadinfo->finiarr = loadinfo->shdr[i].sh_addr - + loadinfo->datasec + + loadinfo->datastart; + loadinfo->nfini = loadinfo->shdr[i].sh_size / + sizeof(uintptr_t); + break; + case SHT_PREINIT_ARRAY : + loadinfo->preiarr = loadinfo->shdr[i].sh_addr - + loadinfo->datasec + + loadinfo->datastart; + loadinfo->nprei = loadinfo->shdr[i].sh_size / + sizeof(uintptr_t); + break; } } else @@ -852,7 +883,7 @@ int modlib_bind(FAR struct module_s *modp, switch (loadinfo->shdr[i].sh_type) { case SHT_REL : - ret = modlib_relocate(modp, loadinfo, i); + ret = modlib_relocate(modp, loadinfo, i); break; case SHT_RELA : ret = modlib_relocateadd(modp, loadinfo, i);