mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 21:36:28 +08:00
modlib:support modlib can load PIC elf
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
@@ -35,7 +35,9 @@ SECTIONS
|
||||
|
||||
.init_array :
|
||||
{
|
||||
_sinit = .;
|
||||
*(.init_array)
|
||||
_einit = .;
|
||||
}
|
||||
|
||||
.fini_array :
|
||||
@@ -77,6 +79,11 @@ SECTIONS
|
||||
_ebss = . ;
|
||||
}
|
||||
|
||||
.got :
|
||||
{
|
||||
*(.got*)
|
||||
}
|
||||
|
||||
/* Stabs debugging sections. */
|
||||
|
||||
.stab 0 : { *(.stab) }
|
||||
|
||||
@@ -292,8 +292,8 @@ static int modlib_relocate(FAR struct module_s *modp,
|
||||
/* Get the value of the symbol (in sym.st_value) */
|
||||
|
||||
ret = modlib_symvalue(modp, loadinfo, sym,
|
||||
loadinfo->shdr[loadinfo->strtabidx].sh_offset,
|
||||
exports, nexports);
|
||||
loadinfo->shdr[loadinfo->strtabidx].sh_offset,
|
||||
exports, nexports);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* The special error -ESRCH is returned only in one condition:
|
||||
@@ -333,19 +333,75 @@ static int modlib_relocate(FAR struct module_s *modp,
|
||||
|
||||
/* Calculate the relocation address. */
|
||||
|
||||
if (rel->r_offset < 0 ||
|
||||
rel->r_offset > dstsec->sh_size)
|
||||
if (loadinfo->gotindex >= 0)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: "
|
||||
"Relocation address out of range, "
|
||||
"offset %" PRIuPTR " size %ju\n",
|
||||
relidx, i, (uintptr_t)rel->r_offset,
|
||||
(uintmax_t)dstsec->sh_size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
{
|
||||
/* Symbol type is undefined, we need to set the address
|
||||
* to the value of the symbol.
|
||||
*/
|
||||
|
||||
addr = dstsec->sh_addr + rel->r_offset;
|
||||
FAR Elf_Shdr *gotsec = &loadinfo->shdr[loadinfo->gotindex];
|
||||
FAR uintptr_t *gotaddr = (FAR uintptr_t *)(gotsec->sh_addr +
|
||||
*((FAR uintptr_t *)(dstsec->sh_addr + rel->r_offset)));
|
||||
|
||||
*gotaddr = sym->st_value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((dstsec->sh_flags & SHF_WRITE) == 0)
|
||||
{
|
||||
/* Skip relocations for read-only sections */
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Use the GOT to store the address */
|
||||
|
||||
if (rel->r_offset - dstsec->sh_offset >
|
||||
dstsec->sh_size)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: "
|
||||
"Relocation address out of range, "
|
||||
"offset %" PRIuPTR " size %ju\n",
|
||||
relidx, i, (uintptr_t)rel->r_offset,
|
||||
(uintmax_t)dstsec->sh_size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = dstsec->sh_addr + rel->r_offset - dstsec->sh_offset;
|
||||
if (ELF_ST_TYPE(sym->st_info) == STT_SECTION)
|
||||
{
|
||||
/* Symbol type is section, we need clear the address
|
||||
* and keep the original value.
|
||||
*/
|
||||
|
||||
*(FAR uintptr_t *)addr -=
|
||||
loadinfo->shdr[sym->st_shndx].sh_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal symbol, just keep it zero */
|
||||
|
||||
*(FAR uintptr_t *)addr = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rel->r_offset > dstsec->sh_size)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: "
|
||||
"Relocation address out of range, "
|
||||
"offset %" PRIuPTR " size %ju\n",
|
||||
relidx, i, (uintptr_t)rel->r_offset,
|
||||
(uintmax_t)dstsec->sh_size);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
addr = dstsec->sh_addr + rel->r_offset;
|
||||
}
|
||||
|
||||
/* Now perform the architecture-specific relocation */
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
static int modlib_section_alloc(FAR struct mod_loadinfo_s *loadinfo,
|
||||
FAR Elf_Shdr *shdr, uint8_t idx)
|
||||
{
|
||||
if (loadinfo->ehdr.e_type != ET_REL)
|
||||
if (loadinfo->ehdr.e_type != ET_DYN)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -339,7 +339,8 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
if (loadinfo->ehdr.e_type == ET_REL)
|
||||
if (loadinfo->ehdr.e_type == ET_REL ||
|
||||
loadinfo->ehdr.e_type == ET_EXEC)
|
||||
{
|
||||
pptr = (FAR uint8_t **)&loadinfo->sectalloc[i];
|
||||
}
|
||||
@@ -410,6 +411,9 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo)
|
||||
binfo("%d. %08lx->%08lx\n", i,
|
||||
(unsigned long)shdr->sh_addr, (unsigned long)*pptr);
|
||||
|
||||
/* Use offset to remember the original file address */
|
||||
|
||||
shdr->sh_offset = (uintptr_t)shdr->sh_addr;
|
||||
shdr->sh_addr = (uintptr_t)*pptr;
|
||||
|
||||
#ifdef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
@@ -425,6 +429,34 @@ static inline int modlib_loadfile(FAR struct mod_loadinfo_s *loadinfo)
|
||||
}
|
||||
}
|
||||
|
||||
/* Update GOT table */
|
||||
|
||||
if (loadinfo->gotindex >= 0)
|
||||
{
|
||||
FAR Elf_Shdr *gotshdr = &loadinfo->shdr[loadinfo->gotindex];
|
||||
FAR uintptr_t *got = (FAR uintptr_t *)gotshdr->sh_addr;
|
||||
FAR uintptr_t *end = got + gotshdr->sh_size / sizeof(uintptr_t);
|
||||
|
||||
for (; got < end; got++)
|
||||
{
|
||||
for (i = 0; i < loadinfo->ehdr.e_shnum; i++)
|
||||
{
|
||||
FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
|
||||
|
||||
if ((shdr->sh_flags & SHF_ALLOC) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*got >= shdr->sh_offset &&
|
||||
*got < shdr->sh_offset + shdr->sh_size)
|
||||
{
|
||||
*got += shdr->sh_addr - shdr->sh_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -461,6 +493,12 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
loadinfo->gotindex = modlib_findsection(loadinfo, ".got");
|
||||
if (loadinfo->gotindex >= 0)
|
||||
{
|
||||
binfo("GOT section found! index %d\n", loadinfo->gotindex);
|
||||
}
|
||||
|
||||
/* Determine total size to allocate */
|
||||
|
||||
modlib_elfsize(loadinfo, true);
|
||||
@@ -474,21 +512,23 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
||||
* GOT. Therefore we cannot do two different allocations.
|
||||
*/
|
||||
|
||||
if (loadinfo->ehdr.e_type == ET_REL)
|
||||
#ifndef CONFIG_MODLIB_LOADTO_LMA
|
||||
|
||||
if (loadinfo->ehdr.e_type == ET_REL || loadinfo->ehdr.e_type == ET_EXEC)
|
||||
{
|
||||
#ifndef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
# ifndef CONFIG_ARCH_USE_SEPARATED_SECTION
|
||||
if (loadinfo->textsize > 0)
|
||||
{
|
||||
# ifdef CONFIG_ARCH_USE_TEXT_HEAP
|
||||
# ifdef CONFIG_ARCH_USE_TEXT_HEAP
|
||||
loadinfo->textalloc = (uintptr_t)
|
||||
up_textheap_memalign(loadinfo->textalign,
|
||||
loadinfo->textsize +
|
||||
loadinfo->segpad);
|
||||
# else
|
||||
# else
|
||||
loadinfo->textalloc = (uintptr_t)lib_memalign(loadinfo->textalign,
|
||||
loadinfo->textsize +
|
||||
loadinfo->segpad);
|
||||
# endif
|
||||
# endif
|
||||
if (!loadinfo->textalloc)
|
||||
{
|
||||
berr("ERROR: Failed to allocate memory for the module text\n");
|
||||
@@ -499,14 +539,14 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
||||
|
||||
if (loadinfo->datasize > 0)
|
||||
{
|
||||
# ifdef CONFIG_ARCH_USE_DATA_HEAP
|
||||
# ifdef CONFIG_ARCH_USE_DATA_HEAP
|
||||
loadinfo->datastart = (uintptr_t)
|
||||
up_dataheap_memalign(loadinfo->dataalign,
|
||||
loadinfo->datasize);
|
||||
# else
|
||||
# else
|
||||
loadinfo->datastart = (uintptr_t)lib_memalign(loadinfo->dataalign,
|
||||
loadinfo->datasize);
|
||||
# endif
|
||||
# endif
|
||||
if (!loadinfo->datastart)
|
||||
{
|
||||
berr("ERROR: Failed to allocate memory for the module data\n");
|
||||
@@ -514,7 +554,7 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
else if (loadinfo->ehdr.e_type == ET_DYN)
|
||||
{
|
||||
@@ -535,6 +575,8 @@ int modlib_load(FAR struct mod_loadinfo_s *loadinfo)
|
||||
loadinfo->segpad;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MODLIB_LOADTO_LMA */
|
||||
|
||||
/* Load ELF section data into memory */
|
||||
|
||||
ret = modlib_loadfile(loadinfo);
|
||||
@@ -597,6 +639,12 @@ int modlib_load_with_addrenv(FAR struct mod_loadinfo_s *loadinfo)
|
||||
goto errout_with_buffers;
|
||||
}
|
||||
|
||||
loadinfo->gotindex = modlib_findsection(loadinfo, ".got");
|
||||
if (loadinfo->gotindex >= 0)
|
||||
{
|
||||
binfo("GOT section found! index %d\n", loadinfo->gotindex);
|
||||
}
|
||||
|
||||
/* Determine total size to allocate */
|
||||
|
||||
modlib_elfsize(loadinfo, false);
|
||||
|
||||
@@ -445,6 +445,10 @@ int modlib_symvalue(FAR struct module_s *modp,
|
||||
(uintptr_t)(sym->st_value + secbase));
|
||||
|
||||
sym->st_value += secbase;
|
||||
if (loadinfo->gotindex >= 0)
|
||||
{
|
||||
sym->st_value -= loadinfo->shdr[sym->st_shndx].sh_offset;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user