繁体   English   中英

为 arm cortex M3 编译 c++ 时对 _fini 和 __dso_handle 的未定义引用

[英]Undefined reference to _fini and __dso_handle when compiling c++ for arm cortex M3

我正在尝试为 arm cortex-m3 编译 c++ 代码。 当我使用任何 class 的 static 变量时,它具有自定义析构函数(例如 std::function<>),我收到以下错误:

/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: CMakeFiles/app.dir/src/acc_lis.cpp.obj: in function `unsigned char* std::__copy_move<false, true, std::random_access_iterator_tag>::__copy_m<unsigned char>(unsigned char const*, unsigned char const*, unsigned char*)':
/Applications/ARM/arm-none-eabi/include/c++/10.3.1/bits/stl_algobase.h:426: undefined reference to `__dso_handle'
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/lib/thumb/v7-m/nofp/libg.a(lib_a-fini.o): in function `__libc_fini_array':
fini.c:(.text.__libc_fini_array+0x20): undefined reference to `_fini'
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: app.elf: hidden symbol `__dso_handle' isn't defined
/Applications/ARM/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: final link failed: bad value

根据我的阅读,问题是 c++ 在调用 exit() 后尝试调用析构函数(我没有手动调用)。 __dso_handle 可以通过添加 -fno-use-cxa-atexit 标志来解决,但我不知道如何处理 _fini 符号。

编译器/链接器标志:

set(CMAKE_C_FLAGS "-mcpu=cortex-m3 -mthumb -std=gnu11 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELEASE "-Os")
set(CMAKE_C_FLAGS_DEBUG "-g -Og -fno-move-loop-invariants")

set(CMAKE_CXX_FLAGS "-mcpu=cortex-m3 -mthumb -std=c++11 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -fno-exceptions")
set(CMAKE_CXX_FLAGS_RELEASE "-Os")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Og -fno-move-loop-invariants")

set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> -Wl,--start-group <OBJECTS> <LINK_LIBRARIES> -Wl,--end-group -o <TARGET>")
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> -Wl,--start-group <OBJECTS> <LINK_LIBRARIES> -Wl,--end-group -o <TARGET>")
set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Xlinker --gc-sections -Xlinker --sort-section -Xlinker alignment --specs=nosys.specs")

SET(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
SET(CMAKE_ASM_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
SET(CMAKE_ASM_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")

Linker 脚本(部分):

SECTIONS
{
    .text :
    {
        . = ALIGN(4);
        KEEP(*(.interrupt_vector))

        KEEP(*(.reset))

        . = ALIGN(4);
        *(.rodata.boot.*)

        /* Pre-initialization Code */
        . = ALIGN(4);
        PROVIDE_HIDDEN (__preinit_array_start__ = .);

        /* System initialization and the platform initialization (if present)
         * should be first */
        KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
        KEEP(*(.preinit_array_platform .preinit_array_platform.*))

        /* Pre-initialization functions (to be executed before C++
         * constructors are run) */
        KEEP(*(.preinit_array .preinit_array.*))

        PROVIDE_HIDDEN (__preinit_array_end__ = .);

        /* Initialization Code */
        . = ALIGN(4);
        PROVIDE_HIDDEN (__init_array_start__ = .);

        KEEP(*(SORT(.init_array.*)))
        KEEP(*(.init_array))

        PROVIDE_HIDDEN (__init_array_end__ = .);

        . = ALIGN(4);

        *(.text .text.*)            /* all remaining code */
        *(.rodata .rodata.*)        /* read-only data (constants) */

        . = ALIGN(4);
        __dsp_start__ = . ;
        KEEP(*(.dsp .dsp.*))        /* all remaining DSP code */
        __dsp_end__ = . ;

        . = ALIGN(4);
    } >FLASH
    
    .ARM.exidx :
    {
      PROVIDE_HIDDEN (__exidx_start = .);
      *(.ARM.exidx* .gnu.linkonce.armexidx.*)
      PROVIDE_HIDDEN (__exidx_end = .);
    } >FLASH

    . = ALIGN(4);
    __data_init__ = .;

    /* Place the SystemClock variable needed for CMSIS in a place that is
     * compatible with the ROM's placement of this variable so that the
     * variable can be used by CMSIS and the ROM's flash write libary */
    .systemclock (NOLOAD) :
    {
        . = ALIGN(4);
        KEEP(*(.systemclock))
    } > DRAM

    .data  : AT ( __data_init__ )
    {
        . = ALIGN(4);

        /* This is used by the startup code to initialize the .data section */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)
        *(.data .data.*)
        *(.data_end .data_end.*)

        /* Place sleep and wakeup routines in retention RAM
         * Wakeup_From_Sleep_Application_asm has to followed directly by
         * Wakeup_From_Sleep_Application */
        *(.app_wakeup_asm)
        KEEP(*(.app_wakeup))
        KEEP(*(.sys_powermodes_wakeup_2mbps))

        . = ALIGN(4);

        /* This is used by the startup code to initialize the .data section */
        __data_end__ = . ;

    } >DRAM

    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        __bss_start__ = .;
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)

        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;
    } >DRAM

    .noinit (NOLOAD) :
    {
        . = ALIGN(4);
        __noinit_start__ = .;

        *(.noinit .noinit.*)

         . = ALIGN(4) ;
        __noinit_end__ = .;
    } > DRAM

    /* Check if there is enough space to allocate the main stack */
    ._stack (NOLOAD) :
    {
        . = ALIGN(4);
        . = . + __Main_Stack_Size ;
        . = ALIGN(4);
    } >DRAM

    . = __data_init__ + (__data_end__ - __data_start__);
    PROVIDE(__flash_end__ = ALIGN(2048));
    PROVIDE(__code_size = __flash_end__ - ORIGIN(FLASH));
}

基于 initfini.c 的libc 源,_fini 和 _init 分别用于模块初始化/取消初始化。 由于嵌入的代码不应该从主程序中退出,__libc_fini_array 不会被调用,而__libc_fini_array 也不会调用 _fini()。 不幸的是,stl 的部分调用 exit() 定义为:

uint8_t i;    
for (i = 0; i < atexit_count; i++) {
    atexit_funcs[i]();
}

__libc_fini_array();
_exit(return_code);

重新启动整个问题。 使用 nosys.specs 时,没有定义 _fini function,但我们可以定义自己的来解决这个问题。

/* Make sure you have C linkage when defining in c++ file */
extern "C"
void _fini()
{
    /* Either leave empty, or infinite loop here */
    while (true)
        __asm volatile ("NOP");
}

此外,还需要在 linker 脚本中为 __libc_fini_array 提供 __fini_array_start 和 __fini_array_end,但仅此而已。


请注意,如果我们支持动态分配,我们可以通过调用 operator new 来延迟初始化 object 时完全跳过这个问题,或者使用 std::aligned_storage 和placement new 来避免一起调用析构函数。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM