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]
