最近MIPS上開發一個程序,需要用到浮點運算。
寫好bootloader,main函數,在main函數調用log浮點運算,包含math庫。
然後再寫好makefile,ld腳本。
gcc的參數用到了:
CFLAGS= -c -march=3081 -msoft-float -fno-inline $(ENDIAN) -G0
ld的參數用到了:
LDFLAGS= -march=3081 -msoft-float -nostartfiles -lgcc -lm -lc -Wl,-Map,rlx_test.map
本文的重點是講述gcc庫的鏈接順序。
剛開始的時候,在鏈接參數部分,我的順序是這麼安排的: -lc -lgcc -lm。
結果compile正常,但是在ld的時候,遇到問題了,總是報log函數找不到errno變量。
經過仔細分析,發現我的程序本身是有問題的,運算表達式可以總結為:log(a)。
結果a為0了,log函數會報錯,會將錯誤代碼賦給__errno這個全局變量。而__errno變量是聲明在errno.h頭文件中,但是定義在libc的某個file中。
gcc庫的鏈接順序,官方是這麼解釋的:
https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Link-Options.html#Link-Options
gcc -l 解釋如下:
-l library
Search the library named library when linking. (The second alter-
native with the library as a separate argument is only for POSIX
compliance and is not recommended.)
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.
這句話翻譯過來的意思就是說,如果你的庫在鏈接時安排的順序是:foo.o -lz bar.o。那麼gcc的鏈接器先搜索庫foo,然後是z庫,然後是bar庫。
這樣就帶來一個問題,如果庫bar調用了庫z裡面的函數,但是鏈接器是先搜索的庫z,這時候並沒有發現庫bar調用庫z啊,所以就不會把庫z中的這部分函數體挑出來進行鏈接。
而是只把庫z中,被foo庫調用的函數體挑出來。
回到我們之前的描述。
由於__errno全局變量是定義在庫libc中,而庫libm中的log函數會訪問__errno全局變量。這就要求鏈接時,libm在libc的前面。所以我們應該這樣安排庫的鏈接順序:
-lm -lgcc -lc
一句話,越是被別人調用的越底層的庫,就越放在後面;越是調用別人的越上層的庫,就越放在前面。
下面我們來講講libm,libgcc, libc分別是做什麼用的:
libm庫,是數學運算函數的庫,裡面包含了各種基本的數學函數實現,例如sin,cos,平方根,log等。
libgcc庫,要想用gcc編譯代碼就需要調用的庫,裡面包含了一些基本的函數。參考https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html。例如部分整形/浮點運算,異常處理,一些雜項函數。
libc庫,是c的標准庫,裡面包含了基本輸入輸出函數,memcpy之類,string copy之類的函數。
從這些庫的用途,我們就知道為什麼要按照-lm -lgcc -lc 的順序調用了。
當然在編譯內核和一些庫時,我們可能會看到nostdlib,這個選項,意思是不調用標准庫libc和libgcc,而是要我們自己去實現這些基本的庫函數被內核函數調用。
-march=3081,是指定cpu架構是MIPS 3081。
-msoft-float,是針對沒有FPU單元的CPU,編譯浮點運算代碼需要的,也叫軟浮點。
-nostartfiles,是指不用默認的bootload代碼,而要用我們自己寫啟動引導代碼。
Linux升級GCC 4.8.1清晰簡明教程(Ubuntu 12.04 64位版為例) http://www.linuxidc.com/Linux/2014-04/99583.htm
在CentOS 6.4中編譯安裝GCC 4.8.1 + GDB 7.6.1 + Eclipse 在CentOS 6.4中編譯安裝GCC 4.8.1 + GDB 7.6.1 + Eclipse
Ubuntu下Vim+GCC+GDB安裝及使用 http://www.linuxidc.com/Linux/2013-01/78159.htm
Ubuntu下兩個GCC版本切換 http://www.linuxidc.com/Linux/2012-10/72284.htm
CentOS6.5升級手動安裝GCC4.8.2 http://www.linuxidc.com/Linux/2015-01/112595.htm
GCC 的詳細介紹:請點這裡
GCC 的下載地址:請點這裡