forked from jasonblog/note
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
gigigigi
committed
Jul 16, 2015
1 parent
5e53d0d
commit 5b44572
Showing
8 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# ld, ld.so 和 ldconfig 的行為 | ||
|
||
|
||
TLPI ch41 相當值得一看, 從開發者使用 library 的角度說明 library 的生成、靜態連結、動態連結 (載入) 的行為, 內容不多不少, 正好就是我想知道的, 省了看 linker、loader 的時間。<br /> | ||
|
||
**shared library 的名詞介紹** | ||
|
||
- soname: 記錄在 shared library header 裡的名稱, 格式為 libX.so.MAJOR。要有同名檔案, 供之後程式載入 shared library 時使用 | ||
- real name: shared library 的檔名, 格式為 libX.so.MAJOR.MINOR.NUMBER | ||
- linker name: 對 library X 來說, 就是 libX.so, 一般會是 symbolic link 指向最新的 major shared library | ||
|
||
以 libjpeg 為例, 對應如下:<br /> | ||
``` | ||
libjpeg.so -> libjpeg.so.62.0.0 # linker name | ||
libjpeg.so.62 -> libjpeg.so.62.0.0 # soname | ||
libjpeg.so.62.0.0 # real name | ||
``` | ||
|
||
這是我在 Ubuntu 裝好 package 後的樣子, 照理說 libjpeg.so 指向 libjpeg.so.62 應該會更彈性。<br /> | ||
|
||
讀出 soname:<br /> | ||
``` | ||
$ readelf -d libjpeg.so | grep SONAME | ||
0x000000000000000e (SONAME) Library soname: [libjpeg.so.62] | ||
``` | ||
|
||
**static 和 dynamic linker** | ||
|
||
- ld (ld.bfd) 是 static linker。Google 開發的 gold 是取代 ld.bfs 的 static linker。用 gcc 連結 shared library 或 executable 時就是呼叫 ld, 並將需要的參數傳給它。不論連結的是 static library 或 shared library, 都是 static linking。 | ||
|
||
- ld 在連結 shared library 或 executable 時, 會將需要的 shared library 的 soname 寫入結果檔裡。注意, 只有 soname 而已, 沒有完整路徑。 | ||
|
||
- ld-VERSION.so 是 dynamic (runtime) linker, 執行程式時, 由 runtime linker 載入 executable 開始。若 OS 用的 glibc 版本為 2.13, 就叫 ld-2.13.so。用 ldd 看所有執行檔, 都會找到它 (某個 symbolic link 連到 ld-2.13.so)。 | ||
|
||
以連結 libm.so 為例, 執行 gcc -lm prog.c -o prog 中間的部份行為如下:<br /> | ||
|
||
- gcc 透過 -lm 的指示告知 ld 要連結 libm.so | ||
|
||
- ld 會找到某處的 libm.so 指向 /lib/x86_64-linux-gnu/libm.so.6, 確認要用到的 symbol 都有, 沒有 link error | ||
|
||
- ld 從 libm.so.6 的 header 讀出 soname "libm.so.6", 寫入 "libm.so.6" 到 prog 的 header。 | ||
執行 prog 時, ld-2.13.so 會從 prog 讀出 "libm.so.6", 再到預設的路徑上找檔名 "libm.so.6"。注意, static linking 時需要 libm.so, 但之後執行 prog 時用不到它, 因為記錄的 soname 為 "libm.so.6"。 | ||
|
||
關於 static linking 找檔名的順序, 可用 strace 觀察:<br /> | ||
|
||
``` | ||
$ strace -e open,execve -f -o gcc.trace gcc -lm prog.c -o prog | ||
``` | ||
在 gcc.trace 裡可看出一二。 | ||
|
||
ps. | ||
|
||
- 使用 execve 的目的是知道 child process 是那一個程式, 目標是看 ld 開敋的檔案 | ||
- 可由 man 2 exec<TAB> 得知 system call 使用的 exec 函式為 execve。 | ||
|
||
**ldconfig** | ||
|
||
執行 ldconfig 後, 它做的事如下:<br /> | ||
|
||
- 讀出 /lib, /usr/lib, /etc/ld.so.conf 內的路徑之下的 shared library (ldconfig 會略過 symbolic link), 將結果寫入 /etc/ld.so.cache。之後 ld-2.13.so 會用 ld.so.cache 的記錄來找 shared library。 | ||
|
||
- ldconfig 會自動產生 symbolic link "libX.so.MAJOR" 指向最新版本的 shared library。例如 /lib/libfoo.so.2.0.1 的 soname 是 libbar.so.2, 執行 ldconfig 後, 它會產生 /lib/libbar.so.2 指向 /lib/libfoo.so.2.0.1。 | ||
|
||
之前困擾我許久的事就是第二步, 而 man ldconfig 裡沒提到這點。<br /> | ||
|
||
結論是別隨便手動更新 soname 的檔案, 執行 ldconfig 後可能會出問題。<br /> | ||
裝套件後, 系統工具會自動跑 ldconfig 更新目錄, 可能會蓋掉自己手動更新的同檔名檔案。另外 ldconfig 沒有管 linker name, 若是自己編的 shared library, 要自己產生。 | ||
|
||
**其它** | ||
|
||
若想連到舊的 major 版本 shared library, 得在 gcc 參數指定舊版檔名。還有可用 rpath 的參數寫入搜尋 shared library 的路徑到 shared library 或 executable 裡。關於這些細節, 還有 static linker 以及 dynamic linker 尋找 shared library 的完整順序, TLPI ch41 講得相當清楚。ch42 描述 dlopen, 之後再來翻翻。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
#解決 undefined symbol / reference | ||
|
||
|
||
基本觀念 | ||
|
||
相較於 script language 或 Java 來說, C/C++ 有完整的「編譯 -> 連結 -> 執行」三個階段, 各階段都可能發生 undefined symbol。在解決惱人的 undefined symbol 前, 得先明白整個編譯流程: | ||
|
||
- 編譯 .c / .cpp 為 .o (object file) 時, 需要提供 header 檔 (用到 gcc 參數 -I)。事實上, 在編譯單一檔案時, gcc/g++ 根本不在意真正的 symbol 是否存在, 反正有宣告它就信了, 所以有引對 header 即可。這也是可分散編譯的原因 (如 distcc ), 程式之間在編譯成 .o 檔時, 並沒有相依性。 | ||
|
||
- 用 linker (ld 或 gold) 將 *.o 連結成 dynamic library 或執行檔時, 需要提供要連結的 library (用到 gcc 參數 -L 指定目錄位置, 用 -l 指定要連什麼函式庫)。不同於前一步, 此時 symbol 一定要在。 | ||
|
||
- 執行的時候, 會再動態開啟 shared library 讀出 symbol。換句話說, 前一個步驟只是檢查是否有。檢查通過也連結成 executable 或 shared library 後, 若執行時對應的檔案不見了, 仍會在執行期間找不到 symbol。若位置沒設好, 可能需要用 LIB_LIBRARY_PATH 指定動態函式的位置, 但不建議這麼做, 最好在執行 linker 時就指定好位置。原因見《Why LD_LIBRARY_PATH is bad》。<br /> | ||
|
||
|
||
明白這點後, 就看 undefined symbol 發生在那個階段, 若是編 object file 時發生, 就是沒和編譯器說 header 檔在那, 記得用 -I 告訴它。若在 linking 時發生, 就要同時設好 -L 和 -l。不過難就難在要去那找 undefined symbol 的出處。 | ||
|
||
**解決問題的流程** | ||
|
||
首先是判斷 symbol 是不是自己用到的原始碼裡, 可配合 id-utils 找看看 (我是用 gj, 比較方便一點)。或是看有沒有 man page, 有 man page 的話, 裡面會記錄用到的 header 和該怎麼下連結參數。若在專案裡找不到, 再用 Google 搜看看 symbol, 運氣好可能會找到套件名稱, 運氣不好.....目前還不知怎麼處理較好, 目前是四處亂翻看看。如果是網路上找來的程式碼, 別人已附好正確的 include 了, 這時用 apt-file search HEADER_PATH 就能找到套件名稱 ( 記得先跑 apt-file update 更新資料庫 ), 比方說: apt-file search openssl/rsa.h 會得到 libssl-dev: /usr/include/openssl/rsa.h。 | ||
|
||
在 Ubuntu 上, 通常需要裝 X-dev 以取得 header 檔。若是已經裝好套件了, 可用 dpkg --search、locate 或是 dpkg -L PKG_NAME 找出 header 位置。 | ||
|
||
若編譯過但 linking 時出錯, 要做進一步分析, 先看是那一個程式用到 undefined symbol。不管是自己的程式出錯, 或是用到的函式庫出錯, 都可從對應的原始碼找到編譯時用的 header X.h。 | ||
|
||
- 先看有沒有 man page, 有的話, 裡面會寫該下什麼參數連結。像 man sqrt 會看到說要 "Link with -lm" (記得裝 manpages-dev) | ||
|
||
- 若 X.h 是自己的, 就在附近找看看原始碼在那, 有沒有編譯到。 | ||
|
||
- 若 X.h 放在系統目錄裡, 可用 apt-file search X.h 找出 library 的可能出處 ( 記得先跑 apt-file update 更新資料庫 )。接著可用下列方式之一找出函式庫的可能位置: | ||
- dpkg --search SUBSTRING_OF_LIBRARY_NAME | ||
- dpkg -L PKG_NAME | grep lib | ||
- locate SUBSTRING_OF_LIBRARY_NAME # 記得先跑 updatedb | ||
|
||
若知道函式庫的確切名稱, 且有 pkg-config 的資訊的話, 可用 pkg-config --libs LIBRARY_NAME 直接找出 gcc/g++ linking 時該下的參數 (附帶一提, 用 --cflags 找出編譯時用到的參數, 像是 -I 接的)。不然, 用其它方式找到函式庫位置後, 要依 -L 和 -l 的規則寫下參數。記得 -l 後接的名稱不用加 "lib", 像 libm.so 是用 -lm。 | ||
|
||
實際寫較具規模的專案時, 可能不會用手刻 makefile, 要視自己用的整合工具, 將找到的資訊加入整合工具中。 | ||
|
||
**其它相關資訊** | ||
|
||
- 可配合 nm LIBRARY 查看 symbol, man nm 有各狀態說明, U 表示 undefined。若該函式應該要出自該函式庫, 卻標為 U, 表示該函式庫一開始就沒編好, 要重編該函式庫。反之, 若該函式定義在外部函式庫, 則是連結時出錯。 | ||
|
||
- nm 只適用 static library 或未 strip 前的 shared library。strip 後的 shared lib 得用 readelf -Ws 來看, 這個情境下沒 nm 簡單易讀。(2014-10-27 更新: 也可用 nm -D) | ||
|
||
- 函式庫有 U 通常是正常的, 編執行檔或 dynamic library 時才要指定連結的位置。換句話說, 若執行檔 X 用到 static library A, 而 A 用到 library B。則編 X 時, 要加上 -lA 和 -lB 的參數。編 X 的部份要知道它用到的函式庫有那些相依性, 而不是 A 自己會搞定自己的相依性, 這點不太直覺 (ref.)。 | ||
|
||
- static library 只是一堆 object file 的集合體。之所以會用 ar 和 ranlib 編 static library, 目的是減少連結的檔案以方便管理。在用 readelf -Ws 讀 static library 時, 會列出各個 object file 的內容。讀 dynamic library 時就沒這樣列了 (ref.)。 | ||
- 在 Linux 下 linking 時要注意函式庫的順序, 摘錄 gcc manpage 關於 -l 的說明: | ||
|
||
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded. | ||
|
||
- 當 libm.so 和 libm.a 同時存在時, -lm 會連到 libm.so, 官方說明見 man ld 中 --library=namespec 該段 (ref.)。感謝 cmtsij 的說明。 | ||
- 可用 ldd 找出 dynamic library 實際連到的檔案。 | ||
參考資料 | ||
|
||
《Linux Tutorial - Static, Shared Dynamic and Loadable Linux Libraries》 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# [轉] 列出用到的 shared library | ||
|
||
static library 就是一包 object file, 沒什麼需要提的, static library 沒有記錄其它資訊。所以, 編 shared library 或 executable 時要自行處理好 static library 的相依性, 在前篇有提到一點資訊。 | ||
|
||
shared library 有兩種, 一種在 linking 時要指定好 shared library 用到的 undefined symbol 放在那些 shared library 裡, 待執行時再載入到記憶體使用; 另一種用 dlopen() 和 dlsym() 載入 (這兩個函式存在 libdl 內)。 | ||
|
||
前者比較單純, **可用 ldd 透過靜態分析了解用到那些 shared library, 且各自實際指到的檔案**。ldd 本身是一個 shell script, 用到 ld.so 事先定義的一些機制 (LD_TRACE_LOADED_OBJECTS) 來讀取資料, man ld.so 裡有相關的說明。其中 LD_LIBRARY_PATH 和 LD_PRELOAD 相當實用, 無法在連結時解決問題時, 至少還有這招可在載入時處理。 | ||
|
||
若想分析透過 dlopen() 載入的動態函式庫, 有幾個做法 | ||
|
||
- 在程式執行中觀察 /proc/PID/maps, 這個檔案記錄 process 用到的各區段記憶體為何, 可從對應到的檔案看出有載入的 shared library。必要時可配合 gdb 在想觀察的部份停住, 再從外部看 /proc/PID/maps。這裡或 man proc 有相關說明。 | ||
|
||
- 用 strace 執行程式, 觀察開啟的檔案: strace -f -e open PROGRAM 2>&1 | grep "\.so" | ||
就我自己小試的心得, 看 /proc/PID/maps 最穩, 且方便看各別 process、thread 載入的函式庫, 也不會拖慢觀察目標的執行程式。不過 strace 不需配合 gdb 停在該停的地方, 就「快篩」的角度來看, 也滿有用的, 加上 -f 後方便追蹤 multi-process、multi-thread, 不過執行速度好像有慢一些, 不太確定。之後再比較看看兩者適合的使用時機。 | ||
|
||
參考資料 | ||
- 《Linux Tutorial - Static, Shared Dynamic and Loadable Linux Libraries》 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# 用 LD_PRELOAD 替換動態連結的函式庫 | ||
|
||
換掉動態連結的函式庫有不少用途, 比方說像 Scott 提的「用來驗證是否執行到特定函式」, 或如 jserv 提的「在沒有原始碼的情況下修補執行檔的行為」。最近又看到這個東西, 記一下筆記以免忘了。 | ||
|
||
來看程式碼和執行效果。 | ||
- mylib.c | ||
|
||
``` | ||
#include <stddef.h> | ||
#include <stdio.h> | ||
int putchar(int c) { | ||
printf("call putchar()\n"); | ||
return c; | ||
} | ||
void *memset(void *s, int c, size_t n) { | ||
printf("call memset()\n"); | ||
return s; | ||
} | ||
``` | ||
- main.c | ||
|
||
``` | ||
#include <string.h> | ||
#include <stdio.h> | ||
int main(void) { | ||
char s[10]; | ||
memset(s, 0, 0); | ||
putchar('X'); | ||
putchar('\n'); | ||
return 0; | ||
} | ||
``` | ||
|
||
- 執行結果 | ||
|
||
``` | ||
$ gcc -Wall -fpic -shared -o libmylib.so mylib.c | ||
$ gcc -o main main.c | ||
# 沒用 LD_PRELOAD 的結果 | ||
$ ./main | ||
X | ||
# 用 LD_PRELOAD 後的結果, 記得加 "./", 不然會找不到 libmylib.so | ||
$ LD_PRELOAD=./libmylib.so ./main | ||
call putchar() | ||
call putchar() | ||
$ strings main | grep memset | ||
``` | ||
|
||
可以看出 putchar 有被換成自己編的版本, 但 memset 沒有。用 strings 查看 binary 檔 main 會發覺並沒有呼叫 memset 的跡象。猜測是 compiler 發覺 memset 實際上沒任何作用, 所以沒呼叫。 | ||
|
||
修改 main.c, 將 memset(s, 0, 0) 換成 memset(s, 0, 1) 再來看看: | ||
``` | ||
$ gcc -o main main.c | ||
$ strings main | grep memset | ||
memset | ||
$ LD_PRELOAD=./libmylib.so ./main | ||
call memset() | ||
call putchar() | ||
call putchar() | ||
``` | ||
|
||
結果顯示有換到 memset, 表示之前是完全沒呼叫 memset, 才會以為沒換到。printf 也是如此, 只輸出字串時, 不會呼叫 printf, 而是用 puts。 | ||
|
||
- 參考資料: 《Modifying a Dynamic Library Without Changing the Source Code | Linux Journal》 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# 用 strace 和 ltrace 找出用到的 system call 和 library call | ||
|
||
|
||
前面提到 host 沒有 call gethostbyaddr, 面惡心善的 Scott 大概是查覺我下載了原始碼, 卻沒有找出確認它的方法。於是在另一篇留言裡說可以用 strace、ltrace 或 gdb 輕易做到這事 (幸好我還沒開始試 profiler 啊...)。 | ||
|
||
strace 和 ltrace 顧名思議, 它們會列出執行期間用到的 system / library call。若不確定有興趣的函式是那個, 可以用 man page 編號來判別。比方 man gethostbyaddr 顯示被分在 section 3 下, 所以 gethostbyaddr 是 library call [*1]。 | ||
|
||
分別拿 host 和對照組 getent 試的結果, 可以看到 getent 有打開 /etc/hosts (從 strace 那看到的), 並呼叫 gethostbyaddr;而 host 卻兩者皆無。解開疑惑實乃人生一大痛快之事, 感謝 Scott 的指點。 | ||
|
||
附上參考用指令: | ||
``` | ||
$ ltrace getent hosts 127.0.0.1 2>&1 | grep gethostby | ||
gethostbyaddr("\177", 4, 2) = 0xb7ed0aa0 | ||
$ strace getent hosts 127.0.0.1 2>&1 | grep "/etc/hosts" | ||
open("/etc/hosts", O_RDONLY|O_CLOEXEC) = 3 | ||
$ strace host 127.0.0.1 2>&1 | grep "/etc/hosts" | ||
$ ltrace host 127.0.0.1 2>&1 | grep gethostby | ||
``` | ||
另外我好奇之下試了傳說中人人都會寫的 C 版 「Hello, world! 」, 結果發現 compiler 很聰明地用 puts 而非 printf。 | ||
|
||
參考程式如下: | ||
``` | ||
#include <stdio.h> | ||
int main(void) | ||
{ | ||
printf("hello, world!\n"); | ||
puts("hello, world!\n"); | ||
printf("hello, world! %d\n", 3); | ||
return 0; | ||
} | ||
``` | ||
執行結果: | ||
``` | ||
$ ltrace ./f > /dev/null | ||
__libc_start_main(0x80483f4, 1, 0xbf812ab4, 0x8048450, 0x8048440 | ||
puts("hello, world!") = 14 | ||
puts("hello, world!\n") = 15 | ||
printf("hello, world! %d\n", 3) = 16 | ||
+++ exited (status 0) +++ | ||
``` | ||
|
||
接著我用 ltrace 執行 python (ltrace python -c ''), 結果 ltrace 狂噴訊息卻不會停......, 今日閒暇時間用盡這待那天有緣再來研究吧。 | ||
2010-02-25 更新 | ||
|
||
Scott 在留言裡提到也可以用 LD_PRELOAD 抽換動態載入的函式來達到同樣目的 (確認是否有呼叫 gethostbyaddr)。範例程式如下 (稍微修正 Scott 的範例讓它在我的機器能正常 compile): | ||
``` | ||
$ printf '#include <stdio.h>\n#include <assert.h>\nvoid gethostbyaddr(void) { assert(0); }\n' > t.c | ||
$ gcc -fPIC -shared t.c -o t.so | ||
$ LD_PRELOAD=./t.so getent hosts 127.0.0.1 | ||
getent: t.c:3: gethostbyaddr: Assertion `0' failed. | ||
Aborted | ||
$ LD_PRELOAD=./t.so host 127.0.0.1 | ||
1.0.0.127.in-addr.arpa domain name pointer localhost. | ||
``` | ||
上面的範例透過 LD_PRELOAD 讓程式改用自訂的 gethostbyaddr。如此一來, 抽換掉懷疑的函式再執行指令, 就知道是否有用到了。LD_PRELOAD 的詳細說明可參考 jserv 翻譯的 《Modifying a Dynamic Library Without Changing the Source Code / 在不更動原始程式碼的前提下,修改動態程式庫》。 | ||
|
||
**備註** | ||
man man 可看到各 section 的含意, 摘錄如下: | ||
|
||
* 1 Executable programs or shell commands | ||
* 2 System calls (functions provided by the kernel) | ||
* 3 Library calls (functions within program libraries) | ||
* 4 Special files (usually found in /dev) | ||
* 5 File formats and conventions eg /etc/passwd | ||
* 6 Games | ||
* 7 Miscellaneous (including macro packages and conven- | ||
tions), e.g. man(7), groff(7) | ||
* 8 System administration commands (usually only for root) | ||
* 9 Kernel routines [Non standard] | ||
|
||
總共也才九節, 遊戲竟然自成一節......。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# fcamel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# [轉] 加速 linking time | ||
|
||
頻繁修改一點程式又要執行看結果時, 主要的時間都花在 linking。這時才體會到省下 linking time 也是很重要的事。 | ||
|
||
這篇提到兩個減少 linking time 的做法 | ||
|
||
- 使用 ramdisk | ||
- 用 gold | ||
我本來就有用 SSD, 改將編譯結果全放到 ramdisk 後, 提昇的效果不怎麼明顯。到是用 gold 後減少了一半的 linking 時間。 | ||
|
||
不過 gold 也不是那麼完美, 這篇提到一些問題。我自己用的時候發覺滿常遇到 ld 可以編, 但 gold 不行。最後的解套方式是寫個小 script 切換 /usr/bin/ld 連到的程式。不常編的東西就暫時換回 ld 連結個一次就好。 | ||
|
||
``` | ||
#!/bin/bash | ||
LD=/usr/bin/ld | ||
GNULD=${LD}.bfd | ||
GOLD=${LD}.gold | ||
current=$(\ls -l $LD | awk '{print $NF}') | ||
if [ $current = $GNULD ]; then | ||
sudo ln -fs ${GOLD} ${LD} | ||
echo "switch ld to ${GOLD}" | ||
else | ||
sudo ln -fs ${GNULD} ${LD} | ||
echo "switch ld to ${GNULD}" | ||
fi | ||
``` | ||
|
||
另外 jserv 提到 gcc 有命令列參數可直接指定用那個 linker (ref.)。wens 則查到 Debian/Ubuntu changelog 裡有寫 下可用 -B/usr/lib/compat-ld 和 -B/usr/lib/gold-ld for ld.gold。 | ||
|
||
順便 google 一下看怎麼查 changelog, 似乎是看 /usr/share/doc/binutils/changelog.Debian.gz 或用 aptitude changelog PKG, 不過這兩個作法都只有最近的 changelog, 沒有完整記錄, 像查 binutils 時就沒有找到上面提的參數說明。 |