如何防止包含C库析构函数和atexit()?

use*_*551 9 c embedded gcc arm bare-metal

对于Cortex-M4(裸机应用程序)使用arm-none-eabi-gcc,malloc即使我从未malloc在我的代码中使用过,也会发出代码.

看到程序集输出arm-none-eabi-objdump -xS obj.elf,似乎malloc通过被__register_exitproc调用来atexit调用register_fini

004036a8 <register_fini>:
  4036a8:       4b02            ldr     r3, [pc, #8]    ; (4036b4 <register_fini+0xc>)
  4036aa:       b113            cbz     r3, 4036b2 <register_fini+0xa>
  4036ac:       4802            ldr     r0, [pc, #8]    ; (4036b8 <register_fini+0x10>)
  4036ae:       f000 b805       b.w     4036bc <atexit>
  4036b2:       4770            bx      lr
  4036b4:       00000000        .word   0x00000000
  4036b8:       004036c9        .word   0x004036c9
Run Code Online (Sandbox Code Playgroud)

但是,register_fini从未在代码中调用过.main()使用以下启动代码调用,因此即使主要退出,atexit()也不会调用析构函数(或注册的函数).

/**
 * \brief This is the code that gets called on processor reset.
 * To initialize the device, and call the main() routine.
 */
void Reset_Handler(void)
{
    uint32_t *pSrc, *pDest;

    /* Initialize the relocate segment */
    pSrc = &_etext;
    pDest = &_srelocate;

    if (pSrc > pDest) {
        for (; pDest < &_erelocate;) {
            *pDest++ = *pSrc++;
        }
    } else if (pSrc < pDest) {
        uint32_t nb_bytes = (uint32_t)&_erelocate - (uint32_t)&_srelocate;
        pSrc = (uint32_t*)((uint32_t)pSrc + nb_bytes) - 1;
        pDest = (uint32_t*)((uint32_t)pDest + nb_bytes) - 1;
        for (;nb_bytes;nb_bytes -= 4) {
            *pDest-- = *pSrc--;
        }
    }
    __NOP();

    /* Clear the zero segment */
    for (pDest = &_szero; pDest < &_ezero;) {
        *pDest++ = 0;
    }

    /* Set the vector table base address */
    pSrc = (uint32_t *) & _sfixed;
    SCB->VTOR = ((uint32_t) pSrc);

    /* Initialize the C library */
    __libc_init_array();

    /* Branch to main function */
    main();

    /* Infinite loop */
    while (1);
}
Run Code Online (Sandbox Code Playgroud)

代码编译与-ffunction-sections-fdata-sections,并与标志链接的--gc-sections,以便任何可达代码/功能不包括在输出文件中.


所以,我怎样才能阻止这些功能(register_fini,atexit,malloc等),这些从来没有在我的代码中使用被包含在目标文件中?


编译选项

arm-none-eabi-gcc -o build/main.o -c -mcpu=cortex-m4 -mthumb -pipe -g3 -Wall -Wextra -Wno-expansion-to-defined -Werror -std=gnu11 -fno-strict-aliasing -ffunction-sections -fdata-sections -DARM_MATH_CM4=true -D__SAM4SD32C__ -Ibunch -Iof -Iinclude -Idirs src/main.c
Run Code Online (Sandbox Code Playgroud)

链接选项

arm-none-eabi-g++ -o build/tnc.elf -mcpu=cortex-m4 -mthumb -pipe -Wl,--entry=Reset_Handler -Wl,--gc-sections -Wl,--script my/linker/script.ld build/src/bunch.o build/src/of.o build/src/object.o build/src/files.o build/src/main.o -lm
Run Code Online (Sandbox Code Playgroud)

vlk*_*vlk 5

也许您需要-fno-use-cxa-atexit编译器的参数。

查看这个简单的示例,在纯裸机上获取可工作的 C++ 代码: https: //github.com/cortexm/baremetal


use*_*551 3

这是我正在使用的解决方法。不完美,但足够好。

使用--wrap的选项ld,我可以提供我自己的定义,但atexit它不会执行任何操作。

int __wrap_atexit(void __attribute__((unused)) (*function)(void)) {
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

然后与--wrap=atexit选项链接。

现在,atexit不调用任何其他函数,并且-ffunction-sections--gc-sections选项确保它malloc不包含在输出文件中。


此外,为了强制malloc不包含该内容,--wrap=malloc可以在链接时传递一个选项,而无需在任何地方进行定义__wrap_malloc。如果某些其他函数碰巧使用了 ,这将失败并出现链接错误malloc