Aix上使用庫文件和編寫庫文件。
一直以來,被動態(tài)鏈接庫,靜態(tài)庫,靜態(tài)鏈接,動態(tài)鏈接,最近又聽到運行時鏈接弄得一塌糊涂。天下文章一大抄,知道的大家都知道,靜態(tài)鏈接是編譯時鏈接,生成的文件大,動態(tài)鏈接是運行時鏈接,生成的文件小。不知道的大家都不知道,或者大家都以為自己知道...有時windows,有時linux,有時Aix,有時gcc,有時g++,有時cc,有時xlc,有時.so,有時.a,有時.dll有時.lib有時.o,太多不一致,太多麻煩。
還有,因為工作的原因,經(jīng)常在以Aix為工作環(huán)境,有的說.so是動態(tài)鏈接庫,.a是靜態(tài)鏈接庫,但在Aix上咋看咋不像。
這周末,我花了兩天時間研究Aix上的這些問題,用的是vac的xlc和ccs的ld,不能說現(xiàn)在有多了解,但至少不像以前那么糊涂了。現(xiàn)在做做總結(jié)。
一,鏈接文件和鏈接方式。
其實沒有將動態(tài)鏈接和動態(tài)鏈接方式仔細地想一想,是導(dǎo)致我原來混亂的主要原因。之所以想到這個問題,是在工作中要編寫一個庫a,那我要編譯a,然后要寫另一個庫b,b依賴于a,我又要編譯b,在這個過程中,我開始思考,我當初編譯a的時候是用的什么鏈接方式,我現(xiàn)在要用a了,那a又是什么?
于是我開始區(qū)分鏈接文件和鏈接方式,開始了以下實驗
1,使用庫文件libc.a,靜態(tài)鏈接成可執(zhí)行程序 hello.c
- #include <stdio.h>
- int main() {
- printf("Hello, world!\n");
- }
#include <stdio.h>
int main() {
printf("Hello, world!\n");
}
運行
# xlc -o hello.o -c hello.c
生成目標文件hello.o
運行
ld -o hello_s -bstatic hello.o -lc
想靜態(tài)鏈接hello.o和libc.a,并生成可執(zhí)行文件hello_s。我這里沒有直接使用xlc來生成可執(zhí)行文件,是想把其中每一步弄清楚,結(jié)果求知的代價就是大量的時間和無盡的搜索。-bnso是告訴ld靜態(tài)鏈接。(你還可以用xlc的-E和-S參數(shù)看hello.c的預(yù)處理文件和匯編文件,再用as來編譯匯編文件生成對象文件)
結(jié)果
ld: 0711-327 WARNING: Entry point not found: __start
ld: 0711-244 ERROR: No csects or exported symbols have been saved.
這里說沒有找到__start,這個__start看起來很像系統(tǒng)的一個子歷程。出現(xiàn)這個錯的原因是因為我們沒有在鏈接時加入這樣一個庫/usr/lib/crt0.o,如果你用xlc直接靜態(tài)鏈接,那么這個庫應(yīng)該是xlc自己幫你加的(這個庫好像是線程初始化相關(guān)),你可以通過nm命令查看這個目標文件相關(guān)的symbol,里面是包含有__start的。于是我們再運行
ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o
結(jié)果報錯說一大堆符號找不到,
ld: 0711-224 WARNING: Duplicate symbol: .is_posix_tz
ld: 0711-224 WARNING: Duplicate symbol: .__icuinit
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
ld: 0711-317 ERROR: Undefined symbol: __loadx
ld: 0711-317 ERROR: Undefined symbol: _system_TB_config
ld: 0711-317 ERROR: Undefined symbol: errno
ld: 0711-317 ERROR: Undefined symbol: .___bzero
ld: 0711-317 ERROR: Undefined symbol: smcr_timebase
ld: 0711-317 ERROR: Undefined symbol: .___memmove
ld: 0711-317 ERROR: Undefined symbol: .___memset
ld: 0711-317 ERROR: Undefined symbol: _system_configuration
ld: 0711-317 ERROR: Undefined symbol: disclaim
ld: 0711-317 ERROR: Undefined symbol: kwritev
ld: 0711-317 ERROR: Undefined symbol: kpwritev
ld: 0711-317 ERROR: Undefined symbol: kpwrite
ld: 0711-317 ERROR: Undefined symbol: kwrite
ld: 0711-317 ERROR: Undefined symbol: kopenx
...
ld提示可以用-bloadmap來查看具體的出錯信息,于是我運行
ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o -bloadmap:out.txt
并查看輸出文件,得到
...
ld: 0711-318 ERROR: Undefined symbols were found.
The following symbols are in error:
Symbol Inpndx TY CL Source-File(Object-File) OR Import-File{Shared-object}
RLD: Address Section Rld-type Referencing Symbol
----------------------------------------------------------------------------------------------
__loadx [262] ER DS (/usr/lib/libc.a[shr.o])
0006919c .data R_POS [1658] <__loadx>
_system_TB_config [792] ER UA (/usr/lib/libc.a[shr.o])
000691a8 .data R_POS [1664] <_system_TB_config>
errno [8] ER UA (/usr/lib/libc.a[shr.o])
00068e3c .data R_POS [1226]
...
這說明是libc.a中的shr.o中的定義的一些符號找不到,于是我們將這個shr.o解出來,運行
ar -x /usr/lib/libc.a shr.o
得到shr.o,然后
ldd shr.o
得到輸出
shr.o needs:
/unix
/usr/lib/libcrypt.a(shr.o)
/usr/lib/libc.a(shr.o)
這個shr.o需要以上三個庫,libc.a我們已經(jīng)包括了,那么哪里去找/unix這個庫?相比現(xiàn)在所找不到的符號應(yīng)該都是系統(tǒng)調(diào)用吧。查看ld的手冊得知我們需要導(dǎo)入系統(tǒng)調(diào)用的符號表/lib/syscalls.exp
于是我們再運行
# ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp
結(jié)果還是報錯
# ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp
ld: 0711-224 WARNING: Duplicate symbol: .open
ld: 0711-224 WARNING: Duplicate symbol: .openx
ld: 0711-224 WARNING: Duplicate symbol: .is_posix_tz
ld: 0711-224 WARNING: Duplicate symbol: .__icuinit
ld: 0711-224 WARNING: Duplicate symbol: .send
ld: 0711-224 WARNING: Duplicate symbol: .nrecvmsg
ld: 0711-224 WARNING: Duplicate symbol: .nrecvfrom
ld: 0711-224 WARNING: Duplicate symbol: .recvmsg
ld: 0711-224 WARNING: Duplicate symbol: .recvfrom
ld: 0711-224 WARNING: Duplicate symbol: .recv
ld: 0711-224 WARNING: Duplicate symbol: .nsendmsg
ld: 0711-224 WARNING: Duplicate symbol: .sendmsg
ld: 0711-224 WARNING: Duplicate symbol: .sendto
ld: 0711-224 WARNING: Duplicate symbol: .naccept
ld: 0711-224 WARNING: Duplicate symbol: .accept
ld: 0711-224 WARNING: Duplicate symbol: .thread_wait
ld: 0711-345 Use the -bloadmap or -bnoquiet option to obtain more information.
ld: 0711-317 ERROR: Undefined symbol: encrypted_pw_passlen
ld: 0711-317 ERROR: Undefined symbol: crypt_r
ld: 0711-317 ERROR: Undefined symbol: max_history_size
ld: 0711-317 ERROR: Undefined symbol: getpass_auto
ld: 0711-317 ERROR: Undefined symbol: max_pw_passlen
但現(xiàn)在只有少量符號找不到了,我查看/lib下還有哪些exp,但是沒有發(fā)現(xiàn)和加密解密相關(guān),我又查看/lib/syscalls.exp的內(nèi)容,發(fā)現(xiàn)里面也只是一些符號表,我懷疑是否可以自己創(chuàng)建一個符號表。結(jié)果網(wǎng)上的一篇資料證實了我的想法,于是我創(chuàng)建一個名為StaticLinkScript的文件,輸入:
#!
encrypted_pw_passlen
crypt_r
max_history_size
getpass_auto
max_pw_passlen
接著運行:
# ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
雖然有些警告,但是hello_s還是生出來了。運行
# ./hello_s
Hello, world!成功出現(xiàn),然后再運行
# ls -l
看到這個文件近3M,僅僅一個printf語句,可以估計這個是靜態(tài)鏈接出來的文件了
-rw-r--r-- 1 root system 78 Nov 30 04:41 StaticLinkScript
-rw-r--r-- 1 root system 1812 Dec 02 07:52 crt0.syms
-rw-r--r-- 1 root system 64 Nov 29 09:39 hello.c
-rw-r--r-- 1 root system 1100 Dec 02 07:28 hello.o
-rwxr-xr-x 1 root system 2963741 Dec 02 08:28 hello_s
-rw-r--r-- 1 root system 36438 Dec 02 08:00 out.txt
-r-xr-xr-x 1 root system 5111233 Dec 02 08:03 shr.o
-rw-r--r-- 1 root system 657423 Nov 30 03:41 shr.syms
在運行
ldd hello_s
結(jié)果
hello_s needs:
/unix
這充分證明hello_s是靜態(tài)出鏈接出來的。好了,有了上面的經(jīng)歷,后面就簡單了
2,使用庫文件libc.a,動態(tài)鏈接成可執(zhí)行程序
我們?nèi)サ?bstatic選項,運行
# ld -o hello_d hello.o -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
生成可以成功運行的可執(zhí)行文件hello_d,我們再 運行
# ldd hello_d
輸出
hello_d needs:
/usr/lib/libc.a(shr.o)
/unix
/usr/lib/libcrypt.a(shr.o)
這說明hello_d是動態(tài)鏈接出來的。或者運行
# ls -l
得到
-rwxr-xr-x 1 root system 4402 Dec 02 08:37 hello_d
-rwxr-xr-x 1 root system 2963741 Dec 02 08:28 hello_s
這里我們得到一個結(jié)論,Aix上其實沒有動態(tài)鏈接庫和靜態(tài)鏈接庫的概念,只有共享對象的概念: shared object,即so,拿到一個.so,你可以將它靜態(tài)鏈接到某個可執(zhí)行程序上去,也可將它靜態(tài)鏈接到某個可執(zhí)行程序上去。
3,關(guān)于-bstatic選項和-nso選項
手冊上說,它只將它之后的共享對象以靜態(tài)鏈接的方式鏈接起來,所以,我們來看看以下結(jié)果
# ld -o hello_s -bstatic hello.o -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o hello_s2 -lc -bstatic hello.o /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o hello_s3 hello.o -bstatic -lc /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o hello_s4 -lc -bnso hello.o /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ls -l
-rwxr-xr-x 1 root system 4402 Dec 02 08:37 hello_d
-rwxr-xr-x 1 root system 2963741 Dec 02 08:28 hello_s
-rwxr-xr-x 1 root system 4402 Dec 02 08:38 hello_s2
-rwxr-xr-x 1 root system 2963741 Dec 02 08:39 hello_s3
-rwxr-xr-x 1 root system 2963741 Dec 02 09:13 hello_s4
這驗證了-bstatic并不是讓所有共享對象以靜態(tài)方式鏈接。同樣,我們知道了.so和.o文件的區(qū)別,.so可以動態(tài)或靜態(tài)鏈接到結(jié)果,而.o好像只能靜態(tài)鏈接到結(jié)果,或者說.o根本就不是共享文件,不能用上動態(tài)鏈接的概念,只能說被鏈接,那么這里的鏈接就只能是將.o文件的靜態(tài)鏈接了
另外,以上例子說明-bnso選項是對全局有效的。
4,編寫“靜態(tài)鏈接庫”,和使用“靜態(tài)鏈接庫”
按照我們第3步的分析,所謂的靜態(tài)鏈接庫可以認為就是.o文件,aix上又可以把文件打包成.a文件。難怪有人會說.a就是靜態(tài)鏈接庫
我們先寫源文件mylib.h和mylib.c
mylib.h
- void hello();
- mylib.c
- #include <stdio.h>
- int m1 = 1;
- char m2[10];
- char *m3 = "jjww";
-
- void hello(){
- int i = 0;
- char name[10];
- name[0] = 'l';
- name[1] = 'i';
- name[2] = 'u';
- name[3] = '\0';
-
- printf("success call from perl to c library: i=%d, name=%s, m3=%s\n", i, name, m3);
- }
void hello();
mylib.c
#include <stdio.h>
int m1 = 1;
char m2[10];
char *m3 = "jjww";
void hello(){
int i = 0;
char name[10];
name[0] = 'l';
name[1] = 'i';
name[2] = 'u';
name[3] = '\0';
printf("success call from perl to c library: i=%d, name=%s, m3=%s\n", i, name, m3);
}
運行
# xlc -o mylib.o -c mylib.c
得到mylib.o,打包成mylib.a,運行
ar -r mylib.a mylib.o
好了,所謂的“靜態(tài)鏈接庫”就出來了
編寫應(yīng)用程序test_lib.c
- #include "mylib.h"
- int main() {
- hello();
- }
#include "mylib.h"
int main() {
hello();
}
運行
# xlc -o test_lib.o -c test_lib.c
得到對象文件test_lib.o
運行
# ld -o test_lib_s test_lib.o mylib.o -bnso /usr/lib/crt0.o -lc -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o test_lib_s2 test_lib.o mylib.a -bnso /usr/lib/crt0.o -lc -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o test_lib_d test_lib.o mylib.o /usr/lib/crt0.o -lc -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o test_lib_d2 test_lib.o mylib.a /usr/lib/crt0.o -lc -bI:/lib/syscalls.exp -bI:StaticLinkScript
# mv mylib.a libmylib.a
# ld -o test_lib_s3 test_lib.o -L"." -lmylib /usr/lib/crt0.o -lc -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ls -l
得到
-rwxr-xr-x 1 root system 4868 Dec 02 09:22 test_lib_d
-rwxr-xr-x 1 root system 4868 Dec 02 09:22 test_lib_d2
-rwxr-xr-x 1 root system 2964203 Dec 02 09:19 test_lib_s
-rwxr-xr-x 1 root system 2964203 Dec 02 09:19 test_lib_s2
-rwxr-xr-x 1 root system 4870 Dec 02 09:28 test_lib_s3
前兩個語句我是靜態(tài)鏈接成可執(zhí)行程序,接下來的兩個采用動態(tài)鏈接,最后一個,我仿照libc.a生成了一個libmylib.a,想動態(tài)鏈接mylib.a,但是發(fā)現(xiàn)test_lib_s3比test_lib_d和test_lib_d2略大,而且
# ldd test_lib_s3
得到
test_lib_s3 needs:
/usr/lib/libc.a(shr.o)
/unix
/usr/lib/libcrypt.a(shr.o)
依賴列表中沒有/libmylib.a,可以說明/libmylib.a還是被靜態(tài)鏈接的,就和其他的test_lib.o一樣
5,編寫共享對象.so,和使用.so
# xlc -o libmylib.so -qmkshrobj mylib.c
# xlc -o libmylib2.so -qmkshrobj -c mylib.c
生成共享對象libmylib.so,注意前者沒有-c而后者有,libmylib2.so被生成為一般的oject文件,雖然其后綴是.so,比如
# ldd libmylib.so
輸出
libmylib.so needs:
/usr/lib/libc.a(shr.o)
/unix
/usr/lib/libcrypt.a(shr.o)
# ldd libmylib2.so
輸出
libmylib2.so needs:
除了大小和mylib.o一樣外,libmylib2.so同樣不依賴任何庫
運行
# ld -o test_lib_ss -lc libmylib.so test_lib.o -bnso /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o test_lib_dd -lc libmylib.so test_lib.o /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ld -o test_lib_dd2 -lc -L"." libmylib.so test_lib.o /usr/lib/crt0.o -bI:/lib/syscalls.exp -bI:StaticLinkScript
# ldd test_lib_dd
test_lib_dd needs:
/usr/lib/libc.a(shr.o)
Cannot find libmylib.so
/unix
/usr/lib/libcrypt.a(shr.o)
# ldd test_lib_dd2
test_lib_dd2 needs:
/usr/lib/libc.a(shr.o)
./libmylib.so
/unix
/usr/lib/libcrypt.a(shr.o)
test_lib_dd雖然成功生成,但是文件有問題,從ldd test_lib_dd2的結(jié)果看出,/libmylib.so是被動態(tài)鏈接了
參考資料
ld手冊
xlc手冊
http://linux.chinaitlab.com/c/769617_2.html
http://faq.csdn.net/read/201458.html
http://post.doit.wisc.edu/library/aix51/usr/share/man/info/en_US/a_doc_lib/libs/basetrf1/crypt.htm
http://blog.163.com/cn_prince/blog/static/638790120078289170781/
http://blog.solrex.cn/articles/the-true-story-of-hello-world.html