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 e666653b807286d3481d9566d7460bfde046b37a
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Aug 3 11:34:35 2026 +0200

    libs/libc/elf: Publish FDPIC functions as descriptors for dlsym.
    
    A module that dlopen()s a library gets back function addresses from
    dlsym() and calls them.  Under FDPIC a bare code address is not enough:
    the callee needs its own data base as well, so what dlsym() returns has
    to be a function descriptor.
    
    The exported symbol table carries no type information -- symtab_s is a
    name and a value, and its own comment says typing would have to be added
    to support anything but function pointers -- so by the time dlsym() is
    asked there is no way to tell a function from an object.
    libelf_insertsymtab() is the last point that can: st_info is still in
    hand there.  So an FDPIC object's exported functions are published as the
    address of a descriptor carved from the module's pool, and dlopen(),
    dlsym() and the module registry need no knowledge of FDPIC at all.  The
    pool is sized for the dynamic symbol table as well as the relocations,
    since both can draw from it.
    
    That leaves the symbol values themselves, which were wrong for any
    ET_DYN object.  libelf_loadsymtab() adds the symbol's section address to
    its value, which is right for ET_REL, where the section address is where
    the section was actually placed and the value is relative to it.  In a
    shared object both are already full link-time addresses, so adding them
    counts the section twice.  It needs translating onto wherever the object
    was placed instead.
    
    Library data is shared between everything that dlopen()s it, because the
    registry holds one instance per name.  Giving each user its own copy
    would mean teaching the registry about instances, which is a much larger
    change to shared code; an executable loaded through exec() already gets
    its own data, since that path loads a fresh copy each time.
    
    Built and run on lm3s6965-ek with the examples/elf ROMFS; the FDPIC
    module continues to load, relocate and call through its own descriptors.
    
    Assisted-by: Claude Opus 5 (1M context) <[email protected]>
    Signed-off-by: Marco Casaroli <[email protected]>
---
 libs/libc/elf/elf_insert.c  | 16 ++++++++++++++--
 libs/libc/elf/elf_load.c    |  8 +++++---
 libs/libc/elf/elf_symbols.c | 20 ++++++++++++++++++++
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/libs/libc/elf/elf_insert.c b/libs/libc/elf/elf_insert.c
index 5b646115248..d9e7739e8de 100644
--- a/libs/libc/elf/elf_insert.c
+++ b/libs/libc/elf/elf_insert.c
@@ -247,9 +247,21 @@ static int libelf_loadsymtab(FAR struct module_s *modp,
       if (sym[i].st_shndx != SHN_UNDEF &&
           sym[i].st_shndx < loadinfo->ehdr.e_shnum)
         {
-          FAR Elf_Shdr *s = &loadinfo->shdr[sym[i].st_shndx];
+          if (loadinfo->ehdr.e_type == ET_DYN)
+            {
+              /* A shared object's symbol value is already the full
+               * link-time address.  It only needs translating onto where
+               * the object was placed.
+               */
 
-          sym[i].st_value = sym[i].st_value + s->sh_addr;
+              sym[i].st_value = libelf_addr(loadinfo, sym[i].st_value);
+            }
+          else
+            {
+              FAR Elf_Shdr *s = &loadinfo->shdr[sym[i].st_shndx];
+
+              sym[i].st_value = sym[i].st_value + s->sh_addr;
+            }
         }
     }
 
diff --git a/libs/libc/elf/elf_load.c b/libs/libc/elf/elf_load.c
index 4fbdb1cba63..b63ad6ed601 100644
--- a/libs/libc/elf/elf_load.c
+++ b/libs/libc/elf/elf_load.c
@@ -243,8 +243,9 @@ static void libelf_elfsize(FAR struct mod_loadinfo_s 
*loadinfo, bool alloc)
     }
 
   /* Reserve the descriptor pool.  R_ARM_FUNCDESC asks the loader to
-   * manufacture a descriptor after the segment is placed, and the
-   * relocation count bounds how many.
+   * manufacture a descriptor after the segment is placed, and a library
+   * publishes one per exported function for dlsym().  The relocation and
+   * dynamic symbol counts bound how many.
    */
 
   if (loadinfo->fdpic)
@@ -255,7 +256,8 @@ static void libelf_elfsize(FAR struct mod_loadinfo_s 
*loadinfo, bool alloc)
         {
           FAR Elf_Shdr *shdr = &loadinfo->shdr[i];
 
-          if (shdr->sh_type == SHT_REL && shdr->sh_entsize != 0)
+          if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_DYNSYM) &&
+              shdr->sh_entsize != 0)
             {
               nrels += shdr->sh_size / shdr->sh_entsize;
             }
diff --git a/libs/libc/elf/elf_symbols.c b/libs/libc/elf/elf_symbols.c
index aa55d595fed..488777962f5 100644
--- a/libs/libc/elf/elf_symbols.c
+++ b/libs/libc/elf/elf_symbols.c
@@ -34,6 +34,7 @@
 #include <nuttx/debug.h>
 
 #include <nuttx/symtab.h>
+#include <nuttx/fdpic.h>
 #include <nuttx/lib/elf.h>
 
 #include "libc.h"
@@ -542,6 +543,25 @@ int libelf_insertsymtab(FAR struct module_s *modp,
                       strdup((FAR char *)loadinfo->iobuffer);
                   symbol[j].sym_value =
                       (FAR const void *)(uintptr_t)sym[i].st_value;
+
+                  /* Publish an FDPIC function as a descriptor, so dlsym()
+                   * hands back something callable.  Only here does st_info
+                   * still say what is a function.
+                   */
+
+                  if (loadinfo->fdpic &&
+                      ELF_ST_TYPE(sym[i].st_info) == STT_FUNC &&
+                      loadinfo->usedesc < loadinfo->ndesc)
+                    {
+                      FAR struct fdpic_desc_s *desc =
+                        loadinfo->descpool + loadinfo->usedesc++;
+
+                      desc->entry = sym[i].st_value;
+                      desc->got   = loadinfo->gotbase;
+
+                      symbol[j].sym_value = (FAR const void *)desc;
+                    }
+
                   j++;
                 }
             }

Reply via email to