问题描述
针对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
调用,而atexit
由register_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_fini
,atexit
,malloc
等)不包含在目标文件中?
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()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!