[6/10] libs/libc/machine/arm: Relocate FDPIC function descriptors - #20089
Open
casaroli wants to merge 1 commit into
Open
[6/10] libs/libc/machine/arm: Relocate FDPIC function descriptors#20089casaroli wants to merge 1 commit into
casaroli wants to merge 1 commit into
Conversation
casaroli
requested review from
anchao,
antmerlino,
jerpelea,
masayuki2009,
pussuw,
xiaoxiang781216 and
yamt
as code owners
September 8, 2026 12:34
|
casaroli
force-pushed
the
fdpic-arm-reloc
branch
2 times, most recently
from
September 8, 2026 19:57
7f42251 to
cfce0a3
Compare
| *(FAR uintptr_t *)addr = (uintptr_t)ep; | ||
| } | ||
| } | ||
| else if (loadinfo->fdpic) |
Contributor
There was a problem hiding this comment.
can we share the same else if and else block, let up_relocate handle the difference?
Contributor
There was a problem hiding this comment.
but no change here?
A function pointer under FDPIC is not a code address. Because each PT_LOAD segment is placed independently, a pointer has to carry the data base its callee will need, so it is a two-word descriptor: the entry point, and the base to install in the PIC register before branching. R_ARM_FUNCDESC_VALUE says "the thing you are patching is such a descriptor", and R_ARM_FUNCDESC says "manufacture one and give me its address". Both need state a relocation cannot carry. A descriptor's second word is the *object's* data base, from DT_PLTGOT, and R_ARM_FUNCDESC carves descriptors from a pool whose cursor has to survive from one relocation to the next. up_relocate() is handed only a relocation, a resolved symbol and an address to patch. arch_data is the existing channel for exactly this -- RISC-V already uses it to remember a HI20 relocation while its LO12 partner is processed -- but nothing has ever put loader state into it: it is declared zeroed and written only by up_relocate() itself. So ARCH_ELFDATA_INIT and ARCH_ELFDATA_FINI are added, seeding the block from the loadinfo before the relocation loop and reading the cursor back after. Both default to nothing, so an architecture that does not define them is unaffected, and RISC-V's use of arch_data is untouched. libelf_relocatedyn() walks both dynamic tables under one arch_data, so the cursor spans the whole object. The addend handling is the part that is easy to get wrong. REL format keeps the addend in place, in the word about to become the entry point, and a pointer to a static function is referenced through its *section* symbol -- the value is the section base and the offset, including the Thumb bit, is entirely in the addend. Dropping it yields an even address and the core faults trying to execute it as ARM code. The GOT written into a descriptor is the loading object's own, even for an imported function, which is what makes a callback work: when the base firmware's qsort() calls back into a module's comparison function, the module needs its own data base in the PIC register. libelf_relocatedyn()'s imported-symbol path needed a change to suit. It stores the resolved address directly and never calls up_relocate(), which cannot produce a two-word descriptor, so under FDPIC the resolved value now goes through up_relocate() and the relocation type decides what to write. Implemented for armv7-m and armv8-m, the profiles FDPIC targets; the other ARM variants gain the arch_data block but no new relocations. Built and booted mps3-an547:picostest and lm3s6965-ek:qemu-nxflat, the ELF PIC and NXFLAT users of this code, both unchanged. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
casaroli
force-pushed
the
fdpic-arm-reloc
branch
from
September 10, 2026 08:18
cfce0a3 to
74836bc
Compare
xiaoxiang781216
approved these changes
Sep 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[5/10]#19942 places an FDPIC object's segments and reads its dynamic tags. This relocates it.A function pointer under FDPIC is not a code address. The two
PT_LOADsegments are placed independently, so a pointer has to carry the data base its callee needs: a two word descriptor of entry point and base.R_ARM_FUNCDESC_VALUEsays the word being patched is such a descriptor;R_ARM_FUNCDESCsays to manufacture one and store its address.Both need state a relocation cannot carry. The second word is the object's own data base, from
DT_PLTGOT, andR_ARM_FUNCDESCtakes descriptors from a pool whose cursor must survive from one relocation to the next.up_relocate()gets only a relocation, a symbol and an address.arch_datais the existing channel for that; RISC-V already uses it to hold a HI20 relocation while its LO12 partner is processed. Nothing has ever seeded it from the loader, soARCH_ELFDATA_INITandARCH_ELFDATA_FINIare added. Both default to nothing.The GOT written into a descriptor is always the loading object's own, even for an imported function. That is what makes a callback work: when the firmware's
qsort()calls into a module's comparison function, the module needs its own base in the PIC register.Impact
Nothing changes without
CONFIG_FDPIC.ARCH_ELFDATA_INIT/FINIare empty when an architecture does not define them, and RISC-V's use ofarch_datais untouched.An FDPIC relocation in an object whose OS/ABI byte does not say FDPIC is now refused rather than mis-applied.
Implemented for armv7-m and armv8-m, the profiles FDPIC targets. Other ARM variants gain the
arch_elfdata_tfields but no new relocations.Testing
mps3-an547:picosteston QEMU, which is the ELF PIC user of this code: it loads PIC ELF modules from a romfs,helloprints andostestruns through the timed mutex test, the same as without this patch.pimoroni-pico-2-plus:xipfs-fdpicbuilds withCONFIG_FDPICon and off.tools/checkpatch.sh -c -u -m -gpasses.