背景

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

    Anacond的介绍 Anaconda指的是一个开源的Python发行版本,其包含了conda.Python等180多个科学包及其依赖项. 因为包含了大量的科学包,Anaconda 的下载文件比较大( ...

  2. JSP 页面跳转中的参数传递

    1. 从一个 JSP 页面跳转到另一个 JSP 页面时的参数传递 1)使用 request 内置对象获取客户端提交的信息 2)使用 session 对象获取客户端提交的信息 3)利用隐藏域传递数据 4 ...

  3. 结巴分词的stopword.txt

    1. read the stop words to a list: stopwords = [line.strip() for line in open('d:/stopword.txt','r'). ...

  4. vue中提示$index is not defined

    今天学习Vue中遇到了一个报错信息:$index is not defined,是我写了个for循环在HTML中,然后是因为版本的问题 下面是解决方法: 原来的是 v-for="person ...

  5. Robot Framework+python的安装,配置,环境搭建(纯白篇)

    弄了大半天 终于把-Robot Framework-弄好了,总是一个发现问题,一个一个去解决的过程,只是时间嘛,咳咳咳咳 言归正传 第一. 记住了 Robot Framework 的库 只支持 pyt ...

  6. JS中的instanceof和typeof,以及特殊引用类型

    1.instanceof是用于测试对象类型,通常格式为:a instanceof b,返回true或falise,表示为对象a是否是类型b的实例. typeof则是用于测试基本类型,包括undefin ...

  7. 2019.03.28 bzoj3326: [Scoi2013]数数(数位dp)

    传送门 题意: 一个人数数,规则如下: 确定数数的进制B 确定一个数数的区间[L, R] 对于[L, R] 间的每一个数,把该数视为一个字符串,列出该字符串的所有连续子串对应的B进制数的值. 对所有列 ...

  8. vuex的mutations传值

    mutations是要通过方法触发的,用于更改store里的数据的.this.$store.commit("mutationsName") 例子: store.js import ...

  9. opencv2.4.13+python2.7学习笔记--OpenCV中的图像处理--图像轮廓

    阅读对象:无要求. 1.代码 ''' OpenCV中的轮廓 轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度.为了更加准确,要使用二值化图像.在寻找轮廓之前,要进行阈值化 ...

  10. robotframework 远程连接数据库问题

    今天在使用RF远程连接数据库时出现报错的问题,因为我发现只安装databaselibrary跟PyMsql的话,连接本地的数据库是OK的,但是如果我们的测试机性能有限,那么既要编写代码.运行测试.还有 ...