modlib:support modlib can load PIC elf

Signed-off-by: anjiahao <anjiahao@xiaomi.com>
This commit is contained in:
anjiahao 2024-07-03 15:33:48 +08:00 committed by GUIDINGLI
parent cfc90ad1f3
commit 112b6fd9a5
8 changed files with 174 additions and 30 deletions

View File

@ -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

View File

@ -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

View File

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

View File

@ -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.
*

View File

@ -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) }

View File

@ -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 */

View File

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

View File

@ -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;
}