Skip to content

Commit 6322802

Browse files
committed
arch, boards, cmake: Build C++ ELF modules without __cxa_atexit.
A C++ module with a static object does not link. GCC registers each such object's destructor with __cxa_atexit(dtor, obj, &__dso_handle), and __dso_handle comes from crtbegin, which a module does not link: hello++3.cxx:119: undefined reference to `__dso_handle' It is reachable today with CONFIG_PIC, where a module is linked as an executable and the symbol has to resolve. Without it the link is relocatable, the symbol stays undefined and nothing complains until something makes it resolve. -fno-use-cxa-atexit registers the destructors with atexit() instead, which puts them in .fini_array. That is also where libelf_uninit() looks for them when the module is unloaded, so the flag that makes the link work is also the flag that makes the destructors run. The option goes wherever CXXELFFLAGS is defined, which is the architecture Toolchain.defs and the boards that reassign it. The toolchains that are not GCC or Clang are left alone: ceva, tricore, z16 and the z80 family. The CMake build sets it once, next to where the architecture elf.cmake is included. A generator expression keeps it off the C compiles, because the option is valid for C++ alone and GCC warns about it otherwise, and the compiler id gates it so that a toolchain which is neither GCC nor Clang does not see it. It cannot go in the toolchain file itself: CMake reads that file again inside try_compile, in a project that has not included the NuttX extensions, so the call is an unknown command there. Reproduced with apps/examples/elf on mps3-an547:picostest with CONFIG_PIC enabled: hello++3 fails to link before and links after. Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Marco Casaroli <marco.casaroli@gmail.com>
1 parent 76b90e0 commit 6322802

29 files changed

Lines changed: 127 additions & 0 deletions

File tree

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,20 @@ if(EXISTS ${NUTTX_DIR}/arch/${CONFIG_ARCH}/src/cmake/elf.cmake)
516516
include(${NUTTX_DIR}/arch/${CONFIG_ARCH}/src/cmake/elf.cmake)
517517
endif()
518518

519+
# The default registers each static object's destructor with __cxa_atexit(dtor,
520+
# obj, &__dso_handle), and __dso_handle comes from crtbegin, which a module does
521+
# not link. Turning it off also puts the destructors in .fini_array, which is
522+
# where the loader looks for them when the module is unloaded.
523+
#
524+
# GCC and Clang alone take the option, which is why the architectures built by
525+
# another compiler do not carry it in their Toolchain.defs either. ARMClang
526+
# reports ARMClang, so it keeps it. The generator expression keeps the option
527+
# off the C compiles, which it is not valid for.
528+
529+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
530+
nuttx_elf_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fno-use-cxa-atexit>)
531+
endif()
532+
519533
include(platform)
520534

521535
if(CONFIG_ARCH_TOOLCHAIN_TASKING)

arch/arm/src/common/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,10 @@ CELFFLAGS = $(filter-out --fixed-r9,$(CFLAGS)) -fvisibility=hidden \
633633
CXXELFFLAGS = $(filter-out --fixed-r9,$(CXXFLAGS)) -fvisibility=hidden \
634634
-mlong-calls
635635

636+
# __dso_handle comes from crtbegin, which a module does not link
637+
638+
CXXELFFLAGS += -fno-use-cxa-atexit
639+
636640
ifeq ($(CONFIG_PIC),y)
637641
# ARCHCFLAGS, not CFLAGS: board Make.defs reassign CFLAGS with ':='
638642
# after including this file, which would discard the flag.

arch/arm64/src/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,10 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
292292
CELFFLAGS = $(CFLAGS) -fvisibility=hidden # --target1-abs
293293
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden # --target1-abs
294294

295+
# __dso_handle comes from crtbegin, which a module does not link
296+
297+
CXXELFFLAGS += -fno-use-cxa-atexit
298+
295299
LDELFFLAGS = -r -e _start
296300
ifneq ($(CONFIG_BUILD_KERNEL),y)
297301
# Flat build and protected elf entry point use crt0,

arch/avr/src/avr/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,5 +219,9 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
219219
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
220220
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
221221

222+
# __dso_handle comes from crtbegin, which a module does not link
223+
224+
CXXELFFLAGS += -fno-use-cxa-atexit
225+
222226
LDELFFLAGS = -r -e _start
223227
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/avr/src/avr32/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,9 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
115115
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
116116
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
117117

118+
# __dso_handle comes from crtbegin, which a module does not link
119+
120+
CXXELFFLAGS += -fno-use-cxa-atexit
121+
118122
LDELFFLAGS = -r -e _start
119123
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/mips/src/mips32/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,5 +332,9 @@ LDMODULEFLAGS = -EL -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld
332332
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
333333
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
334334

335+
# __dso_handle comes from crtbegin, which a module does not link
336+
337+
CXXELFFLAGS += -fno-use-cxa-atexit
338+
335339
LDELFFLAGS = -r -e _start
336340
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/misoc/src/lm32/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,5 +146,9 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
146146
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
147147
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
148148

149+
# __dso_handle comes from crtbegin, which a module does not link
150+
151+
CXXELFFLAGS += -fno-use-cxa-atexit
152+
149153
LDELFFLAGS = -r -e _start
150154
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/misoc/src/minerva/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,5 +94,9 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
9494
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
9595
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
9696

97+
# __dso_handle comes from crtbegin, which a module does not link
98+
99+
CXXELFFLAGS += -fno-use-cxa-atexit
100+
97101
LDELFFLAGS = -r -e _start
98102
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/or1k/src/mor1kx/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,5 +132,9 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
132132
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
133133
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
134134

135+
# __dso_handle comes from crtbegin, which a module does not link
136+
137+
CXXELFFLAGS += -fno-use-cxa-atexit
138+
135139
LDELFFLAGS = -r -e _start
136140
LDELFFLAGS += -T $(call CONVERT_PATH,$(TOPDIR)$(DELIM)libs$(DELIM)libc$(DELIM)elf$(DELIM)gnu-elf.ld)

arch/risc-v/src/common/Toolchain.defs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,10 @@ LDMODULEFLAGS = -r -T $(call CONVERT_PATH,$(TOPDIR)/libs/libc/elf/gnu-elf.ld)
449449
CELFFLAGS = $(CFLAGS) -fvisibility=hidden
450450
CXXELFFLAGS = $(CXXFLAGS) -fvisibility=hidden
451451

452+
# __dso_handle comes from crtbegin, which a module does not link
453+
454+
CXXELFFLAGS += -fno-use-cxa-atexit
455+
452456
LDELFFLAGS = -e _start
453457

454458
ifeq ($(CONFIG_BINFMT_ELF_RELOCATABLE),y)

0 commit comments

Comments
 (0)