gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 参数详解

转载:https://blog.csdn.net/pengfei240/article/details/55228228

背景

有时我们的程序会定义一些暂时使用不上的功能和函数,虽然我们不使用这些功能和函数,但它们往往会浪费我们的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 fun0(void)
{
    printf("%s:%d\n",__FUNCTION__,__LINE__);
    return 0;
}


int fun1(void)
{
    printf("%s:%d\n",__FUNCTION__,__LINE__);
    return 0;
}


int fun2(void)
{
    printf("%s:%d\n",__FUNCTION__,__LINE__);
    return 0;
}

int fun3(void)
{
    printf("%s:%d\n",__FUNCTION__,__LINE__);
    return 0;
}


void main(void)
{
    fun0();
    fun3();
}

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

比较大小

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

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

分析sections

$readelf -t main.o
Section Headers:
  [Nr] Name
       Type            Addr     Off    Size   ES   Lk Inf Al
       Flags
  [ 0] 
       NULL            00000000 000000 000000 00   0   0  0
       [00000000]: 
  [ 1] .text
       PROGBITS        00000000 000034 000000 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 2] .data
       PROGBITS        00000000 000034 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 3] .bss
       NOBITS          00000000 000034 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 4] .rodata
       PROGBITS        00000000 000034 000007 00   0   0  1
       [00000002]: ALLOC
  [ 5] .text.fun0
       PROGBITS        00000000 00003b 000029 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 6] .rel.text.fun0
       REL             00000000 00093c 000018 08  24   5  4
       [00000000]: 
  [ 7] .text.fun1
       PROGBITS        00000000 000064 000029 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 8] .rel.text.fun1
       REL             00000000 000954 000018 08  24   7  4
       [00000000]: 
  [ 9] .text.fun2
       PROGBITS        00000000 00008d 000029 00   0   0  1
       [00000006]: ALLOC, EXEC
  [10] .rel.text.fun2
       REL             00000000 00096c 000018 08  24   9  4
       [00000000]: 
  [11] .text.fun3
       PROGBITS        00000000 0000b6 000029 00   0   0  1
       [00000006]: ALLOC, EXEC
  [12] .rel.text.fun3
       REL             00000000 000984 000018 08  24  11  4
       [00000000]: 
  [13] .text.main
       PROGBITS        00000000 0000df 000012 00   0   0  1
       [00000006]: ALLOC, EXEC
  [14] .rel.text.main
       REL             00000000 00099c 000010 08  24  13  4
       [00000000]: 
  [15] .rodata.__FUNCTION__.1826
       PROGBITS        00000000 0000f1 000005 00   0   0  1
       [00000002]: ALLOC
  [16] .rodata.__FUNCTION__.1830
       PROGBITS        00000000 0000f6 000005 00   0   0  1
       [00000002]: ALLOC
  [17] .rodata.__FUNCTION__.1834
       PROGBITS        00000000 0000fb 000005 00   0   0  1
       [00000002]: ALLOC
  [18] .rodata.__FUNCTION__.1838
       PROGBITS        00000000 000100 000005 00   0   0  1
       [00000002]: ALLOC
  [19] .comment
       PROGBITS        00000000 000105 00002c 01   0   0  1
       [00000030]: MERGE, STRINGS
  [20] .note.GNU-stack
       PROGBITS        00000000 000131 000000 00   0   0  1
       [00000000]: 
  [21] .eh_frame
       PROGBITS        00000000 000134 0000b8 00   0   0  4
       [00000002]: ALLOC
  [22] .rel.eh_frame
       REL             00000000 0009ac 000028 08  24  21  4
       [00000000]: 
  [23] .shstrtab
       STRTAB          00000000 0001ec 00010e 00   0   0  1
       [00000000]: 
  [24] .symtab
       SYMTAB          00000000 00070c 0001c0 10  25  22  4
       [00000000]: 
  [25] .strtab
       STRTAB          00000000 0008cc 000070 00   0   0  1
       [00000000]: 

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

helongbao@lubaoquan-HP-280-Pro-G1-MT:~/leixiaoye$ readelf -t main.o
There are 13 section headers, starting at offset 0x24c:

Section Headers:
  [Nr] Name
       Type            Addr     Off    Size   ES   Lk Inf Al
       Flags
  [ 0] 
       NULL            00000000 000000 000000 00   0   0  0
       [00000000]: 
  [ 1] .text
       PROGBITS        00000000 000034 0000b6 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 2] .rel.text
       REL             00000000 0005f4 000070 08  11   1  4
       [00000000]: 
  [ 3] .data
       PROGBITS        00000000 0000ea 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 4] .bss
       NOBITS          00000000 0000ea 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 5] .rodata
       PROGBITS        00000000 0000ea 00001b 00   0   0  1
       [00000002]: ALLOC
  [ 6] .comment
       PROGBITS        00000000 000105 00002c 01   0   0  1
       [00000030]: MERGE, STRINGS
  [ 7] .note.GNU-stack
       PROGBITS        00000000 000131 000000 00   0   0  1
       [00000000]: 
  [ 8] .eh_frame
       PROGBITS        00000000 000134 0000b8 00   0   0  4
       [00000002]: ALLOC
  [ 9] .rel.eh_frame
       REL             00000000 000664 000028 08  11   8  4
       [00000000]: 
  [10] .shstrtab
       STRTAB          00000000 0001ec 00005f 00   0   0  1
       [00000000]: 
  [11] .symtab
       SYMTAB          00000000 000454 000130 10  12  13  4
       [00000000]: 
  [12] .strtab
       STRTAB          00000000 000584 000070 00   0   0  1
       [00000000]: 

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,820评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,648评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,324评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,714评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,724评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,328评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,897评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,804评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,345评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,431评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,561评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,238评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,928评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,417评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,528评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,983评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,573评论 2 359