gcc 編譯 + 選項
一般來說要現有專案中的編譯選項,設定新的project的編譯選項
編譯器 就是將“高階語言”翻譯為“機器語言(低階語言)”的程式。一個現代編譯器的主要工作流程:原始碼 (source code) → 前處理器 (preprocessor) → 編譯器 (compiler) → 彙編程式 (assembler) → 目的碼 (object code) → 連結器 (Linker) → 可執行程式 (executables)。
分類
GCC家族
Cygwin Mingw32 DJGPP Dev-C++ (Mingw32) 還有正宗的GNU GCC 2.95.5~3.0.0.4版本 GNU C++
MS家族
MSC 5.0、6.0、7.0 MSQC 1.0、2.5 MSVC 1.0、4.2、6.0、7.0 Visual C++ VC++6.0對標準化C++的相容僅達83.43%。 它是Visual Studio、Visual Studio.net 2002、Visual Studio.net 2003、Visual Studio.net 2005的後臺 C++編譯器。隨著Stanley Lippman等編譯器設計大師的加盟,它變得非常成熟可靠了。Visual C++ 7.1對標準C++的相容性達到98.22%。
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的機器上該選項無效
-static-libgcc
-specs=<filename> gcc驅動程式讀取該檔案以確定哪些選項應該傳遞給那些子程序。
該選項可以通過指定配置檔案來覆蓋預設配置,指定的檔案將在預設配置檔案讀取後進行處理以修改預設配置。
-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的編譯選項實在太多,本文檢了幾個最常用的選項。
★ 演示程式
[[email protected] alert7]$ cat > test.c
#include <stdio.h>
void hi(void)
{
printf("hi");
}
int main(int argc, char *argv[])
{
hi();
return 0;
}
★ 一般情況
[[email protected] alert7]$ gcc -o test test.c
[[email protected] alert7]$ wc -c test
11773 test
[[email protected] 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
優化,減少程式碼大小和執行的時間
[[email protected] alert7]$ gcc -O -o test test.c
[[email protected] alert7]$ wc -c test
11757 test
[[email protected] 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.
[[email protected] alert7]$ gcc -O2 -o test test.c
[[email protected] alert7]$ wc -c test
11757 test
[[email protected] 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了,在函式中就可以隨便使用了。
[[email protected] alert7]$ gcc -fomit-frame-pointer -o test test.c
[[email protected] alert7]$ wc -c test
11773 test
[[email protected] 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不平衡呢?
[[email protected] alert7]$ gcc -fomit-frame-pointer -O2 -o test test.c
[[email protected] alert7]$ wc -c test
11741 test
[[email protected] 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進行操作的。
[[email protected] alert7]$ gcc -fPIC -o test test.c
[[email protected] alert7]$ wc -c test
11805 test
[[email protected] 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.
把一些函式都靜態的編譯到程式中,而無需動態連結了。
[[email protected] alert7]$ gcc -o test -static test.c
[[email protected] alert7]$ wc -c test
962808 test
[[email protected] 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.
[[email protected] 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 編譯程式存放臨時工作檔案的臨時目錄,這些臨時檔案通常在編譯結束時被刪除。
相關推薦
gcc編譯選項-Wl
-Wl選項告訴編譯器將後面的引數傳遞給連結器。 -soname則指定了動態庫的soname(簡單共享名,Short for shared object name) -Wl 表示後面的引數也就是-soname,libhello.so.1直接傳給聯結器ld進行處理
(轉載)gcc編譯選項總結
轉載自:https://blog.csdn.net/gatieme/article/details/21389603 常用編譯選項 gcc and g++分別是gnu的c & c++編譯器 gcc/g++在執行編譯工作的時候,總共需要4步 1.預處理,生成.i的檔案[前處理器cpp] 2.將預處
linux64平臺上編譯32位程式: GCC編譯選項 -m64 -m32 -mx32
x86-64 與 IA-64 x86-64一般稱為AMD x86-64,難道x86-64不是Intel首先搞出來的指令集麼?這回的確是AMD乾的,但是用的是Intel 16bits升到32bits向下相容的套路。大致是這樣的: x86:從1978年來的8086處理器開
gcc 編譯選項
摘自http://blog.csdn.net/liuchao1986105/article/details/6674822 版本] -0.13 [宣告] 這篇文件是我的關於gcc引數的筆記,我很懷念dos年代我用小本子,紀錄任何的dos 命令的引數.哈哈,下面的
gcc 編譯 + 選項
一般來說要現有專案中的編譯選項,設定新的project的編譯選項 編譯器 就是將“高階語言”翻譯為“機器語言(低階語言)”的程式。一個現代編譯器的主要工作流程:原始碼 (source code) → 前處理器 (preprocessor) → 編譯器 (compil
GCC編譯選項-包含的標頭檔案
許多情況下,標頭檔案和原始檔會單獨存放在不同的目錄中。 可以直接在.c檔案中利用#include“/path/file.h", 通過指定標頭檔案的路徑(可以是絕對路徑,也可以是相對路徑)來包含標頭檔案. 但這明顯降低了程式的可移植性. 在別的系統環境下編譯可能會出現問題
gcc編譯選項:c++11 多執行緒編譯
c++11原生支援多執行緒程式設計,如下程式碼(假設檔名為test.cpp): #include <iostream> #include <future> using namespace std; int main() { auto fr0 =
gcc 編譯控制選項
ansi 不包含 描述 尺寸 根據 警告 如果 編譯 語法 gcc 編譯控制選項前面已經講過, gcc 的基本用法是:$ gcc [選項] [文件名]gcc 有很多編譯控制選項,使得 gcc 可以根據不同的參數進行不同的編譯處理,可供 gcc調用的參數大約有 100 來個,
gcc基本功能以及常見編譯選項
執行文件 類型 pos 轉換 控制臺 控制 spa 擴展 -c 1、gcc xxx.c主要包含以下4部分功能: (1) 預處理:主要實現對頭文件的包含以及宏替換等 (2) 編 譯:主要將高級語言轉換為匯編語言 (3) 匯 編:主要將匯編語言翻譯成機器指令,得到目
gcc 常用編譯選項
應用程序 默認 ron 一個 linu str 技術 出錯 arm gcc 和 arm-linux-gcc的常用選項 gcc 的使用方法: gcc 【選項】 文件名 gcc常用選項: -v:查看gcc 編譯器的版本,顯示gcc執行時的詳細過程 -
GCC編譯命令常用選項
GCC是GUN Compiler Collection的簡稱,除編譯程式外,還包含其他相關工具。GCC可將高階語言編寫的原始碼構建成計算機直接執行的二進位制程式碼。GCC是Linux平臺下最常用的編譯程式,也是Linux平臺編譯器的事實標準。GCC支援四十餘種不同目標體系結構(如X86系列、ARM
除了vim, 還有哪些常用的牛逼的編輯器。 自行查詢資料, 調研除了gcc, 還有哪些常用的牛逼的編譯器,為什麼除錯的時候需要編譯選項中新增 -g在Linux下實現進度條程式
除了vim, 還有哪些常用的牛逼的編輯器, 並能夠橫向對比編輯器之間的區別和優缺點。 首先先有一個概念IDE(整合開發環境),厲害的有vs等等。vim以及Emacs就向著這個方向發展。為了實現其強大功能。vim有了多模式編輯有(normal,insert,vis
除了vim, 還有哪些常用的牛逼的編輯器,除了gcc, 還有哪些常用的牛逼的編譯器,為什麼除錯的時候需要編譯選項中新增 -g,調研readelf命令,Linux下實現進度條程式.
除了vim, 還有哪些常用的牛逼的編輯器 Brackets Brackets也是一款為Linux開發者設計的開原始碼編輯器,使用Brackets寫程式碼,你不會被任何事情所打斷。比如在寫HTML程式碼時,即便你沒有儲存程式碼也可以及時預覽你的Web頁面效果。你也可以使用T
GCC & G++編譯選項
gcc & g++現在是gnu中最主要和最流行的c & c++編譯器 。 g++是c++的命令,以.cpp為主,對於c語言字尾名一般為.c。這時候命令換做gcc即可。其實是無關緊要的。 其實編譯器是根據gcc還是g++來確定是按照C標準還是C++標準編譯連結。
gcc編譯部分編譯選項
使用gcc命令顯示的幫助資訊 用法:gcc [選項] 檔案... 選項: -pass-exit-codes 在某一階段退出時返回最高的錯誤碼 --help 顯示此幫助說明
[Linux][2015-03-17] gcc/g++ 編譯選項
GCC的幾個常用選項 gcc常用的編譯選項對程式碼的影響 建立時間:2001-12-21 文章屬性:原創 文章來源:http://xfocus.org/ 文章提交:alert7 (sztcww_at_sina.com) 測試環境 redhat 6
【轉】gcc/g++常用編譯選項和gdb常用除錯命令
gcc/g++編譯器是我們寫編譯C/C++程式時離不開的編譯工具,而gdb又是除錯C/C++程式的利器,這一篇文章我們記錄一下它們的慣常用法。 gcc/g++常用編譯選項 選項 作
gcc -D選項 編譯時新增巨集定義
程式例項: #include <stdio.h> #include <stdlib.h> int main(int argc, char* argv[]) { #ifde
和菜鳥一起學c之gcc編譯過程及其常用編譯選項
上篇文章,知道了,C程式碼編譯後存放在記憶體中的位置,那麼C程式碼的整個編譯過程又是怎樣的呢?一條命令gcc hello.c就可以編譯成可執行程式a.out,然後./a.out之後就可以
gcc/g++常用編譯選項
-x language filename 設定檔案所使用的語言,使字尾名無效,對以後的多個有效.也就是根據約定,C語言的字尾名稱是.c的,而C++的字尾名是.C或者.cpp,如果你很個 性,決定你的C程式碼檔案的字尾名是.pig 哈哈,那你就要用這個引數,這個引數對他後