Fix and improve dynamic loader
This patch fixes some issues found by Mark Stevens and improve the dynamic loader.
This commit is contained in:
parent
4d285cb14d
commit
878384fef0
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user