1. 靜態庫(static library)的主要缺陷:
1) 靜態庫通常需要維護和定期更新,而這些庫的使用者就得注意這些變化,并且在庫修改后重新將自己的程序和庫鏈接起來
2) 以printf和scanf這兩個函數為例,它們的代碼在每個運行的進程里都保留了一份,在一個典型的操作系統上運行著50-100個進程,這無疑是對系統資源的嚴重浪費。(內存的一個有趣的特性是,它永遠是一個短缺的資源,無關一個系統里有多大的內存)
2. 共享庫(shared library)彌補了靜態庫的這些缺陷。所謂共享庫,就是指在運行時可以被讀入到任意的內存地址,并與程序鏈接的模塊。這個過程也被稱為動態鏈接(dynamic linking),由動態鏈接器(dynamic linker)完成。
Unix系統中共享對象通常后綴為.so,微軟的操作系統中大量使用了共享庫,通常被稱為DLL(dynamic link libraries)
3. 共享庫的“共享”表現在兩個方面:
1) 在任何一個給定的文件系統中,對于某個特定的庫,只有一個.so文件
2) 共享庫單獨的一份.text域可以由多個不同的運行進程共享。
4. 編譯一個共享庫:gcc -shared -fPIC -o libvector.so addvec.c multvec.c
-fPIC開關讓編譯器產生位置獨立的代碼(PIC, position independent code)
-shared開關使得編譯器產生共享對象的文件
5. 動態鏈接的幾個應用:
1) 軟件的分布式開發
2) 開發高效的Web服務器
早期的Web服務器通過fork和execve調用子進程來產生動態的內容,被稱為CGI,而現代的Web服務器則通過基于動態鏈接庫的一種高效的方式。
主要的方法是把生成動態內容的函數打包到一個共享庫中,當服務器端接收到一個請求后,服務器動態地讀入并且鏈接到相應的函數,并直接調用這個函數,而 fork和execve則是在子進程的環境中運行的。函數調用后繼續存在,以后的類似請求都只需要一個簡單的調用就可以了。另外,方法也可以在不停止服務 器的情況下更新,也可以加入新的函數。
6. Unix系統中讀入并鏈接共享庫的方法
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
// returns: ptr to handle if OK, NULL on error
需要通過-rdynamic編譯,具體見CSAPP P569
獲得已經打開的庫的句柄(handle)
#include <dlfcn.h>
void #dlsym(void *handle, char *symbol);
// returns: ptr to symbol if OK, NULL on error
關閉共享庫
#include <dlfcn.h>
int dlclose(void *handle);
// returns: 0 if OK, -1 on error
獲得錯誤信息
#include <dlfcn.h>
const char *dlerror(void);
1) 靜態庫通常需要維護和定期更新,而這些庫的使用者就得注意這些變化,并且在庫修改后重新將自己的程序和庫鏈接起來
2) 以printf和scanf這兩個函數為例,它們的代碼在每個運行的進程里都保留了一份,在一個典型的操作系統上運行著50-100個進程,這無疑是對系統資源的嚴重浪費。(內存的一個有趣的特性是,它永遠是一個短缺的資源,無關一個系統里有多大的內存)
2. 共享庫(shared library)彌補了靜態庫的這些缺陷。所謂共享庫,就是指在運行時可以被讀入到任意的內存地址,并與程序鏈接的模塊。這個過程也被稱為動態鏈接(dynamic linking),由動態鏈接器(dynamic linker)完成。
Unix系統中共享對象通常后綴為.so,微軟的操作系統中大量使用了共享庫,通常被稱為DLL(dynamic link libraries)
3. 共享庫的“共享”表現在兩個方面:
1) 在任何一個給定的文件系統中,對于某個特定的庫,只有一個.so文件
2) 共享庫單獨的一份.text域可以由多個不同的運行進程共享。
4. 編譯一個共享庫:gcc -shared -fPIC -o libvector.so addvec.c multvec.c
-fPIC開關讓編譯器產生位置獨立的代碼(PIC, position independent code)
-shared開關使得編譯器產生共享對象的文件
5. 動態鏈接的幾個應用:
1) 軟件的分布式開發
2) 開發高效的Web服務器
早期的Web服務器通過fork和execve調用子進程來產生動態的內容,被稱為CGI,而現代的Web服務器則通過基于動態鏈接庫的一種高效的方式。
主要的方法是把生成動態內容的函數打包到一個共享庫中,當服務器端接收到一個請求后,服務器動態地讀入并且鏈接到相應的函數,并直接調用這個函數,而 fork和execve則是在子進程的環境中運行的。函數調用后繼續存在,以后的類似請求都只需要一個簡單的調用就可以了。另外,方法也可以在不停止服務 器的情況下更新,也可以加入新的函數。
6. Unix系統中讀入并鏈接共享庫的方法
#include <dlfcn.h>
void *dlopen(const char *filename, int flag);
// returns: ptr to handle if OK, NULL on error
需要通過-rdynamic編譯,具體見CSAPP P569
獲得已經打開的庫的句柄(handle)
#include <dlfcn.h>
void #dlsym(void *handle, char *symbol);
// returns: ptr to symbol if OK, NULL on error
關閉共享庫
#include <dlfcn.h>
int dlclose(void *handle);
// returns: 0 if OK, -1 on error
獲得錯誤信息
#include <dlfcn.h>
const char *dlerror(void);