libs/libc/elf: Read the dynamic relocations at their file offset.

DT_REL and DT_JMPREL hold the link-time address of their table, and the
loader read the table at that value as a file offset.  The two are equal
only when the segment that holds it starts at file offset 0.  An object
linked with its text at file offset 0x1000, as the tree's gnu-elf.ld does,
had its relocations read from padding, so none were applied and the
module called through unrelocated pointers.

Translate the address through the PT_LOAD headers first.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-09-28 20:35:27 +02:00 • committed by Alan C. Assis
parent ec78241ebe
commit 4db7594eb6

View file

@ -643,6 +643,34 @@ static int libelf_relocateadd(FAR struct module_s *modp,
return ret;
}
/****************************************************************************
* Name: libelf_fileoff
*
* Description:
* Translate a link-time address named by a dynamic tag into its offset in
* the file. They are the same only when its segment starts at offset 0.
*
****************************************************************************/
static off_t libelf_fileoff(FAR struct mod_loadinfo_s *loadinfo,
uintptr_t vaddr)
{
int i;
for (i = 0; loadinfo->phdr != NULL && i < loadinfo->ehdr.e_phnum; i++)
{
FAR Elf_Phdr *phdr = &loadinfo->phdr[i];
if (phdr->p_type == PT_LOAD && vaddr >= phdr->p_vaddr &&
vaddr - phdr->p_vaddr < phdr->p_filesz)
{
return phdr->p_offset + (vaddr - phdr->p_vaddr);
}
}
return vaddr;
}
/****************************************************************************
* Name: libelf_relocatedyn
*
@ -714,7 +742,8 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
switch (dyn[i].d_tag)
{
case DT_REL:
reldata.reloff[I_REL] = dyn[i].d_un.d_val;
reldata.reloff[I_REL] = libelf_fileoff(loadinfo,
dyn[i].d_un.d_ptr);
break;
case DT_RELSZ:
reldata.relsz[I_REL] = dyn[i].d_un.d_val;
@ -729,7 +758,8 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
reldata.stroff = dyn[i].d_un.d_val;
break;
case DT_JMPREL:
reldata.reloff[I_PLT] = dyn[i].d_un.d_val;
reldata.reloff[I_PLT] = libelf_fileoff(loadinfo,
dyn[i].d_un.d_ptr);
break;
case DT_PLTRELSZ:
reldata.relsz[I_PLT] = dyn[i].d_un.d_val;