gcc -ffunction-sections -fdata-s

2019-03-08  本文已影响0人  Hope_加贝

转载: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]: 

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

上一篇下一篇

猜你喜欢

热点阅读