casaroli opened a new pull request, #3682:
URL: https://github.com/apache/nuttx-apps/pull/3682

   ## Summary
   
   The apps half of the FDPIC ELF loader: 
https://github.com/apache/nuttx/pull/19584. Two commits, both new directories, 
both guarded by `CONFIG_FDPIC`.
   
   `examples/fdpicxip` demonstrates FDPIC modules executed in place out of 
XIPFS. It writes modules into the volume at run time, the way a download would, 
then runs them. Four subcommands, one loader property each: `qsort` is one 
self-contained module as two concurrent instances, sharing a single copy of its 
text in flash while each instance gets its own data; `solib` adds a shared 
library, so two objects are mapped and each instance gets its own copy of both 
objects' data; `cxx` is the same in C++, which additionally requires each 
object's global constructors to have run in dependency order before `main`; and 
`jmprel` is a module whose imports are all in `DT_JMPREL` rather than `DT_REL`. 
It is the FDPIC counterpart of `examples/nxflatxip`, kept separate because one 
program demonstrating both module formats would demonstrate neither clearly.
   
   `testing/fs/xipfs` grows two sections, `fdpic` and `reject`, so a loader 
regression fails a test rather than waiting to be noticed on someone's board. 
They belong in the xipfs suite because what they exercise is modules loaded 
*out of the filesystem* — the pin, the in-place mapping and the loader are one 
path. `fdpic` covers the properties that otherwise fail silently: constructors 
in dependency order, per-instance data, the manufactured `R_ARM_FUNCDESC` 
descriptors, both relocation tables, the GOT fallback for a leaf library with 
no `DT_PLTGOT`, and every firmware entry point that has to resolve a module 
callback, including `mq_notify` and `timer_create` with `SIGEV_THREAD`. Each 
module reports its own invariants through its exit status, because a callback 
that never runs is the failure being tested for. `reject` mutates a known-good 
module and asserts the loader refuses it rather than loading something broken.
   
   The modules are embedded as C headers rather than built as part of either 
app, because linking one needs `arm-uclinuxfdpiceabi` binutils, which building 
NuttX does not. Their sources are in `examples/fdpicxip/modules` with a 
makefile that regenerates every header on an explicit `make regen 
NUTTX_DIR=...`, never as part of the application build. That one makefile 
writes the headers both apps embed, so the two cannot drift apart, and it 
drives the tooling in `nuttx/tools/fdpic`. `CPU` is `cortex-m3` there 
deliberately: a v7-M module also runs on the v8-M targets, so one set of blobs 
serves both the RP2350 and `mps2-an500`, whereas a `cortex-m33` build produces 
blobs a Cortex-M7 cannot execute at all.
   
   ## Impact
   
   New feature, off by default. Both `CONFIG_EXAMPLES_FDPICXIP` and the two new 
test sections require `CONFIG_FDPIC`, which defaults to `n`, so a tree without 
it is unaffected. The new sections in `testing/fs/xipfs` are `#ifdef 
CONFIG_FDPIC`, so an existing xipfs test configuration behaves exactly as 
before.
   
   Both apps build with a plain `arm-none-eabi` toolchain, because the module 
blobs are committed. Nothing invokes `modules/`; regeneration is opt-in.
   
   No change to any existing app.
   
   ## Testing
   
   Host: macOS 26.5.1 on arm64. Arm GNU Toolchain 15.2.Rel1 
(`arm-none-eabi-gcc` 15.2.1), `arm-uclinuxfdpiceabi-ld` from GNU Binutils 2.43, 
QEMU 11.0.3.
   
   **QEMU, `mps2-an500` (Cortex-M7, ARMv7E-M)**, xipfs on a `rammtd` device 
that answers `BIOC_XIPBASE`. Full `xipfs_test` suite, which is the 90 
filesystem checks plus the 40 this PR adds:
   
   ```
   ==== 130 passed, 0 failed ====
   ```
   
   The two new sections on their own:
   
   ```
   nsh> xipfs_test fdpic
   ==== 33 passed, 0 failed ====
   
   nsh> xipfs_test reject
   -- FDPIC loader rejections --
     PASS  a non-32-bit ELF class is refused
     PASS  a non-ET_DYN object is refused
     PASS  a module for the wrong machine is refused
     PASS  a module with RELA PLT relocations is refused
     PASS  a module whose needed library is absent is refused
     PASS  a module importing an unexported symbol is refused
     PASS  a module with too many DT_NEEDED entries is refused
   ==== 7 passed, 0 failed ====
   ```
   
   The demo, all four subcommands. `solib`:
   
   ```
   nsh> fdpicxip solib
   === FDPIC shared library, executed in place ===
   
   staged libcounter.so (2052 bytes) and user (2732 bytes)
     libcounter.so text at 0x6000cd20
     user          text at 0x6000dd20
   
   spawning two instances, each bumping by its own seed...
   
   [while running] pins on the library's shared text = 2
   
   [user 1] library total = 3 (expected 3) -- PASS
   [user 2] library total = 6 (expected 6) -- PASS
   
   [after exit]    pins on the library's shared text = 0
   ```
   
   `cxx`, showing each object's constructors ran, the library's before the 
module's, and the destructors on unload:
   
   ```
   nsh> fdpicxip cxx
     [libshape] Registry() ran
     [libshape] Registry() ran
   [user 1] own ctor ran: yes, library ctor ran: yes, library first: yes
   [user 2] own ctor ran: yes, library ctor ran: yes, library first: yes
   [while running] pins on the library's shared text = 2
   
   [user 1] library total = 3 (expected 3) -- PASS
     [libshape] ~Registry() ran after 3 adds
   [user 2] library total = 6 (expected 6) -- PASS
     [libshape] ~Registry() ran after 3 adds
   
   [after exit]    pins on the library's shared text = 0
   ```
   
   `qsort` runs two instances with no library behind them, and `jmprel` 
confirms a module bound through `DT_JMPREL` reaches the firmware and returns.
   
   **Hardware, Pimoroni Pico Plus 2 (RP2350, Cortex-M33, ARMv8-M)** against 
real QSPI flash, `pimoroni-pico-2-plus:xipfs-fdpic`: full suite 130/130, 
`fdpic` 33/33, `reject` 7/7, and all four demo subcommands. The same blobs run 
on both cores.
   
   **Simulator, `sim:xipfs`** on the host, confirming the new sections are 
correctly guarded — the loader is ARM-only, so only the 90 filesystem checks 
run and nothing regressed:
   
   ```
   ==== 90 passed, 0 failed ====
   ```
   
   **Blob provenance is reproducible.** `make -C examples/fdpicxip/modules 
regen NUTTX_DIR=...` rebuilds all 15 headers from the committed sources and 
reproduces the committed bytes exactly, so the blobs can be audited against 
their sources.
   
   **Assertions verified against deliberate breakage.** Each check in the 
`fdpic` section was confirmed to fail when the loader property it names is 
broken. On Cortex-M that manifests as a HardFault taking the system down 
mid-test rather than a FAIL line, so a run that ends without its summary line 
is a failure, not a hang.
   
   `tools/checkpatch.sh -f` passes on every changed C, C++ and header file, 
including the generated `*_bin.h`.
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   
   https://claude.ai/code/session_01X77FVXXW4bvvBtfFmz1JPz
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to