Fix and improve dynamic loader

This patch fixes some issues found by Mark Stevens and
improve the dynamic loader.
This commit is contained in:
Neale Ferguson
2023-07-12 14:37:56 -03:00
committed by Xiang Xiao
parent 4d285cb14d
commit 878384fef0
7 changed files with 122 additions and 30 deletions
+3
View File
@@ -175,6 +175,9 @@
#define SHT_REL 9 #define SHT_REL 9
#define SHT_SHLIB 10 #define SHT_SHLIB 10
#define SHT_DYNSYM 11 #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_LOPROC 0x70000000
#define SHT_HIPROC 0x7fffffff #define SHT_HIPROC 0x7fffffff
#define SHT_LOUSER 0x80000000 #define SHT_LOUSER 0x80000000
+5
View File
@@ -40,6 +40,11 @@
#define ELF32_ST_TYPE(i) ((i) & 0xf) #define ELF32_ST_TYPE(i) ((i) & 0xf)
#define ELF32_ST_INFO(b,t) (((b) << 4) | ((t) & 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 */ /* Definitions for Elf32_Rel*::r_info */
#define ELF32_R_SYM(i) ((i) >> 8) #define ELF32_R_SYM(i) ((i) >> 8)
+14 -5
View File
@@ -38,14 +38,23 @@
/* See ELF-64 Object File Format: Version 1.5 Draft 2 */ /* 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 */ /* Definitions for Elf64_Rel*::r_info */
#define ELF64_R_SYM(i) ((i) >> 32) #define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffffL) #define ELF64_R_TYPE(i) ((i) & 0xffffffffL)
#define ELF64_R_INFO(s,t) (((s)<< 32) + ((t) & 0xffffffffL)) #define ELF64_R_INFO(s,t) (((s)<< 32) + ((t) & 0xffffffffL))
#define ELF_R_SYM(i) ELF64_R_SYM(i) #define ELF_R_SYM(i) ELF64_R_SYM(i)
#define ELF_R_TYPE(i) ELF64_R_TYPE(i) #define ELF_R_TYPE(i) ELF64_R_TYPE(i)
/**************************************************************************** /****************************************************************************
* Public Type Definitions * Public Type Definitions
+8
View File
@@ -173,6 +173,8 @@ struct module_s
FAR struct module_s *dependencies[CONFIG_MODLIB_MAXDEPEND]; FAR struct module_s *dependencies[CONFIG_MODLIB_MAXDEPEND];
#endif #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 /* 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 */ uint8_t *iobuffer; /* File I/O buffer */
uintptr_t datasec; /* ET_DYN - data area start from Phdr */ uintptr_t datasec; /* ET_DYN - data area start from Phdr */
uintptr_t segpad; /* Padding between text and data */ 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 symtabidx; /* Symbol table section index */
uint16_t strtabidx; /* String table section index */ uint16_t strtabidx; /* String table section index */
uint16_t dsymtabidx; /* Dynamic symbol table section index */ uint16_t dsymtabidx; /* Dynamic symbol table section index */
+11
View File
@@ -57,7 +57,9 @@
static inline int dlremove(FAR void *handle) static inline int dlremove(FAR void *handle)
{ {
FAR struct module_s *modp = (FAR struct module_s *)handle; FAR struct module_s *modp = (FAR struct module_s *)handle;
void (**array)(void);
int ret; int ret;
int i;
DEBUGASSERT(modp != NULL); DEBUGASSERT(modp != NULL);
@@ -104,6 +106,15 @@ static inline int dlremove(FAR void *handle)
/* Nullify so that the uninitializer cannot be called again */ /* Nullify so that the uninitializer cannot be called again */
modp->modinfo.uninitializer = NULL; 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) #if defined(CONFIG_FS_PROCFS) && !defined(CONFIG_FS_PROCFS_EXCLUDE_MODULE)
modp->initializer = NULL; modp->initializer = NULL;
modp->modinfo.arg = NULL; modp->modinfo.arg = NULL;
+32 -7
View File
@@ -181,7 +181,9 @@ static inline FAR void *dlinsert(FAR const char *filename)
struct mod_loadinfo_s loadinfo; struct mod_loadinfo_s loadinfo;
FAR struct module_s *modp; FAR struct module_s *modp;
mod_initializer_t initializer; mod_initializer_t initializer;
void (**array)(void);
int ret; int ret;
int i;
binfo("Loading file: %s\n", filename); binfo("Loading file: %s\n", filename);
@@ -249,14 +251,37 @@ static inline FAR void *dlinsert(FAR const char *filename)
/* Call the module initializer */ /* Call the module initializer */
if (loadinfo.ehdr.e_type == ET_REL) switch (loadinfo.ehdr.e_type)
{ {
ret = initializer(&modp->modinfo); case ET_REL :
if (ret < 0) ret = initializer(&modp->modinfo);
{ if (ret < 0)
binfo("Failed to initialize the module: %d\n", ret); {
goto errout_with_load; 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 */ /* Add the new module entry to the registry */
+49 -18
View File
@@ -591,7 +591,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
for (i = 0; dyn[i].d_tag != DT_NULL; i++) for (i = 0; dyn[i].d_tag != DT_NULL; i++)
{ {
switch (dyn[i].d_tag) switch (dyn[i].d_tag)
{ {
case DT_REL : case DT_REL :
relData.relOff[I_REL] = dyn[i].d_un.d_val; relData.relOff[I_REL] = dyn[i].d_un.d_val;
break; break;
@@ -601,18 +601,18 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
case DT_RELENT : case DT_RELENT :
relData.relEntSz = dyn[i].d_un.d_val; relData.relEntSz = dyn[i].d_un.d_val;
break; break;
case DT_SYMTAB : case DT_SYMTAB :
relData.symOff = dyn[i].d_un.d_val; relData.symOff = dyn[i].d_un.d_val;
break; break;
case DT_STRTAB : case DT_STRTAB :
relData.strOff = dyn[i].d_un.d_val; relData.strOff = dyn[i].d_un.d_val;
break; break;
case DT_JMPREL : case DT_JMPREL :
relData.relOff[I_PLT] = dyn[i].d_un.d_val; relData.relOff[I_PLT] = dyn[i].d_un.d_val;
break; break;
case DT_PLTRELSZ : case DT_PLTRELSZ :
relData.relSz[I_PLT] = dyn[i].d_un.d_val; relData.relSz[I_PLT] = dyn[i].d_un.d_val;
break; break;
} }
} }
@@ -658,10 +658,19 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
if (!(i % CONFIG_MODLIB_RELOCATION_BUFFERCOUNT)) 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, ret = modlib_read(loadinfo, (FAR uint8_t *) rels,
sizeof(Elf_Rel) * CONFIG_MODLIB_RELOCATION_BUFFERCOUNT, relSize,
relData.relOff[idx_rel] + relData.relOff[idx_rel] +
i * sizeof(Elf_Rel)); i * sizeof(Elf_Rel));
if (ret < 0) if (ret < 0)
{ {
berr("ERROR: Section %d reloc %d:" 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 ((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; void *ep;
ep = modlib_findglobal(modp, loadinfo, symhdr, ep = modlib_findglobal(modp, loadinfo, symhdr,
&sym[idx_sym]); &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", berr("ERROR: Unable to resolve addr of ext ref %s\n",
loadinfo->iobuffer); loadinfo->iobuffer);
@@ -707,7 +717,7 @@ static int modlib_relocatedyn(FAR struct module_s *modp,
} }
addr = rel->r_offset + loadinfo->textalloc; addr = rel->r_offset + loadinfo->textalloc;
*(uintptr_t *)addr = (uintptr_t)ep; *(uintptr_t *)addr = (uintptr_t)ep;
} }
} }
else else
@@ -834,6 +844,27 @@ int modlib_bind(FAR struct module_s *modp,
case SHT_DYNSYM : case SHT_DYNSYM :
loadinfo->dsymtabidx = i; loadinfo->dsymtabidx = i;
break; 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 else
@@ -852,7 +883,7 @@ int modlib_bind(FAR struct module_s *modp,
switch (loadinfo->shdr[i].sh_type) switch (loadinfo->shdr[i].sh_type)
{ {
case SHT_REL : case SHT_REL :
ret = modlib_relocate(modp, loadinfo, i); ret = modlib_relocate(modp, loadinfo, i);
break; break;
case SHT_RELA : case SHT_RELA :
ret = modlib_relocateadd(modp, loadinfo, i); ret = modlib_relocateadd(modp, loadinfo, i);