背景

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

参数详解

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

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

  1. CFLAGS += -ffunction-sections -fdata-sections
  2. LDFLAGS += -Wl,--gc-sections

例子

main.c 文件如下:

  1. #include <stdio.h>
  2. int fun_0(void)
  3. {
  4. printf("%s: %d\n", __FUNCTION__, __LINE__);
  5. return 0;
  6. }
  7. int fun_1(void)
  8. {
  9. printf("%s: %d\n", __FUNCTION__, __LINE__);
  10. return 0;
  11. }
  12. int fun_2(void)
  13. {
  14. printf("%s: %d\n", __FUNCTION__, __LINE__);
  15. return 0;
  16. }
  17. int fun_3(void)
  18. {
  19. printf("%s: %d\n", __FUNCTION__, __LINE__);
  20. return 0;
  21. }
  22. void main(void)
  23. {
  24. fun_0();
  25. fun_3();
  26. }

Makefile文件如下:

  1. main_sections:
  2. gcc -ffunction-sections -fdata-sections -c main.c
  3. gcc -Wl,--gc-sections -o $@ main.o
  4. main_normal:
  5. gcc -c main.c
  6. gcc -o $@ main.o
  7. clean:
  8. rm -rf *.o main_sections main_normal

验证

运行

  1. $ make main_sections
  2. gcc -ffunction-sections -fdata-sections -c main.c
  3. gcc -Wl,--gc-sections -o main_sections main.o
  4. $ make main_normal
  5. gcc -c main.c
  6. gcc -o main_normal main.o

比较大小

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

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

分析sections

  1. $ make clean
  2. rm -rf *.o main_sections main_normal
  3. $ make main_sections
  4. gcc -ffunction-sections -fdata-sections -c main.c
  5. gcc -Wl,--gc-sections -o main_sections main.o
  6. $ readelf -t main.o
  7. ...
  8. [ 5] .text.fun_0
  9. PROGBITS PROGBITS 0000000000000000 0000000000000048 0
  10. 0000000000000024 0000000000000000 0 1
  11. [0000000000000006]: ALLOC, EXEC
  12. [ 6] .rela.text.fun_0
  13. RELA RELA 0000000000000000 0000000000000508 24
  14. 0000000000000048 0000000000000018 5 8
  15. [0000000000000040]: INFO LINK
  16. [ 7] .text.fun_1
  17. PROGBITS PROGBITS 0000000000000000 000000000000006c 0
  18. 0000000000000024 0000000000000000 0 1
  19. [0000000000000006]: ALLOC, EXEC
  20. [ 8] .rela.text.fun_1
  21. RELA RELA 0000000000000000 0000000000000550 24
  22. 0000000000000048 0000000000000018 7 8
  23. [0000000000000040]: INFO LINK
  24. [ 9] .text.fun_2
  25. PROGBITS PROGBITS 0000000000000000 0000000000000090 0
  26. 0000000000000024 0000000000000000 0 1
  27. [0000000000000006]: ALLOC, EXEC
  28. [10] .rela.text.fun_2
  29. RELA RELA 0000000000000000 0000000000000598 24
  30. 0000000000000048 0000000000000018 9 8
  31. [0000000000000040]: INFO LINK
  32. [11] .text.fun_3
  33. PROGBITS PROGBITS 0000000000000000 00000000000000b4 0
  34. 0000000000000024 0000000000000000 0 1
  35. [0000000000000006]: ALLOC, EXEC
  36. [12] .rela.text.fun_3
  37. RELA RELA 0000000000000000 00000000000005e0 24
  38. 0000000000000048 0000000000000018 11 8
  39. [0000000000000040]: INFO LINK

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

分析elf文件

  1. $ readelf -a main_normal | grep fun_
  2. 52: 0000000000400526 36 FUNC GLOBAL DEFAULT 14 fun_0
  3. 55: 000000000040056e 36 FUNC GLOBAL DEFAULT 14 fun_2
  4. 65: 0000000000400592 36 FUNC GLOBAL DEFAULT 14 fun_3
  5. 66: 000000000040054a 36 FUNC GLOBAL DEFAULT 14 fun_1
  6. $ readelf -a main_sections | grep fun_
  7. 49: 0000000000400526 36 FUNC GLOBAL DEFAULT 14 fun_0
  8. 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. 树莓派3 开机自启动(SPI)

    转自:https://www.raspberrypi-spy.co.uk/2014/08/enabling-the-spi-interface-on-the-raspberry-pi/ 方案一:图形界 ...

  2. 支付宝app对接的坑

    主要流程是: 1.申请成为开发者 2.创建应用 3.设置应用公钥/私钥/支付宝公钥 4.制作服务器端代码(此处注意,不要解析htmlencode) https://blog.csdn.net/zzzi ...

  3. Percona XtraBackup使用说明(转)

    Percona XtraBackup使用说明 转载出自: https://blog.csdn.net/wfs1994/article/details/80396604 XtraBackup介绍 Per ...

  4. Maven学习 八 采用Maven搭建SSM环境

    第一步:创建一个Maven项目 项目的打包方式选择,war 第二步:在webapp下面创建java web项目的目录结构,并配置web.xml文件 <?xml version="1.0 ...

  5. Springboot & Mybatis 构建restful 服务三

    Springboot & Mybatis 构建restful 服务三 1 前置条件 成功执行完Springboot & Mybatis 构建restful 服务二 2 restful ...

  6. PHP日期格式化函数

    date函数 描述:格式化一个本地时间/日期 语法:string date(string format [,int timestamp]) format字符 说明 format字符 说明 Y 4位数字 ...

  7. 别人的Linux私房菜(21)基础系统设置与备份策略

    网络设置,手动设置IP,DHCP自动获取. 以太网协议开发出来的网卡ethN,N为数字. CentOS7对网卡命名的规则:eno代表由主板BIOS内建立的网卡,ens1由主板BIOS内建的PCI-E界 ...

  8. 2019.03.25 bzoj4539: [Hnoi2016]树(主席树+倍增)

    传送门 题意:给一棵大树,令一棵模板树与这棵树相同,然后进行mmm次操作,每次选择模板树中的一个节点aaa和大树中一个节点bbb,把aaa这棵子树接在bbb上面,节点编号顺序跟aaa中的编号顺序相同. ...

  9. Linux 解压/压缩xxx.zip格式(unZip Zip的安装和使用)

    Linux系统没有自带的压缩解压工具:需要我们自己安装:当压缩包为.zip格式时,需要安装zip包 1.apt-get安装: apt-get install zip 2.yum安装: yum inst ...

  10. 消除blur属性的边框

    直接设置样式为:  outline:none <!DOCTYPE html> <html lang="en"> <head> <meta ...