apache / apache/nuttx

[BUG] CMake build: CONFIG_PIC gives ELF applications contradictory register flags and no -fpic, and never reserves r10 in the base firmware

Open
#19,509 1 comment 0 reactions 0 assignees View on GitHub
Arch: arm Area: Build system OS: Mac Type: Bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.