中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux靜態庫與動態庫如何制作

發布時間:2022-02-19 10:48:54 來源:億速云 閱讀:161 作者:iii 欄目:開發技術

這篇“Linux靜態庫與動態庫如何制作”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Linux靜態庫與動態庫如何制作”文章吧。

靜態庫就是在編譯過程中一些目標文件的集合。靜態庫在程序鏈接的時候使用,鏈接器會將程序中使用到函數的代碼從庫文件中拷貝到應用程序中。

相對于靜態函數庫,動態函數庫在編譯的時候并沒有被編譯進目標代碼中,而只是作些標記。然后在程序開始啟動運行的時候,動態地加載所需模塊,因此動態函數庫所產生的可執行文件比較小。

Linux系統中:

1.靜態庫的擴展名為.a; 2.動態庫的擴展名為.so;

源代碼到可執行程序的轉換時需要經歷如下圖所示的過程:

Linux靜態庫與動態庫如何制作

1.編譯是指把用高級語言編寫的程序轉換成相應處理器的匯編語言程序的過程。 2.匯編是從匯編語言程序生成目標系統的二進制代碼(機器代碼)的過程。 3.鏈接是指將匯編生成的多段機器代碼組合成一個可執行程序。

通過編譯和匯編過程,每一個源文件將生成一個目標文件。連接器的作用就是將這些目標文件組合起來,組合的過程包括了代碼段、數據段等部分的合并,以及添加相應的文件頭。

最后得到的可執行文件如何作用的:

  Linux靜態庫與動態庫如何制作

ELF文件格式包括三種主要的類型:可執行文件、可重定向文件、共享庫。

1.可執行文件(應用程序)

可執行文件包含了代碼和數據,是可以直接運行的程序。

2.可重定向文件(*.o)

可重定向文件又稱為目標文件,它包含了代碼和數據(這些數據是和其他重定位文件和共享的object文件一起連接時使用的)。

.o文件參與程序的連接(創建一個程序)和程序的執行(運行一個程序),它提供了一個方便有效的方法來用并行的視角看待文件的內容,這些.o文件的活動可以反映出不同的需要。

Linux下,我們可以用gcc -c編譯源文件時可將其編譯成*.o格式。

3.共享文件(*.so)

也稱為動態庫文件,它包含了代碼和數據(這些數據是在連接時候被連接器ld和運行時動態連接器使用的)。動態連接器可能稱為ld.so.1,libc.so.1或者 ld-linux.so.1。我的CentOS6.0系統中該文件為:/lib/ld-2.12.so

庫是一種可執行代碼的二進制格式,能夠被載入到內存中執行,庫分靜態庫和動態庫兩種:

靜態庫:這類庫的名字一般是libxxx.a,xxx為庫的名字。利用靜態函數庫編譯成的文件比較大,因為整個函數庫的所有數據都會被整合進目標代碼中,他的優點就顯而易見了,即編譯后的執行程序不需要外部的函數庫支持,因為所有使用的函數都已經被編譯進去了。當然這也會成為他的缺點,因為如果靜態函數庫改變了,那么你的程序必須重新編譯。

動態庫:這類庫的名字一般是libxxx.M.N.so,同樣的xxx為庫的名字,M是庫的主版本號,N是庫的副版本號。當然也可以不要版本號,但名字必須有。相對于靜態函數庫,動態函數庫在編譯的時候并沒有被編譯進目標代碼中,你的程序執行到相關函數時才調用該函數庫里的相應函數,因此動態函數庫所產生的可執行文件比較小。由于函數庫沒有被整合進你的程序,而是程序運行時動態的申請并調用,所以程序的運行環境中必須提供相應的庫。動態函數庫的改變并不影響你的程序,所以動態函數庫的升級比較方便。linux系統有幾個重要的目錄存放相應的函數庫,如/lib /usr/lib。

當要使用靜態的程序庫時,連接器會找出程序所需的函數,然后將它們拷貝到執行文件,由于這種拷貝是完整的,所以一旦連接成功,靜態程序庫也就不再需要了。然而,對動態庫而言,就不是這樣。動態庫會在執行程序內留下一個標記指明當程序執行時,首先必須載入這個庫。由于動態庫節省空間,linux下進行連接的缺省操作是首先連接動態庫,也就是說,如果同時存在靜態和動態庫,不特別指定的話,將與動態庫相連接。

制作靜態鏈接庫:

1.準備兩個源碼文件st1.cpp和st2.cpp,用它們來制作庫libmytest.a

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat st1.cpp#include using namespace std;
void display1()
{
   cout"This is my first static library!!!"#include using namespace std;
void display2()
{
   cout"This is my second static library"

2.把兩個源碼文件生成目標文件

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -c st1.cpp  st2.cpp
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
總用量 24
drwxrwxr-x 2 xzj xzj 4096 7月  16 15:39 ./
drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../
-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o

3.使用ar -rsv libmytest.a st1.o st2.o制作靜態庫

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -rsv libmytest.a st1.o st2.o
ar: 正在創建 libmytest.a
a - st1.o
a - st2.o
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
總用量 32
drwxrwxr-x 2 xzj xzj 4096 7月  16 15:42 ./
drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../
-rw-rw-r-- 1 xzj xzj 5586 7月  16 15:42 libmytest.a
-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o
用file命令查看其屬性,發現它確實是歸檔壓縮文件
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ file libmytest.a
libmytest.a: current ar archive
用ar -t libmytest.a可以查看一個靜態庫包含了那些obj文件:
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ar -t libmytest.a
st1.o
st2.o

4.寫個測試程序來調用庫libmytest.a中所提供的兩個接口display1()和display2()。

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ cat main.cpp
void display1();
void display2();
int main()
{
   display1();
   display2();
   return 0;
}

xzj@xzj-VirtualBox:~/development_test/static_lib_test$ g++ -o run main.cpp  -L./  -lmytest
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ll
總用量 48
drwxrwxr-x 2 xzj xzj 4096 7月  16 15:54 ./
drwxrwxr-x 7 xzj xzj 4096 7月  16 15:26 ../
-rw-rw-r-- 1 xzj xzj 5586 7月  16 15:42 libmytest.a
-rw-rw-r-- 1 xzj xzj   95 7月  16 15:53 main.cpp
-rwxrwxr-x 1 xzj xzj 9424 7月  16 15:54 run*
-rw-rw-r-- 1 xzj xzj  115 7月  16 15:35 st1.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st1.o
-rw-rw-r-- 1 xzj xzj  113 7月  16 15:35 st2.cpp
-rw-rw-r-- 1 xzj xzj 2680 7月  16 15:39 st2.o

結果調用成功:
xzj@xzj-VirtualBox:~/development_test/static_lib_test$ ./run
This is my first static library!!!
This is my second static library

制作動態庫

靜態庫*.a文件的存在主要是為了支持較老的a.out格式的可執行文件而存在的。目前用的最多的要數動態庫了。

動態庫的后綴為*.so。在Linux發行版中大多數的動態庫基本都位于/usr/lib和/lib目錄下。在開發和使用我們自己動態庫之前,請容許我先落里羅嗦的跟大家嘮叨嘮叨Linux下和動態庫相關的事兒吧。

有時候當我們的應用程序無法運行時,它會提示我們說它找不到什么樣的庫,或者哪個庫的版本又不合它胃口了等等之類的話。那么應用程序它是怎么知道需要哪些庫的呢?我們前面已幾個學了個很棒的命令ldd,用就是用來查看一個文件到底依賴了那些so庫文件。

Linux系統中動態鏈接庫的配置文件一般在/etc/ld.so.conf文件內,它里面存放的內容是可以被Linux共享的動態聯庫所在的目錄的名字。我的系統中,該文件的內容如下:

xzj@xzj-VirtualBox:/etc$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf

然后/etc/ld.so.conf.d/目錄下存放了很多*.conf文件,如下:

xzj@xzj-VirtualBox:/etc$ ls /etc/ld.so.conf.d/
fakeroot-x86_64-linux-gnu.conf  libc.conf                  x86_64-linux-gnu_GL.conf
i386-linux-gnu.conf             x86_64-linux-gnu.conf      zz_i386-biarch-compat.conf
i386-linux-gnu_GL.conf          x86_64-linux-gnu_EGL.conf  zz_x32-biarch-compat.conf


其中每個conf文件代表了一種應用的庫配置內容,以libc為例:
xzj@xzj-VirtualBox:/etc$ cat /etc/ld.so.conf.d/libc.conf# libc default configuration/usr/local/lib



在/etc目錄下還存在一個名叫ld.so.cache的文件。從名字來看,我們知道它肯定是動態鏈接庫的什么緩存文件。
xzj@xzj-VirtualBox:/etc$ ls -l |grep ld.so.cache
-rw-r--r--  1 root root   125054 7月  16 09:09 ld.so.cache

為了使得動態鏈接庫可以被系統使用,當我們修改了/etc/ld.so.conf或/etc/ld.so.conf.d/目錄下的任何文件,或者往那些目錄下拷貝了新的動態鏈接庫文件時,都需要運行一個很重要的命令:ldconfig,該命令位于/sbin目錄下,主要的用途就是負責搜索/lib和/usr/lib,以及配置文件/etc/ld.so.conf里所列的目錄下搜索可用的動態鏈接庫文件,然后創建處動態加載程序/lib/ld-linux.so.2所需要的連接和(默認)緩存文件/etc/ld.so.cache(此文件里保存著已經排好序的動態鏈接庫名字列表)。

也就是說:當用戶在某個目錄下面創建或拷貝了一個動態鏈接庫,若想使其被系統共享,可以執行一下”ldconfig目錄名”這個命令。此命令的功能在于讓ldconfig將指定目錄下的動態鏈接庫被系統共享起來,即:在緩存文件/etc/ld.so.cache中追加進指定目錄下的共享庫。請注意:如果此目錄不在/lib,/usr/lib及/etc/ld.so.conf文件所列的目錄里面,則再次單獨運行ldconfig時,此目錄下的動態鏈接庫可能不被系統共享了。單獨運行ldconfig時,它只會搜索/lib、/usr/lib以及在/etc/ld.so.conf文件里所列的目錄,用它們來重建/etc/ld.so.cache。

因此,等會兒我們自己開發的共享庫就可以將其拷貝到/lib、/etc/lib目錄里,又或者修改/etc/ld.so.conf文件將我們自己的庫路徑添加到該文件中,再執行ldconfig命令。

動態庫的實戰搞起來

我們有一個頭文件my_so_test.h和三個源文件test_hubei.cpp、test_wuhan.cpp和test_xiaogan.cpp,將他們制作成一個名為libtest.so的動態鏈接庫文件:

頭文件:
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ cat my_so_test.h#ifndef MY_SO_TEST_H#define MY_SO_TEST_Hvoid test_hubei();
void test_wuhan();
void test_xiaogan();#endif三個源文件:
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ cat test_hubei.cpp#include "my_so_test.h"#include using namespace std;
void test_hubei()
{
   cout"歡迎來到湖北"#include "my_so_test.h"#include using namespace std;
void test_wuhan()
{
   cout"歡迎來到武漢"#include "my_so_test.h"#include using namespace std;
void test_wuhan()
{
   cout"歡迎來到武漢"

生產.so文件的方法:

方法一:

1、先生成目標.o文件:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ -c *.cpp
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ll
總用量 36
drwxrwxr-x 2 xzj xzj 4096 7月  16 17:21 ./
drwxrwxr-x 8 xzj xzj 4096 7月  16 16:26 ../
-rw-rw-r-- 1 xzj xzj  108 7月  16 17:14 my_so_test.h
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:18 test_hubei.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_hubei.o
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:19 test_wuhan.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_wuhan.o
-rw-rw-r-- 1 xzj xzj  127 7月  16 17:20 test_xiaogan.cpp
-rw-rw-r-- 1 xzj xzj 2672 7月  16 17:21 test_xiaogan.o

2、再生成so文件:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ -shared -fPCI -o libcity.so test_hubei.o test_wuhan.o test_xiaogan.o
g++: error: unrecognized command line option ‘-fPCI’
出現了錯誤,我使用了第二種方法。

方法二:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ test_hubei.cpp  test_wuhan.cpp test_xiaogan.cpp -fPIC  -shared -o libtest.so
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ll
總用量 48
drwxrwxr-x 2 xzj xzj 4096 7月  16 17:37 ./
drwxrwxr-x 8 xzj xzj 4096 7月  16 16:26 ../
-rwxrwxr-x 1 xzj xzj 9048 7月  16 17:37 libtest.so*
-rw-rw-r-- 1 xzj xzj  108 7月  16 17:14 my_so_test.h
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:18 test_hubei.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_hubei.o
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:19 test_wuhan.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_wuhan.o
-rw-rw-r-- 1 xzj xzj  127 7月  16 17:20 test_xiaogan.cpp
-rw-rw-r-- 1 xzj xzj 2672 7月  16 17:21 test_xiaogan.o

動態鏈接庫的使用有兩種方法:既可以在運行時對其進行動態鏈接,又可以動態加載在程序中是用它們

+++動態庫的使用+++

用法一:動態鏈接。

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ main.cpp -o run -L. -ltest
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ll
總用量 64
drwxrwxr-x 2 xzj xzj 4096 7月  16 18:14 ./
drwxrwxr-x 8 xzj xzj 4096 7月  16 16:26 ../
-rwxrwxr-x 1 xzj xzj 9048 7月  16 17:37 libtest.so*
-rw-rw-r-- 1 xzj xzj  130 7月  16 17:55 main.cpp
-rw-rw-r-- 1 xzj xzj  108 7月  16 17:14 my_so_test.h
-rwxrwxr-x 1 xzj xzj 8688 7月  16 18:14 run*
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:18 test_hubei.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_hubei.o
-rw-rw-r-- 1 xzj xzj  125 7月  16 17:19 test_wuhan.cpp
-rw-rw-r-- 1 xzj xzj 2664 7月  16 17:21 test_wuhan.o
-rw-rw-r-- 1 xzj xzj  127 7月  16 17:20 test_xiaogan.cpp
-rw-rw-r-- 1 xzj xzj 2672 7月  16 17:21 test_xiaogan.o
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ LD_LIBRARY_PATH=. ./run
歡迎來到湖北
歡迎來到武漢
歡迎來到孝感

將main.cpp與libtest.so鏈接成一個可執行文件main。命令如下:

$ g++ main.cpp -o run -L. -ltest

測試可執行程序main是否已經鏈接的動態庫libtest.so,如果列出了libtest.so,那么就說明正常鏈接了。可以執行以下命令:

$ ldd run

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ldd run
linux-vdso.so.1 =>  (0x00007ffe08fc7000)
libtest.so => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f685d1a2000)
/lib64/ld-linux-x86-64.so.2 (0x00007f685d56c000)
如果你直接執行可執行文件run的話就會出現以下錯誤:
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ./run
./run: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory

這里我們注意,ldd的輸出表示我們的libtest.so動態庫沒有找到。因為我們的libtest.so既不在/etc/ld.so.cache里,又不在/lib、/usr/lib或/etc/ld.so.conf所指定的任何一個目錄中

解決辦法:

方法一:LD_LIBRARY_PATH=. 可執行文件

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ LD_LIBRARY_PATH=. ./run
歡迎來到湖北
歡迎來到武漢
歡迎來到孝感

方法二:如果你在開發一款軟件,或者給自己的系統DIY一個非常有用的功能模塊,那么建議你將libtest.so拷貝到/lib、/usr/lib目錄下,

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ sudo cp libtest.so  /lib/
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ cd /lib/
xzj@xzj-VirtualBox:/lib$ ls
apparmor  hdparm                                ld-linux.so.2     modules        terminfo
brltty    i386-linux-gnu                        libtest.so        recovery-mode  udev
cpp       ifupdown                              linux-sound-base  resolvconf     ufw
crda      init                                  lsb               systemd        x86_64-linux-gnu
firmware  klibc-k3La8MUnuzHQ0_kG8hokcGAC0PA.so  modprobe.d        sysvinit       xtables

之后在使用ldd命令來看是否使用動態庫時,可以看到成功了
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ldd run
linux-vdso.so.1 =>  (0x00007ffe8b3fe000)
libtest.so => /lib/libtest.so (0x00007fe6af1f2000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe6aee28000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe6aeaa6000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe6af3f4000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe6ae79d000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe6ae587000)

直接運行可執行文件時,就成功了!

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ./run
歡迎來到湖北
歡迎來到武漢
歡迎來到孝感

方法三:動態加載。

動態加載是非常靈活的,它依賴于一套Linux提供的標準API來完成。在源程序里,你可以很自如的運用API來加載、使用、釋放so庫資源。以下函數在代碼中使用需要包含頭文件:dlfcn.h

函數原型說明
const char *dlerror(void)當動態鏈接庫操作函數執行失敗時,dlerror可以返回出錯信息,返回值為NULL時表示操作函數執行成功。
void *dlopen(const char *filename, int flag)用于打開指定名字(filename)的動態鏈接庫,并返回操作句柄。調用失敗時,將返回NULL值,否則返回的是操作句柄。
void *dlsym(void *handle, char *symbol)根據動態鏈接庫操作句柄(handle)與符號(symbol),返回符號對應的函數的執行代碼地址。由此地址,可以帶參數執行相應的函數。
int dlclose (void *handle)用于關閉指定句柄的動態鏈接庫,只有當此動態鏈接庫的使用計數為0時,才會真正被系統卸載。2.2在程序中使用動態鏈接庫函數。

dlsym(void *handle, char *symbol)

filename:如果名字不以“/”開頭,則非絕對路徑名,將按下列先后順序查找該文件。

(1)用戶環境變量中的LD_LIBRARY_PATH的值;

(2)動態鏈接緩沖文件/etc/ld.so.cache

(3)目錄/lib,/usr/lib

flag表示在什么時候解決未定義的符號(調用)。取值有兩個:

1) RTLD_LAZY : 表明在動態鏈接庫的函數代碼執行時解決。

2) RTLD_NOW :表明在dlopen返回前就解決所有未定義的符號,一旦未解決,dlopen將返回錯誤。

dlsym(void *handle, char *symbol)

dlsym()的用法一般如下:

void(*add)(int x,int y); /*說明一下要調用的動態函數add */

add=dlsym(”xxx.so”,”add”); /* 打開xxx.so共享庫,取add函數地址 */

add(89,369); /* 帶兩個參數89和369調用add函數 */ 代碼搞起

#include "my_so_test.h"#include #include #include extern "C"{
   void (*fn)(void);
}


int main(int argc, char const *argv[])
{
void *handle = dlopen("./libtest.so",RTLD_LAZY);
/*const char *err = dlerror();if(err !=NULL){
 perror("could not open shared object!");
}*/if (NULL != handle) {
 /* code */
 printf("nihao\n");

}
fn = (void (*)(void))dlsym(handle,"test_hubei");
fn();

dlclose(handle);return 0;
}

執行結果:

xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ test_hubei.cpp  test_wuhan.cpp test_xiaogan.cpp -fPIC  -shared -o libtest.so
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ g++ -o mmain_run mmain.cpp  -rdynamic -ldl
xzj@xzj-VirtualBox:~/development_test/dynamic_lib_test$ ./mmain_run
nihao
歡迎來到湖北!
歡迎來到武漢!!
歡迎來到孝感!

每次修改源文件,一定要重新生成動態文件.so,否則一直在用之前生產的文件。不利于調式出現的錯誤!

3、編譯參數

-shared 該選項指定生成動態連接庫(讓連接器生成T類型的導出符號表,有時候也生成弱連接W類型的導出符號),不用該標志外部程序無法連接。相當于一個可執行文件

-fPIC:表示編譯為位置獨立的代碼,不用此選項的話編譯后的代碼是位置相關的所以動態載入時是通過代碼拷貝的方式來滿足不同進程的需要,而不能達到真正代碼段共享的目的。

-L.:表示要連接的庫在當前目錄中

-ltest:編譯器查找動態連接庫時有隱含的命名規則,即在給出的名字前面加上lib,后面加上.so來確定庫的名稱

LD_LIBRARY_PATH:這個環境變量指示動態連接器可以裝載動態庫的路徑。

4、注意的問題

調用動態庫的時候有幾個問題會經常碰到,有時,明明已經將庫的頭文件所在目錄 通過 “-I” include進來了,庫所在文件通過 “-L”參數引導,并指定了“-l”的庫名,但通過ldd命令察看時,就是死活找不到你指定鏈接的so文件,這時你要作的就是通過修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件來指定動態庫的目錄。通常這樣做就可以解決庫無法鏈接的問題了。

在生成動態庫時的參數-fPIC

-fPIC 作用于編譯階段,告訴編譯器產生與位置無關代碼(Position-Independent Code), 則產生的代碼中,沒有絕對地址,全部使用相對地址,故而代碼可以被加載器加載到內存的任意 位置,都可以正確的執行。這正是共享庫所要求的,共享庫被加載時,在內存的位置不是固定的。

gcc -shared -fPIC -o 1.so 1.c 這里有一個-fPIC參數 PIC就是position independent code PIC使.so文件的代碼段變為真正意義上的共享 如果不加-fPIC,則加載.so文件的代碼段時,代碼段引用的數據對象需要重定位, 重定位會修改代碼段的內容,這就造成每個使用這個.so文件代碼段的進程在內核里都會生成這個.so文件代碼段的copy.每個copy都不一樣,取決于 這個.so文件代碼段和數據段內存映射的位置.

不加fPIC編譯出來的so,是要再加載時根據加載到的位置再次重定位的.(因為它里面的代碼并不是位置無關代碼) 如果被多個應用程序共同使用,那么它們必須每個程序維護一份so的代碼副本了.(因為so被每個程序加載的位置都不同,顯然這些重定位后的代碼也不同,當然不能共享) 我們總是用fPIC來生成so,也從來不用fPIC來生成a. fPIC與動態鏈接可以說基本沒有關系,libc.so一樣可以不用fPIC編譯,只是這樣的so必須要在加載到用戶程序的地址空間時重定向所有表目.

PIC原理與意義

載入時重定位的缺點:

(1)動態庫的代碼段不能在進程間共享:多個進程加載同一個動態庫到各自不同的地址空間,導致代碼段需要不同的重定位,所以最終每個引用該動態庫的進程擁有一份該動態庫代碼段的不同拷貝。

(2)代碼段必須是可寫的,增加了被攻擊風險。



為了解決載入時重定位的問題,引入了PIC的概念,即位置無關代碼。

PIC實現原理:

(1)GOT:在動態庫的數據段增加GOT(Global Offset Table),該表的每一項是符號到地址的絕對映射。由于代碼段到數據段的偏移是固定的,因此可以在編譯時確定代碼段中的某個符號到GOT特定項之間的偏移。這樣,代碼段中的符號偏移就可以在編譯時確定了,在加載時也無需修改代碼段的內容,只需要填寫位于數據段的GOT的所有項的符號的絕對地址就完成了。因為數據段本來就是進程間不共享,每個進程獨立的一份,因此GOT的設計完全解決了以上兩個問題,從而達到兩個目的:1,代碼段可以在多進程間共享;2,代碼段是只讀的。

(2)PLT:PLT是 Program Linkage Table 的縮寫,即程序鏈接表,PLT的出現是為了延時定位的目的。一個動態庫中的函數往往要遠多于全局變量,并且被調用的函數往往少于定義的函數。GOT中包含了該動態庫中的所有的全局變量的映射,并且在連接器加載時解析所有的全局變量的地址。如果用同樣的方式去處理函數調用符號,則開銷會非常大。因此在代碼段設計了一個PLT表,每一項其實是個代碼段,用于執行如下邏輯:首次訪問時,解析參數和向GOT填寫函數地址,后續訪問直接訪問GOT中的函數地址。如此達到了延時定位的目的。

因此,一個PIC的動態庫中,對全局變量使用GOT來映射,對函數調用使用PLT+GOT來映射,從而達到共享庫代碼段復用,代碼段安全訪問的目的。而這些就是 PIC 的意義。

以上就是關于“Linux靜態庫與動態庫如何制作”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

枣庄市| 西和县| 茶陵县| 堆龙德庆县| 商南县| 汝南县| 阜城县| 襄城县| 陇川县| 清丰县| 嘉黎县| 徐汇区| 洪湖市| 万源市| 台北县| 巢湖市| 普格县| 迁安市| 通化县| 连江县| 玉环县| 十堰市| 安远县| 莲花县| 徐汇区| 大兴区| 通州区| 自贡市| 上饶市| 鹿泉市| 山丹县| 石门县| 万年县| 浮山县| 江孜县| 万安县| 勐海县| 宝应县| 邢台市| 普宁市| 富川|