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 014ea57042cd8813537f43d3f936c613118f2ead
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Aug 3 00:49:15 2026 +0200

    libs/libc/elf: Translate link-time addresses through one place.
    
    The ET_DYN path computes run-time addresses from link-time ones in five
    places, each open-coding the arithmetic, and two of them disagree about
    how: libelf_relocatedyn() adds textalloc to a relocation's r_offset in
    one branch and subtracts datasec before adding datastart in the next,
    while the value translation a few lines further down picks between those
    two forms with an explicit test on datasec.
    
    Collect that into libelf_addr(), which makes the test once: an address
    below the data segment's link-time base belongs to text, anything at or
    above it to data.
    
    This changes nothing today.  libelf_elfsize() sets
    
      segpad   = datasec - (text_vaddr + textsize)
    
    and libelf_load() then places
    
      datastart = textalloc + textsize + segpad
    
    so datastart - datasec is textalloc, and the data branch reduces to
    textalloc + vaddr -- exactly what the text branch returns, and exactly
    what adding a single load bias did before.  The two forms are the same
    arithmetic written twice.
    
    They stop being the same once text and data are placed independently,
    which is what an FDPIC object requires: its two PT_LOAD segments are
    relocated separately so that the read-only one can be mapped in place on
    the media while only the writable one is copied.  Having the translation
    in one function is what makes that possible without auditing every
    open-coded expression again.
    
    Built for mps3-an547:picostest, which is CONFIG_ELF with CONFIG_PIC, and
    boots identically to the same configuration without this change.
    
    Assisted-by: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/elf/elf.h      | 28 ++++++++++++++++++++++++++++
 libs/libc/elf/elf_bind.c | 31 ++++++++++---------------------
 2 files changed, 38 insertions(+), 21 deletions(-)

diff --git a/libs/libc/elf/elf.h b/libs/libc/elf/elf.h
index 986a3fa5803..7d5a7bcd671 100644
--- a/libs/libc/elf/elf.h
+++ b/libs/libc/elf/elf.h
@@ -238,6 +238,34 @@ int libelf_reallocbuffer(FAR struct mod_loadinfo_s 
*loadinfo,
 
 int libelf_freebuffers(FAR struct mod_loadinfo_s *loadinfo);
 
+/****************************************************************************
+ * Name: libelf_addr
+ *
+ * Description:
+ *   Translate a link-time address in a loaded object to the address it
+ *   occupies now.  An address below the data segment's link-time base
+ *   belongs to text, anything at or above it to data.
+ *
+ * Input Parameters:
+ *   loadinfo - Load state information
+ *   vaddr    - The link-time address to translate
+ *
+ * Returned Value:
+ *   The run-time address.
+ *
+ ****************************************************************************/
+
+static inline uintptr_t libelf_addr(FAR struct mod_loadinfo_s *loadinfo,
+                                    uintptr_t vaddr)
+{
+  if (loadinfo->datasec != 0 && vaddr >= loadinfo->datasec)
+    {
+      return loadinfo->datastart + (vaddr - loadinfo->datasec);
+    }
+
+  return loadinfo->textalloc + vaddr;
+}
+
 #ifdef CONFIG_ARCH_ADDRENV
 
 /****************************************************************************
diff --git a/libs/libc/elf/elf_bind.c b/libs/libc/elf/elf_bind.c
index 34f3fddf79d..c712ac6f5f0 100644
--- a/libs/libc/elf/elf_bind.c
+++ b/libs/libc/elf/elf_bind.c
@@ -831,7 +831,7 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
                         return ret;
                       }
 
-                    addr = rel->r_offset + loadinfo->textalloc;
+                    addr = libelf_addr(loadinfo, rel->r_offset);
 
                     if (reldata.relrela[idx_rel] == 1)
                       {
@@ -848,23 +848,15 @@ static int libelf_relocatedyn(FAR struct module_s *modp,
                   0
                 };
 
-              addr = rel->r_offset - loadinfo->datasec + loadinfo->datastart;
+              addr = libelf_addr(loadinfo, rel->r_offset);
 
               if (reldata.relrela[idx_rel] == 1)
                 {
                   addr += rela->r_addend;
                 }
 
-              if ((*(FAR uint32_t *)addr) < loadinfo->datasec)
-                {
-                  dynsym.st_value = *(FAR uint32_t *)addr +
-                                    loadinfo->textalloc;
-                }
-              else
-                {
-                  dynsym.st_value = *(FAR uint32_t *)addr -
-                                    loadinfo->datasec + loadinfo->datastart;
-                }
+              dynsym.st_value = libelf_addr(loadinfo,
+                                            *(FAR uint32_t *)addr);
 
               ret = up_relocate(rel, &dynsym, addr, ARCH_ELFDATA_PARM);
             }
@@ -968,23 +960,20 @@ int libelf_bind(FAR struct module_s *modp,
                 loadinfo->dsymtabidx = i;
                 break;
               case SHT_INIT_ARRAY:
-                loadinfo->initarr = loadinfo->shdr[i].sh_addr -
-                                    loadinfo->datasec +
-                                    loadinfo->datastart;
+                loadinfo->initarr = libelf_addr(loadinfo,
+                                                loadinfo->shdr[i].sh_addr);
                 loadinfo->ninit = loadinfo->shdr[i].sh_size /
                                   sizeof(uintptr_t);
                 break;
               case SHT_FINI_ARRAY:
-                loadinfo->finiarr = loadinfo->shdr[i].sh_addr -
-                                    loadinfo->datasec +
-                                    loadinfo->datastart;
+                loadinfo->finiarr = libelf_addr(loadinfo,
+                                                loadinfo->shdr[i].sh_addr);
                 loadinfo->nfini = loadinfo->shdr[i].sh_size /
                                   sizeof(uintptr_t);
                 break;
               case SHT_PREINIT_ARRAY:
-                loadinfo->preiarr = loadinfo->shdr[i].sh_addr -
-                                    loadinfo->datasec +
-                                    loadinfo->datastart;
+                loadinfo->preiarr = libelf_addr(loadinfo,
+                                                loadinfo->shdr[i].sh_addr);
                 loadinfo->nprei = loadinfo->shdr[i].sh_size /
                                   sizeof(uintptr_t);
                 break;

Reply via email to