現在的位置: 首頁 > 技術文章 > 基礎知識 > 正文

gcc -ffunction-sections -fdata-sections -Wl,–gc-sections 參數詳解

2018年08月29日 基礎知識 ⁄ 共 3086字 ⁄ 字號 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\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 [email protected] main.o

main_normal:
gcc -c main.c
gcc -o [email protected] 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

二八杠讨论心得
×