轉自:http://blog.csdn.net/princess9/article/details/6567678html
通常來講要現有項目中的編譯選項,設置新的project的編譯選項linux
編譯器 就是將「高級語言」翻譯爲「機器語言(低級語言)」的程序。一個現代編譯器的主要工做流程:源代碼 (source code) → 預處理器 (preprocessor) → 編譯器 (compiler) → 彙編程序 (assembler) → 目標代碼 (object code) → 連接器 (Linker) → 可執行程序 (executables)。c++
分類
GCC家族
Cygwin Mingw32 DJGPP Dev-C++ (Mingw32) 還有正宗的GNU GCC 2.95.5~3.0.0.4版本 GNU C++ g++ 是一個開源的C++編譯器,GCC3.3對標準化C++的支持達96.15%。 值得一提的是,gcc是gnu c的編譯器, g++是gnu c++的編譯器, 而egcs(Enhanced GNU Compiler Suite)能夠認爲是gcc的改進版。目前gcc已經更名,從原來表明GNU C Compiler改變爲表明GNU Compiler Collection。而MinGW或Cgywin,是在windows平臺上的gnu c/c++編譯器,以及庫文件,運行環境的集合。 在GCC家族中GNU GCC是根本,其它的編譯器版本都是從它導出的。其中,Cygwin和Mingw32都是WIN32平臺下的編譯器,DJGPP是DOS下的32位編譯 器。你們所熟知的DEV-C++充其量只是GCC的一個外殼,它所自帶的編譯器就是Mingw32的一個版本。這些GCC的版本中,Cygwin是最大 的,它與其說是一個編譯器,倒不如說是一套編程工具。它不只有編譯器,還有其它不少的工具。其實,它就是一個UNIX系統在WIN32平臺上的實現。實現 了大多經常使用的UNIX工具,最近的版本中連Apache這樣的「工具」都集成進來的。不過,Cygwin雖然功能強大,但它卻不是很易用(和UNIX相 似,熟悉UNIX的人用它能夠很快上手),由於太多其它的工具分散了人們的注意力。相比之下Mingw32就要好用得多,它只有最基本的幾個編程工具(只 惋惜它不自帶GDB)。GCC中並不僅是C/C++編譯器,其中還有不少其它的編譯器如JAVA,Fortran,ADA等。它是一個編譯器集合,不過有 些編譯器只能在UNIX系統上用。web
MS家族
MSC 5.0、6.0、7.0 MSQC 1.0、2.5 MSVC 1.0、4.二、6.0、7.0 Visual C++ VC++6.0對標準化C++的兼容僅達83.43%。 它是Visual Studio、Visual Studio.net 200二、Visual Studio.net 200三、Visual Studio.net 2005的後臺 C++編譯器。隨着Stanley Lippman等編譯器設計大師的加盟,它變得很是成熟可靠了。Visual C++ 7.1對標準C++的兼容性達到98.22%。objective-c
Linux中gcc,g++經常使用編譯選項
-x language filename
設定文件所使用的語言,使後綴名無效,對之後的多個有效.也就是根據約定,C語言的後綴名稱是.c的,而C++的後綴名是.C或者.cpp,若是你很個 性,決定你的C代碼文件的後綴名是.pig 哈哈,那你就要用這個參數,這個參數對他後面的文件名都起做用,除非到了下一個參數的使用。創意產品網 可使用的參數有下面的這些:
`c', `objective-c', `c-header', `c++', `cpp-output', `assembler', and `a
ssembler-with-cpp'.
看到英文,應該能夠理解的。
例子用法: cd..
gcc -x c hello.pig數據庫
-x none filename
關掉上一個 選項 ,也就是讓gcc根據文件名後綴,自動識別文件類型
例子用法:
gcc -x c hello.pig -x none hello2.c
-c
只激活預處理,編譯,和彙編,也就是他只把程序作成obj文件
例子用法:
gcc -c hello.c
他將生成.o的obj文件
-S
只激活預處理和編譯,就是指把文件編譯成爲彙編代碼。
例子用法
gcc -S hello.c
他將生成.s的彙編代碼,你能夠用文本編輯器察看
-E
只激活預處理,這個不生成文件,你須要把它重定向到一個輸出文件裏面.
例子用法:
gcc -E hello.c > pianoapan.txt
gcc -E hello.c | more
慢慢看吧,一個hello word 也要預處理成800行的代碼
-o
制定目標名稱,缺省的時候,gcc 編譯出來的文件是a.out,很難聽,若是你和我有同感,改掉它,哈哈
例子用法
gcc -o hello.exe hello.c (哦,windows用習慣了)
gcc -o hello.asm -S hello.c
-pipe
使用管道代替編譯中臨時文件,在使用非gnu彙編工具的時候,可能有些問題
gcc -pipe -o hello.exe hello.c 編程
-shared-libgcc 該選項指定使用共享版本的libgcc,在沒有共享版本的libgcc的機器上該選項無效windows
-static-libgcc數組
-specs=<filename> gcc驅動程序讀取該文件以肯定哪些選項應該傳遞給那些子進程。
該選項能夠經過指定配置文件來覆蓋默認配置,指定的文件將在默認配置文件讀取後進行處理以修改默認配置。sass
-ansi
關閉gnu c中與ansi c不兼容的特性,激活ansi c的專有特性(包括禁止一些asm inline typeof關鍵字,以及UNIX,vax等預處理宏
/* 註釋中的不經常使用****************************************************
-fno-asm
此選項 實現ansi 選項 的功能的一部分,它禁止將asm,inline和typeof用做關鍵字。
-fno-strict-prototype
只對g++ 起做用,使用這個 選項 ,g++ 將對不帶參數的函數,都認爲是沒有顯式的對參數的個數和類型說明,而不是沒有參數.
而gcc不管是否使用這個參數,都將對沒有帶參數的函數,認爲沒有顯式說明的類型
-fthis-is-varialble
就是向傳統c++看齊,可使用this當通常變量使用.
-fcond-mismatch
容許條件表達式的第二和第三參數類型不匹配,表達式的值將爲void類型
-funsigned-char
-fno-signed-char
-fsigned-char
-fno-unsigned-char
這四個參數是對char類型進行設置,決定將char類型設置成unsigned char(前兩個參
數)或者 signed char(後兩個參數)
*註釋完成*********************************************/
-include file
包含某個代碼,簡單來講,就是便於某個文件須要另外一個文件的時候,就能夠用它設
定,功能就至關於在代碼中使用#i nclude<filename>
例子用法:
gcc hello.c -include /root/pianopan.h
-imacros file
將file文件的宏,擴展到gcc/g++ 的輸入文件,宏定義自己並不出如今輸入文件中
-Dmacro
至關於C語言中的#define macro
-Dmacro=defn
至關於C語言中的#define macro=defn
-Umacro
至關於C語言中的#undef macro
-undef
取消對任何非標準宏的定義
-Idir
在你是用#i nclude"file"的時候,gcc/g++ 會先在當前目錄查找你所制定的頭文件,如
果沒有找到,他回到缺省的頭文件目錄找,若是使用-I制定了目錄,他
回先在你所制定的目錄查找,而後再按常規的順序去找.
對於#i nclude<file>,gcc/g++ 會到-I制定的目錄查找,查找不到,而後將到系統的缺
省的頭文件目錄查找
-I-
就是取消前一個參數的功能,因此通常在-Idir以後使用
-idirafter dir
在-I的目錄裏面查找失敗,講到這個目錄裏面查找.
-iprefix prefix
-iwithprefix dir
通常一塊兒使用,當-I的目錄查找失敗,會到prefix+dir下查找
-nostdinc
使編譯器再也不繫統缺省的頭文件目錄裏面找頭文件,通常和-I聯合使用,明確限定頭
文件的位置
-nostdin C++
規定不在g++ 指定的標準路經中搜索,但仍在其餘路徑中搜索,.此選項 在創libg++庫
使用
-C
在預處理的時候,不刪除註釋信息,通常和-E使用,有時候分析程序,用這個很方便的
-M
生成文件關聯的信息。包含目標文件所依賴的全部源代碼你能夠用gcc -M hello.c
來測試一下,很簡單。
-MM
和上面的那個同樣,可是它將忽略由#i nclude<file>形成的依賴關係。
-MD
和-M相同,可是輸出將導入到.d的文件裏面
-MMD
和-MM相同,可是輸出將導入到.d的文件裏面
-Wa,option
此選項 傳遞option給彙編程序;若是option中間有逗號,就將option分紅多個選項 ,然
後傳遞給會彙編程序
-Wl.option
此選項 傳遞option給鏈接程序;若是option中間有逗號,就將option分紅多個選項 ,然
後傳遞給會鏈接程序.
-llibrary
制定編譯的時候使用的庫
例子用法
gcc -lcurses hello.c
使用ncurses庫編譯程序
-Ldir
制定編譯的時候,搜索庫的路徑。好比你本身的庫,能夠用它制定目錄,否則
編譯器將只在標準庫的目錄找。這個dir就是目錄的名稱。
-O0
-O1
-O2
-O3
編譯器的優化選項 的4個級別,-O0表示沒有優化,-O1爲缺省值,-O3優化級別最高
-g
只是編譯器,在編譯的時候,產生調試信息。
-gstabs
此選項 以stabs格式聲稱調試信息,可是不包括gdb調試信息.
-gstabs+
此選項 以stabs格式聲稱調試信息,而且包含僅供gdb使用的額外調試信息.
-ggdb
此選項 將盡量的生成gdb的可使用的調試信息.
-static
此選項 將禁止使用動態庫,因此,編譯出來的東西,通常都很大,也不須要什麼
動態鏈接庫,就能夠運行.
-share
此選項 將盡可能使用動態庫,因此生成文件比較小,可是須要系統由動態庫.
-traditional
試圖讓編譯器支持傳統的C語言特性
-
-v
-
打印詳細的編譯連接過程,
本文討論gcc的一些經常使用編譯選項對代碼的影響。固然代碼變了,
它的內存佈局也就會變了,隨之exploit也就要作相應的變更。
gcc的編譯選項實在太多,本文檢了幾個最經常使用的選項。
★ 演示程序
[alert7@redhat62 alert7]$ cat > test.c
#include <stdio.h>
void hi(void)
{
printf("hi");
}
int main(int argc, char *argv[])
{
hi();
return 0;
}
★ 通常狀況
[alert7@redhat62 alert7]$ gcc -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e4 <main>: push %ebp
0x80483e5 <main+1>: mov %esp,%ebp
0x80483e7 <main+3>: call 0x80483d0 <hi>
0x80483ec <main+8>: xor %eax,%eax
0x80483ee <main+10>: jmp 0x80483f0 <main+12>
0x80483f0 <main+12>: leave
0x80483f1 <main+13>: ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push %ebp
0x80483d1 <hi+1>: mov %esp,%ebp
0x80483d3 <hi+3>: push $0x8048450
0x80483d8 <hi+8>: call 0x8048308 <printf>
0x80483dd <hi+13>: add $0x4,%esp
0x80483e0 <hi+16>: leave
0x80483e1 <hi+17>: ret
0x80483e2 <hi+18>: mov %esi,%esi
End of assembler dump.
來看看部分的內存映象
(內存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 調用main函數前的esp
|bffffb98| 調用main函數前的ebp
0xbffffb78 +--------+ <-- main函數的ebp
|080483ec| hi()的返回地址
0xbffffb74 +--------+
|bffffb78| 調用hi()前的esp
0xbffffb70 +--------+
|08048450| "hi"的地址
0xbffffb6c +--------+
| ...... |
(內存低址)
leave 指令所作的操做至關於MOV ESP,EBP 而後 POP EBP
ret 指令所作的操做至關於POP EIP
★ -O 編譯選項
With `-O', the compiler tries to reduce code size and execution time.
When you specify `-O', the two options `-fthread-jumps' and
`-fdefer-pop' are turned on
優化,減小代碼大小和執行的時間
[alert7@redhat62 alert7]$ gcc -O -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: push %ebp
0x80483d9 <main+1>: mov %esp,%ebp
0x80483db <main+3>: call 0x80483c8 <hi>
0x80483e0 <main+8>: xor %eax,%eax
0x80483e2 <main+10>: leave
0x80483e3 <main+11>: ret
0x80483e4 <main+12>: nop
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push %ebp
0x80483c9 <hi+1>: mov %esp,%ebp
0x80483cb <hi+3>: push $0x8048440
0x80483d0 <hi+8>: call 0x8048308 <printf>
0x80483d5 <hi+13>: leave
0x80483d6 <hi+14>: ret
0x80483d7 <hi+15>: nop
End of assembler dump.
在main()中,把一條jmp指令優化掉了,很顯然,這條指令是能夠不須要的。
在hi()中,把add $0x4,%esp優化掉了,這會不會使stack不平衡呢?
來看看部分的內存映象
(內存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 調用main函數前的esp
|bffffb98| 調用main函數前的ebp
0xbffffb78 +--------+ <-- main函數的ebp
|080483e0| hi()的返回地址
0xbffffb74 +--------+
|bffffb78| 調用hi()前的esp
0xbffffb70 +--------+
|08048440| "hi"的地址
0xbffffb6c +--------+
| ...... |
(內存低址)
leave 指令所作的操做至關於把MOV ESP,EBP 而後 POP EBP
看到leave指令操做了沒有,先把ebp-->esp,再pop ebp,這樣即便
在過程內堆棧的esp,ebp是不平衡的,但只要返回時候碰到leave指令
就會平衡了,因此把add $0x4,%esp優化掉也是沒有問題的。
★ -O2 編譯選項
-O2 Optimize even more. Nearly all supported optimizations that do
not involve a space-speed tradeoff are performed. Loop unrolling
and function inlining are not done, for example. As compared to -O,
this option increases both compilation time and the performance of
the generated code.
[alert7@redhat62 alert7]$ gcc -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11757 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: push %ebp
0x80483d9 <main+1>: mov %esp,%ebp
0x80483db <main+3>: call 0x80483c8 <hi>
0x80483e0 <main+8>: xor %eax,%eax
0x80483e2 <main+10>: leave
0x80483e3 <main+11>: ret
...
0x80483ef <main+23>: nop
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push %ebp
0x80483c9 <hi+1>: mov %esp,%ebp
0x80483cb <hi+3>: push $0x8048440
0x80483d0 <hi+8>: call 0x8048308 <printf>
0x80483d5 <hi+13>: leave
0x80483d6 <hi+14>: ret
0x80483d7 <hi+15>: nop
End of assembler dump.
因爲程序比較簡單,再優化也沒有好優化的了,因此跟-O出來的同樣。
★ -fomit-frame-pointer 編譯選項
-fomit-frame-pointer
Don't keep the frame pointer in a register for functions
that don't need one. This avoids the instructions to save,
set up and restore frame pointers; it also makes an extra
register available in many functions. It also makes
debugging impossible on most machines.
忽略幀指針。這樣在程序就不須要保存,安裝,和恢復ebp了。這樣ebp也就是一個
free的register了,在函數中就能夠隨便使用了。
[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11773 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483e0 <main>: call 0x80483d0 <hi>
0x80483e5 <main+5>: xor %eax,%eax
0x80483e7 <main+7>: jmp 0x80483f0 <main+16>
0x80483e9 <main+9>: lea 0x0(%esi,1),%esi
0x80483f0 <main+16>: ret
....
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push $0x8048450
0x80483d5 <hi+5>: call 0x8048308 <printf>
0x80483da <hi+10>: add $0x4,%esp
0x80483dd <hi+13>: ret
0x80483de <hi+14>: mov %esi,%esi
End of assembler dump.
在main()和hi()中都去掉了如下指令
push %ebp
mov %esp,%ebp//這兩條指令安裝
leave//這條指令恢復
來看看部分的內存映象
(內存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+
|080483e5| hi()的返回地址
0xbffffb78 +--------+
|08048450| "hi"字符串的地址
0xbffffb74 +--------+
| ...... |
(內存低址)
沒有保存上層執行環境的ebp.
★ -fomit-frame-pointer && -O2
-fomit-frame-pointer編譯選項去掉了
push %ebp
mov %esp,%ebp//這兩條指令安裝
leave//這條指令恢復
-O2編譯選項去掉了
add $0x4,%esp
兩個加起來會不會這四條指令一塊兒去掉,從而使stack不平衡呢?
[alert7@redhat62 alert7]$ gcc -fomit-frame-pointer -O2 -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11741 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483d8 <main>: call 0x80483c8 <hi>
0x80483dd <main+5>: xor %eax,%eax
0x80483df <main+7>: ret
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483c8 <hi>: push $0x8048430
0x80483cd <hi+5>: call 0x8048308 <printf>
0x80483d2 <hi+10>: add $0x4,%esp
0x80483d5 <hi+13>: ret
0x80483d6 <hi+14>: mov %esi,%esi
End of assembler dump.
來看看部分的內存映象
(內存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+
|080483dd| hi()的返回地址
0xbffffb78 +--------+
|08048430| "hi"字符串的地址
0xbffffb74 +--------+
| ...... |
(內存低址)
此時就沒有把add $0x4,%esp優化掉,若是優化掉的話,整個stack就
會變的不平衡,從而會致使程序出錯。
★ -fPIC 編譯選項
-fPIC If supported for the target machine, emit position-independent
code, suitable for dynamic linking,even if branches need large
displacements.
產生位置無關代碼(PIC),通常建立共享庫時用到。
在x86上,PIC的代碼的符號引用都是經過ebx進行操做的。
[alert7@redhat62 alert7]$ gcc -fPIC -o test test.c
[alert7@redhat62 alert7]$ wc -c test
11805 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80483f8 <main>: push %ebp
0x80483f9 <main+1>: mov %esp,%ebp
0x80483fb <main+3>: push %ebx
0x80483fc <main+4>: call 0x8048401 <main+9>
0x8048401 <main+9>: pop %ebx//取得該指令的地址
0x8048402 <main+10>: add $0x1093,%ebx//此時ebx裏面存放着是GOT表的地址
0x8048408 <main+16>: call 0x80483d0 <hi>
0x804840d <main+21>: xor %eax,%eax
0x804840f <main+23>: jmp 0x8048411 <main+25>
0x8048411 <main+25>: mov 0xfffffffc(%ebp),%ebx
0x8048414 <main+28>: leave
0x8048415 <main+29>: ret
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80483d0 <hi>: push %ebp
0x80483d1 <hi+1>: mov %esp,%ebp
0x80483d3 <hi+3>: push %ebx
0x80483d4 <hi+4>: call 0x80483d9 <hi+9>
0x80483d9 <hi+9>: pop %ebx
0x80483da <hi+10>: add $0x10bb,%ebx
0x80483e0 <hi+16>: lea 0xffffefdc(%ebx),%edx
0x80483e6 <hi+22>: mov %edx,%eax
0x80483e8 <hi+24>: push %eax
0x80483e9 <hi+25>: call 0x8048308 <printf>
0x80483ee <hi+30>: add $0x4,%esp
0x80483f1 <hi+33>: mov 0xfffffffc(%ebp),%ebx
0x80483f4 <hi+36>: leave
0x80483f5 <hi+37>: ret
0x80483f6 <hi+38>: mov %esi,%esi
End of assembler dump.
來看看部分的內存映象
(內存高址)
+--------+
|bffffbc4| argv的地址(即argv[0]的地址)
0xbffffb84 +--------+
|00000001| argc的值
0xbffffb80 +--------+
|400309cb|main的返回地址
0xbffffb7c +--------+ <-- 調用main函數前的esp
|bffffb98| 調用main函數前的ebp
0xbffffb78 +--------+ <-- main函數的ebp
|401081ec| 保存的ebx
0xbffffb74 +--------+
|0804840d| (存放過call 0x8048401的下一條指令地址)
0xbffffb70 +--------+
|bffffb78| 調用hi()前的esp
0xbffffb6c +--------+
|08049494| GOT表地址
0xbffffb68 +--------+
|08048470|(存放過call 0x80483d9的下一條指令地址)
0xbffffb64 +--------+
| ...... |
(內存低址)
★ -static 編譯選項
-static
On systems that support dynamic linking, this prevents
linking with the shared libraries. On other systems,
this option has no effect.
把一些函數都靜態的編譯到程序中,而無需動態連接了。
[alert7@redhat62 alert7]$ gcc -o test -static test.c
[alert7@redhat62 alert7]$ wc -c test
962808 test
[alert7@redhat62 alert7]$ gdb -q test
(gdb) disass main
Dump of assembler code for function main:
0x80481b4 <main>: push %ebp
0x80481b5 <main+1>: mov %esp,%ebp
0x80481b7 <main+3>: call 0x80481a0 <hi>
0x80481bc <main+8>: xor %eax,%eax
0x80481be <main+10>: jmp 0x80481c0 <main+12>
0x80481c0 <main+12>: leave
0x80481c1 <main+13>: ret
...
End of assembler dump.
(gdb) disass hi
Dump of assembler code for function hi:
0x80481a0 <hi>: push %ebp
0x80481a1 <hi+1>: mov %esp,%ebp
0x80481a3 <hi+3>: push $0x8071528
0x80481a8 <hi+8>: call 0x804865c <printf>
0x80481ad <hi+13>: add $0x4,%esp
0x80481b0 <hi+16>: leave
0x80481b1 <hi+17>: ret
0x80481b2 <hi+18>: mov %esi,%esi
End of assembler dump.
[alert7@redhat62 alert7]$ ldd test
not a dynamic executable
-static出來的代碼已經沒有PLT了,GOT雖然有,已經所有爲0了。
★ 小節
拋磚引玉般簡單的實例描述了下gcc經常使用的編譯選項對代碼的影響。
不正之處,還請斧正。謝謝。
不少弟兄可能都很關心如何優化編譯本身的程序,雖然本人不同意"骨灰"玩法,卻也不得不認可這是掌握gcc的絕佳途徑;
所以獻上此帖,以供各位玩家參考,絕對原創噢
============================
大多數程序和庫在編譯時默認的優化級別是"2"(使用gcc選項:"-O2")而且在Intel/AMD平臺上默認按照i386處理器來編譯。
若是你只想讓編譯出來的程序運行在特定的平臺上,就須要執行更高級的編譯器優化選項,以產生只能運行於特定平臺的代碼。
一種方法是修改每一個源碼包中的Makefile文件,在其中尋找CFLAGS和CXXFLAGS變量(C和C++編譯器的編譯選項)並修改它的值。
一些源碼包好比binutils, gcc, glibc等等,在每一個子文件夾中都有Makefile文件,這樣修改起來就太累了!
另外一種簡易作法是設置CFLAGS和CXXFLAGS環境變量。大多數configure腳本會使用這兩個環境變量代替Makefile文件中的值。
可是少數configure腳本並不這樣作,他們必須須要手動編輯才行。
爲了設置CFLAGS和CXXFLAGS環境變量,你能夠在bash中執行以下命令(也能夠寫進.bashrc以成爲默認值):
export CFLAGS="-O3 -march=<cpu類型>" && CXXFLAGS=$CFLAGS
這是一個確保可以在幾乎全部平臺上都能正常工做的最小設置。
"-march"選項表示爲特定的cpu類型編譯二進制代碼(不能在更低級別的cpu上運行),
Intel一般是:pentium2, pentium3, pentium3m, pentium4, pentium4m, pentium-m, prescott, nocona
說明:pentium3m/pentium4m是筆記本用的移動P3/P4;pentium-m是迅馳I/II代筆記本的cpu;
prescott是帶SSE3的P4(以滾燙到能夠煎雞蛋而聞名);nocona則是最新的帶有EMT64(64位)的P4(一樣能夠煎雞蛋)
AMD一般是:k6, k6-2, k6-3, athlon, athlon-tbird, athlon-xp, athlon-mp, opteron, athlon64, athlon-fx
用AMD的通常都是DIYer,就沒必要解釋了吧。
若是編譯時沒有抱怨"segmentation fault, core dumped",那麼你設定的"-O"優化參數通常就沒什麼問題。
不然請下降優化級別("-O3" -> "-O2" -> "-O1" -> 取消)。
我的意見:服務器使用"-O2"就能夠了,它是最安全的優化參數(集合);桌面可使用"-O3" ;
不鼓勵使用過多的自定義優化選項,其實他們之間沒什麼明顯的速度差別(有時"-O3"反而更慢)。
編譯器對硬件很是敏感,特別是在使用較高的優化級別的時候,一丁點的內存錯誤均可能致使致命的失敗。
因此在編譯時請千萬不要超頻你的電腦(我編譯關鍵程序時老是先降頻然的)。
注意:選項的順序很重要,若是有兩個選項互相沖突,則之後一個爲準。
好比"-O3"將打開-finline-functions選項,可是能夠用"-O3 -fno-inline-functions"既使用-O3的功能又關閉函數內嵌功能。
更多的優化選項請參見:
http://gcc.gnu.org/onlinedocs/gcc-3....e-Options.html
http://gcc.gnu.org/onlinedocs/gcc-3....4-Options.html
http://gcc.gnu.org/onlinedocs/gcc-4....e-Options.html
http://gcc.gnu.org/onlinedocs/gcc-4....4-Options.html
全部GCC選項完整列表參見:
http://gcc.gnu.org/onlinedocs/gcc-3....n-Summary.html
http://gcc.gnu.org/onlinedocs/gcc-4....n-Summary.html
有兩個頁面值的參考:
(對於gentoo-1.4)比較安全的優化選項
http://www.freehackers.org/gentoo/gc...flag_gcc3.html
(對於gentoo-1.4)進階優化選項
http://www.freehackers.org/gentoo/gc...g_gcc3opt.html
*******************************************************************
哦,忘了說一聲,"-O2"已經啓用絕大多數安全的優化選項了,因此其實你沒必要對那一堆選項發愁。
先說說"-O3"在"-O2"基礎上增長的幾項,你能夠按需添加(還算比較安全):
[gcc-3.4.4]
-finline-functions 容許編譯器選擇某些簡單的函數在其被調用處展開
-fweb 爲每一個web結構體分配一個僞寄存器
-frename-registers 試圖驅除代碼中的假依賴關係,這個選項對具備大量寄存器的機器頗有效。
[gcc-4.0.2]
-finline-functions 說明如上
-funswitch-loops 將循環體中不改變值的變量移動到循環體以外
-fgcse-after-reload **不太明白它的含義**[哪位大峽知道給小弟講解一下,先行謝過 ]
說完"-O3"再說說在嵌入式系統上經常使用的"-Os"選項,這個選項其實也很重要,它的含義是對生成的二進制代碼進行尺寸上的優化,它打開了所 有"-O2"打開的選項,所以一般認爲的"-Os"生成的二進制代碼執行效率低的潛在乎識是錯誤的!固然該選項與"-O2"的不一樣之處在於它在"-O2" 的基礎上禁止了全部爲了對齊而插入的空間,也就是將全部"-falign-*"系列的選項禁用了。這種禁用到底是否必定下降了代碼的執行效率,依據程序的 不一樣而不一樣,聽說某些狀況下"-Os"的效率比"-O3"還要高14%!請兄弟們在實踐中本身摸索吧...
---------------------------------------------
下面選擇我認爲比較重要的幾項簡單介紹一下[gcc-3.4.4],GCC選項完整列表太長了!精力有限。
[注意]這裏列出的都是非默認 的選項,你只須要添加你所須要的選項便可
-w 禁止輸出警告消息
-Werror 將全部警告轉換爲錯誤
-Wall 顯示全部的警告消息
-v 顯示編譯程序的當前版本號
-V<version> 指定gcc將要運行的版本。只有在安裝了多個版本gcc的機器上纔有效。
-ansi 按照ANSI標準編譯程序,但並不限制與標準並不衝突的GNU擴展(通常不用該選項)
-pedantic 若是要限制代碼必須嚴格符合ISO標準,就在"-ansi"的基礎上同時啓用這個選項(不多使用)
-std=<name> 指定C語言的標準(c89,c99,gnu89),該選項禁止了GNU C的擴展關鍵字asm,typeof,inline (通常不用該選項)
-static 鏈接器將忽略動態鏈接庫,同時經過將靜態目標文件直接包含到結果目標文件完成對全部引用的解析。
-shared 鏈接器將生成共享目標代碼,該共享庫可在運行時動態鏈接到程序造成完整的可執行體。
若是使用gcc命令建立共享庫做爲其輸出,該選項能夠防止鏈接器將缺失main()方法視爲錯誤。
爲了能夠正確的工做,應該一致的使用選項"-fpic"以及目標平臺選項編譯構成同一個庫的全部共享目標模塊。
-shared-libgcc 該選項指定使用共享版本的libgcc,在沒有共享版本的libgcc的機器上該選項無效。
-specs=<filename> gcc驅動程序讀取該文件以肯定哪些選項應該傳遞給那些子進程。
該選項能夠經過指定配置文件來覆蓋默認配置,指定的文件將在默認配置文件讀取後進行處理以修改默認配置。
-pipe 使用管道而不是臨時文件一個階段到另外一個階段交換輸出的方式,能夠加快編譯速度。建議使用。
-o <filename> 指定輸出文件,對各類輸出皆有效。因爲只能指定一個文件,因此在產生多個輸出文件的狀況下不要使用該選項。
--help 顯示gcc的命令行選項列表;與"-v"一塊兒使用時還將顯示gcc調用的各個進程所接受的選項。
--target-help 顯示目標機器相關的命令行選項列表
-b<machine> 指示須要編譯程序的目標機器;默認爲編譯程序所運行的目標機編譯代碼。
目標機經過指定包含編譯程序的目錄來肯定,一般爲/usr/local/lib/gcc-lib/<machine>/<version>
-B<lib-prefix> 指定庫文件的位置,包括編譯程序的文件、執行程序和數據文件,若是須要運行子程序(如cpp,as,ld)就會用該前綴來定位。
這個前綴能夠是用冒號分割的多個路徑,環境變量GCC_EXEC_PREFIX和這個選項有相同的效果。
-I<dir> 指定搜索系統頭文件的目錄,能夠重複使用多個該選項指定多個目錄。
-dumpmachine 顯示該程序的目標機名字,不作其餘任何動做
-dumpspecs 顯示構件編譯程序的規範信息,包括用來編譯、彙編和鏈接gcc編譯程序自身用到的全部選項,不作其餘任何動做。
-dumpversion 顯示編譯程序自身的版本號,不作其餘任何動做
-falign-functions=N 將全部函數的起始地址在N(N=1,2,4,8,16...)的邊界上對齊,默認爲機器自身的默認值,指定爲1表示禁止對齊。
-falign-jumps=N 將分支目標在N(N=1,2,4,8,16...)的邊界上對齊,默認爲機器自身的默認值,指定爲1表示禁止對齊。
-fno-align-labels 建議使用它,以保證不和-falign-jumps("-O2"默認啓用的選項)衝突
-fno-align-loops 建議使用它,以確保不會在分支目標前插入多餘的空指令。
-fbranch-probabilities 在使用"-fprofile-arcs"選項編譯程序並執行它來建立包含每一個代碼塊執行次數的文件以後,程序能夠利用這一選項再次編譯,
文件中所產生的信息將被用來優化那些常常發生的分支代碼。若是沒有這些信息,gcc將猜想那一分支可能常常發生並進行優化。
這類優化信息將會存放在一個以源文件爲名字的並以".da"爲後綴的文件中。
-fno-guess-branch-probability 默認狀況下gcc將使用隨機模型進行猜想哪一個分支更可能被常常執行,並以此來優化代碼,該選項關閉它。
-fprofile-arcs 在使用這一選項編譯程序並運行它以建立包含每一個代碼塊的執行次數的文件後,程序能夠再次使用"-fbranch-probabilities"編譯,
文件中的信息能夠用來優化那些常常選取的分支。若是沒有這些信息,gcc將猜想哪一個分支將被常常運行以進行優化。
這類優化信息將會存放在一個以源文件爲名字的並以".da"爲後綴的文件中。
-fforce-addr 必須將地址複製到寄存器中才能對他們進行運算。因爲所需地址一般在前面已經加載到寄存器中了,因此這個選項能夠改進代碼。
-fforce-mem 必須將數值複製到寄存器中才能對他們進行運算。因爲所需數值一般在前面已經加載到寄存器中了,因此這個選項能夠改進代碼。
-ffreestanding 所編譯的程序可以在獨立的環境中運行,該環境能夠沒有標準庫,並且能夠不從main()函數開始運行。
該選項將設置"-fno-builtin",且等同於"-fno-hosted"。
-fhosted 所編譯的程序須要運行在宿主環境中,其中須要有完整的標準庫,並且main()函數具備int型的返回值。
-fno-builtin 除非利用"__builtin_"進行引用,不然不識別全部內建函數。
-fmerge-all-constants 試圖將跨編譯單元的全部常量值和數組合並在一個副本中。可是標準C/C++要求每一個變量都必須有不一樣的存儲位置。
-fmove-all-movables 將全部不變的表達式移動到循環體以外,這種作法的好壞取決於源代碼中的循環結構。
-fnon-call-exceptions 產生的代碼可供陷阱指令(如非法浮點運算和非法內存尋址)拋出異常,須要相關平臺的運行時支持,並不廣泛有效。
-fomit-frame-pointer 對於不須要棧指針的函數就不在寄存器中保存指針,所以能夠忽略存儲和檢索地址的代碼,並將寄存器用於普通用途。
全部"-O"級別都打開着一選項,但僅在調試器能夠不依靠棧指針運行時纔有效。建議不須要調試的狀況下顯式的設置它。
-fno-optional-diags 禁止輸出診斷消息,C++標準並不須要這些消息。
-fpermissive 將代碼中與標準不符合的診斷消息做爲警告而不是錯誤輸出。
-fpic 生成可用於共享庫的位置獨立代碼(PIC),全部的內存尋址均經過全局偏移表(GOT)完成。該選項並不是在全部的機器上都有效。
要肯定一個地址,須要將代碼自身的內存位置做爲表中的一項插入。該選項能夠產生在共享庫中存放並從中加載的目標模塊。
-fprefetch-loop-arrays 生成數組預讀取指令,對於使用巨大數組的程序能夠加快代碼執行速度,適合數據庫相關的大型軟件等。
-freg-struct-return 生成用寄存器返回短結構的代碼,若是寄存器沒法榮納將使用內存。
-fstack-check 爲防止程序棧溢出而進行必要的檢測,在多線程環境中運行時纔可能須要它。
-ftime-report 編譯完成後顯示編譯耗時的統計信息
-funroll-loops 若是在編譯時能夠肯定迭代的次數很是少並且循環中的指令也很是少,可使用該選項進行循環展開,以驅除循環和複製指令。
-finline-limit=<size> 對僞指令數超過<size>的函數,編譯程序將不進行展開,默認爲600
--param <name>=<value> gcc內部存在一些優化代碼程度的限制,調整這些限制就是調整整個優化全局。下面列出了參數的名字和對應的解釋:
名字 解釋
max-delay-slot-insn-search 較大的數目能夠生成更優化的代碼,可是會下降編譯速度,默認爲100
max-delay-slot-live-search 較大的數目能夠生成更優化的代碼,可是會下降編譯速度,默認爲333
max-gcse-memory 執行GCSE優化使用的最大內存量,過小將使該優化沒法進行,默認爲50M
max-gcse-passes 執行GCSE優化的最大迭代次數,默認爲1
*******************************************************************
說完了命令行選項,下面來講說與硬件體系結構(主要是cpu)相關的設置[僅針對i386/x86_64] 最大名鼎鼎的"-march"上面已經說過了,下面講講別的(僅挑些實用的) -mfpmath=sse P3和athlon-tbird以上級別的cpu支持 -masm=<dialect> 使用指定的dialect輸出彙編語言指令,可使用"intel"或"att";默認爲"att" -mieee-fp 指定編譯器使用IEEE浮點比較,這樣將會正確的處理比較結果爲無序的狀況。 -malign-double 將double, long double, long long對齊於雙字節邊界上;有助於生成更高速的代碼,可是程序的尺寸會變大。 -m128bit-long-double 指定long double爲128位,pentium以上的cpu更喜歡這種標準。 -mregparm=N 指定用於傳遞整數參數的寄存器數目(默認不使用寄存器)。0<=N<=3 ;注意:當N>0時你必須使用同一參數從新構建全部的模塊,包括全部的庫。 -mmmx -mno-mmx -msse -mno-sse -msse2 -mno-sse2 -msse3 -mno-sse3 -m3dnow -mno-3dnow 上面的這些不用解釋了,一看就明白,根據本身的CPU決定吧 -maccumulate-outgoing-args 指定在函數引導段中計算輸出參數所需最大空間,這在大部分現代cpu中是較快的方法;缺點是會增長代碼尺寸。 -mthreads 支持Mingw32的線程安全異常處理。對於依賴於線程安全異常處理的程序,必須啓用這個選項。 使用這個選項時會定義"-D_MT",它將包含使用選項"-lmingwthrd"鏈接的一個特殊的線程輔助庫,用於爲每一個線程清理異常處理數據。 -minline-all-stringops 嵌入全部的字符串操做。能夠提升字符串操做的性能,可是會增長代碼尺寸。 -momit-leaf-frame-pointer 不爲葉子函數在寄存器中保存棧指針,這樣能夠節省寄存器,可是將會是調試變的困難。參見"-fomit-frame-pointer"。 下面這幾個僅用於x86_64環境: -m64 生成專門運行於64位環境的代碼,不能運行於32位環境 -mcmodel=small [默認值]程序和它的符號必須位於2GB如下的地址空間。指針仍然是64位。程序能夠靜態鏈接也能夠動態鏈接。 -mcmodel=kernel 內核運行於2GB地址空間以外。在編譯linux內核時必須使用該選項! -mcmodel=medium 程序必須位於2GB如下的地址空間,可是它的符號能夠位於任何地址空間。程序能夠靜態鏈接也能夠動態鏈接。 注意:共享庫不能使用這個選項編譯! -mcmodel=large 對地址空間沒有任何限制,這個選項的功能目前還沒有實現。 ============================== 既然已經講了這麼多了索性再講講gcc使用的一些環境變量 除了大名鼎鼎的CFLAGS和CXXFLAGS之外(實際上是Autoconf的環境變量),再挑幾個說說: 全部的PATH類環境變量(除LD_RUN_PATH外)都是用冒號分割的目錄列表。 C_INCLUDE_PATH 編譯C程序時使用的環境變量,用於查找頭文件。 CPLUS_INCLUDE_PATH 編譯C++程序時使用的環境變量,用於查找頭文件。 OBJC_INCLUDE_PATH 編譯Obj-C程序時使用的環境變量,用於查找頭文件。 CPATH 編譯C/C++/Obj-C程序時使用的環境變量,用於查找頭文件。 COMPILER_PATH 若是沒有用GCC_EXEC_PREFIX定位子程序,編譯程序將會在此查找它的子程序。 LIBRARY_PATH 鏈接程序將在這些目錄中尋找特殊的鏈接程序文件。 LD_LIBRARY_PATH 該環境變量不影響編譯程序,可是程序運行的時候會有影響:程序會查找該目錄列表以尋找共享庫。 當不可以在編譯程序的目錄中找到共享庫的時候,執行程序必須設置該環境變量。 LD_RUN_PATH 該環境變量不影響編譯程序,可是程序運行的時候會有影響:它在運行時指出了文件的名字,運行的程序能夠由此獲得它的符號名字和地址。 因爲地址不會從新載入,於是可能符號應用其餘文件中的絕對地址。這個和ld工具使用的"-R"選項徹底同樣。 GCC_EXEC_PREFIX 編譯程序執行全部子程序的名字的前綴,默認值是"<prefix>/lib/gcc-lib/", 其中的<prefix>是安裝時configure腳本指定的前綴。 LANG 指定編譯程序使用的字符集,可用於建立寬字符文件、串文字、註釋;默認爲英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP",不支持中文] LC_ALL 指定多字節字符的字符分類,主要用於肯定字符串的字符邊界以及編譯程序使用何種語言發出診斷消息;默認設置與LANG相同。 中文相關的幾項:"zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5" TMPDIR 編譯程序存放臨時工做文件的臨時目錄,這些臨時文件一般在編譯結束時被刪除。