arch/arm: Keep GCC from making tail calls in an FDPIC module.

With -mfdpic and -mlong-calls, GCC turns a call to an imported function
in tail position into "ldr r3, [r9, #off]; bx r3".  The GOT slot holds
the address of the function descriptor, so the branch goes to the
descriptor in RAM instead of through it, and the core faults.  A normal
call loads the code address and the data base from the descriptor
first.  GCC 13.2 and 15.3 both do this.

Only an optimized build makes tail calls.  The C++ library of
apps/testing/fs/xipfs then faults in its constructor, which ends in a
call to syslog(), and the test stops at "stage the C++ module".

Pass -fno-optimize-sibling-calls with the other FDPIC flags, in the make
build and the CMake build.

Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
This commit is contained in:
Marco Casaroli 2026-10-07 08:09:50 +02:00 • committed by Alan C. Assis
parent 00e51b847a
commit ebabdd57f3
2 changed files with 20 additions and 6 deletions

View file

@ -58,15 +58,22 @@ if(CONFIG_FDPIC)
# GCC before 14 does not pass --fdpic to the assembler for -mfdpic, and the
# assembler then rejects the FDPIC relocations, so pass it here.
#
# With -mlong-calls, GCC turns a call in tail position into a branch to the
# function descriptor rather than through it, which faults. Keep it from
# making tail calls.
nuttx_elf_compile_options(-mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic)
set(FDPIC_FLAGS -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic
-fno-optimize-sibling-calls)
nuttx_elf_compile_options(${FDPIC_FLAGS})
nuttx_elf_link_options(-m armelf_linux_fdpiceabi -shared -z now)
# A shared library is an FDPIC shared object too, as LDMODULEFLAGS makes it in
# common/Toolchain.defs
nuttx_mod_compile_options(-mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic)
nuttx_mod_compile_options(${FDPIC_FLAGS})
nuttx_mod_link_options(-m armelf_linux_fdpiceabi -shared -z now)

View file

@ -686,9 +686,16 @@ ifeq ($(CONFIG_FDPIC),y)
# GCC before 14 does not pass --fdpic to the assembler for -mfdpic, and the
# assembler then rejects the FDPIC relocations, so pass it here.
#
# With -mlong-calls, GCC turns a call in tail position into a branch to the
# function descriptor rather than through it, which faults. Keep it from
# making tail calls.
CELFFLAGS += -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic
CXXELFFLAGS += -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic
FDPICFLAGS = -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic \
-fno-optimize-sibling-calls
CELFFLAGS += $(FDPICFLAGS)
CXXELFFLAGS += $(FDPICFLAGS)
LDELFFLAGS += -m armelf_linux_fdpiceabi -shared -z now
@ -700,8 +707,8 @@ ifeq ($(CONFIG_FDPIC),y)
# The entry point is left to the caller: a module is entered at _start,
# a library is only called into.
CMODULEFLAGS += -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic
CXXMODULEFLAGS += -mfdpic -fPIC -Wa,--noexecstack -Wa,--fdpic
CMODULEFLAGS += $(FDPICFLAGS)
CXXMODULEFLAGS += $(FDPICFLAGS)
LDMODULEFLAGS = -m armelf_linux_fdpiceabi -shared -z now \
-T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)