gcc編譯器完全優化指南

CFLAGS 與 CXXFLAGS

  CFLAGS 表示用於 C 編譯器的選項,CXXFLAGS 表示用於 C++ 編譯器的選項。這兩個變量實際上涵蓋了編譯和彙編兩個步驟。大多數程序和庫在編譯時默認的優化級別是"2"(使用"-O2"選項)並且帶有調試符號來編譯,也就是 CFLAGS="-O2 -g", CXXFLAGS=$CFLAGS 。事實上,"-O2"已經啓用絕大多數安全的優化選項了。另一方面,由於大部分選項可以同時用於這兩個變量,所以僅在最後講述只能用於其中一個變量的選項。[提醒]下面所列選項皆爲非默認選項,你只要按需添加即可。

  先說說"-O3"在"-O2"基礎上增加的幾項:

  -finline-functions

  允許編譯器選擇某些簡單的函數在其被調用處展開,比較安全的選項,特別是在CPU二級緩存較大時建議使用。

  -funswitch-loops

  將循環體中不改變值的變量移動到循環體之外。

  -fgcse-after-reload

  爲了清除多餘的溢出,在重載之後執行一個額外的載入消除步驟。

  另外:

  -fomit-frame-pointer

  對於不需要棧指針的函數就不在寄存器中保存指針,因此可以忽略存儲和檢索地址的代碼,同時對許多函數提供一個額外的寄存器。所有"-O"級別都打開它,但僅在調試器可以不依靠棧指針運行時纔有效。在AMD64平臺上此選項默認打開,但是在x86平臺上則默認關閉。建議顯式的設置它。

  -falign-functions=N

  -falign-jumps=N

  -falign-loops=N

  -falign-labels=N

  這四個對齊選項在"-O2"中打開,其中的根據不同的平臺N使用不同的默認值。如果你想指定不同於默認值的N,也可以單獨指定。比如,對於L2-cache>=1M的cpu而言,指定 -falign-functions=64 可能會獲得更好的性能。建議在指定了 -march 的時候不明確指定這裏的值。

  調試選項:

  -fprofile-arcs

  在使用這一選項編譯程序並運行它以創建包含每個代碼塊的執行次數的文件後,程序可以再次使用 -fbranch-probabilities 編譯,文件中的信息可以用來優化那些經常選取的分支。如果沒有這些信息,gcc將猜測哪個分支將被經常運行以進行優化。這類優化信息將會存放在一個以源文件爲名字的並以".da"爲後綴的文件中。

  全局選項:

  -pipe

  在編譯過程的不同階段之間使用管道而非臨時文件進行通信,可以加快編譯速度。建議使用。

  目錄選項:

  --sysroot=dir

  將dir作爲邏輯根目錄。比如編譯器通常會在 /usr/include 和 /usr/lib 中搜索頭文件和庫,使用這個選項後將在 dir/usr/include 和 dir/usr/lib 目錄中搜索。如果使用這個選項的同時又使用了 -isysroot 選項,則此選項僅作用於庫文件的搜索路徑,而 -isysroot 選項將作用於頭文件的搜索路徑。這個選項與優化無關,但是在 CLFS 中有着神奇的作用。

  代碼生成選項:

  -fno-bounds-check

  關閉所有對數組訪問的邊界檢查。該選項將提高數組索引的性能,但當超出數組邊界時,可能會造成不可接受的行爲。

  -freg-struct-return

  如果struct和union足夠小就通過寄存器返回,這將提高較小結構的效率。如果不夠小,無法容納在一個寄存器中,將使用內存返回。建議僅在完全使用GCC編譯的系統上才使用。

  -fpic

  生成可用於共享庫的位置獨立代碼。所有的內部尋址均通過全局偏移表完成。要確定一個地址,需要將代碼自身的內存位置作爲表中一項插入。該選項產生可以在共享庫中存放並從中加載的目標模塊。

  -fstack-check

  爲防止程序棧溢出而進行必要的檢測,僅在多線程環境中運行時纔可能需要它。

  -fvisibility=hidden

  設置默認的ELF鏡像中符號的可見性爲隱藏。使用這個特性可以非常充分的提高連接和加載共享庫的性能,生成更加優化的代碼,提供近乎完美的API輸出和防止符號碰撞。我們強烈建議你在編譯任何共享庫的時候使用該選項。參見 -fvisibility-inlines-hidden 選項。

  硬件體系結構相關選項[僅僅針對x86與x86_64]:

  -march=cpu-type

  爲特定的cpu-type編譯二進制代碼(不能在更低級別的cpu上運行)。Intel可以用:pentium2, pentium3(=pentium3m), pentium4(=pentium4m), pentium-m, prescott, nocona, core2(GCC-4.3新增) 。AMD可以用:k6-2(=k6-3), athlon(=athlon-tbird), athlon-xp(=athlon-mp), k8(=opteron=athlon64=athlon-fx)

  -mfpmath=sse

  P3和athlon-xp級別及以上的cpu支持"sse"標量浮點指令。僅建議在P4和K8以上級別的處理器上使用該選項。

  -malign-double

  將double, long double, long long對齊於雙字節邊界上;有助於生成更高速的代碼,但是程序的尺寸會變大,並且不能與未使用該選項編譯的程序一起工作。

  -m128bit-long-double

  指定long double爲128位,pentium以上的cpu更喜歡這種標準,並且符合x86-64的ABI標準,但是卻不附合i386的ABI標準。

  -mregparm=N

  指定用於傳遞整數參數的寄存器數目(默認不使用寄存器)。0<=N<=3 ;注意:當N>0時你必須使用同一參數重新構建所有的模塊,包括所有的庫。

  -msseregparm

  使用SSE寄存器傳遞float和double參數和返回值。注意:當你使用了這個選項以後,你必須使用同一參數重新構建所有的模塊,包括所有的庫。

  -mmmx

  -msse

  -msse2

  -msse3

  -m3dnow

  -mssse3(沒寫錯!GCC-4.3新增)

  -msse4.1(GCC-4.3新增)

  -msse4.2(GCC-4.3新增)

  -msse4(含4.1和4.2,GCC-4.3新增)

  是否使用相應的擴展指令集以及內置函數,按照自己的cpu選擇吧!

  -maccumulate-outgoing-args

  指定在函數引導段中計算輸出參數所需最大空間,這在大部分現代cpu中是較快的方法;缺點是會明顯增加二進制文件尺寸。

  -mthreads

  支持Mingw32的線程安全異常處理。對於依賴於線程安全異常處理的程序,必須啓用這個選項。使用這個選項時會定義"-D_MT",它將包含使用選項"-lmingwthrd"連接的一個特殊的線程輔助庫,用於爲每個線程清理異常處理數據。

  -minline-all-stringops

  默認時GCC只將確定目的地會被對齊在至少4字節邊界的字符串操作內聯進程序代碼。該選項啓用更多的內聯並且增加二進制文件的體積,但是可以提升依賴於高速 memcpy, strlen, memset 操作的程序的性能。

  -minline-stringops-dynamically

  GCC-4.3新增。對未知尺寸字符串的小塊操作使用內聯代碼,而對大塊操作仍然調用庫函數,這是比"-minline-all-stringops"更聰明的策略。決定策略的算法可以通過"-mstringop-strategy"控制。


  -momit-leaf-frame-pointer

  不爲葉子函數在寄存器中保存棧指針,這樣可以節省寄存器,但是將會使調試變的困難。注意:不要與 -fomit-frame-pointer 同時使用,因爲會造成代碼效率低下。

  -m64

  生成專門運行於64位環境的代碼,不能運行於32位環境,僅用於x86_64[含EMT64]環境。

  -mcmodel=small

  [默認值]程序和它的符號必須位於2GB以下的地址空間。指針仍然是64位。程序可以靜態連接也可以動態連接。僅用於x86_64[含EMT64]環境。

  -mcmodel=kernel

  內核運行於2GB地址空間之外。在編譯linux內核時必須使用該選項!僅用於x86_64[含EMT64]環境。

  -mcmodel=medium

  程序必須位於2GB以下的地址空間,但是它的符號可以位於任何地址空間。程序可以靜態連接也可以動態連接。注意:共享庫不能使用這個選項編譯!僅用於x86_64[含EMT64]環境。

  其它優化選項:

  -fforce-addr

  必須將地址複製到寄存器中才能對他們進行運算。由於所需地址通常在前面已經加載到寄存器中了,所以這個選項可以改進代碼。

  -finline-limit=n

  對僞指令數超過n的函數,編譯程序將不進行內聯展開,默認爲600。增大此值將增加編譯時間和編譯內存用量並且生成的二進制文件體積也會變大,此值不宜太大。

  -fmerge-all-constants

  試圖將跨編譯單元的所有常量值和數組合併在一個副本中。但是標準C/C++要求每個變量都必須有不同的存儲位置,所以該選項可能會導致某些不兼容的行爲。

  -fgcse-sm

  在全局公共子表達式消除之後運行存儲移動,以試圖將存儲移出循環。gcc-3.4中曾屬於"-O2"級別的選項。

  -fgcse-las

  在全局公共子表達式消除之後消除多餘的在存儲到同一存儲區域之後的加載操作。gcc-3.4中曾屬於"-O2"級別的選項。

  -floop-optimize

  已廢除(GCC-4.1曾包含在"-O1"中)。

  -floop-optimize2

  使用改進版本的循環優化器代替原來"-floop-optimize"。該優化器將使用不同的選項(-funroll-loops, -fpeel-loops, -funswitch-loops, -ftree-loop-im)分別控制循環優化的不同方面。目前這個新版本的優化器尚在開發中,並且生成的代碼質量並不比以前的版本高。已廢除,僅存在於GCC-4.1之前的版本中。

  -funsafe-loop-optimizations

  假定循環不會溢出,並且循環的退出條件不是無窮。這將可以在一個比較廣的範圍內進行循環優化,即使優化器自己也不能斷定這樣做是否正確。

  -fsched-spec-load

  允許一些裝載指令執行一些投機性的動作。

  -ftree-loop-linear

  在trees上進行線型循環轉換。它能夠改進緩衝性能並且允許進行更進一步的循環優化。

  -fivopts

  在trees上執行歸納變量優化。

  -ftree-vectorize

  在trees上執行循環向量化。

  -ftracer

  執行尾部複製以擴大超級塊的尺寸,它簡化了函數控制流,從而允許其它的優化措施做的更好。據說挺有效。

  -funroll-loops

  僅對循環次數能夠在編譯時或運行時確定的循環進行展開,生成的代碼尺寸將變大,執行速度可能變快也可能變慢。

  -fprefetch-loop-arrays

  生成數組預讀取指令,對於使用巨大數組的程序可以加快代碼執行速度,適合數據庫相關的大型軟件等。具體效果如何取決於代碼。

  -fweb

  建立經常使用的緩存器網絡,提供更佳的緩存器使用率。gcc-3.4中曾屬於"-O3"級別的選項。

  -ffast-math

  違反IEEE/ANSI標準以提高浮點數計算速度,是個危險的選項,僅在編譯不需要嚴格遵守IEEE規範且浮點計算密集的程序考慮採用。

  -fsingle-precision-constant

  將浮點常量作爲單精度常量對待,而不是隱式地將其轉換爲雙精度。

  -fbranch-probabilities

  在使用 -fprofile-arcs 選項編譯程序並執行它來創建包含每個代碼塊執行次數的文件之後,程序可以利用這一選項再次編譯,文件中所產生的信息將被用來優化那些經常發生的分支代碼。如果沒有這些信息,gcc將猜測那一分支可能經常發生並進行優化。這類優化信息將會存放在一個以源文件爲名字的並以".da"爲後綴的文件中。

  -frename-registers

  試圖驅除代碼中的假依賴關係,這個選項對具有大量寄存器的機器很有效。gcc-3.4中曾屬於"-O3"級別的選項。

  -fbranch-target-load-optimize

  -fbranch-target-load-optimize2

  在執行序啓動以及結尾之前執行分支目標緩存器加載最佳化。

  -fstack-protector

  在關鍵函數的堆棧中設置保護值。在返回地址和返回值之前,都將驗證這個保護值。如果出現了緩衝區溢出,保護值不再匹配,程序就會退出。程序每次運行,保護值都是隨機的,因此不會被遠程猜出。

  -fstack-protector-all

  同上,但是在所有函數的堆棧中設置保護值。

  --param max-gcse-memory=xxM

  執行GCSE優化使用的最大內存量(xxM),太小將使該優化無法進行,默認爲50M。

  --param max-gcse-passes=n

  執行GCSE優化的最大迭代次數,默認爲 1。

  傳遞給彙編器的選項:

  -Wa,options

  options是一個或多個由逗號分隔的可以傳遞給彙編器的選項列表。其中的每一個均可作爲命令行選項傳遞給彙編器。

  -Wa,--strip-local-absolute

  從輸出符號表中移除局部絕對符號。

  -Wa,-R

  合併數據段和正文段,因爲不必在數據段和代碼段之間轉移,所以它可能會產生更短的地址移動。

  -Wa,--64

  設置字長爲64bit,僅用於x86_64,並且僅對ELF格式的目標文件有效。此外,還需要使用"--enable-64-bit-bfd"選項編譯的BFD支持。

  -Wa,-march=CPU

  按照特定的CPU進行優化:pentiumiii, pentium4, prescott, nocona, core, core2; athlon, sledgehammer, opteron, k8 。

僅可用於 CFLAGS 的選項:

  -fhosted

  按宿主環境編譯,其中需要有完整的標準庫,入口必須是main()函數且具有int型的返回值。內核以外幾乎所有的程序都是如此。該選項隱含設置了 -fbuiltin,且與 -fno-freestanding 等價。

  -ffreestanding

  按獨立環境編譯,該環境可以沒有標準庫,且對main()函數沒有要求。最典型的例子就是操作系統內核。該選項隱含設置了 -fno-builtin,且與 -fno-hosted 等價。

  僅可用於 CXXFLAGS 的選項:

  -fno-enforce-eh-specs

  C++標準要求強制檢查異常違例,但是該選項可以關閉違例檢查,從而減小生成代碼的體積。該選項類似於定義了"NDEBUG"宏。

  -fno-rtti

  如果沒有使用'dynamic_cast'和'typeid',可以使用這個選項禁止爲包含虛方法的類生成運行時表示代碼,從而節約空間。此選項對於異常處理無效(仍然按需生成rtti代碼)。

  -ftemplate-depth-n

  將最大模版實例化深度設爲'n',符合標準的程序不能超過17,默認值爲500。

  -fno-optional-diags

  禁止輸出診斷消息,C++標準並不需要這些消息。

  -fno-threadsafe-statics

  GCC自動在訪問C++局部靜態變量的代碼上加鎖,以保證線程安全。如果你不需要線程安全,可以使用這個選項。

  -fvisibility-inlines-hidden

  默認隱藏所有內聯函數,從而減小導出符號表的大小,既能縮減文件的大小,還能提高運行性能,我們強烈建議你在編譯任何共享庫的時候使用該選項。參見 -fvisibility=hidden 選項。

  LDFLAGS

  LDFLAGS 是傳遞給連接器的選項。這是一個常被忽視的變量,事實上它對優化的影響也是很明顯的。

  [提示]以下選項是在完整的閱讀了ld-2.18文檔之後挑選出來的選項。http://blog.chinaunix.net/u1/41220/showart_354602.html 有2.14版本的中文手冊。

  -s

  刪除可執行程序中的所有符號表和所有重定位信息。其結果與運行命令 strip 所達到的效果相同,這個選項是比較安全的。

  -Wl,options

  options是由一個或多個逗號分隔的傳遞給鏈接器的選項列表。其中的每一個選項均會作爲命令行選項提供給鏈接器。

  -Wl,-On

  當n>0時將會優化輸出,但是會明顯增加連接操作的時間,這個選項是比較安全的。

  -Wl,--exclude-libs=ALL

  不自動導出庫中的符號,也就是默認將庫中的符號隱藏。

  -Wl,-m<emulation>

  仿真<emulation>連接器,當前ld所有可用的仿真可以通過"ld -V"命令獲取。默認值取決於ld的編譯時配置。

  -Wl,--sort-common

  把全局公共符號按照大小排序後放到適當的輸出節,以防止符號間因爲排布限制而出現間隙。

  -Wl,-x

  刪除所有的本地符號。

  -Wl,-X

  刪除所有的臨時本地符號。對於大多數目標平臺,就是所有的名字以'L'開頭的本地符號。

  -Wl,-zcomberloc

  組合多個重定位節並重新排布它們,以便讓動態符號可以被緩存。

  -Wl,--enable-new-dtags

  在ELF中創建新式的"dynamic tags",但在老式的ELF系統上無法識別。

  -Wl,--as-needed

  移除不必要的符號引用,僅在實際需要的時候才連接,可以生成更高效的代碼。

  -Wl,--no-define-common

  限制對普通符號的地址分配。該選項允許那些從共享庫中引用的普通符號只在主程序中被分配地址。這會消除在共享庫中的無用的副本的空間,同時也防止了在有多個指定了搜索路徑的動態模塊在進行運行時符號解析時引起的混亂。

  -Wl,--hash-style=gnu

  使用gnu風格的符號散列表格式。它的動態鏈接性能比傳統的sysv風格(默認)有較大提升,但是它生成的可執行程序和庫與舊的Glibc以及動態鏈接器不兼容。

  --------------------------------------------------------------------------------

  最後說兩個與優化無關的系統環境變量,因爲會影響GCC編譯程序的方式,下面兩個是咱中國人比較關心的:

  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"。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章