mirror of
https://github.com/apache/nuttx.git
synced 2026-09-09 18:36:37 +00:00
libs/libc/elf: Fix two ways an FDPIC module failed to relocate.
Running one for the first time turned up two holes in the ET_DYN path. Neither shows up in a build. An undefined symbol is resolved with libelf_findglobal(), which searches only the table of globally registered symbols. The export table that exec() hands its caller went no further than the ET_REL path, so an ET_DYN module could not import anything the caller supplied. Invisible while such modules resolved everything internally; an FDPIC module imports its libc, and every import failed with "Unable to resolve addr of ext ref printf" although the caller had passed a table containing printf. The export table is now threaded into libelf_relocatedyn() and consulted when the global table has no answer, leaving the existing lookup order intact. A relocation naming a symbol defined inside the object was dropped silently. The code handles a relocation with no symbol, and one against an undefined symbol, but a defined symbol fell through both. That was harmless while every dynamic relocation arriving here had symbol index zero, which is the case for R_ARM_RELATIVE. FDPIC brings the first ones that do not: a pointer to a static function is emitted against the *section* symbol, so the value is the section base and the offset within it -- including the Thumb bit -- is carried as the addend. Deriving a value from the word being patched, as the no-symbol case does, would translate that addend as though it were an address. Confirmed against a real module: .text at 0x23c plus an addend of 0x95 gives 0x2d1, which is the function with its Thumb bit. Also stop libelf_symname() reporting a nameless symbol as an error. A section symbol has no name, and libelf_findsymbol() walks the whole table looking for optional entries such as nx_stacksize, so it meets these routinely and checks for -ESRCH itself. At error level it printed ten or more lines per module load and buried the diagnostics that matter. Built and run on lm3s6965-ek with the examples/elf ROMFS. The ET_REL test modules load as before, and an FDPIC module now loads, relocates, resolves printf and puts from the table exec() supplied, and calls through a function descriptor of its own. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
parent
450cfad383
commit
04dc50e71a
2 changed files with 62 additions and 3 deletions
|
|
@ -35,6 +35,7 @@
|
|||
#include <nuttx/arch.h>
|
||||
#include <nuttx/cache.h>
|
||||
#include <nuttx/elf.h>
|
||||
#include <nuttx/symtab.h>
|
||||
#include <nuttx/lib/elf.h>
|
||||
|
||||
#include "libc.h"
|
||||
|
|
@ -637,7 +638,9 @@ static int libelf_relocateadd(FAR struct module_s *modp,
|
|||
|
||||
static int libelf_relocatedyn(FAR struct module_s *modp,
|
||||
FAR struct mod_loadinfo_s *loadinfo,
|
||||
int relidx)
|
||||
int relidx,
|
||||
FAR const struct symtab_s *exports,
|
||||
int nexports)
|
||||
{
|
||||
FAR Elf_Shdr *shdr = &loadinfo->shdr[relidx];
|
||||
FAR Elf_Shdr *symhdr;
|
||||
|
|
@ -868,6 +871,26 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
|
|||
|
||||
ep = libelf_findglobal(modp, loadinfo, symhdr,
|
||||
&sym[idx_sym]);
|
||||
|
||||
/* libelf_findglobal() searches only the registered
|
||||
* symbols. A module from exec() has its own export
|
||||
* table, and an FDPIC module imports its libc there.
|
||||
*/
|
||||
|
||||
if (ep == NULL && exports != NULL)
|
||||
{
|
||||
FAR const struct symtab_s *sm;
|
||||
|
||||
sm = symtab_findbyname(exports,
|
||||
(FAR char *)
|
||||
loadinfo->iobuffer,
|
||||
nexports);
|
||||
if (sm != NULL)
|
||||
{
|
||||
ep = (FAR void *)sm->sym_value;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ep == NULL) && (ELF_ST_BIND(sym[idx_sym].st_info)
|
||||
!= STB_WEAK))
|
||||
{
|
||||
|
|
@ -889,6 +912,37 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
|
|||
|
||||
*(FAR uintptr_t *)addr = (uintptr_t)ep;
|
||||
}
|
||||
else if (loadinfo->fdpic)
|
||||
{
|
||||
/* A relocation naming a symbol inside this object. A
|
||||
* pointer to a static function is emitted against the
|
||||
* section symbol, so the offset, Thumb bit included, is
|
||||
* the addend and must not come from the patched word.
|
||||
*/
|
||||
|
||||
Elf_Sym defsym = sym[idx_sym];
|
||||
|
||||
defsym.st_value = libelf_addr(loadinfo,
|
||||
sym[idx_sym].st_value);
|
||||
|
||||
addr = libelf_addr(loadinfo, rel->r_offset);
|
||||
|
||||
if (reldata.relrela[idx_rel] == 1)
|
||||
{
|
||||
addr += rela->r_addend;
|
||||
}
|
||||
|
||||
ret = up_relocate(rel, &defsym, addr, ARCH_ELFDATA_PARM);
|
||||
if (ret < 0)
|
||||
{
|
||||
berr("ERROR: Section %d reloc %d: "
|
||||
"Relocation failed: %d\n", relidx, i, ret);
|
||||
lib_free(sym);
|
||||
lib_free(rels);
|
||||
lib_free(dyn);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1004,7 +1058,8 @@ int libelf_bind(FAR struct module_s *modp,
|
|||
switch (loadinfo->shdr[i].sh_type)
|
||||
{
|
||||
case SHT_DYNAMIC:
|
||||
ret = libelf_relocatedyn(modp, loadinfo, i);
|
||||
ret = libelf_relocatedyn(modp, loadinfo, i,
|
||||
exports, nexports);
|
||||
break;
|
||||
case SHT_DYNSYM:
|
||||
loadinfo->dsymtabidx = i;
|
||||
|
|
|
|||
|
|
@ -107,7 +107,11 @@ static int libelf_symname(FAR struct mod_loadinfo_s *loadinfo,
|
|||
|
||||
if (sym->st_name == 0)
|
||||
{
|
||||
berr("ERROR: Symbol has no name\n");
|
||||
/* Not a failure. A section symbol has no name, and
|
||||
* libelf_findsymbol() meets these routinely and checks for -ESRCH.
|
||||
*/
|
||||
|
||||
binfo("Symbol has no name\n");
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue