如何防止包含C库析构函数和atexit()? [英] How to prevent inclusion of C library destructors and atexit()?

查看:249
本文介绍了如何防止包含C库析构函数和atexit()?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using arm-none-eabi-gcc for Cortex-M4 (baremetal application), the code for malloc is also emitted even though I never use malloc in my code.

看到使用arm-none-eabi-objdump -xS obj.elf的程序集输出,似乎malloc__register_exitproc调用,而atexitregister_fini调用

Seeing the assembly output with arm-none-eabi-objdump -xS obj.elf, it seems that malloc is called by __register_exitproc called by atexit called by 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

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

However, register_fini is never called in the code. main() is called using the following startup code, so even if main exits, the destructors (or functions registered with atexit()) will not get called.

/**
 * \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);
}

该代码使用-ffunction-sections-fdata-sections进行编译,并与标志--gc-sections链接,因此所有无法访问的代码/功能都不会包含在输出文件中.

The code is compiled with -ffunction-sections and -fdata-sections and linked with the flag --gc-sections so that any unreachable code/functions are not included in the output file.

那么,如何防止我的代码中从未使用过的这些功能(register_finiatexitmalloc等)不包含在目标文件中?

So, how can I prevent these functions (register_fini, atexit, malloc, etc) that are never used in my code from being included in the object file?

编译选项

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

链接选项

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

推荐答案

在内存有限的环境(例如Cortex M4)中,另一种选择是使用newlib-nano.它提供了一个__register_exitproc()弱链接.因此,很容易使用您自己的空函数进行覆盖,从而避免调用malloc().这还将具有从二进制文件中删除__call_exitprocs()的额外好处.

In an environment with limited memory such as the Cortex M4, another option is to use newlib-nano. It provides a __register_exitproc() that is weakly linked. Therefore it is easy to override with your own empty function that avoids calling malloc(). This will have the additional benefit of removing __call_exitprocs() from your binary as well.

  • 将标志--specs=nano.specs添加到编译器和链接器选项.
  • 在已编译的代码中的某处创建以下函数: void __register_exitproc(void) { }
  • Add the flag --specs=nano.specs to your compiler and linker options.
  • Create the following function somewhere in your compiled code: void __register_exitproc(void) { }

请注意,这将防止为类的静态实例调用析构函数.在您的示例中,这似乎是适当的.

Note that this will prevent destructors being called for static instances of classes. This seems appropriate in your example.

请参见 newlib源以获取更多详细信息.

See the comments in the newlib source for more details.

这篇关于如何防止包含C库析构函数和atexit()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆