我为ARM(cortex-m3)构建了GCC4.7.1交叉工具链。现在,我正在链接来自C / C ++代码的可执行文件,肯定不会使用某些某些STL类(例如std::string
)。此外,异常和RTTI已关闭。
虽然当我正在寻找目标ELF(例如使用nm)时,有很多符号(显然来自libstdc ++)在我不希望找到的地方(例如std::exception
,{{ 1}}等。)。
为什么会出现这种情况,如何摆脱这些问题以减少目标的std::ios_base
区域大小?
一位同事给了我一个覆盖一些GCC特定存根函数的提示:
.text
仅此一项就将代码大小减少了大约20KB 我可以覆盖更多此类存根吗?
更新
好吧,我发现了一个非常愚蠢的错误,删除了我想知道的大部分内容,修复它时:
在其中一个源文件中留下了namespace __gnu_cxx
{
void __verbose_terminate_handler()
{
for (;;)
;
}
}
语句(虽然没有从那里调用)。这当然会链接到静态#include <iostream>
,std::cin
和std::cout
实例以及随附的所有内容。
删除std::cerr
语句会将#include <iostream>
段减少为另一个&gt; 100KB部分。
尽管如此:
我还在想.text
和std::exception
这些东西:
std::basic_string
使用的代码大小并不多,只有大约100个字节,所以我可以忽视它,但如果我能摆脱它,我会很感激。
因为我明确地使用了没有异常,所以我想知道为什么这些在链接时仍然被实例化。是否在运行时确定是否使用异常?!?
我现在留下的Namespace summaries:
==============================================================================
Type Size Namespace
T 774 'std'
W 184 'std::string::_Rep'
W 268 'std'
W 472 'std::string'
Class summaries:
==============================================================================
Type Size Class
T 50 'std::error_category'
T 52 'std::type_info'
T 54 'std::bad_exception'
T 54 'std::exception'
T 68 'std::bad_alloc'
T 98 'std::length_error'
T 214 'std::logic_error'
W 268 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >'
命名空间中唯一剩下的就是
__gnu_cxx
这是另一个异常类。
最后:
我使用了一些额外的标志来配置GCC4.7交叉构建:
Type Size Class
T 58 '__gnu_cxx::recursive_init_error'
后面的标志用于编译libstdc ++,与用于构建目标代码的标记基本相同(无论如何这是一个合理的操作)。事后引用的异常引用(包括--enable-gold=yes
--enable-lto
--enable-cxx-flags='-fno-exceptions -ffunction-sections -fno-omit-frame-pointer'
)。
最后一件事是,我在代码库中发现__gnu_cxx::recursive_init_error
的意外使用。修好后,对std::string
的引用也消失了。
所以我现在对结果很满意,libstdc ++没有更多不必要的,意外的开销,没有理由不优先使用C ++而不是C语言。
答案 0 :(得分:2)
你永远不会知道使用一个库函数会引入什么。好吧,实际上你可以通过使用其中一个工具创建调用图。那你使用c ++ std库的哪一部分?
除此之外,我已成功通过使用两种方法从可执行文件中删除不需要的函数(在ARM上没有这种方法,但方法不是ARM特定的):
你已经在使用-Os了,对吧?
答案 1 :(得分:2)
如果您未在代码中使用dynamic_cast
或type_id
,请尝试添加-fno-rtti
。这将删除与类层次结构相关的一些代码,并可能为代码中的每个类删除几十个字节。
如果您在功能规范中经常使用throw()
,请尝试添加-fnothrow-opt
。这将鼓励GCC将throw()
视为更严格的noexcept
规范(来自C ++ 11),这将大大减少许多领域的代码大小,因为它不必构造异常帧。 / p>
作为-fnothrow-opt
的伴侣,请添加-Wnoexcept
。这会在找到添加throw()
或noexcept
的位置时发出警告,并进一步减少必须构建异常帧的位置数。
同时作为上述内容的同伴,请将代码库中的new
的所有实例(如果有)替换为new (nothrow)
,并在必要时将-fcheck-new
添加到您的CFLAGS。
如果你没有使用线程,你可能会从-fno-threadsafe-statics
中找到一个小的好处,它会删除执行静态的线程安全初始化的代码。
新的(好的,过去几年)binutils链接器有一个名为gold
的插件,它执行许多链接时优化,包括删除死代码。我还不知道ARM是否支持gold
,但这对于大幅减少导入的标准库的占用空间非常有用。
答案 2 :(得分:2)
为什么会出现这种情况,如何摆脱这些问题以减少目标的
.text
区域大小?
对于从libstdc++
链接的内容,可能存在(静态)引用,无论它们是否在实际执行的代码中被调用或引用,都将被实例化。
仔细搜索包含此类引用声明的#include
语句的用法(例如#include <iostream>
)。
在安装GCC期间构建libstdc++
时,使用与最终目标目标相同的不同C ++编译标志,可能会有不需要的东西链接或被实例化(例如__gnu_cxx::recursive_init_error
异常类,尽管使用-fno-exceptions
旗帜)在构建工具链时,使用--enable-cxx-flags
配置选项与预期的目标编译标志同步。
另外仔细查看代码库中某些STL类的不必要/意外使用情况(例如std::string
),它们可能会编译并链接而不会出现错误或警告,尽管某些功能(例如new()
)不是你的裸机平台确实支持。
我可以覆盖更多此类存根吗?
根据为工具链构建'newlib'的方式(参见--en/disable-newlib-supplied-syscalls
配置选项),可能需要覆盖那里提供的某些或所有存根。
答案 3 :(得分:1)
快速修复
首先,根据您的目标的限制 - 您可能需要考虑@ Carl的建议。我们决定不在我们的cortex m3平台中使用C ++。
第二,嵌入式开发提示减少C或C ++的大小 - 杀死浮点库,在许多应用程序中你可以只使用定点数学,但有些人因为可协商的原因(比如希望使用“% f“在printf
)。
您的同事给出的提示可能非常特定于您的平台,可能它有硬件监视器?所以对于那些不熟悉你的人来说很难 用于提供此类快速修复建议的硬件,代码或应用程序。
深入挖掘
您是否实际上添加了这些库的符号,并且这是您消耗大部分.txt部分的地方?
问题可能不一定是你从那个图书馆没有使用的,但你是什么。您“需要”的库很可能有自己的依赖项。
这是一个痛苦的过程(也许有更好的方法),但如果我是你,我会尝试删除你链接的库,看看你真正吸引了什么(STL标题可能需要这些符号中的几个)。如果没有意外,并且您的应用程序只提取了预期的库,您需要深入挖掘:
方法1: - 分析libstdc ++代码(可能太长时间无法立即跳转)
方法2:
- 我从来没有使用C ++,只使用C libs,但理论应该保持 - 同时删除libstdc ++的链接 - 一次从libstdc ++添加一个对象,你可以从代码构建并明确使用目标文件或你可以尝试使用ar
(ar -t
等工具列出对象和ar -xv
来提取)。请注意,我不建议你搞砸你的链接命令,只是如果你想要划分和征服,看看你实际使用的模块需要这些模块的原因 - 在一天结束时,你可能能够重建库带有一组“无”标志。阅读手册页或ar
,nm
,objdump
可能有助于自动化其中一些如果花费太长时间,我已经完成了多年前的事情,所以我不喜欢我的备忘单很方便。