gcc参数-Wl,–gc-sections,不链接未用函数,减小可执行文件大小
背景
在开发一个项目时,使用了非常多的第三方.a静态库文件,导致编译出的可执行文件非常大。这样一是占用ROM空间,二是会导致程序启动加载速度变慢(项目对启动时间非常敏感)。其实,这些静态库中的函数,并非所有都有调用,项目只使用了其中小部分。这种情况下,gcc的“-Wl,–gc-sections”参数,就非常有用。
参数说明
6.3.3.2 Compilation options
The operation of eliminating the unused code and data from the final executable is directly performed by the linker.In order to do this, it has to work with objects compiled with the following options: -ffunction-sections -fdata-sections.
These options are usable with C and Ada files. They will place respectively each function or data in a separate section in the resulting object file.
Once the objects and static libraries are created with these options, the linker can perform the dead code elimination. You can do this by setting the -Wl,–gc-sections option to gcc command or in the -largs section of gnatmake. This will perform a garbage collection of code and data never referenced.
If the linker performs a partial link (-r linker option), then you will need to provide the entry point using the -e / --entry linker option.
Note that objects compiled without the -ffunction-sections and -fdata-sections options can still be linked with the executable. However, no dead code elimination will be performed on those objects (they will be linked as is).
The GNAT static library is now compiled with -ffunction-sections and -fdata-sections on some platforms. This allows you to eliminate the unused code and data of the GNAT library from your executable.
大致说明如下:
- 在编译C、Ada源文件(C++也可以),在gcc/g++编译选项中增加
-ffunction-sections
、-fdata-sections
,在编译生成的.o目标文件中,会将每个函数或数据段,放在各种单独独立的section
中; - 在链接生成最终可执行文件时,如果带有
-Wl,--gc-sections
参数,并且之前编译目标文件时带有-ffunction-sections
、-fdata-sections
参数,则链接器ld不会链接未使用的函数,从而减小可执行文件大小; - 如果使用了
-r
的链接参数,来产生重定位的输出,需要显示的调用-e
参数来指定程序入口。否则-Wl,--gc-sections
不会生效。
关于GNU ld更多参数的说明,可以参考官网。
使用示例
#include <stdio.h>void func_0(void) {printf("%s\n\r", __func__);
}void func_1(void) {printf("%s\n\r", __func__);
}void func_2(void) {printf("%s\n\r", __func__);
}void func_3(void) {printf("%s\n\r", __func__);
}void func_4(void) {printf("%s\n\r", __func__);
}void func_5(void) {printf("%s\n\r", __func__);
}void func_6(void) {printf("%s\n\r", __func__);
}void func_7(void) {printf("%s\n\r", __func__);
}int main(void) {func_0();return 0;
}
.PHONY: test_sections test_normalall: test_sections test_normaltest_sections:gcc -ffunction-sections -fdata-sections -c section_test.cgcc -Wl,--gc-sections -o $@ section_test.omv section_test.o with_section.otest_normal:gcc -c section_test.cgcc -o $@ section_test.omv section_test.o no_section.oclean:rm -rf *.o main_sections main_normal
执行make
后,编译生成2个.o文件和2个可执行程序:no_section.o
、with_section.o
、test_normal
、test_sections
。
首先,通过ls -l
查看可执行文件大小。可以看到,没有链接未使用函数的test_sections
稍微小一点。如果工程中使用的静态库.a多,且未使用的函数也多的话,效果会更显著:
-rwxr-xr-x 1 user user 8864 9月 10 14:40 test_normal
-rwxr-xr-x 1 user user 8272 9月 10 14:40 test_sections
然后,查看.o目标文件,在gcc编译选项-ffunction-sections -fdata-sections
是否带来区别:
- 没有
-ffunction-sections -fdata-sections
选项的目标文件,只有1个test
和rodata
; - 带有
-ffunction-sections -fdata-sections
选项的目标文件,分别有text.func_0
到text.func_7
,以及8个rodata.__func__
。说明gcc在编译生成目标文件时,将每个函数或数据段,放在各种单独独立的section
;
$ readelf -t no_section.o
There are 13 section headers, starting at offset 0xa08:Section Headers:[Nr] NameType Address Offset LinkSize EntSize Info AlignFlags[ 0] NULL NULL 0000000000000000 0000000000000000 0[ 1] .textPROGBITS PROGBITS 0000000000000000 0000000000000040 0[ 2] .rela.textRELA RELA 0000000000000000 0000000000000670 10[ 3] .dataPROGBITS PROGBITS 0000000000000000 0000000000000148 0[ 4] .bssNOBITS NOBITS 0000000000000000 0000000000000148 0[ 5] .rodataPROGBITS PROGBITS 0000000000000000 0000000000000148 0
$ readelf -t with_section.o
There are 38 section headers, starting at offset 0xce8:Section Headers:[Nr] NameType Address Offset LinkSize EntSize Info AlignFlags[ 0] NULL NULL 0000000000000000 0000000000000000 0[ 1] .textPROGBITS PROGBITS 0000000000000000 0000000000000040 0[ 2] .dataPROGBITS PROGBITS 0000000000000000 0000000000000040 0[ 3] .bssNOBITS NOBITS 0000000000000000 0000000000000040 0[ 4] .rodataPROGBITS PROGBITS 0000000000000000 0000000000000040 0[ 5] .text.func_0PROGBITS PROGBITS 0000000000000000 0000000000000045 0[ 6] .rela.text.func_0RELA RELA 0000000000000000 0000000000000808 35[ 7] .text.func_1PROGBITS PROGBITS 0000000000000000 0000000000000064 0[ 8] .rela.text.func_1RELA RELA 0000000000000000 0000000000000850 35[ 9] .text.func_2PROGBITS PROGBITS 0000000000000000 0000000000000083 0[10] .rela.text.func_2RELA RELA 0000000000000000 0000000000000898 35[11] .text.func_3PROGBITS PROGBITS 0000000000000000 00000000000000a2 0[12] .rela.text.func_3RELA RELA 0000000000000000 00000000000008e0 35[13] .text.func_4PROGBITS PROGBITS 0000000000000000 00000000000000c1 0[14] .rela.text.func_4RELA RELA 0000000000000000 0000000000000928 35[15] .text.func_5PROGBITS PROGBITS 0000000000000000 00000000000000e0 0[16] .rela.text.func_5RELA RELA 0000000000000000 0000000000000970 35[17] .text.func_6PROGBITS PROGBITS 0000000000000000 00000000000000ff 0[18] .rela.text.func_6RELA RELA 0000000000000000 00000000000009b8 35[19] .text.func_7PROGBITS PROGBITS 0000000000000000 000000000000011e 0[20] .rela.text.func_7RELA RELA 0000000000000000 0000000000000a00 35[21] .text.mainPROGBITS PROGBITS 0000000000000000 000000000000013d 0[22] .rela.text.mainRELA RELA 0000000000000000 0000000000000a48 35[23] .rodata.__func__.2250PROGBITS PROGBITS 0000000000000000 000000000000014d 0[24] .rodata.__func__.2254PROGBITS PROGBITS 0000000000000000 0000000000000154 0[25] .rodata.__func__.2258PROGBITS PROGBITS 0000000000000000 000000000000015b 0[26] .rodata.__func__.2262PROGBITS PROGBITS 0000000000000000 0000000000000162 0[27] .rodata.__func__.2266PROGBITS PROGBITS 0000000000000000 0000000000000169 0[28] .rodata.__func__.2270PROGBITS PROGBITS 0000000000000000 0000000000000170 0[29] .rodata.__func__.2274PROGBITS PROGBITS 0000000000000000 0000000000000177 0[30] .rodata.__func__.2278PROGBITS PROGBITS 0000000000000000 000000000000017e 0
$ readelf -a test_normal | grep func_55: 00000000000006c6 31 FUNC GLOBAL DEFAULT 14 func_457: 000000000000064a 31 FUNC GLOBAL DEFAULT 14 func_058: 0000000000000688 31 FUNC GLOBAL DEFAULT 14 func_260: 0000000000000704 31 FUNC GLOBAL DEFAULT 14 func_671: 00000000000006a7 31 FUNC GLOBAL DEFAULT 14 func_372: 0000000000000669 31 FUNC GLOBAL DEFAULT 14 func_173: 0000000000000723 31 FUNC GLOBAL DEFAULT 14 func_774: 00000000000006e5 31 FUNC GLOBAL DEFAULT 14 func_5
readelf -a test_sections | grep func_48: 000000000000064a 31 FUNC GLOBAL DEFAULT 14 func_0
gcc参数-Wl,–gc-sections,不链接未用函数,减小可执行文件大小相关推荐
- 使用gcc参数-Wl,–gc-sections,不链接未用函数,减小可执行文件大小
背景 在开发一个项目时,使用了非常多的第三方.a静态库文件,导致编译出的可执行文件非常大.这样一是占用ROM空间,二是会导致程序启动加载速度变慢(项目对启动时间非常敏感).其实,这些静态库中的函数,并 ...
- 复杂命令行参数gcc的-Wl的含义,注意是字母l不是数字1
复杂命令行参数:gcc的-Wl, -Wl,表示后面的参数将传给link程序ld(因为gcc可能会自动调用ld),如果后面的ld参数有空格,怎么传呢?比如想加一个-rpath /path? 下面几种方法 ...
- Linux平台Makefile文件的编写基础篇和GCC参数详解
问:gcc中的-I.是什么意思....看到了有的是gcc -I. -I/usr/xxxxx..那个-I.是什么意思呢 最佳答案 答:-Ixxx 的意思是除了默认的头文件搜索路径(比如/usr/incl ...
- JVM基础系列第14讲:JVM参数之GC日志配置
说到 Java 虚拟机,不得不提的就是 Java 虚拟机的 GC(Garbage Collection)日志.而对于 GC 日志,我们不仅要学会看懂,而且要学会如何设置对应的 GC 日志参数.今天就让 ...
- gcc参数 -i, -L, -l, -include
gcc参数 -i, -L, -l, -include -i,-L,-l,-include -l和-L -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢? ...
- GCC详解-gcc之-Wl选项
1.介绍 -Wl后面的东西是作为参数传递给链接器ld的.比如: gcc -Wl,aaa,bbb,ccc 最后会被解释为: ld aaa bbb ccc 2.-Wl,-Map=xxx.txt 生成map ...
- 02_可执行文件生成过程和gcc参数介绍
文章结构 可执行文件生成过程 1. 预处理器 2. 编译器 3. 汇编器 4. 链接器 gcc参数用法 语法 参数 可执行文件生成过程 对于一个源文件test.c生成可执行文件test.out的过程如 ...
- jvm 参数 -verbose:gc 和 -XX:+PrintGC 的区别?
文章目录 一.日志内容 1.1. `-verbose:gc` 参数: 1.2. `-XX:+PrintGC` 参数: 二.官方说明 2.1.`-verbose:gc` 是 稳定版本 2.2.`-XX: ...
- java verbose gc_jvm参数-verbose:gc和-XX:+PrintGC有区别?
jvm调优,参数-verbose:gc和-XX:+PrintGC有什么具体的区别?还是说效果一样的,打印下了没发现什么差别. 参数1: -XX:+PrintGC -XX:+PrintGCDetails ...
最新文章
- webpack配置alias别名设置
- linux 硬链接 软链接 简介
- 庆祝Dojo中文博客成为CSDN博客专家!
- 「Apollo」class DescriptorBase(metaclass=DescriptorMetaclass)
- 微软为何痛失移动操作系统?
- PyTorch | torch.randperm()使用方法
- Spring+Quartz实现定时任务的配置步骤
- 计算机上缺少vsix安装程序,使用MSI安装程序部署VSIX
- html透明背景字体不透明,css3背景透明,文字不透明
- css实现方框内打勾
- 由WMT机器翻译双向夺冠看搜狗语音交互布局
- 从拼多多解析社交电商
- python代码画猪头_如何用python画猪头
- ASO 相似测试
- 【数字图像处理】秒懂傅里叶变换,仅需此文
- 4章 RxJava基本响应类型
- 计算机控制篮球,【精品课程设计】计算机控制技术弱电课程之篮球比赛计时计分器doc.doc...
- WPBC乳腺癌数据集建模(Ⅱ)—预后诊断模型建立
- module ‘dlib‘ has no attribute ‘get_face_chips‘
- Java异常处理的简单总结+文件操作