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 04dc50e71afded336404f09f3b38846b1470ffee
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Aug 3 11:28:49 2026 +0200

    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) <[email protected]>
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/elf/elf_bind.c    | 59 +++++++++++++++++++++++++++++++++++++++++++--
 libs/libc/elf/elf_symbols.c |  6 ++++-
 2 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/libs/libc/elf/elf_bind.c b/libs/libc/elf/elf_bind.c
index 4abfbdf2a5d..5409b79bfbb 100644
--- a/libs/libc/elf/elf_bind.c
+++ b/libs/libc/elf/elf_bind.c
@@ -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;
diff --git a/libs/libc/elf/elf_symbols.c b/libs/libc/elf/elf_symbols.c
index 39ad66f0858..aa55d595fed 100644
--- a/libs/libc/elf/elf_symbols.c
+++ b/libs/libc/elf/elf_symbols.c
@@ -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;
     }
 

Reply via email to