How to prevent inclusion of C library destructors and atexit()?

北战南征 提交于 2019-12-04 20:41:47

问题


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.

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

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);
}

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.


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?


Compile options

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

Link options

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

回答1:


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.

  • 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.

See the comments in the newlib source for more details.




回答2:


Probably you need -fno-use-cxa-atexit argument for compiler.

Look on this simple example to get working C++ code on pure bare-metal: https://github.com/cortexm/baremetal




回答3:


So here's the workaround that I'm using. Not perfect, but good enough.

Using the --wrap option of ld, I can provide my own definition for atexit that doesn't do anything.

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

and then link with --wrap=atexit option.

Now, atexit does not call any other functions and the -ffunction-sections and --gc-sections options ensure that malloc is not included in the output file.


Additionally, to enforce that malloc isn't included, a --wrap=malloc option can be passed while linking without defining __wrap_malloc anywhere. This will fail with a link error if some other function happens to use malloc.



来源:https://stackoverflow.com/questions/48711221/how-to-prevent-inclusion-of-c-library-destructors-and-atexit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!