zoukankan      html  css  js  c++  java
  • [转]gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 参数详解

    背景

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

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

  • 相关阅读:
    这不是我心目中的比目猪!快来看看这只3D小猪佩奇!
    基于WebGL(ThingJS)的平面图导航,室内导航,3D聚焦 (二)
    通过3D可视化管理应对物联网数据过载——ThingJS油轮3D可视化管理
    阿里云物联网三维可视化套件(ThingJS)使用初体验
    基于WebGL(ThingJS)的平面图导航,室内导航,3D聚焦
    基于WebGL(ThingJS)的家具城 商场 3D展示 3D可视化 DEMO
    基于WebGL(ThingJS)的社区水电燃气管线3D可视化管理演示【三维管线,3D管线,水管可视化】
    js设置聊天信息停留在最底部
    js鼠标进入,延迟显示提示框
    js动态删除表格中的某一行
  • 原文地址:https://www.cnblogs.com/wlzy/p/10665756.html
Copyright © 2011-2022 走看看