Chromium 在 link 時用的參數
先前在《Linux 編譯 shared library 的方法和注意事項》說明 link 的基本觀念和用法。link 時還有很多參數可用,但實在是太多了,掃完文件也不知該用那些。不如看看別人常用的參數。
以 Chromium 66 在 ubuntu 16.04 編譯 chrome 預設參數為例,抽查 base
、cc
、content
、net
、third_party/WebKit/Source/core/core
等幾個模組主要的 ninja 檔 (例如: out/Debug/obj/base/base.ninja
),發現它們 link 的參數 (設在ldflags
) 都一樣。這篇記錄這些參數代表的意思,日後有需要可以參考。
總結
先寫結論,都是「利>>>弊」的參數。懶得看細節的話,抄一抄就好。以下是 gcc/g++/clang/clang++
使用的參數:
-Wl,-z,noexecstack -Wl,-z,now -Wl,-z,relro
: 增加安全性。編執行檔再多加-pie
。-Wl,-z,defs -Wl,--no-as-needed -lpthread -Wl,--as-needed -Werror -Wl,--fatal-warnings
: 用嚴格的檢查參數,並且只記錄必要用到的 shared library。-fuse-ld lld -Wl,--icf=all -Wl,--gdb-index
: 使用 lld (llvm linker) 效能較好。使用 lld 擴充功能減少 binary 大小和建 index 用來加速 gdb 載入 debug symbol 時間。
前置知識
-Wl…
是 gcc 傳給 static linker 的參數,參閱 man ld。- 沒加
-Wl…
是 gcc 用的參數,參閱 man gcc。 - ld.bfd (俗稱 ld)、gold、lld 都是 static linker,愈後面的愈新,效能也愈好。linker 參數有往前相容,文件看起來是愈舊的愈清楚。可以先找 ld.bfd 的 man page,找不到再找 gold 的 man page。
shared library 用的 ldflags
-fPIC
產生 position independent code,編 shared library 時必要參數。
-Wl,-z,noexecstack
標示不能執行 stack 上的資料,避免安全漏洞。
-Wl,-z,now
標示 executable 或 shared lib 在執行的時候或用 dlopen 載入 library 的開始就確認能找到所有要用的 symbol,不要等用到的時候再找。
-Wl,-z,relro
-z now
加上 -z relro
會啟用 full RETRO,讓動態載入的函式位置變成唯讀,不會被替換成別的位置。細節見《RELRO: RELocation Read-Only》。
還沒研究相關細節,大致上知道加上 -Wl,-z,now -Wl,-z,relro
和 -Wl,-z,noexecstack
都可減少被植入惡意程式的機會。
-Wl,-z,defs
不允許有 undefined symbol。
-Wl,--no-as-needed -lpthread -Wl,--as-needed
link 時,預設 ld 會產生 DT_NEEDED
記錄參數裡所有 shared library。加上 --as-needed
表示只有在用到 shared library 內的 symbol 時才記錄。不知道為啥預設是都加上 DT_NEEDED
。
所以這段的意思是「無論有無用到 libpthread,記錄 pthread; 其餘是用到才記」。之前有看過有些 library 在 single thread 和 multiple thread 的行為不同 (比方說 single thread 不需要用 lock)。這樣可以保證在 single/multiple thread 情況下,會用到同一套實作。我也喜歡這種作法。
-fuse-ld=lld
指定 static linker 使用 LLVM 的 linker lld。預設是 bfd,也就是平時說的 ld。另外有 Google 作的 gold,印象中很久以前 Chromium 用 gold。沒想到 Chromium 已換用 lld 了。lld 官網測的數據滿驚人的,編 chromium debug build,lld、gold、GNU ld 分別用 16.70s、60.82s、209.05s。
-Wl,--icf=all
gold 和 lld 才有的參數,Identical Code Folding,減少產生的 binary 大小。
-m64
產生使用 64bit ABI 的 binary code。
-Werror
warning 視為 error,有 warning 就不會產生 shared library / executable。
-Wl,--gdb-index
gold 和 lld 才有的參數,產生 gdb index。可以大幅加速 gdb 載入 debug symbol 的速度。
-Wl,--fatal-warnings
讓 linker 視 warning 為 error。
-nostdlib++
不要用系統帶的 C++ standard library。找了一會兒只看到 lld 的 code review 對這參數的說明。
--sysroot=../../build/linux/debian_sid_amd64-sysroot
指定用 chromium 自己帶的 build/linux/debian_sid_amd64-sysroot
當作 sysroot。原本是去 /usr/include
或 /usr/lib
找檔案,改成去 build/linux/debian_sid_amd64-sysroot/usr/include
和 build/linux/debian_sid_amd64-sysroot/usr/lib
找。
-L../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu
告訴 gcc 搜尋 lib 時會用 chromium 自己帶的 library。
-Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/usr/local/lib/x86_64-linux-gnu
告訴 static linker 搜尋 lib 時用 chromium 自己帶的 library。
man ld 有說明 static linker 找 shared library 的流程。rpath-link
的優先權最高,再來才是 rpath
。rpath-link
只會用在 link 時,用完也不會記在 shared library / executable 裡。
-L../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu
-Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/lib/x86_64-linux-gnu
-L../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu
-Wl,-rpath-link=../../build/linux/debian_sid_amd64-sysroot/usr/lib/x86_64-linux-gnu
這幾個和前面一樣,只是指定不同路徑。
-Wl,--export-dynamic
看起來是用 dlsym() 動態載入 shared library 時可能需要的參數。這裡提到除了 dlsym() 的情況外,若 shared library 需要使用 executable 的 symbol,也需要這個參數。
chrome 用的 ldflags
除了上面提的那些,chrome (chrome/chrome_initial.ninja
)多用了以下參數。
-pie
產生 position independent executable,減少被攻擊的機會。
-Wl,-rpath=’$ORIGIN’/.
這在前篇解釋過了,方便讀 executable 同目錄下的 shared library。