【问题标题】:How to prevent inclusion of C library destructors and atexit()?如何防止包含 C 库析构函数和 atexit()?
【发布时间】:2018-07-20 13:00:35
【问题描述】:

arm-none-eabi-gcc 用于Cortex-M4(裸机应用程序),即使我从未在我的代码中使用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

但是,register_fini 从未在代码中调用。 main() 使用以下启动代码调用,因此即使 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);
}

代码使用-ffunction-sections-fdata-sections 编译并与标志--gc-sections 链接,因此任何无法访问的代码/函数都不会包含在输出文件中。


那么,我怎样才能防止我的代码中从未使用过的这些函数(register_finiatexitmalloc 等)被包含在目标文件中?


编译选项

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

【问题讨论】:

  • 您使用的任何函数是否隐式调用atexit()?使用 fopen()printf() 等函数可能会导致为流安装退出处理程序,以便在退出时刷新它们。
  • 您是否编译自己的“newlib”C 库?如果是这样,您可以在构建它时使用--disable-newlib-atexit-dynamic-alloc ./configure 选项来防止atexit 使用malloc
  • 列出您在gcc 中使用的所有选项,以便我们更好地了解您实际在做什么。 (-ffreestanding?-nodefaultlibs?-nostdlib?)
  • @NominalAnimal 已添加到问题中。我需要 stdib 中的一些函数(memcpymemset、数学函数等)
  • @IanAbbott 不,我自己没有编译 libc。似乎使用了/usr/arm-none-eabi/lib/thumb/v7e-m/libc.a。 (使用 gcc-arm-embedded ppa 时安装)。 (不确定这是否是新库)

标签: c gcc arm embedded bare-metal


【解决方案1】:

您可能需要-fno-use-cxa-atexit 编译器参数。

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

【讨论】:

    【解决方案2】:

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

    • 将标志 --specs=nano.specs 添加到您的编译器和链接器选项中。
    • 在编译代码的某处创建以下函数: void __register_exitproc(void) { }

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

    更多详情请参阅newlib source 中的 cmets。

    【讨论】:

    • 这确实有效,即使没有 __register_exitproc!虽然我不得不为 -specs 选项使用一个破折号。
    【解决方案3】:

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

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

    int __wrap_atexit(void __attribute__((unused)) (*function)(void)) {
        return -1;
    }
    

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

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


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

    【讨论】:

      【解决方案4】:

      -nostartfiles-nostdlib 在类似的环境中为我工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-05
        • 2014-01-15
        • 2021-10-24
        • 2015-02-21
        • 1970-01-01
        相关资源
        最近更新 更多