Declaring abstract class (pure virtual method) increase binary size substantially
这是故事:
我正在使用AC6 Toolpack在Linux中为ARM Cortex-M0处理器开发C ++软件。在使用Keil(在Windows中)(拥有自己的工具链)之前,我已经迁移到GNU工具链((用于ARM嵌入式处理器的GNU工具)5.2.1)。我意识到的第一件事是;二进制文件的大小大大增加。我已经测试了所有编译器优化(链接时间优化除外,它在内联汇编中给出错误,不是问题的一部分,但可能与答案有关)。然后开始使用任何可用的工具:objdump,readelf,nm检查可执行文件(elf文件不是bin,gnu都会生成)。我发现一些引起大小增加的符号,重要的是:'
定义功能为
1 | virtual Return_type function_name(...)=0; |
代替
1 | virtual Return_type function_name(...); |
添加45 KB和我提到的符号。这是源代码中的唯一更改。基类中存在空定义。注意:方法仍然是虚拟的,并且在子类中被覆盖
没有抽象类的大小输出:
1 2 | text data bss dec hex filename 15316 24 4764 20104 4e88 temc_discovery.elf |
使用Abstract类输出大小:
1 2 | text data bss dec hex filename 61484 128 4796 66408 10368 temc_discovery.elf |
在这里,当方法抽象时显示的符号及其大小,消除了在两个版本中都显示的符号及其大小。 (使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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等)。
任何人都知道是什么导致了这种现象?
更新:
我已经用标志
更新2:
如果您跟踪答案中的链接,这是最全面的网站,解释了所有内容。
几乎可以肯定,这是因为libc ++已内置了异常处理功能,而不管它是否包含了异常处理功能,无论您是否使用
有问题的异常可能是"纯虚函数调用"或类似的东西(一个相当模糊的运行时错误,但如果您在基类构造函数中调用虚函数,则可能出现)。
答案是提供您自己的空实现atexit()以及您真正不需要的任何随机标注。完成此操作后,链接器将不会拖入其他内容(拖入其他内容,拖入其他内容,等等)。
1 2 3 4 | void __cxa_pure_virtual(void) { BKPT(); } |
我的项目是我的,尽管您的libc ++版本可能已更改
据我了解,当您在基类中将虚拟函数设为纯函数时,就会产生进行纯虚拟调用的可能性。因此,编译器生成代码,在该代码中打印有关纯虚拟调用事实的消息,函数和类的已拆名称,并且可能还有其他内容。为此,它向二进制文件添加了许多函数,因此大小增加了。
我建议为您的纯虚函数添加空的实现-可能是因为它阻止了编译器执行该操作。