背景

有时我们的程序会定义一些暂时使用不上的功能和函数,虽然我们不使用这些功能和函数,但它们往往会浪费我们的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

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

参考文档: https://blog.csdn.net/pengfei240/article/details/55228228

gcc编译参数详解一(-ffunction-sections -fdata-sections)的更多相关文章

  1. gcc编译参数详解概述

    gcc 编译器是经常使用的,可是,自己却没有针对它做过专门的研究,当遇到问题了,总结一下,算是对未来有个积累吧. 一 关于编译告警: 1 -w : 关闭所有警告,不建议使用 2 -W 开启素有gcc ...

  2. 【转】 linux 安装nginx及编译参数详解

    版权声明:本文为博主原创文章,未经博主允许不得转载. 从官网下载一个nginx 的tar.gz 版. 安装方式使用make 安装 第一步:解压 tar -zxvf  nginx-1.7.4.tar.g ...

  3. GCC参数详解

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

  4. Linux下nginx编译安装教程和编译参数详解

    这篇文章主要介绍了Linux下nginx编译安装教程和编译参数详解,需要的朋友可以参考下 一.必要软件准备1.安装pcre 为了支持rewrite功能,我们需要安装pcre 复制代码代码如下: # y ...

  5. mysql编译参数详解

    mysql编译参数详解(./configure)   1.--prefix=PREFIX:指定程序安装路径: 2.--enable-assembler:使用汇编模式:(文档说明:compiling i ...

  6. GCC 指令详解及动态库、静态库的使用

    GCC 指令详解及动态库.静态库的使用 一.GCC 1.1 GCC 介绍 GCC 是 Linux 下的编译工具集,是「GNU Compiler Collection」的缩写,包含 gcc.g++ 等编 ...

  7. [转]GCC参数详解

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

  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. github分支规范

    转自:https://www.cnblogs.com/xuld 一.目的 我们制定分支规范,意在实现以下目标: 减少沟通成本:开发者可以很清晰地知道需要修改的代码位于哪个分支. 减少 bug 隐患:避 ...

  2. pip使用国内镜像安装各种库

    1. 指定阿里云镜像, 安装requirements.txt中的所有 pip install -i http://mirrors.aliyun.com/pypi/simple/ --trusted-h ...

  3. Blog Part I

    写随笔是不可能写的,这辈子都不可能写的. ——https://music.163.com/song?id=5039077 ============ Blog?不,并不擅长,毕竟Blog不是Novel, ...

  4. shell逻辑运算总结, 包括[[]]与[]的区别,&&与-a的区别,||与-o的区别

    1. 关于文件和目录 -f  判断某普通文件是否存在 -d  判断某目录是否存在 -b  判断某文件是否块设备 -c  判断某文件是否字符设备 -S  判断某文件是否socket(待修正) -L  判 ...

  5. Python爬虫学习--用Python结合Selenium实现 明日之子节目直播时为自己喜欢的选手自动点赞拉票!!!

    声明:本脚本纯属娱乐,请勿用来非法点赞拉票,任何使用不当造成的后果自行承担. 闲话: 明日之子第二季开始好久了,作者一直再追,特别喜欢里面那个酷酷的小哥-蔡泽明.前两天晋选9大厂牌,采取的是直播的形式 ...

  6. easyui combobox 不能选中值的问题

    easyui comboxbox 下拉框加载到数据,但是不能选中.一般情况是重复渲染,页面有同名元素,valueField重复. 这次遇到的具体问题是,第一次刷新页面,可以选中,第二次不能选中.考虑到 ...

  7. MyBatis中<if test=" ">标签条件不起作用

    问题产生? 今天在做Excel导出的时候,有个判断一个状态的字段,我的这个字段是int类型的,还有两个时间类型,我在判断的时候给的是Long类型的. 在测试的时候发现,不管怎么样都不执行if条件里面的 ...

  8. Java学习笔记day_01

    Java学习笔记(复习整理) 虽然不知道该怎么写,但是不起步就永远不知道该怎么做..刚开始可能会写的很差劲,但会一点一点变好的. 本笔记是以我按照传智播客的视频和Java核心思想来学习,前面的基础部分 ...

  9. PHP安装+使用

        curl -s http://php-osx.liip.ch/install.sh | bash -s 5.4       ...... Extracting usr/local/php5-5 ...

  10. hbase常用操纵操作——增删改查

    查询某个资金账户的信息 get 'dmp:hbase_tags','资金账号' 创建表 create 'emp', 'personal data', 'professional data' 在HBas ...