[BUG] CMake build: CONFIG_PIC gives ELF applications contradictory register flags and no -fpic, and never reserves r10 in the base firmware
- Dominant language
- C
- Stars
- 4k
- Forks
- 1.7k
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 237
Description
### Description / Steps to reproduce the issue
## Description / Steps to reproduce the issue
`CONFIG_PIC` does not appear to be wired up correctly in the CMake build. I
found three related problems while comparing it against the Makefile build, and
I am raising them together because fixing any one of them in isolation looks
wrong without a decision on the others. I have a one-line change for the first,
but it is not obviously the right thing to do on its own — hence an issue rather
than a PR.
### 1. ELF applications get two contradictory flags for the same register
`arch/arm/src/cmake/elf.cmake:30`:
```cmake
nuttx_elf_compile_options_ifdef(CONFIG_PIC --fixed-r10 -mpic-register=r10)
```
These say opposite things about r10. `-mpic-register=r10` tells the compiler
r10 holds the module's data base; `--fixed-r10` tells it r10 is unavailable.
GCC rejects the combination outright once `-fpic` is in effect:
```console
$ arm-none-eabi-gcc -mcpu=cortex-m55 -mthumb -fpic -msingle-pic-base \
--fixed-r10 -mpic-register=r10 -c t.c -o t.o
cc1: error: unable to use 'r10' for PIC register
```
It is not currently fatal only because of problem 2 below — without `-fpic` the
same pair merely warns:
```console
$ arm-none-eabi-gcc -mcpu=cortex-m55 -mthumb --fixed-r10 -mpic-register=r10 \
-c t.c -o t.o
cc1: warning: '-mpic-register=' is useless without '-fpic'
```
The Makefile build keeps the two apart deliberately: it puts `--fixed-r10` in
`CFLAGS` (base firmware) and filters it back out of `CPICFLAGS`/`CELFFLAGS`
(modules). The CMake build applies both to the module side.
To reproduce, on `master`:
```console
$ cmake -B build -DBOARD_CONFIG=mps3-an547:picostest -GNinja \
-DCMAKE_EXPORT_COMPILE_COMMANDS=1
$ grep -o -- "--fixed-r10 [^ ]*" build/compile_commands.json | head -1
--fixed-r10 -mpic-register=r10
$ ninja arch/arm/src/common/CMakeFiles/STARTUP_OBJS.dir/crt0.c.o
[1/1] Building C object arch/arm/src/common/CMakeFiles/STARTUP_OBJS.dir/crt0.c.o
cc1: warning: '-mpic-register=' is useless without '-fpic'
```
(`mps3-an547:picostest` is the only defconfig in the tree with `CONFIG_PIC=y`.)
### 2. ELF applications are not built position-independent at all
The warning above is the symptom: nothing gives these targets `-fpic` under
`CONFIG_PIC`. In the CMake build `PICFLAGS` is applied only under
`CONFIG_BUILD_PIC` (`arch/arm/src/cmake/gcc.cmake:243-248`), which is a
different feature — a position-independent kernel, using r9.
The Makefile build does give them `-fpic`, via
```make
CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS)
```
where `ARCHPICFLAGS` is `-fpic -msingle-pic-base -mpic-register=r10`. So the
two build systems disagree about whether a `CONFIG_PIC` ELF application is
position-independent, and the CMake side looks incomplete rather than
deliberately different.
### 3. The base firmware never reserves r10
`CONFIG_PIC` appears in exactly two places in the whole CMake build, both in
`elf.cmake`, both on the module side:
```console
$ grep -rn "CONFIG_PIC" --include="*.cmake" --include="CMakeLists.txt" . \
| grep -v BUILD_PIC
arch/arm/src/cmake/elf.cmake:30:nuttx_elf_compile_options_ifdef(CONFIG_PIC --fixed-r10 -mpic-register=r10)
arch/arm/src/cmake/elf.cmake:33: CONFIG_PIC --unresolved-symbols=ignore-in-object-files --emit-relocs)
```
Nothing adds `--fixed-r10` to the base firmware, so the firmware is free to
allocate r10 — the register a PIC module reaches its own data through. A base
firmware routine that calls back into module code (`qsort()` with a module
comparison function is the standard case) then arrives with a bad data base.
That is the same defect the Makefile side has, which I have raised separately
in the PR "arch/arm: stop boards silently discarding --fixed-r10".
## Why I have not simply sent a patch
Removing `--fixed-r10` from `elf.cmake:30` is a one-liner and I have it ready.
On its own, though:
- it fixes no observable failure, because problem 2 keeps the error latent;
- it does **not** silence the warning, which comes from the `-mpic-register=r10`
that remains (verified by building `crt0.c` with the change applied);
- it leaves problem 3 — the defect that actually corrupts a callback —
untouched.
Fixing problem 3 centrally is also not a one-liner. The obvious approach,
`add_compile_options(--fixed-r10)` under `CONFIG_PIC`, does not work: directory
scoped options reach the ELF application targets too, recreating exactly the
rejected combination from problem 1. I confirmed that scoping behaviour with a
minimal CMake project — a directory-level option appears on a target that also
carries its own `target_compile_options`. Doing it properly needs either a
kernel-scoped option list (the tree has `NUTTX_ELF_APP_COMPILE_OPTIONS` and
`NUTTX_MOD_APP_COMPILE_OPTIONS`, but no firmware-only equivalent) or a generator
expression keyed on a per-target marker property.
So the real question is what `CONFIG_PIC` is intended to mean in the CMake
build, which someone who knows that design should answer before flags are moved
around. I am happy to write the patch once there is a direction.
### On which OS does this issue occur?
[OS: Mac]
### What is the version of your OS?
26.5.1 (Darwin 25.5.0, arm64)
### NuttX Version
master (`7df7c6ee`)
### Issue Architecture
[Arch: arm]
### Issue Area
[Area: Build System]
### Host information
```
macOS 26.5.1 (Darwin 25.5.0, arm64)
cmake 4.3.4, ninja 1.13.1
Arm GNU Toolchain 15.2.Rel1 (arm-none-eabi-gcc 15.2.1)
```
### Verification
- [x] I have verified before submitting the report.
Contributor guide
Research direction
Start with arch/arm/src/cmake/elf.cmake and gcc.cmake, then compare the CONFIG_PIC handling with the Makefile flags. Reproduce the issue using the mps3-an547:picostest CMake/Ninja configuration and inspect build/compile_commands.json. Done means the intended CONFIG_PIC semantics are decided and the CMake build no longer emits contradictory or missing PIC/register flags, while correctly handling the base firmware.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cmake
- Domain
- build-system, embedded-iot
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100