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;
