From 77f263b4fa3096d488dc12f9e098e29aff3f8687 Mon Sep 17 00:00:00 2001 From: Marco Casaroli Date: Fri, 28 Aug 2026 18:35:28 +0200 Subject: [PATCH] cmake: Build FDPIC modules the way the make build does. The same two differences as in common/Toolchain.defs: the compiler is told -mfdpic -fPIC, and the module link is done by an arm-uclinuxfdpiceabi linker. That linker is not the one that links the firmware, so the module link needs a variable of its own. CMAKE_ELF_LD is the ordinary linker unless the architecture sets it, which arm does under CONFIG_FDPIC. The linker script needs nothing here: it is generated from libs/libc/elf/gnu-elf.ld.in, which both build systems preprocess, and the FDPIC segments are already in it. -r is now conditional on CONFIG_PIC being off, which is what common/Toolchain.defs has always done and the cmake build did not: a position independent module is linked as an executable, and an FDPIC one as a shared object, so neither wants it. -fno-use-cxa-atexit mirrors CXXELFFLAGS for the same reason it was added there. Configured and built mps3-an547:picostest with CONFIG_FDPIC through cmake and ninja: the modules in bin/ are ARM FDPIC with two PT_LOAD segments. Signed-off-by: Marco Casaroli --- arch/arm/src/cmake/elf.cmake | 45 +++++++++++++++++++++++++------ cmake/nuttx_add_application.cmake | 12 +++++++-- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/arch/arm/src/cmake/elf.cmake b/arch/arm/src/cmake/elf.cmake index 7108aa4c174..91b1037d631 100644 --- a/arch/arm/src/cmake/elf.cmake +++ b/arch/arm/src/cmake/elf.cmake @@ -27,17 +27,46 @@ nuttx_mod_compile_options(-fvisibility=hidden -mlong-calls) nuttx_elf_compile_options_ifdef(CONFIG_UNWINDER_ARM -fno-unwind-tables -fno-asynchronous-unwind-tables) -# An ELF module needs r9 as its PIC base, so it must not also have the register -# fixed: GCC rejects that pair with "unable to use 'r9' for PIC register". This -# mirrors CELFFLAGS in common/Toolchain.defs, which filters --fixed-r9 back out -# of the inherited CFLAGS for the same reason. +if(CONFIG_FDPIC) -nuttx_elf_compile_options_ifdef(CONFIG_PIC -mpic-register=r9) + # An FDPIC module is a shared object whose two segments the loader places + # independently. The stock compiler emits correct FDPIC objects for both C + # and C++, so only the link needs the arm-uclinuxfdpiceabi linker: the stock + # one carries the armelf emulation alone and would turn every import into a + # jump slot where the ABI wants a function descriptor. -nuttx_elf_link_options_ifdef( - CONFIG_PIC --unresolved-symbols=ignore-in-object-files --emit-relocs) + if(NOT FDPIC_CROSSDEV) + set(FDPIC_CROSSDEV arm-uclinuxfdpiceabi-) + endif() -nuttx_elf_link_options_ifdef(CONFIG_BINFMT_ELF_RELOCATABLE -r) + set(CMAKE_ELF_LD + "${FDPIC_CROSSDEV}ld" + CACHE INTERNAL "Linker for FDPIC modules") + + nuttx_elf_compile_options(-mfdpic -fPIC -Wa,--noexecstack) + + nuttx_elf_link_options(-m armelf_linux_fdpiceabi -shared -z now) + +elseif(CONFIG_PIC) + + # An ELF module needs r9 as its PIC base, so it must not also have the + # register fixed: GCC rejects that pair with "unable to use 'r9' for PIC + # register". This mirrors CELFFLAGS in common/Toolchain.defs, which filters + # --fixed-r9 back out of the inherited CFLAGS for the same reason. + + nuttx_elf_compile_options(-mpic-register=r9) + + nuttx_elf_link_options(--unresolved-symbols=ignore-in-object-files + --emit-relocs) + +endif() + +# Not with CONFIG_PIC: there the module is linked as an executable, which is +# what common/Toolchain.defs does too. + +if(CONFIG_BINFMT_ELF_RELOCATABLE AND NOT CONFIG_PIC) + nuttx_elf_link_options(-r) +endif() nuttx_mod_link_options(-r) diff --git a/cmake/nuttx_add_application.cmake b/cmake/nuttx_add_application.cmake index 4864eaedbd6..bf4b626ce93 100644 --- a/cmake/nuttx_add_application.cmake +++ b/cmake/nuttx_add_application.cmake @@ -149,7 +149,15 @@ function(nuttx_add_application) if(TARGET STARTUP_OBJS) add_dependencies(${TARGET} STARTUP_OBJS) endif() - if(NOT "${CMAKE_LD}" MATCHES "gcc$") + # A module may need a different linker from the one that links the + # firmware: an FDPIC module does, because the stock linker cannot + # produce one. CMAKE_ELF_LD is that linker, and it is the ordinary one + # unless the architecture says otherwise. + + if(NOT CMAKE_ELF_LD) + set(CMAKE_ELF_LD ${CMAKE_LD}) + endif() + if(NOT "${CMAKE_ELF_LD}" MATCHES "gcc$") set(USE_LINKER True) endif() if(STACKSIZE) @@ -179,7 +187,7 @@ function(nuttx_add_application) POST_BUILD COMMAND # add default link option - ${CMAKE_LD} -T ${NUTTX_BINARY_DIR}/gnu-elf.ld + ${CMAKE_ELF_LD} -T ${NUTTX_BINARY_DIR}/gnu-elf.ld # add global MOD link option if dynlib link $<$:$> # add global ELF link option if m&kernel link