在Linux創建庫函數(7)
2024-07-21 02:37:19
供稿:網友
5. 其他
5.1. nm命令
nm命令可以列出一個函數庫文件中的符號表。它對于靜態的函數庫和共享的函數庫都起作用。對于一個給定的函數庫,nm命令可以列出函數庫中定義的所有符號,包括每個符號的值和類型。還可以給出在原程序中這個函數(符號)是在多少行定義的,不過這必須要求編譯該函數庫的時候加“-l”選項。
關于符號的類型,這里我們再多討論一下。符號的類型是以一個字母的形式顯示的,小寫字母表示這個符號是本地(local)的,而大寫字母則表示這個符號是全局的(global,externel)。一般來說,類型有一下幾種:T、D、B、U、W。各自的含義如下:T表示在代碼段中定義的一般變量符號;D表示時初始化過的數據段;B表示初始化的數據段;U表示沒有定義的,在這個庫里面使用了,但是在其他庫中定義的符號;W,weak的縮寫,表示假如其他函數庫中也有對這個符號的定義,則其他符號的定義可以覆蓋這個定義。
假如你知道一個函數的名字,但是你不知道這個函數在什么庫中定義的,那么可以用mn的“-o”選項和grep命令來查找庫的名字。-o選項使得顯示的每一行都有這個函數庫文件名。例如,你要查找“cos”這個是在什么地方定義的,大致可以用下面的命令:
nm -o /lib/* /usr/lib/* /usr/lib/*/* /usr/local/lib/* 2> /dev/null
grep 'cos$'
關于nm的更具體的用法我們可以參考info文檔,位置是info:binutils#nm。
5.2. 非凡函數_init和_fini
函數庫里面有兩個非凡的函數,_init和_fini,這個我們在前面已經說過了。主要是分別用來初始化函數庫和關閉的時候做一些必要的處理,我們可以把自己認為需要的代碼放到這兩個函數里面,它們分別在函數庫被加載和釋放的時候被執行。具體說,假如一個函數庫里面有一個名字為“_init”的函數輸出,那么在第一次通過dlopen()函數打開這個函數庫,或者只是簡單的作為共享函數庫被打開的時候,_init函數被自動調用執行。與之相對應的就是_fini函數,當一個程序調用dlclose()去釋放對這個函數庫的引用的時候,假如該函數庫的被引用計數器為0了,或者這個函數庫是作為一般的共享函數庫被使用而使用它的程序正常退出的時候,_fini就會被調用執行。C語言定義它們的原型如下:
void _init(void); void _fini(void);
當用gcc編譯源程序為“.o”文件的時候,需要加一個“-nostartfiles”選項。這個選項使得C編譯器不鏈接系統的啟動函數庫里面的啟動函數。否則,就會得到一個“multiple-definition”的錯誤。
5.3. 共享函數庫也可以使腳本(Scripts)
GNU的loader答應使用非凡格式的腳本語言來寫一個函數庫。這對于那些需要間接包含其他函數庫的情況還是有用的。例如,下面是一個/usr/lib/libc.so的例子:
/* GNU ld script Use the shared library, but some functions are only in
the static library, so try that secondarily. */GROUP ( /lib/libc.so.6
/usr/lib/libc_nonshared.a )
更多的信息可以參考texinfo文檔中關于ld鏈接的腳本部分。一般的信息還可以參考: info:ld#Options 和info:ld#Commands,也可以參考info:ld#Option Commands。
5.4. GNU liBTool
假如你正在編譯的系統相很方便的移植到其他操作系統下,你可以使用GNU libtool來創建和安裝這個函數庫。GNU libtool是一個函數庫支持的典型的腳本。Libtool隱藏了使用一個可移植的函數庫的負責性。Libtool提供了一個可以移植的界面來創建object文件,鏈接函數庫(靜態或者共享的),并且安裝這些庫。它還包含了libltdl,一個可移植的動態函數庫調入程序的wrapper。更多的具體討論,可以在http://www.gnu.org/software/libtool/manual.Html看到。
5.5. 刪除一些符號
在一個生產的文件中很多符號都是為了debug而包含的,占用了不少空間。假如空間不夠,而且這些符號也許不再需要,就可以將其中一些刪除。
最好的方法就是先正常的生成你需要的object文件,然后debug和測試你需要的一些東西。一旦你完全測試完畢了,就可以用strip去刪除一些不需要的符號了。Strip命令可以使你很方便的控制刪除什么符號,而保留什么符號。Strip的具體用法可以參考其幫助文件。
另外的方法就是使用GNU ld的選項“-S”和“-s”;“-S”會刪除一些debugger的符號,而“-s”則是將所有的符號信息都刪除。通常我們可以在gcc中加這樣的參數“-Wl,-S”和“-Wl,-s”來達到這個目的。