Yip*_*Yay 107 c c++ gcc strip ld
我需要严格优化可执行文件的大小(ARM
开发),我注意到在我当前的构建方案(gcc
+ ld
)中,未使用的符号不会被剥离.
的用法arm-strip --strip-unneeded
为生成的可执行文件/库不改变可执行文件的输出大小(我不知道为什么,也许它根本不能).
修改我的构建管道的方式是什么(如果存在),以便从结果文件中删除未使用的符号?
我甚至都不会想到这一点,但我当前的嵌入式环境并不是非常"强大",甚至500K
可以节省2M
非常好的加载性能.
更新:
不幸的是,gcc
我使用的当前版本没有-dead-strip
选项,并且-ffunction-sections... + --gc-sections
for ld
不会对结果输出产生任何显着差异.
我很震惊,这甚至成了问题,因为我确信gcc + ld
应该自动删除未使用的符号(为什么他们甚至要保留它们?).
J T*_*J T 129
对于海湾合作委员会来说,这分两个阶段完成:
首先编译数据,但告诉编译器将代码分成翻译单元中的单独部分.这将通过使用以下两个编译器标志来完成函数,类和外部变量:
-fdata-sections -ffunction-sections
Run Code Online (Sandbox Code Playgroud)
使用链接器优化标志将转换单元链接在一起(这会导致链接器丢弃未引用的部分):
-Wl,--gc-sections
Run Code Online (Sandbox Code Playgroud)
因此,如果您有一个名为test.cpp的文件,其中声明了两个函数,但其中一个未使用,您可以使用以下命令省略未使用的文件到gcc(g ++):
gcc -Os -fdata-sections -ffunction-sections test.cpp -o test -Wl,--gc-sections
Run Code Online (Sandbox Code Playgroud)
(注意-Os是一个额外的编译器标志,告诉GCC优化大小)
Nem*_*emo 34
如果要相信这个线程,你需要提供-ffunction-sections
和-fdata-sections
gcc,它将把每个函数和数据对象放在它自己的部分中.然后你给--gc-sections
GNU ld删除未使用的部分.
Mic*_*son 24
您需要查看您的文档以获取您的gcc和ld版本:
但对我来说(OS X gcc 4.0.1)我发现这些是ld
Run Code Online (Sandbox Code Playgroud)-dead_strip
删除入口点或导出符号无法访问的函数和数据.
Run Code Online (Sandbox Code Playgroud)-dead_strip_dylibs
删除入口点或导出符号无法访问的dylib.也就是说,抑制了在链接期间没有提供符号的dylib的负载命令命令的产生.当链接到运行时需要的dylib时,不应该使用此选项,因为某些间接原因(例如dylib具有重要的初始值设定项).
这个有用的选择
Run Code Online (Sandbox Code Playgroud)-why_live symbol_name
记录对symbol_name的引用链.仅适用于
-dead_strip
.它可以帮助调试为什么你认为应该删除死区的东西不被删除.
在gcc/g ++ man中还有一个注释,即只有在编译时启用了优化时才会执行某些类型的死代码消除.
虽然这些选项/条件可能不适用于您的编译器,但我建议您在文档中查找类似的内容.
Tim*_*mmm 16
答案是-flto
.您必须将它传递给编译和链接步骤,否则它不会执行任何操作.
它实际上工作得非常好 - 将我编写的微控制器程序的大小减小到不到之前大小的50%!
不幸的是,它看起来确实有些错误 - 我的事情没有正确构建.这可能是由于我正在使用的构建系统(QBS;它是非常新的),但无论如何我建议你只在可能的情况下为最终构建启用它,并彻底测试构建.
zxc*_*cdw 13
虽然不是严格有关的符号,若去为大小-总是编译-Os
和-s
标志.-Os
优化生成的代码以获得最小的可执行文件大小,并-s
从可执行文件中删除符号表和重定位信息.
有时 - 如果需要小尺寸 - 玩不同的优化标志可能 - 或可能不 - 具有重要性.例如,切换-ffast-math
和/或-fomit-frame-pointer
有时甚至可以节省数十个字节.
Gea*_*phy 11
在我看来,Nemo提供的答案是正确的.如果这些说明不起作用,问题可能与您正在使用的gcc/ld版本有关,作为练习我使用此处详述的说明编译了一个示例程序
#include <stdio.h>
void deadcode() { printf("This is d dead codez\n"); }
int main(void) { printf("This is main\n"); return 0 ; }
Run Code Online (Sandbox Code Playgroud)
然后我使用逐步更积极的死代码删除开关编译代码:
gcc -Os test.c -o test.elf
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections
gcc -Os -fdata-sections -ffunction-sections test.c -o test.elf -Wl,--gc-sections -Wl,--strip-all
Run Code Online (Sandbox Code Playgroud)
这些编译和链接参数分别产生了大小为8457,8164和6160字节的可执行文件,这是来自'strip-all'声明的最重要的贡献.如果您无法在您的平台上产生类似的缩减,那么您的gcc版本可能不支持此功能.我在Linux Mint 2.6.38-8-generic x86_64上使用gcc(4.5.2-8ubuntu4),ld(2.21.0.20110327)
从 GCC 4.2.1 手册,部分-fwhole-program
:
假设当前编译单元代表正在编译的整个程序。所有公共函数和变量(除了
main
和 按属性合并的那些之外)都externally_visible
成为静态函数,并且在影响过程中被过程间优化器更积极地优化。虽然此选项等效于static
为由单个文件组成的程序正确使用关键字,但与选项结合使用--combine
此标志可用于编译大多数较小规模的 C 程序,因为函数和变量对于整个组合编译单元而言是局部的,而不是用于编译单个源文件本身。