From 4db7594eb66f69b21fb737abc4ad9befb76d7326 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Mon, 28 Sep 2026 20:35:27 +0200 Subject: [PATCH] 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 --- libs/libc/elf/elf_bind.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/libs/libc/elf/elf_bind.c b/libs/libc/elf/elf_bind.c index f59c413f117..510b336c614 100644 --- a/libs/libc/elf/elf_bind.c +++ b/libs/libc/elf/elf_bind.c @@ -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;