减少可执行程序的大小

一、背景
可执行程序需要链接一些静态库,但是静态库中的函数并没有全部使用,只用了其中的几个,但是系统默认会自动把整个静态库全部链接到可执行程序中,造成可执行程序的大小大大增加,浪费了flash空间和内存空间。

二、方法
因为GCC链接操作以section作为最小的处理单元,只要一个section中有某个符号被引用,该section就会被加入。
如果我们的某个.c程序中所有function都加入同一个section.则如果用到这个.c生成的.o的其中任何一个function.则必须将所有function(符号)加入其中。如此,则使用-ffunction-sections 和 -fdata-sections将每个符号创建为一个sections. sections名与function,data名保持一致。

则在link阶段,-Wl,–gc-sections 申明去掉不用的section。就可以去掉没用的function(符号)了。
1、编译时候加上 -ffunction-sections
2、链接时候加上 -Wl,–gc-sections

三、示例

func.h

int fun_0();
int fun_1();
int fun_2();
int fun_3();
int fun_4();
int fun_5();
int fun_6();

func.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "func.h"


int fun_0()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_1()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_2()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_3()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_4()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_5()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}
int fun_6()
{
    printf("%s: %d\n", __FUNCTION__, __LINE__);
    return 0;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "func.h"

int main()
{
    fun_0();

    return 0;
}

makefile



drop:
    gcc -c -ffunction-sections func.c
    gcc -c -ffunction-sections main.c
    gcc -Wl,--gc-sections -o test_size func.o main.o 

normal:
    gcc -c func.c
    gcc -c main.c
    gcc -o test_size func.o main.o

clean:
    rm *.o test_size

运行结果对比

root@ubuntu:/home/work/test/func# make normal 
gcc -c func.c
gcc -c main.c
gcc -o test_size func.o main.o
root@ubuntu:/home/work/test/func# ls -l
total 32
-rwxr--r-- 1 nobody nogroup  622 Jul  1 16:24 func.c
-rwxr--r-- 1 nobody nogroup  102 Jul  1 15:53 func.h
-rw-r--r-- 1 root   root    2048 Jul  1 16:25 func.o
-rwxr--r-- 1 nobody nogroup  125 Jul  1 16:24 main.c
-rw-r--r-- 1 root   root     960 Jul  1 16:25 main.o
-rwxr--r-- 1 nobody nogroup  239 Jul  1 16:01 Makefile
-rwxr-xr-x 1 root   root    7744 Jul  1 16:25 test_size
root@ubuntu:/home/work/test/func# make drop 
gcc -c -ffunction-sections func.c
gcc -c -ffunction-sections main.c
gcc -Wl,--gc-sections -o test_size func.o main.o 
root@ubuntu:/home/work/test/func# ls -l
total 32
-rwxr--r-- 1 nobody nogroup  622 Jul  1 16:24 func.c
-rwxr--r-- 1 nobody nogroup  102 Jul  1 15:53 func.h
-rw-r--r-- 1 root   root    2788 Jul  1 16:25 func.o
-rwxr--r-- 1 nobody nogroup  125 Jul  1 16:24 main.c
-rw-r--r-- 1 root   root    1028 Jul  1 16:25 main.o
-rwxr--r-- 1 nobody nogroup  239 Jul  1 16:01 Makefile
-rwxr-xr-x 1 root   root    7432 Jul  1 16:25 test_size

减少了 7744-7432=312 bytes

查看func.o关于section情况对比,看rel.text的内容,如果每个函数都有,那么就证明每个函数都是独立的section了,同理可查看静态库.a文件,readelf -t func.a

root@ubuntu:/home/work/test/func# readelf -t func.o 
There are 26 section headers, starting at offset 0x6d4:

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 000032 00   0   0  1
       [00000002]: ALLOC
  [ 5] .text.fun_0
       PROGBITS        00000000 000066 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 6] .rel.text.fun_0
       REL             00000000 0005f4 000018 08  24   5  4
       [00000040]: INFO LINK
  [ 7] .text.fun_1
       PROGBITS        00000000 00008a 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 8] .rel.text.fun_1
       REL             00000000 00060c 000018 08  24   7  4
       [00000040]: INFO LINK
  [ 9] .text.fun_2
       PROGBITS        00000000 0000ae 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [10] .rel.text.fun_2
       REL             00000000 000624 000018 08  24   9  4
       [00000040]: INFO LINK
  [11] .text.fun_3
       PROGBITS        00000000 0000d2 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [12] .rel.text.fun_3
       REL             00000000 00063c 000018 08  24  11  4
       [00000040]: INFO LINK
  [13] .text.fun_4
       PROGBITS        00000000 0000f6 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [14] .rel.text.fun_4
       REL             00000000 000654 000018 08  24  13  4
       [00000040]: INFO LINK
  [15] .text.fun_5
       PROGBITS        00000000 00011a 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [16] .rel.text.fun_5
       REL             00000000 00066c 000018 08  24  15  4
       [00000040]: INFO LINK
  [17] .text.fun_6
       PROGBITS        00000000 00013e 000024 00   0   0  1
       [00000006]: ALLOC, EXEC
  [18] .rel.text.fun_6
       REL             00000000 000684 000018 08  24  17  4
       [00000040]: INFO LINK
  [19] .comment
       PROGBITS        00000000 000162 000025 01   0   0  1
       [00000030]: MERGE, STRINGS
  [20] .note.GNU-stack
       PROGBITS        00000000 000187 000000 00   0   0  1
       [00000000]: 
  [21] .eh_frame
       PROGBITS        00000000 000188 0000f8 00   0   0  4
       [00000002]: ALLOC
  [22] .rel.eh_frame
       REL             00000000 00069c 000038 08  24  21  4
       [00000040]: INFO LINK
  [23] .shstrtab
       STRTAB          00000000 000280 0000cb 00   0   0  1
       [00000000]: 
  [24] .symtab
       SYMTAB          00000000 00034c 0001f0 10  25  23  4
       [00000000]: 
  [25] .strtab
       STRTAB          00000000 00053c 0000b7 00   0   0  1
       [00000000]: 
root@ubuntu:/home/work/test/func# 
root@ubuntu:/home/work/test/func# make clean
rm *.o test_size
root@ubuntu:/home/work/test/func# 
root@ubuntu:/home/work/test/func# 
root@ubuntu:/home/work/test/func# make normal 
gcc -c func.c
gcc -c main.c
gcc -o test_size func.o main.o
root@ubuntu:/home/work/test/func# 
root@ubuntu:/home/work/test/func# 
root@ubuntu:/home/work/test/func# readelf -t func.o 
There are 13 section headers, starting at offset 0x5f8:

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 0000fc 00   0   0  1
       [00000006]: ALLOC, EXEC
  [ 2] .rel.text
       REL             00000000 000518 0000a8 08  11   1  4
       [00000040]: INFO LINK
  [ 3] .data
       PROGBITS        00000000 000130 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 4] .bss
       NOBITS          00000000 000130 000000 00   0   0  1
       [00000003]: WRITE, ALLOC
  [ 5] .rodata
       PROGBITS        00000000 000130 000032 00   0   0  1
       [00000002]: ALLOC
  [ 6] .comment
       PROGBITS        00000000 000162 000025 01   0   0  1
       [00000030]: MERGE, STRINGS
  [ 7] .note.GNU-stack
       PROGBITS        00000000 000187 000000 00   0   0  1
       [00000000]: 
  [ 8] .eh_frame
       PROGBITS        00000000 000188 0000f8 00   0   0  4
       [00000002]: ALLOC
  [ 9] .rel.eh_frame
       REL             00000000 0005c0 000038 08  11   8  4
       [00000040]: INFO LINK
  [10] .shstrtab
       STRTAB          00000000 000280 00005f 00   0   0  1
       [00000000]: 
  [11] .symtab
       SYMTAB          00000000 0002e0 000180 10  12  16  4
       [00000000]: 
  [12] .strtab
       STRTAB          00000000 000460 0000b7 00   0   0  1
       [00000000]: 

注:
1)使用了section选项,当函数被声明了,但是函数没有被调用,函数体不实现也编译ok
2)但是函数体不能重复定义

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值