Skip to content

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

Description

@casaroli

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:

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:

$ 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:

$ 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:

$ 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

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:

$ 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

  • I have verified before submitting the report.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Arch: armIssues related to ARM (32-bit) architectureArea: Build systemOS: MacIssues related to MacOS (building system, etc)Type: BugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions