|
01 編譯選項和內(nèi)核編譯 首先我們都知道,Linux內(nèi)核如果用O0編譯,是無法編譯過的,Linux的內(nèi)核編譯,要么是O2,要么是Os,這點從Linux的Makefile里面可以看出: 當選擇了 CONFIG_CC_OPTIMIZE_FOR_SIZE 它會是Os,否則就是O2。 其實O2和Os,都是一些優(yōu)化選項的集合: gcc -c -Q -O2 --help=optimizers > /tmp/O2-opts gcc -c -Q -Os --help=optimizers > /tmp/Os-opts 前者傾向于基于速度的優(yōu)化,后者傾向于基于size更小的優(yōu)化。對比二者的開關(guān)選項: meld /tmp/O2-opts /tmp/Os-opts 發(fā)現(xiàn)差異小的可憐: O2和Os都使能了inline small函數(shù)和called once的函數(shù),但是O2里面-finline-functions是關(guān)閉的,而Os里面是開的。O2里面optimize-strlen是開的,Os里面這個選項是關(guān)閉的。相關(guān)選項的含義可以通過'man gcc'看出(有問題,找男人),譬如man gcc后檢索inline-functions: 從O0到O1,O2,O3,是一個開啟的優(yōu)化選項逐步加大的過程: kernel用O0編譯不過,是因為kernel本身也沒有想用O0能夠編譯過,它的設(shè)計里面包含了編譯會優(yōu)化的假想。下面我們用一個簡單的例子來說明。 02 一個簡單的例子 下面的代碼: O0編譯會報如下錯,說f()函數(shù)沒有定義: $ gcc -O0 cc.c cc.c:1:13: warning: ‘f’ used but never defined [enabled by default] void f(void); ^ /tmp/ccTwwtHG.o: In function `main': cc.c:(.text+0x19): undefined reference to `f' collect2: error: ld returned 1 exit status 但是用O2編譯,則沒有問題: $ gcc -O2 cc.c 原因在于,O2編譯,它意識到a==1,所以if(a>2),它不會成立,所以f()沒有定義也沒有關(guān)系。 把代碼稍微改一下后: O2這個時候也不行了: $ gcc -O2 cc.c /tmp/ccXiyBHn.o: In function `main': cc.c:(.text.startup+0x7): undefined reference to `f' collect2: error: ld returned 1 exit status 所以,通過這個例子,大家可以看出來為什么同樣的代碼,用O2就可以過,用O0就過不了。內(nèi)核里面有許多類似設(shè)想編譯器會進行優(yōu)化的代碼。 3.我們不想inline了 由于編譯的優(yōu)化,有些函數(shù)(比如小函數(shù)和全工程里面只被一個人調(diào)用的函數(shù))雖然沒有顯示地寫成inline,但是編譯器優(yōu)化為inline了,這給調(diào)試造成了一些麻煩,因為找不到這個函數(shù)對應(yīng)的symbol了。 這個時候,我們可以顯示地寫明某些函數(shù)我們不想inline: 否則,上面2個函數(shù),即便你代碼里面沒有寫inline,由于O2和Os使能了相關(guān)的inline選項,也可能被編譯器自動inline掉,如果我們想拒絕inline,可以通過noline來標識。 4.我不想被優(yōu)化 在全局已經(jīng)使能O1, O2, O3, Os的情況下,某個單獨的函數(shù)我們不想做任何的優(yōu)化,可以用__attribute__((optimize('O0')))來修飾這個函數(shù),比如我們把上述用O2可以編譯過的代碼進行如下修改: 重新用O2編譯: $ gcc -O2 cc.c /tmp/cc8M338p.o: In function `main': cc.c:(.text+0x19): undefined reference to `f' collect2: error: ld returned 1 exit status 5. 總結(jié)的話 下面給幾條實踐指南:
|
|
|
來自: 西北望msm66g9f > 《編程》