This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 878384fef0 Fix and improve dynamic loader
878384fef0 is described below
commit 878384fef040dc57f8d117a92c2a128dad694bc0
Author: Neale Ferguson <[email protected]>
AuthorDate: Wed Jul 12 14:37:56 2023 -0300
Fix and improve dynamic loader
This patch fixes some issues found by Mark Stevens and
improve the dynamic loader.
---
include/elf.h | 3 ++
include/elf32.h | 5 ++++
include/elf64.h | 19 ++++++++----
include/nuttx/lib/modlib.h | 8 +++++
libs/libc/dlfcn/lib_dlclose.c | 11 +++++++
libs/libc/dlfcn/lib_dlopen.c | 39 +++++++++++++++++++-----
libs/libc/modlib/modlib_bind.c | 67 ++++++++++++++++++++++++++++++------------
7 files changed, 122 insertions(+), 30 deletions(-)
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);