modlib:support modlib can load PIC elf
Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
parent
cfc90ad1f3
commit
112b6fd9a5
|
@ -502,11 +502,21 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/modlib/gnu-elf.ld)
|
|||
|
||||
# ELF module definitions
|
||||
|
||||
CELFFLAGS = $(CFLAGS) -fvisibility=hidden -mlong-calls # --target1-abs
|
||||
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
|
||||
ifeq ($(CONFIG_PIC),y)
|
||||
CFLAGS += --fixed-r10
|
||||
PICFLAGS = -fpic -fPIE -mno-pic-data-is-text-relative \
|
||||
-msingle-pic-base -mpic-register=r10
|
||||
|
||||
LDELFFLAGS = -r -e main
|
||||
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)modlib$(DELIM)gnu-elf.ld)
|
||||
# Generate an executable elf, need to ignore undefined symbols
|
||||
LDELFFLAGS += --unresolved-symbols=ignore-in-object-files --emit-relocs
|
||||
else
|
||||
LDELFFLAGS += -r
|
||||
endif
|
||||
|
||||
CELFFLAGS = $(CFLAGS) $(PICFLAGS) -fvisibility=hidden -mlong-calls # --target1-abs
|
||||
CXXELFFLAGS = $(CXXFLAGS) $(PICFLAGS) -fvisibility=hidden
|
||||
|
||||
LDELFFLAGS += -e main -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)modlib$(DELIM)gnu-elf.ld)
|
||||
|
||||
# Zig toolchain
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ config BINFMT_LOADABLE
|
|||
Automatically selected if a loadable binary format is selected.
|
||||
|
||||
config PIC
|
||||
bool
|
||||
bool "Executable elf position-independent support"
|
||||
default n
|
||||
---help---
|
||||
Automatically selected if the binary format requires position
|
||||
|
|
20
binfmt/elf.c
20
binfmt/elf.c
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/binfmt/binfmt.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#ifdef CONFIG_ELF
|
||||
|
||||
|
@ -119,7 +120,7 @@ static int elf_loadbinary(FAR struct binary_s *binp,
|
|||
|
||||
/* Bind the program to the exported symbol table */
|
||||
|
||||
if (loadinfo.ehdr.e_type == ET_REL)
|
||||
if (loadinfo.ehdr.e_type == ET_REL || loadinfo.gotindex >= 0)
|
||||
{
|
||||
ret = modlib_bind(&binp->mod, &loadinfo, exports, nexports);
|
||||
if (ret != 0)
|
||||
|
@ -207,6 +208,23 @@ static int elf_loadbinary(FAR struct binary_s *binp,
|
|||
#endif
|
||||
|
||||
modlib_dumpentrypt(&loadinfo);
|
||||
#ifdef CONFIG_PIC
|
||||
if (loadinfo.gotindex >= 0)
|
||||
{
|
||||
FAR struct dspace_s *dspaces = kmm_zalloc(sizeof(struct dspace_s));
|
||||
|
||||
if (dspaces == NULL)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_load;
|
||||
}
|
||||
|
||||
dspaces->region = (FAR void *)loadinfo.shdr[loadinfo.gotindex].sh_addr;
|
||||
dspaces->crefs = 1;
|
||||
binp->picbase = (FAR void *)dspaces;
|
||||
}
|
||||
#endif
|
||||
|
||||
modlib_uninitialize(&loadinfo);
|
||||
return OK;
|
||||
|
||||
|
|
|
@ -231,6 +231,7 @@ struct mod_loadinfo_s
|
|||
uint16_t buflen; /* size of iobuffer[] */
|
||||
int filfd; /* Descriptor for the file being loaded */
|
||||
int nexports; /* ET_DYN - Number of symbols exported */
|
||||
int gotindex; /* Index to the GOT section */
|
||||
|
||||
/* Address environment.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue