Skip to content

arch/arm: stop boards silently discarding --fixed-r10#19508

Open
casaroli wants to merge 2 commits into
apache:masterfrom
casaroli:fix-pic-fixed-register-lost
Open

arch/arm: stop boards silently discarding --fixed-r10#19508
casaroli wants to merge 2 commits into
apache:masterfrom
casaroli:fix-pic-fixed-register-lost

Conversation

@casaroli

@casaroli casaroli commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

arch/arm/src/common/Toolchain.defs adds --fixed-r10 to CFLAGS when
CONFIG_PIC is enabled. Nearly every board Make.defs includes that file and
then assigns

CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) ...

with :=, which discards it. 346 of the tree's board files contain that exact
CPICFLAGS = $(ARCHPICFLAGS) $(CFLAGS) idiom, and every one of them assigns
CFLAGS this way first.

That flag is what stops the base firmware from allocating r10 — the register a
PIC module reaches its own data through. When it is lost, a base firmware
routine that calls back into module code (qsort() with a module comparison
function is the standard case) arrives with r10 holding whatever the firmware
last put there, and the module reads its data through a bad base pointer.

The failure is silent and remote from its cause: the build succeeds, every
module loads, and only the callback misbehaves.

mps3-an547:picostest is the only defconfig in the tree that sets
CONFIG_PIC=y, so it is the only board changed here. It re-applies the flag
after the := and filters it back out of CPICFLAGS and CELFFLAGS, because
GCC rejects --fixed-r10 alongside the -mpic-register=r10 those carry once
-fpic is in effect:

cc1: error: unable to use 'r10' for PIC register

That filtering is also why the flag cannot simply move to ARCHCPUFLAGS to
survive the := — the module flags derive from CFLAGS, so it would land in
exactly that rejected combination. Toolchain.defs now records this, since the
next board to enable CONFIG_PIC will otherwise hit the same trap.

Why the second commit touches the spellcheck config

tools: exempt the "*.siz" gsize comment from codespell is unrelated to the
register, and is here only because CI will not go green without it. An existing
comment in arch/arm/src/common/Toolchain.defs reads:

# instruct the gsize to generate a "*.siz" file that contains the detailed section size

codespell reports siz ==> size, six. It is neither — .siz is the filename
extension gsize produces. The line is on master and this PR does not touch it;
it adds no line containing siz at all.

It fails anyway because tools/checkpatch.sh:224 invokes

codespell $codespell_args ${@: -1}

passing the filename, so codespell scans the whole file rather than the
changed hunks. checkpatch builds its file list from the commit range, so
editing Toolchain.defs for any reason pulls all ~600 of its lines into the
check. Confirmed by the other two PRs in this series: they do not touch that
file and report ✔️ All checks pass.

I put the line in .codespell-ignore-lines, which .codespellrc documents as
the place for exotic-but-correct occurrences, rather than in
ignore-words-list, which that file reserves for frequently used words. It is a
separate commit so it can be dropped, taken separately, or replaced with a
different remedy without disturbing the fix itself.

Impact

  • Users: affects CONFIG_PIC configurations only. mps3-an547:picostest
    now genuinely reserves r10 in the base firmware.
  • Build process: no change for the other 345 boards — they get a comment in
    Toolchain.defs and nothing else. No new warnings.
  • Hardware: none directly; changes generated code for CONFIG_PIC firmware
    only (one fewer allocatable register, which is the point).
  • Documentation / security / compatibility: unaffected.
  • Not fixed here: any board that enables CONFIG_PIC in future still needs
    the same three lines. A tree-wide mechanical change to all 346 files would
    fix it once and for all; I did not attempt that, and would rather a
    maintainer say whether it is wanted before 346 files are touched.
  • Spellcheck config: the second commit adds one line to
    .codespell-ignore-lines (see above). It changes no build behaviour and
    unblocks CI for every future PR touching Toolchain.defs, not just this one.

Testing

Board: mps3-an547:picostest — the only defconfig with CONFIG_PIC=y.

Because the failure is a lost compiler flag, the test is what the build system
computes for CFLAGS. Reproduce with:

./tools/configure.sh mps3-an547:picostest
cat > /tmp/show.mk <<'EOF'
include $(TOPDIR)/Make.defs
show:
	@echo "CONFIG_PIC = $(CONFIG_PIC)"
	@echo "CFLAGS    has --fixed-r10 : $(if $(filter --fixed-r10,$(CFLAGS)),YES,NO)"
	@echo "CPICFLAGS has --fixed-r10 : $(if $(filter --fixed-r10,$(CPICFLAGS)),YES,NO)"
	@echo "CELFFLAGS has --fixed-r10 : $(if $(filter --fixed-r10,$(CELFFLAGS)),YES,NO)"
EOF
make -f /tmp/show.mk TOPDIR=$PWD show

Before (master 7df7c6ee) — the flag is gone:

CONFIG_PIC = y
CFLAGS    has --fixed-r10 : NO
CPICFLAGS has --fixed-r10 : NO
CELFFLAGS has --fixed-r10 : NO

After this patch — firmware reserves r10, module flags do not:

CONFIG_PIC = y
CFLAGS    has --fixed-r10 : YES
CPICFLAGS has --fixed-r10 : NO
CELFFLAGS has --fixed-r10 : NO

The conflict that makes the filtering necessary, shown directly:

$ 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

$ arm-none-eabi-gcc -mcpu=cortex-m55 -mthumb -fpic -msingle-pic-base \
      -mpic-register=r10 -c t.c -o t.o          # accepted

Limitation, stated plainly: I could not produce a full link of
mps3-an547:picostest, and it is not for want of a toolchain — I repeated this
with the Arm GNU Toolchain 15.2.Rel1 (full newlib). The Makefile build of this
board does not complete on unmodified master either, for reasons unrelated
to this patch:

$ ./tools/configure.sh mps3-an547:picostest && make
arm-none-eabi-gcc: error: missing argument to '-Wstack-usage='

CONFIG_STACK_USAGE_WARNING is unset for this config, and Toolchain.defs
only omits -Wstack-usage= when the value is exactly 0, so an empty value is
passed through. Setting it to 0 gets further, and then:

make[1]: *** No rule to make target `arm_exception.S', needed by `.depend'.  Stop.
make: *** [pass2dep] Error 2

Both failures reproduce identically on master with and without this patch, so
they are pre-existing and out of scope here — but they do mean the one board in
the tree that enables CONFIG_PIC currently has no working Makefile build,
which is probably why this flag went missing unnoticed. The flag-level evidence
above is therefore the strongest available; a maintainer with a working
CONFIG_PIC build is very welcome to add a link log.

The same mechanism is exercised end-to-end in a downstream tree of mine on
RP2350 hardware, where the equivalent register (r9, for FDPIC modules) being
lost to this same := caused a firmware qsort() callback into module code to
read garbage, and re-applying the flag fixed it.

Tree checks, both commits applied:

$ ./tools/checkpatch.sh -c -u -m -g master..HEAD
Used config files:
    1: .codespellrc
✔️ All checks pass.

Without the second commit this reports
arch/arm/src/common/Toolchain.defs:485: siz ==> size, six.

@github-actions github-actions Bot added Arch: arm Issues related to ARM (32-bit) architecture Size: S The size of the change in this PR is small Board: arm labels Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

MemBrowse Memory Report

No memory changes detected for:

# misbehaves, reading its data through a register the firmware has since
# felt free to reuse.

CFLAGS += --fixed-r10

@xiaoxiang781216 xiaoxiang781216 Jul 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's move to ARCHCFLAGS instead. it's better to fix the root cause directly.

@casaroli casaroli Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that your suggestion is the correct fix, however we need to change all 500 arm files, so that ARCHPICFLAGS and CPICFLAGS all move to Toolchain.defs

This is a huge change, so I have prepared the fix in a separate PR so you can analyze and compare, and we can check the CI status:

#19510

casaroli added 2 commits July 23, 2026 11:51
Toolchain.defs adds --fixed-r10 to CFLAGS under CONFIG_PIC, but nearly
every board Make.defs includes that file and then assigns

  CFLAGS := $(ARCHCFLAGS) $(ARCHOPTIMIZATION) $(ARCHCPUFLAGS) ...

with ':=', which discards it.  266 of the 269 ARM board files assign
CFLAGS that way; the remaining three delegate to a shared makefile that
does the same thing.

The flag is what keeps the base firmware from allocating r10, the
register a PIC module reaches its own data through.  Losing it is silent
and the symptom is remote from the cause: the build succeeds, and only a
callback from base firmware into module code -- qsort() with a module
comparison function is the standard case -- misbehaves, reading its data
through a register the firmware has since felt free to reuse.

mps3-an547:picostest is the only defconfig in the tree that enables
CONFIG_PIC, so it is the only board fixed here.  It re-applies the flag
after the ':=' and filters it back out of CPICFLAGS and CELFFLAGS,
because GCC rejects --fixed-r10 alongside the -mpic-register=r10 those
carry ("unable to use 'r10' for PIC register").

That filtering is also why the flag cannot simply move to ARCHCPUFLAGS to
survive the ':=': the module flags derive from CFLAGS, so it would land
in exactly that rejected combination.  Toolchain.defs now says so, since
the next board to enable CONFIG_PIC will otherwise hit this again.

Before, with CONFIG_PIC=y:  CFLAGS has --fixed-r10: NO
After:                      CFLAGS has --fixed-r10: YES
                            CPICFLAGS/CELFFLAGS:    NO

Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
codespell reads "siz" in

  # instruct the gsize to generate a "*.siz" file that contains the
  # detailed section size

as a misspelling of "size" or "six".  It is neither: ".siz" is the
filename extension gsize produces.

The hit predates this branch and fires for anyone who touches
arch/arm/src/common/Toolchain.defs, because checkpatch scans whole files
rather than changed lines, so any PR editing that file fails CI on it.
Recorded in .codespell-ignore-lines, which the config documents as the
place for exotic-but-correct word occurrences, rather than in
ignore-words-list, which is reserved for frequently used words.

Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
@casaroli
casaroli force-pushed the fix-pic-fixed-register-lost branch from a9832ac to 7498ef2 Compare July 23, 2026 09:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arch: arm Issues related to ARM (32-bit) architecture Board: arm Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants