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);

Reply via email to