这是故事背景:
我正在Linux中使用AC6 Toolpack为ARM Cortex-M0处理器开发C++软件。之前我使用Keil(在windows上)(他们有自己的工具链),现在我已经迁移到GNU-toolchain(GNU工具套件 for ARM嵌入式处理器5.2.1)。第一件事我意识到的是,二进制文件大小显著增加。
我测试了每种编译器优化(除了链接时优化,它会在内联汇编时出错,不是问题的一部分,但可能与答案相关)。然后开始使用任何可用的工具来检查可执行文件(elf文件而不是bin文件,gnu可以生成两个):objdump、readelf、nm。我发现一些符号导致了大小的增加,其中最重要的是:“d_print_comp_inner”,“d_exprlist”和“d_template_args”。但我不知道什么导致这些函数出现在二进制文件中。(我只使用了最小限度的库:nano newlib)。长话短说,我开始逐个消除代码,试图找到问题所在。最后,我发现问题出在抽象方法声明上!
将函数定义为
virtual Return_type function_name(...)=0;
替代
virtual Return_type function_name(...);
添加了45 KB和我提到的符号。 这是源代码中唯一的更改。在基类中存在空定义。请注意:该方法仍然是虚拟的,并在子类中被覆盖
没有抽象类的大小输出:
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的符号)
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等)。
有人知道是什么原因导致了这种行为吗?
更新:
我已经使用标志--noexception
禁用了异常,所以我没有考虑过它。事实证明,它与答案有关,所以在这里提一下。
更新2: 这是最全面的网站,解释了所有问题,如果你追踪答案中的链接。
-fno-exception
和-fno-rtti
来显著减少程序的体积。请注意,默认情况下,new
分配器会抛出异常。显然,-fno-rtti
至少解决了链接的问题中一个帖子的问题。 - artless noise