问题描述
这里是故事:我正在使用AC6 Toolpack在Linux中为ARM Cortex-M0处理器开发C ++软件.在使用Keil(在Windows中)(拥有自己的工具链)之前,我已经迁移到GNU工具链((用于ARM嵌入式处理器的GNU工具)5.2.1).我意识到的第一件事是;二进制文件的大小显着增加. 我已经测试了所有编译器的优化(链接时间优化除外,它会在内联汇编中产生错误,不是问题的一部分,但可能与答案有关).然后开始检查可执行文件(elf文件不是bin, gnu可以使用任何可用的工具(objdump,readelf,nm)生成两者.我发现一些引起大小增加的符号,重要的是:'d_print_comp_inner
','d_exprlist
','d_template_args
'.但是不知道是什么导致这些函数以二进制形式出现. (我使用了最少的库:nano newlib).长话短说,我开始一一消除代码以找到罪魁祸首.最后是抽象方法声明!
Here is the story:I am developing C++ software for ARM Cortex-M0 processor in Linux with AC6 Toolpack. Before I was using Keil (in windows) (who has their own toolchain) and I have migrated to GNU-toolchain ((GNU Tools for ARM Embedded Processors) 5.2.1) . First thing i have realized is; binary file size increased substantially. I have tested every compiler optimizations (except link time optimization, it gives an error in inline assembly, not part of question but may be related to answer). Then started to inspect executables (elf file not bin, gnu produces both) with any tool available :objdump, readelf, nm. I found some symbols causing size increase, significant ones are: 'd_print_comp_inner
' , 'd_exprlist
', 'd_template_args
'. But have no idea what is causing these functions to appear in binary. (i have used minimal libraries: nano newlib). Long story short I started to eliminate codes one by one to find culprit. At last it was Abstract Method declaration!
将功能定义为
virtual Return_type function_name(...)=0;
代替
virtual Return_type function_name(...);
添加45 KB和我提到的符号. 这是对源代码的唯一更改.基类中存在空定义.请注意:方法仍然是虚拟的,并且在子类中被覆盖
adding 45 KB and the symbols I have mentioned. And this is the only change in source code. Empty definition in base class is present. Note that: method is still virtual and overridden in child classes
不带抽象类的大小输出:
Size output without Abstract Class:
text data bss dec hex filename
15316 24 4764 20104 4e88 temc_discovery.elf
使用抽象类输出大小:
text data bss dec hex filename
61484 128 4796 66408 10368 temc_discovery.elf
这里是抽象方法时显示的符号及其大小,消除了两个版本中都显示的符号及其大小. (使用nm
工具.列表不完整,尺寸> = 0x60的列表)
Here the symbols and theirs size that shows up when method is abstract, eliminated the ones show up in both versions. (nm
tool is used. Not complete list, the ones with size >=0x60)
00002de4 t d_print_comp_inner
00001a34 t d_exprlist
00000ca4 t d_template_args
00000678 t d_type
00000574 t d_print_mod
000003f8 t d_encoding
000003e0 r cplus_demangle_operators
000003c8 t d_expression_1
000003a8 t d_name
00000354 t d_demangle_callback.constprop.15
000002e0 t d_print_mod_list
00000294 r cplus_demangle_builtin_types
00000268 t d_unqualified_name
00000244 T _printf_i
00000238 t d_print_function_type.isra.11
000001fc T _svfprintf_r
000001fc T _svfiprintf_r
000001f4 t d_print_array_type.isra.10
000001ce t d_print_cast.isra.12
0000018c t d_substitution
00000110 t d_operator_name
0000010c T __sflush_r
000000e8 T __swsetup_r
000000e6 t d_cv_qualifiers
000000e0 t d_print_subexpr
000000e0 t d_expr_primary
000000dc T _printf_common
000000cc T __cxa_demangle
000000c8 t d_source_name
000000c4 r standard_subs
000000c4 T __ssputs_r
000000b0 T __swbuf_r
000000ac T _malloc_r
000000a8 T _fputs_r
000000a4 T __smakebuf_r
000000a0 T __gnu_cxx::__verbose_terminate_handler()
00000096 t d_print_expr_op
0000008c T _free_r
0000008c t d_parmlist
0000008a t d_growable_string_callback_adapter
0000007c T __sfp
00000072 t d_append_buffer
00000068 T __sinit
00000060 d impure_data
在源代码中甚至都没有提到我熟悉的一些名称(例如printf,flush,malloc,fputs等).
Some names familiar to me (such as printf,flush,malloc,fputs etc.) are not even mentioned in the source code.
任何人不知道是什么原因导致了这种行为?
Any one with any idea what is causing this behavior?
更新:我已经用标志--noexception
禁用了异常,所以我什么也没给.事实证明,在这里提及这一点与回答有关.
Update:I was already disabling exceptions with flag --noexception
, so I haven't given any though to it. As it turns out, it is related to answer so good to mention this here.
更新2:这是最全面的网站如果您跟踪答案中的链接,请进行全部解释.
Update 2:This is the most comprehensive website explaining it all, if you track the links in answers.
推荐答案
几乎可以肯定,这是因为意外地包含了异常处理,这是libc ++内置的,无论您是否使用--noexception
编译代码正确的手法是.
It's almost certainly because of unexpected inclusion of exception handling, which libc++ has built into it, regardless of whether or not you compile your code with --noexception
or whatever the proper gnu-ism is.
有问题的异常可能是纯虚函数调用"或类似的东西(一个相当模糊的运行时错误,但是如果您在基类构造函数中调用虚函数,则可能出现).
The exception in question is probably 'pure virtual function call' or something like that (a fairly obscure runtime error to get, but possible if you call virtual functions in the base class constructor).
答案是提供您自己的空实现atexit()以及您真正不需要的任何随机标注.完成此操作后,链接器将不会拖入其他内容(拖入其他内容,拖入其他内容,等等).
The answer is to provide your own empty implementation of this, atexit(), and whatever random callout that you don't really need. Once you do that, the linker won't drag in the other stuff (which drags in other stuff, which drags in other stuff, etc).
void __cxa_pure_virtual(void)
{
BKPT();
}
这是我在项目中所拥有的,尽管您的libc ++版本中的情况可能已更改
Is what I have on our project, though things may have changed in your version of libc++
这篇关于声明抽象类(纯虚方法)会大大增加二进制文件的大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!