當我們給
$ gcc -o foo.o foo.c |
當初在編譯時指定的(在~gcc/gcc/collect2.c:locatelib()
寫在specs內的
後來用-D -I -L指定的
gcc環境變數設定(編譯的時候)
ld.so的環境變數(這是run time的時候)
prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.9.5/ |
/usr/lib/gcc-lib/xxxx-gnulibc/version/ |
*asm: %{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} *asm_final: %| *cpp: %(cpp_cpu) %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{posix: -D_POSIX_SOURCE} %{pthread:-D_REENTRANT} *cc1: %(cc1_cpu) %{profile:-p} *cc1plus: *endfile: %{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s *link: -m elf_i386 %{shared:-shared} %{!shared: %{!ibcs: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} %{static:-static}}} *lib: %{shared: -lc --version-script libgcc.map%s} %{!shared: %{mieee-fp:-lieee} %{pthread:-lpthread} %{profile:-lc_p} %{!profile: -lc}} *libgcc: -lgcc *startfile: %{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s} %{!profile:crt1.o%s}}}} crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} *switches_need_spaces: *signed_char: %{funsigned-char:-D__CHAR_UNSIGNED__} *predefines: -D__ELF__ -Dunix -Di386 -D__i386__ -Dlinux -Asystem(posix) *cross_compile: 0 *version: egcs-2.91.66 *multilib: . ; *multilib_defaults: *multilib_extra: *multilib_matches: *linker: collect2 *cpp_cpu_default: -D__tune_i386__ *cpp_cpu: -Asystem(unix) -Acpu(i386) -Amachine(i386) %{!ansi:-Di386} -D__i386 -D__i386__ %{march=i486:-D__i486 -D__i486__} %{march=pentium|march=i586:-D__pentium -D__pentium__ } %{march=pentiumpro|march=i686:-D__pentiumpro -D__pentiumpro__ } %{m386|mcpu=i386:-D__tune_i386__ } %{m486|mcpu=i486:-D__tune_i486__ } %{mpentium|mcpu=pentium|mcpu=i586:-D__tune_pentium__ } %{mpentiumpro|mcpu=pentiumpro|mcpu=i686:-D__tune_pentiumpro__ } %{!mcpu*:%{!m386:%{!m486:%{!mpentium*:%(cpp_cpu_default)}}}} *cc1_cpu: %{!mcpu*: %{m386:-mcpu=i386} %{mno-486:-mcpu=i386 -march=i386} %{m486:-mcpu=i486} %{mno-386:-mcpu=i486 -march=i486} %{mno-pentium:-mcpu=i486 -march=i486} %{mpentium:-mcpu=pentium} %{mno-pentiumpro:-mcpu=pentium} %{mpentiumpro:-mcpu=pentiumpro}} |
$ echo 'main(){}' | gcc -E -v - |
Reading specs from /usr/lib/gcc-lib/i386-linux/2.95.2/specs gcc version 2.95.2 20000220 (Debian GNU/Linux) /usr/lib/gcc-lib/i386-linux/2.95.2/cpp -lang-c -v -D__GNUC__=2 -D__GNUC_MINOR__=95 -D__ELF__ -Dunix -D__i386__ -Dlinux -D__ELF__ -D__unix__ -D__i386__ -D__linux__ -D__unix -D__linux -Asystem(posix) -Acpu(i386) -Amachine(i386) -Di386 -D__i386 -D__i386__ - GNU CPP version 2.95.2 20000220 (Debian GNU/Linux) (i386 Linux/ELF) #include "..." search starts here: #include <...> search starts here: /usr/local/include /usr/lib/gcc-lib/i386-linux/2.95.2/include /usr/include End of search list. The following default directories have been omitted from the search path: /usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3 /usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include End of omitted list. # 1 "" main(){} |
/usr/include /usr/local/include /usr/lib/gcc-lib/i386-linux/2.95.2/include /usr/lib/gcc-lib/i386-linux/2.95.2/../../../../include/g++-3 /usr/lib/gcc-lib/i386-linux/2.95.2/../../../../i386-linux/include |
/usr/include prefix/include prefix/xxx-xxx-xxx-gnulibc/include prefix/lib/gcc-lib/xxxx-xxx-xxx-gnulibc/2.8.1/include |
當我們用到數學函式cos(),cos這個symbol,gcc並不曉它到底是什麼東西, 是變數,是函式,要預留多少空間給他等等,完全沒有任何訊息,你必須標頭 檔要#include <math.h>,gcc才知道。而且因為specs這個檔裡面只有要 link -lc也就是只有libc.so這個檔內的symbol會被蒐尋, 像printf scanf等都在這裡面,可是像cos()等就沒有了, 所以函式庫的選項要多加 -lm ,這時ld才會來找libm這個函式庫,
編譯的時候,gcc會去找-L,再找gcc的環境變數LIBRARY_PATH,再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程式內的, gcc環境變數與pass給ld的機制在~gcc/gcc/collect2.c下找得到。 這上面只是搜尋路徑而已,如果要不加-lm 也能正確的主動搜尋某個特定的lib,例如libm, 就要去在specs這個檔案改一下,把math這個函式庫加進自動聯結函式庫 之一。就不用寫-lm了。
RUN TIME的時候, 如果編譯時沒有指定-static這個選項,其實可執行檔並不是真的可執行, 它必須在執行(run time)時需要ld.so來做最後的連結動作,建造一個可執行的 image丟到記憶體。如果是靜態連結,編譯時ld會去找libm.a的檔 。如果是動態連結去找libm.so。 所以每次有新改版程式, 或新加動態函式庫如果不在原本的/etc/ld.so.conf搜尋路徑中,都要把路徑 加進來,然後用
ldconfig -v |
一些重要的程式
ld :Link Editor 連結各obj寫進一個可執行檔(executable)。 ldd :秀出一個執行檔用了那些動態函式庫。 ld.so :Dynamic Linker, 動態連結的話,是由ld.so完成執行時期symbol的 :參照與連結。 ld-linux.so :ELF檔的動態連結,跟ld.so一樣。只是ld.so是給a.out format的。 :新的glicb2的ld-linux.so.2已經跟ld.so.2結合成單一程式了。 ldconfig :根據/etc/ld.so.conf內的目錄,做出動態連結所需的cache檔。 |
LD_LIBRARY_PATH 或LD_AOUT_LIBRARY_PATH環境變數所指的路逕
ldconfig所建立的cache
/lib /usr/lib內的檔
ldconfig會根據/etc/ld.so.conf這個檔的設定,加上內定的兩個目錄 /lib /usr/lib來設定ld.so要用到所需要的連結 以及連結的cache到/etc/ld.so.cache。 所以如果換了新的函式庫,新的kernel,內部的標頭檔可能會有變化, 都要跟著改變讓gcc正確的找到,喔不,應該是cpp, ld, ld.so能正確的找到。 不然編出來的執行檔可能是錯誤的,執行時還可能segmentation fault。