Chromium 在 link 時用的參數

fcamel
fcamel的程式開發心得
7 min readAug 7, 2018

先前在《Linux 編譯 shared library 的方法和注意事項》說明 link 的基本觀念和用法。link 時還有很多參數可用,但實在是太多了,掃完文件也不知該用那些。不如看看別人常用的參數。

以 Chromium 66 在 ubuntu 16.04 編譯 chrome 預設參數為例,抽查 basecccontentnetthird_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)、goldlld 都是 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/includebuild/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 的優先權最高,再來才是 rpathrpath-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。

相關資料

--

--