背景

有时我们的程序会定义一些暂时使用不上的功能和函数,虽然我们不使用这些功能和函数,但它们往往会浪费我们的ROM和RAM的空间。这在使用静态库时,体现的更为严重。有时,我们只使用了静态库仅有的几个功能,但是系统默认会自动把整个静态库全部链接到可执行程序中,造成可执行程序的大小大大增加。

参数详解

为了解决前面分析的问题,我们引入了标题中的几个参数。GCC链接操作是以section作为最小的处理单元,只要一个section中的某个符号被引用,该section就会被加入到可执行程序中去。因此,GCC在编译时可以使用 -ffunction-sections 和 -fdata-sections 将每个函数或符号创建为一个sections,其中每个sections名与function或data名保持一致。而在链接阶段, -Wl,–gc-sections 指示链接器去掉不用的section(其中-wl, 表示后面的参数 -gc-sections 传递给链接器),这样就能减少最终的可执行程序的大小了。

我们常常使用下面的配置启用这个功能:

CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS += -Wl,--gc-sections

  

例子

main.c 文件如下:

#include <stdio.h>

int fun_0(void)
{
printf("%s: %d\n", __FUNCTION__, __LINE__);
return 0;
} int fun_1(void)
{
printf("%s: %d\n", __FUNCTION__, __LINE__);
return 0;
} int fun_2(void)
{
printf("%s: %d\n", __FUNCTION__, __LINE__);
return 0;
} int fun_3(void)
{
printf("%s: %d\n", __FUNCTION__, __LINE__);
return 0;
} void main(void)
{
fun_0();
fun_3();
}

  Makefile文件如下:

main_sections:
gcc -ffunction-sections -fdata-sections -c main.c
gcc -Wl,--gc-sections -o $@ main.o main_normal:
gcc -c main.c
gcc -o $@ main.o clean:
rm -rf *.o main_sections main_normal

  

验证

运行

$ make main_sections
gcc -ffunction-sections -fdata-sections -c main.c
gcc -Wl,--gc-sections -o main_sections main.o
$ make main_normal
gcc -c main.c
gcc -o main_normal main.o

  

比较大小

$ ll main_*
-rwxrwxr-x 1 8896 2月 16 00:42 main_normal*
-rwxrwxr-x 1 8504 2月 16 00:42 main_sections*

  

可以看见使用该功能的二进制文件要小于不使用该功能的二进制文件

分析sections

$ make clean
rm -rf *.o main_sections main_normal
$ make main_sections
gcc -ffunction-sections -fdata-sections -c main.c
gcc -Wl,--gc-sections -o main_sections main.o
$ readelf -t main.o
...
[ 5] .text.fun_0
PROGBITS PROGBITS 0000000000000000 0000000000000048 0
0000000000000024 0000000000000000 0 1
[0000000000000006]: ALLOC, EXEC
[ 6] .rela.text.fun_0
RELA RELA 0000000000000000 0000000000000508 24
0000000000000048 0000000000000018 5 8
[0000000000000040]: INFO LINK
[ 7] .text.fun_1
PROGBITS PROGBITS 0000000000000000 000000000000006c 0
0000000000000024 0000000000000000 0 1
[0000000000000006]: ALLOC, EXEC
[ 8] .rela.text.fun_1
RELA RELA 0000000000000000 0000000000000550 24
0000000000000048 0000000000000018 7 8
[0000000000000040]: INFO LINK
[ 9] .text.fun_2
PROGBITS PROGBITS 0000000000000000 0000000000000090 0
0000000000000024 0000000000000000 0 1
[0000000000000006]: ALLOC, EXEC
[10] .rela.text.fun_2
RELA RELA 0000000000000000 0000000000000598 24
0000000000000048 0000000000000018 9 8
[0000000000000040]: INFO LINK
[11] .text.fun_3
PROGBITS PROGBITS 0000000000000000 00000000000000b4 0
0000000000000024 0000000000000000 0 1
[0000000000000006]: ALLOC, EXEC
[12] .rela.text.fun_3
RELA RELA 0000000000000000 00000000000005e0 24
0000000000000048 0000000000000018 11 8
[0000000000000040]: INFO LINK

  

从object文件中可以发现,fun_0 ~ fun_3 每个函数都是一个独立的section. 
而如果使用 make main_normal 生成的object文件,则共享一个默认的sections(.text)。

分析elf文件

$ readelf -a main_normal | grep fun_
52: 0000000000400526 36 FUNC GLOBAL DEFAULT 14 fun_0
55: 000000000040056e 36 FUNC GLOBAL DEFAULT 14 fun_2
65: 0000000000400592 36 FUNC GLOBAL DEFAULT 14 fun_3
66: 000000000040054a 36 FUNC GLOBAL DEFAULT 14 fun_1
$ readelf -a main_sections | grep fun_
49: 0000000000400526 36 FUNC GLOBAL DEFAULT 14 fun_0
57: 000000000040054a 36 FUNC GLOBAL DEFAULT 14 fun_3

  可以看见,在最终的目标文件中,未使用的函数并未被链接进最终的目标文件。

[转]gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 参数详解的更多相关文章

  1. Linux 之 编译器 gcc/g++参数详解

    2016年12月9日16:48:53 ----------------------------- 内容目录: [介绍] gcc and g++分别是gnu的c & c++编译器 gcc/g++ ...

  2. [转]GCC参数详解

    [介绍] gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2.将预处理后的文件不转换成 ...

  3. scons用户指南翻译(附gcc/g++参数详解)

    scons用户指南 翻译 http://blog.csdn.net/andyelvis/article/category/948141 官网文档 http://www.scons.org/docume ...

  4. GCC参数详解

    GCC参数详解 [介绍] gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件 2.将预处理后的文件不转换成汇 ...

  5. [转]GCC常用参数详解

    简介gcc and g++现在是gnu中最主要和最流行的c & c++编译器 .gcc/g++在执行编译工作的时候,总共需要以下几步:1.预处理,生成.i的文件[预处理器cpp]2.将预处理后 ...

  6. gcc与g++区别以及相关参数详解

    ---恢复内容开始--- 原文链接:g++和gcc的区别 一 .二者区别 gcc和g++都是GNU(一个组织)的编译器. 1.对于.c后缀的文件,gcc把它当做是C程序:g++当做是C++程序: 2. ...

  7. GCC常用参数详解

    转载:http://www.cnblogs.com/zhangsir6/articles/2956798.html 简介gcc and g++现在是gnu中最主要和最流行的c & c++编译器 ...

  8. GCC 参数详解

    转载出处:http://blog.csdn.net/yff1030/article/details/8592077 原文:http://www.cppblog.com/SEMAN/archive/20 ...

  9. GCC参数详解-(转自:篱笆博客)

    gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2.将预处理后的文件不转换成汇编语言, ...

随机推荐

  1. BZOJ3772精神污染——可持久化线段树+出栈入栈序

    题目描述 兵库县位于日本列岛的中央位置,北临日本海,南面濑户内海直通太平洋,中央部位是森林和山地,与拥有关西机场的大阪府比邻而居,是关西地区面积最大的县,是集经济和文化于一体的一大地区,是日本西部门户 ...

  2. [hgoi#2019/3/10]赛后总结

    关于本次hg模拟赛,题目来源于CF1110. t1-无意义运算符(meaning) 题目描述 最大公约数和位运算之间有共同点吗?是时候来研究一下了. 给定一个正整数a,请找到一个闭区间[1,a-1] ...

  3. pandas merge

    merge pandas的merge方法提供了一种类似于SQL的内存链接操作,官网文档提到它的性能会比其他开源语言的数据操作(例如R)要高效. merge的参数 on:列名,join用来对齐的那一列的 ...

  4. c++纯虚函数在父类中调用的规避

    构造和析构函数不允许调用纯虚函数,可以先调用虚函数,里面再调用纯虚函数实现. class Base{public:    virtual void foo()=0;    Base() { call_ ...

  5. HDU 1069 Monkey and Banana / ZOJ 1093 Monkey and Banana (最长路径)

    HDU 1069 Monkey and Banana / ZOJ 1093 Monkey and Banana (最长路径) Description A group of researchers ar ...

  6. Segment 李超线段树

    题目大意: 要求在平面直角坐标系下维护两个操作: 1.在平面上加入一条线段.记第 i 条被插入的线段的标号为 i 2.给定一个数 k,询问与直线 x = k 相交的线段中,交点最靠上的线段的编号. 若 ...

  7. 关于scrollintoview()真的是有意思极了,结合普通tab切换一起看看

    scrollIntoView(alignWithTop) 是html5新特性中的一个元素,他主要是指滚动浏览器窗口或容器元素,以便在当前视窗的可见范围看见当前元素. alignWithTop是true ...

  8. mysql常见问题解决

    日常使用mysql数据库遇到的一些问题,做下记录,会持续更新. 一.MySql Host is blocked because of many connection errors; unblock w ...

  9. myEclipse全局搜索时报错

    1.全局搜索时出错. 大家都知道,Eclipse可以用Ctrl+ H 进行全局搜索,但今天搜索时出现了一个问题: Problem Occurred ‘File Search’ has encounte ...

  10. vue2.0 keep-alive最佳实践

    1.基本用法 vue2.0提供了一个keep-alive组件用来缓存组件,避免多次加载相应的组件,减少性能消耗 <keep-alive> <component> <!-- ...