This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 4db7594eb66f69b21fb737abc4ad9befb76d7326
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Sep 28 20:35:27 2026 +0200

    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 <[email protected]>
---
 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;

Reply via email to