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 450cfad3830127a0f4ec0b5c1816fcf5e919548b Author: Marco Casaroli <[email protected]> AuthorDate: Mon Aug 3 08:49:25 2026 +0200 libs/libc/elf: Read the dynamic tags an FDPIC object needs. libelf_relocatedyn() reads the handful of DT_* tags it needs to walk the relocation tables and ignores the rest. Three more matter now. DT_PLTGOT is where the object's data base lives. An FDPIC module runs with that in the PIC base register, and every function descriptor built for it names the same base as the one its callee should run with, so without it there is nothing to put in a descriptor's second word. The DT_*_ARRAY tags are the constructor and destructor tables. These are already found through the section headers a few lines further down, and that path is kept, but the dynamic tags are the authoritative copy and an object is not obliged to carry section headers at all. Both paths now translate through libelf_addr(), so they agree on the answer rather than depending on which ran last. The tag values themselves were missing from include/elf.h and are added. Sizing the descriptor pool has to happen here rather than later. R_ARM_FUNCDESC asks the loader to manufacture a descriptor and hand back its address, which means the space must exist by the time the relocation is applied, and by then the segment has been placed. So libelf_elfsize() reserves it behind the writable data, bounded by the relocation count -- one relocation cannot ask for more than one descriptor. That bound has slack in it, but a descriptor is two words and modules are small, which is cheaper than walking every relocation twice to get an exact count. Nothing here runs for a non-FDPIC object. Built and booted mps3-an547:picostest with no change in behaviour. Assisted-by: Claude Opus 5 (1M context) <[email protected]> Signed-off-by: Marco Casaroli <[email protected]> --- include/elf.h | 6 ++++++ include/nuttx/lib/elf.h | 16 ++++++++++++++++ libs/libc/elf/elf_bind.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ libs/libc/elf/elf_load.c | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) diff --git a/include/elf.h b/include/elf.h index f940dbabb67..fdecf44c075 100644 --- a/include/elf.h +++ b/include/elf.h @@ -279,6 +279,12 @@ #define DT_TEXTREL 22 /* d_un=ignored */ #define DT_JMPREL 23 /* d_un=d_ptr */ #define DT_BINDNOW 24 /* d_un=ignored */ +#define DT_INIT_ARRAY 25 /* d_un=d_ptr */ +#define DT_FINI_ARRAY 26 /* d_un=d_ptr */ +#define DT_INIT_ARRAYSZ 27 /* d_un=d_val */ +#define DT_FINI_ARRAYSZ 28 /* d_un=d_val */ +#define DT_PREINIT_ARRAY 32 /* d_un=d_ptr */ +#define DT_PREINIT_ARRAYSZ 33 /* d_un=d_val */ #define DT_LOPROC 0x70000000 /* d_un=unspecified */ #define DT_HIPROC 0x7fffffff /* d_un= unspecified */ diff --git a/include/nuttx/lib/elf.h b/include/nuttx/lib/elf.h index 1648da450e5..7eee93fe61e 100644 --- a/include/nuttx/lib/elf.h +++ b/include/nuttx/lib/elf.h @@ -168,6 +168,8 @@ typedef CODE int (*mod_initializer_t)(FAR struct mod_info_s *modinfo); struct module_s; typedef CODE int (*mod_callback_t)(FAR struct module_s *modp, FAR void *arg); +struct fdpic_desc_s; + /* This describes the file to be loaded. */ struct module_s @@ -276,6 +278,20 @@ struct mod_loadinfo_s FAR struct file *pinfile; #endif + /* The object's data base, from DT_PLTGOT. An FDPIC module runs with this + * in the PIC base register. + */ + + uintptr_t gotbase; + + /* Pool of function descriptors behind the writable segment. Reserved + * when the segment is sized, and bounded by the relocation count. + */ + + FAR struct fdpic_desc_s *descpool; + uint16_t ndesc; /* Capacity */ + uint16_t usedesc; /* Next free slot */ + /* Address environment. * * addrenv - This is the handle created by addrenv_allocate() that can be diff --git a/libs/libc/elf/elf_bind.c b/libs/libc/elf/elf_bind.c index dddb626add8..4abfbdf2a5d 100644 --- a/libs/libc/elf/elf_bind.c +++ b/libs/libc/elf/elf_bind.c @@ -712,12 +712,61 @@ static int libelf_relocatedyn(FAR struct module_s *modp, case DT_PLTRELSZ: reldata.relsz[I_PLT] = dyn[i].d_un.d_val; break; + case DT_PLTGOT: + + /* The object's data base. Every function descriptor built + * for it names this base. + */ + + loadinfo->gotbase = dyn[i].d_un.d_ptr; + break; + + /* The constructor and destructor tables. Section headers are + * optional, so the dynamic tags are the authoritative copy. + */ + + case DT_INIT_ARRAY: + loadinfo->initarr = libelf_addr(loadinfo, dyn[i].d_un.d_ptr); + break; + + case DT_INIT_ARRAYSZ: + loadinfo->ninit = dyn[i].d_un.d_val / sizeof(uintptr_t); + break; + + case DT_FINI_ARRAY: + loadinfo->finiarr = libelf_addr(loadinfo, dyn[i].d_un.d_ptr); + break; + + case DT_FINI_ARRAYSZ: + loadinfo->nfini = dyn[i].d_un.d_val / sizeof(uintptr_t); + break; + + case DT_PREINIT_ARRAY: + loadinfo->preiarr = libelf_addr(loadinfo, dyn[i].d_un.d_ptr); + break; + + case DT_PREINIT_ARRAYSZ: + loadinfo->nprei = dyn[i].d_un.d_val / sizeof(uintptr_t); + break; + case DT_PLTREL: if (dyn[i].d_un.d_val == DT_REL) { reldata.relentsz[I_PLT] = sizeof(Elf_Rel); reldata.relrela[I_PLT] = 0; } + else if (loadinfo->fdpic) + { + /* The ARM FDPIC ABI is REL throughout. RELA entries are + * longer, so walking them as REL reads the wrong place. + */ + + berr("ERROR: FDPIC object claims RELA PLT relocations\n"); + lib_free(sym); + lib_free(rels); + lib_free(dyn); + return -ENOEXEC; + } else { reldata.relentsz[I_PLT] = sizeof(Elf_Rela); diff --git a/libs/libc/elf/elf_load.c b/libs/libc/elf/elf_load.c index ceea2eb2d59..4fbdb1cba63 100644 --- a/libs/libc/elf/elf_load.c +++ b/libs/libc/elf/elf_load.c @@ -40,6 +40,7 @@ #include <nuttx/debug.h> #include <nuttx/arch.h> +#include <nuttx/fdpic.h> #include <nuttx/lib/elf.h> #include <nuttx/fs/fs.h> #include <nuttx/fs/ioctl.h> @@ -241,6 +242,31 @@ 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. + */ + + if (loadinfo->fdpic) + { + size_t nrels = 0; + + for (i = 0; i < loadinfo->ehdr.e_shnum; i++) + { + FAR Elf_Shdr *shdr = &loadinfo->shdr[i]; + + if (shdr->sh_type == SHT_REL && shdr->sh_entsize != 0) + { + nrels += shdr->sh_size / shdr->sh_entsize; + } + } + + loadinfo->ndesc = nrels; + datasize += nrels * sizeof(struct fdpic_desc_s); + + binfo("fdpic: reserving %zu descriptors behind the data\n", nrels); + } + /* An ET_DYN object is sized from its program headers, which give no * section alignment. A word is enough. */ @@ -822,6 +848,14 @@ int libelf_load(FAR struct mod_loadinfo_s *loadinfo) goto errout_with_buffers; } } + + /* The pool was reserved at the end of the segment when it was + * sized, so it starts that many descriptors back from the end. + */ + + loadinfo->descpool = (FAR struct fdpic_desc_s *) + (loadinfo->datastart + loadinfo->datasize) - + loadinfo->ndesc; } else {
