一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

GCC程序編譯的靜態(tài)鏈接和動(dòng)態(tài)鏈接

Linux愛(ài)好者 ? 來(lái)源:Mr_Bluyee ? 作者:Mr_Bluyee ? 2020-11-12 15:50 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在鏈接階段中,所有對(duì)應(yīng)于源文件的 .o 文件、"-l" 選項(xiàng)指定的庫(kù)文件、無(wú)法識(shí)別的文件名(包括指定的.o目標(biāo)文件和.a庫(kù)文件)按命令行中的順序傳遞給鏈接器。

下面看一下,鏈接的過(guò)程是怎樣的:

gcc -v -o helloworld helloworld.o Usingbuilt-inspecs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exeTarget: mingw32Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nlsThread model: win32gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) COMPILER_PATH=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../libexec/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/LIBRARY_PATH=d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../lib/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../COLLECT_GCC_OPTIONS='-v' '-o' 'helloworld.exe' '-mtune=generic' '-march=i586' d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/collect2.exe -plugin d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/liblto_plugin-0.dll -plugin-opt=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe -plugin-opt=-fresolution=C:UsersMrBluAppDataLocalTempcceFgn0y.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -Bdynamic -o helloworld.exe d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../crt2.o d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/crtbegin.o -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0 -Ld:/software/mingw/bin/../lib/gcc -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../.. helloworld.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/crtend.oCOLLECT_GCC_OPTIONS='-v' '-o' 'helloworld.exe' '-mtune=generic' '-march=i586'

crt2.o 、crtbegin.o、crtend.o是gcc加入的系統(tǒng)標(biāo)準(zhǔn)啟動(dòng)文件,對(duì)于一般應(yīng)用程序,這些啟動(dòng)是必須的。


-Ldir:在庫(kù)文件的搜索路徑列表中添加dir目錄。
-lname:添加鏈接庫(kù)文件。

靜態(tài)鏈接與動(dòng)態(tài)鏈接

庫(kù)有兩種:靜態(tài)庫(kù)(.a、.lib)和動(dòng)態(tài)庫(kù)(.so、.dll)。
window上對(duì)應(yīng)的是 .lib、.dll。
linux上對(duì)應(yīng)的是 .a、.so

如果函數(shù)庫(kù)的一份拷貝是可執(zhí)行文件的物理組成部分,稱之為靜態(tài)鏈接。

靜態(tài)鏈接當(dāng)鏈接程序時(shí),需要使用的每個(gè)庫(kù)函數(shù)的一份拷貝被加入到可執(zhí)行文件中。

靜態(tài)鏈接使用靜態(tài)庫(kù)進(jìn)行鏈接,生成的程序包含程序運(yùn)行所需要的全部庫(kù),可以直接運(yùn)行,不過(guò)靜態(tài)鏈接生成的程序體積較大(即使是在靜態(tài)鏈接中,整個(gè)庫(kù)文件也并沒(méi)有全部裝入到可執(zhí)行文件中,所裝入的只是需要的函數(shù))。

如果可執(zhí)行文件只是包含了文件名,讓載入器在運(yùn)行時(shí)能夠?qū)ふ页绦蛩枰暮瘮?shù)庫(kù),稱之為動(dòng)態(tài)鏈接。

動(dòng)態(tài)鏈接允許系統(tǒng)提供一個(gè)龐大的函數(shù)庫(kù)集合,可以提供許多有用的服務(wù),程序在運(yùn)行時(shí)尋找它們。

動(dòng)態(tài)鏈接使用動(dòng)態(tài)鏈接庫(kù)進(jìn)行鏈接,生成的程序在執(zhí)行的時(shí)候需要加載所需的動(dòng)態(tài)庫(kù)才能運(yùn)行。動(dòng)態(tài)鏈接生成的程序體積較小,但是必須依賴所需的動(dòng)態(tài)庫(kù),否則無(wú)法執(zhí)行。

收集模塊準(zhǔn)備執(zhí)行的三個(gè)階段的規(guī)范名稱是鏈接-編輯(link-editing)、載入(loading)和運(yùn)行時(shí)鏈接(runtime linking)。靜態(tài)鏈接的模塊被鏈接編輯時(shí)載入,以便運(yùn)行。動(dòng)態(tài)鏈接的模塊被鏈接編輯后載入,并在運(yùn)行時(shí)進(jìn)行鏈接以便運(yùn)行。

程序執(zhí)行時(shí),在main函數(shù)被調(diào)用之前,運(yùn)行時(shí)載入器把共享的數(shù)據(jù)對(duì)象載入到進(jìn)程的地址空間。外部函數(shù)被真正調(diào)用之前,運(yùn)行時(shí)載入器并不解析它們。所以動(dòng)態(tài)鏈接即使鏈接了函數(shù)庫(kù),如果沒(méi)有實(shí)際調(diào)用,也不會(huì)帶來(lái)額外開(kāi)銷。

gcc編譯器默認(rèn)使用動(dòng)態(tài)鏈接:

gcc -o helloworld_shared helloworld.o

gcc編譯器使用靜態(tài)鏈接:

gcc -static -o helloworld_static helloworld.o

在windows平臺(tái)上使用mingw編譯發(fā)現(xiàn)這兩種方式生成的exe文件的大小都一樣,為40kb,懷疑mingw的編譯的庫(kù)是靜態(tài)庫(kù)。

下面看一下linux平臺(tái)上使用gcc兩種編譯方式的文件大小區(qū)別:

可以看到helloworld_shared的大小為8344,而helloworld_static的大小達(dá)到844792。

-nostartfiles:


不鏈接系統(tǒng)標(biāo)準(zhǔn)啟動(dòng)文件,而標(biāo)準(zhǔn)庫(kù)文件仍然正常使用。

gcc -v -nostartfiles -o helloworld helloworld.oUsing built-in specs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exeTarget: mingw32Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nlsThread model: win32gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) COMPILER_PATH=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../libexec/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/LIBRARY_PATH=d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../lib/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../COLLECT_GCC_OPTIONS='-v' '-nostartfiles' '-o' 'helloworld.exe' '-mtune=generic' '-march=i586' d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/collect2.exe -plugin d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/liblto_plugin-0.dll -plugin-opt=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe -plugin-opt=-fresolution=C:UsersMrBluAppDataLocalTempccZxAfxD.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -Bdynamic -o helloworld.exe -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0 -Ld:/software/mingw/bin/../lib/gcc -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../.. helloworld.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrtertr000001.o:(.rdata+0x0): undefined reference to `_pei386_runtime_relocator'collect2.exe: error: ld returned 1 exit status

-nostdlib

不鏈接系統(tǒng)標(biāo)準(zhǔn)啟動(dòng)文件和標(biāo)準(zhǔn)庫(kù)文件,會(huì)提示因?yàn)闆](méi)有鏈接系統(tǒng)標(biāo)準(zhǔn)啟動(dòng)文件和標(biāo)準(zhǔn)庫(kù)文件,而鏈接失敗。


該選項(xiàng)常用于裸機(jī)/bootloader、linux內(nèi)核等程序,因?yàn)樗鼈儾恍枰獑?dòng)文件、標(biāo)準(zhǔn)庫(kù)文件。

gcc -v -nostdlib -o helloworld helloworld.oUsing built-in specs.COLLECT_GCC=gccCOLLECT_LTO_WRAPPER=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exeTarget: mingw32Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nlsThread model: win32gcc version 6.3.0 (MinGW.org GCC-6.3.0-1) COMPILER_PATH=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../libexec/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/LIBRARY_PATH=d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/;d:/software/mingw/bin/../lib/gcc/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib/;d:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../COLLECT_GCC_OPTIONS='-v' '-nostdlib' '-o' 'helloworld.exe' '-mtune=generic' '-march=i586' d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/collect2.exe -plugin d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/liblto_plugin-0.dll -plugin-opt=d:/software/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe -plugin-opt=-fresolution=C:UsersMrBluAppDataLocalTempccRAu2K4.res -Bdynamic -o helloworld.exe -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0 -Ld:/software/mingw/bin/../lib/gcc -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib -Ld:/software/mingw/bin/../lib/gcc/mingw32/6.3.0/../../.. helloworld.ohelloworld.o(.text+0xa): undefined reference to `__main'helloworld.o(.text+0x25): undefined reference to `puts'helloworld.o(.text+0x3b): undefined reference to `printf'helloworld.o(.text+0x47): undefined reference to `puts'collect2.exe: error: ld returned 1 exit status

動(dòng)態(tài)鏈接的優(yōu)點(diǎn)

動(dòng)態(tài)鏈接的優(yōu)點(diǎn)是可執(zhí)行文件的體積可以非常小。雖然運(yùn)行速度稍慢一些,但動(dòng)態(tài)鏈接能夠更加有效的利用磁盤空間,而且鏈接-編輯階段的時(shí)間也會(huì)縮短(因?yàn)殒溄悠鞯挠行┕ぷ鞅煌七t到載入時(shí))。

動(dòng)態(tài)鏈接的主要目的是把程序與它們使用的特定的函數(shù)庫(kù)版本中分離開(kāi)來(lái)。取而代之的是,我們約定由系統(tǒng)向程序提供一個(gè)接口,該接口保持穩(wěn)定,不隨時(shí)間和操作系統(tǒng)的后續(xù)版本發(fā)生變化。

程序可以調(diào)用接口所承諾的服務(wù),而不必?fù)?dān)心這些功能是怎樣提供的或者它們的底層實(shí)現(xiàn)是否改變。由于它是介于應(yīng)用程序和函數(shù)庫(kù)二進(jìn)制可執(zhí)行文件所提供的服務(wù)之間的接口,所以稱它為應(yīng)用程序二進(jìn)制接口(Application Binary Interface,ABI)。

盡管單個(gè)可執(zhí)行文件的啟動(dòng)速度稍受影響,但動(dòng)態(tài)鏈接可以從兩個(gè)方面提高性能:


1.動(dòng)態(tài)鏈接可執(zhí)行文件比功能相同的靜態(tài)鏈接可執(zhí)行文件的體積小。它能夠節(jié)省磁盤空間和虛擬內(nèi)存,因?yàn)楹瘮?shù)庫(kù)只有在需要時(shí)才被映射到進(jìn)程中。


2.所有動(dòng)態(tài)鏈接到某個(gè)特定函數(shù)庫(kù)的可執(zhí)行文件在運(yùn)行時(shí)共享該函數(shù)庫(kù)的一個(gè)單獨(dú)拷貝。操作系統(tǒng)內(nèi)核保證映射到內(nèi)存中的函數(shù)庫(kù)可以被所有使用它們的進(jìn)程共享。這就提供了更好的I/O和交換空間利用率,節(jié)省了物理內(nèi)存,從而提高了系統(tǒng)的整體性能。如果可執(zhí)行文件是靜態(tài)鏈接的,每個(gè)文件都將擁有一份函數(shù)庫(kù)的拷貝,顯然極為浪費(fèi)。

動(dòng)態(tài)鏈接使得函數(shù)庫(kù)的版本升級(jí)更為容易。新的函數(shù)庫(kù)可以隨時(shí)發(fā)布,只要安裝到系統(tǒng)中,舊的程序就能夠自動(dòng)獲得新版本函數(shù)庫(kù)的優(yōu)點(diǎn)而無(wú)需重新鏈接。動(dòng)態(tài)鏈接允許用戶在運(yùn)行時(shí)選擇需要執(zhí)行的函數(shù)庫(kù)。這就使為了提高速度或提高內(nèi)存使用效率或包含額外的調(diào)試信息而創(chuàng)建新版本的函數(shù)庫(kù)是完全可能的,用戶可以根據(jù)自己的喜好,在程序執(zhí)行時(shí)用一個(gè)庫(kù)文件取代另一個(gè)庫(kù)文件。

動(dòng)態(tài)鏈接是一種“just-in-time(JIT)”鏈接,這意味著程序在運(yùn)行時(shí)必須能夠找到它們所需要的函數(shù)庫(kù)。鏈接器通過(guò)把庫(kù)文件名或路徑名植入可執(zhí)行文件中來(lái)做到這一點(diǎn)。這意味著,函數(shù)庫(kù)的路徑不能隨意移動(dòng)。如果把程序鏈接到/usr/lib/libthread.so庫(kù),那么就不能把該函數(shù)庫(kù)移動(dòng)到其他目錄,除非在鏈接器中進(jìn)行特別說(shuō)明。否則,當(dāng)程序調(diào)用該函數(shù)庫(kù)的函數(shù)時(shí),就會(huì)在運(yùn)行時(shí)導(dǎo)致失敗。當(dāng)在一臺(tái)機(jī)器上編譯完程序后,把它拿到另一臺(tái)不同的機(jī)器上運(yùn)行時(shí),也可能出現(xiàn)這種情況。執(zhí)行程序的機(jī)器必須具有該程序需要鏈接的函數(shù)庫(kù),而且這些函數(shù)庫(kù)必須位于在鏈接器中所說(shuō)明的目錄。對(duì)于標(biāo)準(zhǔn)系統(tǒng)函數(shù)庫(kù)而言,這并不成問(wèn)題。

任何人都可以創(chuàng)建靜態(tài)或動(dòng)態(tài)的函數(shù)庫(kù)。只需簡(jiǎn)單的編譯一些不包含main函數(shù)的代碼,并把編譯所生的.o用正確的工具進(jìn)行處理。


使用gcc程序編譯的過(guò)程中的示例代碼在Ubuntu下使用gcc創(chuàng)建靜態(tài)和動(dòng)態(tài)庫(kù):

1.首先將helloworld代碼拆分開(kāi)來(lái):

分別為“helloworld.c”、“helloworld.h”、“main.c”,


helloworld.c內(nèi)容如下:

#include #define TRUE 1#define FALSE 0 #define DEBUG_ENABLE void helloworld(void){ int i = 0; if(i == TRUE){ printf("hello "); }else{#ifdef DEBUG_ENABLE printf("i = %d ",i);#endif printf("hello world "); }}

helloworld.h內(nèi)容如下:

#ifndef HELLO_WORLD_H #define HELLO_WORLD_H void helloworld(void);#endif

main.c內(nèi)容如下:

#include "helloworld.h"int main(){ helloworld(); return 0; }

2.將helloworld.c生成動(dòng)態(tài)鏈接庫(kù):

gcc -fPIC -shared helloworld.c -o libhelloworld.so

-fPIC:表示編譯為位置獨(dú)立的代碼,不用此選項(xiàng)的話編譯后的代碼是位置相關(guān)的所以動(dòng)態(tài)載入時(shí)是通過(guò)代碼拷貝的方式來(lái)滿足不同進(jìn)程的需要,而不能達(dá)到真正代碼段共享的目的。與位置無(wú)關(guān)的代碼表示用這種方法產(chǎn)生的代碼保證對(duì)于任何全局?jǐn)?shù)據(jù)的訪問(wèn)都是通過(guò)額外的間接方法完成的。這使它很容易對(duì)數(shù)據(jù)進(jìn)行重新定位,只要簡(jiǎn)單的修改全局偏移量表的其中一個(gè)值就可以了。類似的,每個(gè)函數(shù)調(diào)用的產(chǎn)生就像是通過(guò)過(guò)程鏈接表的某個(gè)間接地址所產(chǎn)生的一樣。這樣,文本可以很容易的重新定位到任何地方,只要修改一下偏移量表就可以了。所以當(dāng)代碼在運(yùn)行時(shí)被映射進(jìn)來(lái)時(shí),運(yùn)行時(shí)鏈接器可以直接把它們放在任何空閑的地方,而代碼本身并不需要修改。

在缺省情況下,編譯器并不產(chǎn)生與位置無(wú)關(guān)的代碼,因?yàn)轭~外的指針解除引用操作將使程序在運(yùn)行時(shí)稍慢。然而,如果不使用與位置無(wú)關(guān)的代碼,所產(chǎn)生的代碼就會(huì)被對(duì)應(yīng)到固定的地址,這對(duì)于可執(zhí)行文件來(lái)說(shuō)確實(shí)很好,但對(duì)于共享庫(kù),速度卻要慢一點(diǎn),因?yàn)楝F(xiàn)在每個(gè)全局引用就不得不在運(yùn)行時(shí)通過(guò)修改頁(yè)面安排到固定的位置,這使得頁(yè)面無(wú)法共享。

運(yùn)行時(shí)鏈接器總能夠安排對(duì)頁(yè)面的引用。但是,使用位置無(wú)關(guān)代碼,任務(wù)被極大的簡(jiǎn)化了。當(dāng)然需要權(quán)衡一下,位置無(wú)關(guān)代碼與由運(yùn)行時(shí)鏈接器安排代碼相比,速度是快了還是慢了。根據(jù)經(jīng)驗(yàn),對(duì)于函數(shù)庫(kù)應(yīng)該始終使用與位置無(wú)關(guān)代碼。對(duì)于共享庫(kù),與位置無(wú)關(guān)的代碼顯得格外有用,因?yàn)槊總€(gè)使用共享庫(kù)的進(jìn)程一般都會(huì)把它映射到不同的虛擬地址(盡管共享庫(kù)同一份物理拷貝)。

一個(gè)相關(guān)的術(shù)語(yǔ)是“純代碼(pure code)”。純可執(zhí)行文件是只包含代碼(無(wú)靜態(tài)或初始化過(guò)的數(shù)據(jù))的文件。它之所以稱為“純”是因?yàn)樗槐剡M(jìn)行修改就能被其他特定的進(jìn)程執(zhí)行。它從堆?;蛘咂渌ǚ羌儯┒我脭?shù)據(jù)。純代碼可以被共享。如果生成與位置無(wú)關(guān)代碼(意味著共享),你通常也希望它是純代碼。

3.編譯main時(shí)加入libhelloworld.so:

gcc helloworld.h main.c -L. -lhelloworld -o main

-L. : 標(biāo)記告訴gcc函數(shù)庫(kù)可能位于當(dāng)前目錄。
-l :后面加上動(dòng)態(tài)鏈接庫(kù),動(dòng)態(tài)鏈接庫(kù)的名字前的lib不用加上去。傳給C編譯器的命令行參數(shù)里并沒(méi)有提到函數(shù)庫(kù)的完整路徑名。它甚至沒(méi)有提到在函數(shù)庫(kù)目錄中該文件的完整名字。實(shí)際上,編譯器被告知根據(jù)選項(xiàng)-lname鏈接到相應(yīng)的函數(shù)庫(kù),函數(shù)庫(kù)的名字是libname.so——換句話說(shuō),“l(fā)ib”部分和文件擴(kuò)展名被省略掉了,但在前面加了一個(gè)“l(fā)”。

4.運(yùn)行main,出錯(cuò):

./main: error while loading shared libraries: libhelloworld.so: cannot open shared object file: No such file or directory

程序在運(yùn)行時(shí),會(huì)查找需要的動(dòng)態(tài)庫(kù)文件,若找到,則載入動(dòng)態(tài)庫(kù),否則將提示類似上述錯(cuò)誤而終止程序運(yùn)行。有多種方法可以解決:

a.將文件 libhelloworld.so復(fù)制到目錄/usr/lib中,再執(zhí)行則沒(méi)有問(wèn)題:

mrbluyee@mrbluyee:~/mypro/C$ sudo mv libhelloworld.so /usr/libmrbluyee@mrbluyee:~/mypro/C$ ./maini = 0hello world

b.既然連接器會(huì)搜尋LD_LIBRARY_PATH所指定的目錄,那么我們可以將這個(gè)環(huán)境變量設(shè)置成當(dāng)前目錄:

mrbluyee@mrbluyee:~/mypro/C$ export LD_LIBRARY_PATH=$(pwd)mrbluyee@mrbluyee:~/mypro/C$ ./maini = 0helloworld

c. ldconfig命令

mrbluyee@mrbluyee:~/mypro/C$ sudo ldconfig ~/mypro/Cmrbluyee@mrbluyee:~/mypro/C$ ./maini = 0hello world

當(dāng)用戶在某個(gè)目錄下面創(chuàng)建或拷貝了一個(gè)動(dòng)態(tài)鏈接庫(kù),若想使其被系統(tǒng)共享,可以執(zhí)行一下”ldconfig 目錄名”這個(gè)命令。此命令的功能在于讓ldconfig將指定目錄下的動(dòng)態(tài)鏈接庫(kù)被系統(tǒng)共享起來(lái),意即:在緩存文件/etc/ld.so.cache中追加進(jìn)指定目錄下的共享庫(kù)。上述指令讓系統(tǒng)共享了~/mypro/C目錄下的動(dòng)態(tài)鏈接庫(kù)。

可以查看程序執(zhí)行時(shí)調(diào)用動(dòng)態(tài)庫(kù)的過(guò)程:

mrbluyee@mrbluyee:~/mypro/C$ ldd main linux-vdso.so.1 (0x00007ffd56fa4000) libhelloworld.so => /home/mrbluyee/mypro/C/libhelloworld.so (0x00007fcec730f000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcec6f1e000) /lib64/ld-linux-x86-64.so.2 (0x00007fcec7713000)

5.將helloworld.c生成靜態(tài)鏈接庫(kù):

a. 先將helloworld.c編譯生成.o文件:

gcc -c -o helloworld.o helloworld.c

b.通過(guò)ar工具將目標(biāo)文件打包成.a靜態(tài)庫(kù)文件:

ar -rc libhelloworld.a helloworld.o

注意:靜態(tài)庫(kù)與匯編生成的目標(biāo)文件一起鏈接為可執(zhí)行文件,那么靜態(tài)庫(kù)必定跟.o文件格式相似。其實(shí)一個(gè)靜態(tài)庫(kù)可以簡(jiǎn)單看成是一組目標(biāo)文件(.o/.obj文件)的集合,即很多目標(biāo)文件經(jīng)過(guò)壓縮打包后形成的一個(gè)文件。故ar工具里打包的一定是.o的文件,否則當(dāng)運(yùn)行連接了該靜態(tài)庫(kù)的可執(zhí)行程序會(huì)報(bào)錯(cuò)。

6.編譯main時(shí)加入libhelloworld.a:

gcc helloworld.h main.c -static -L. -lhelloworld -o main_static

可以看到,使用動(dòng)態(tài)鏈接庫(kù)生成的mian與靜態(tài)鏈接庫(kù)生成的main_static的大小區(qū)別:

動(dòng)態(tài)鏈接庫(kù)生成的mian大小為8288,而靜態(tài)鏈接庫(kù)生成的main_static的大小為844856。

7.刪除libhelloworld.a后運(yùn)行main_static:

mrbluyee@mrbluyee:~/mypro/C$ rm libhelloworld.amrbluyee@mrbluyee:~/mypro/C$ ./main_static i = 0hello world

程序照常運(yùn)行,靜態(tài)庫(kù)中的helloworld函數(shù)已經(jīng)鏈接到main_static文件中了。

8.多個(gè)文件生成動(dòng)態(tài)/靜態(tài)庫(kù)的用法:

動(dòng)態(tài)庫(kù):

1.gcc -fPIC -shared xxx1.c xxx2.c xxx3.c -o libxxx.so 2.gcc -fPIC -shared xxx1.o xxx2.o xxx3.o -o libxxx.so

靜態(tài)庫(kù):

ar -rc libxxx.a xxx1.o xxx2.o xxx3.o

責(zé)任編輯:lq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 模塊
    +關(guān)注

    關(guān)注

    7

    文章

    2785

    瀏覽量

    49992
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1659

    瀏覽量

    50046
  • 函數(shù)庫(kù)
    +關(guān)注

    關(guān)注

    1

    文章

    84

    瀏覽量

    32677

原文標(biāo)題:GCC 程序編譯的靜態(tài)鏈接和動(dòng)態(tài)鏈接

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    飛凌嵌入式ElfBoard ELF 1板卡-uboot編譯鏈接文件uboot.lds

    編譯完成之后在uboot根目錄下生成的uboot.lds是鏈接文件。鏈接器就是通過(guò)這個(gè)文件將成千上萬(wàn)的.o文件鏈接在一起,此文件是根據(jù)arch/arm/cpu/uboot.lds生成
    發(fā)表于 05-22 11:20

    請(qǐng)問(wèn)如何鏈接動(dòng)態(tài)庫(kù)?

    是否有可參考的工程? 鏈接成功后動(dòng)態(tài)庫(kù)應(yīng)該放在哪里???SDK是RTOS_ONLY
    發(fā)表于 04-25 08:15

    深入探討Linux系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)機(jī)制

    本文將深入探討Linux系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)機(jī)制,這其中包括但不限于全局符號(hào)介入、延遲綁定以及地址無(wú)關(guān)代碼等內(nèi)容。 引言 在軟件開(kāi)發(fā)過(guò)程中,動(dòng)態(tài)庫(kù)鏈接問(wèn)題時(shí)常出現(xiàn),這可能導(dǎo)致符號(hào)沖突,從
    的頭像 發(fā)表于 12-18 10:06 ?551次閱讀
    深入探討Linux系統(tǒng)中的<b class='flag-5'>動(dòng)態(tài)</b><b class='flag-5'>鏈接</b>庫(kù)機(jī)制

    分享關(guān)于編譯器的科普

    源代碼分析工具和IDE集成。GCC被構(gòu)建成一個(gè)單一的靜態(tài)編譯器,這使得它非常難以被作為API并集成到其他工具中。 GCC比Clang支
    的頭像 發(fā)表于 12-09 09:49 ?524次閱讀

    安卓動(dòng)態(tài)鏈接庫(kù)文件體積優(yōu)化探索實(shí)踐

    諸多方面影響,針對(duì)dex、資源文件、so文件都有不同的優(yōu)化策略,在此不做一一展開(kāi),本文主要記錄了在研發(fā)時(shí)針對(duì)動(dòng)態(tài)鏈接庫(kù)的文件體積裁剪優(yōu)化方案。 我開(kāi)發(fā)的鏈接庫(kù)使用rust語(yǔ)言開(kāi)發(fā),通過(guò)安卓jni接口實(shí)現(xiàn)java層和native層
    的頭像 發(fā)表于 11-21 14:07 ?410次閱讀

    深入解析Tricore的Tasking鏈接文件

    目錄 1.鏈接文件有什么用? 2.文件結(jié)構(gòu)和語(yǔ)法解析 2.1 文件結(jié)構(gòu) 2.2 語(yǔ)法解析 3.小結(jié) 玩慣了ld文件,突然讓搞lsl文件,被其中花里胡哨的語(yǔ)法搞暈了,例如: memory
    的頭像 發(fā)表于 11-12 16:31 ?1762次閱讀
    深入解析Tricore的Tasking<b class='flag-5'>鏈接</b>文件

    三星貼片電容的引腳結(jié)構(gòu)和鏈接方式

    三星貼片電容,作為一種廣泛應(yīng)用的電子元件,其引腳結(jié)構(gòu)和鏈接方式對(duì)于電路的性能和穩(wěn)定性具有至關(guān)重要的作用。下面,我們將詳細(xì)介紹三星貼片電容的引腳結(jié)構(gòu)和鏈接方式。
    的頭像 發(fā)表于 10-29 17:47 ?645次閱讀

    KeyStone I和IlDevices上的SERDES鏈接調(diào)試

    電子發(fā)燒友網(wǎng)站提供《KeyStone I和IlDevices上的SERDES鏈接調(diào)試.pdf》資料免費(fèi)下載
    發(fā)表于 10-11 10:05 ?0次下載
    KeyStone I和IlDevices上的SERDES<b class='flag-5'>鏈接</b>調(diào)試

    C2000 SysConfig 鏈接器命令工具數(shù)據(jù)手冊(cè)

    電子發(fā)燒友網(wǎng)站提供《C2000 SysConfig 鏈接器命令工具數(shù)據(jù)手冊(cè).pdf》資料免費(fèi)下載
    發(fā)表于 09-09 09:20 ?0次下載
    C2000 SysConfig <b class='flag-5'>鏈接</b>器命令工具數(shù)據(jù)手冊(cè)

    先進(jìn)的鏈接器技術(shù),方便高效地使用內(nèi)存

    電子發(fā)燒友網(wǎng)站提供《先進(jìn)的鏈接器技術(shù),方便高效地使用內(nèi)存.pdf》資料免費(fèi)下載
    發(fā)表于 09-06 15:02 ?0次下載
    先進(jìn)的<b class='flag-5'>鏈接</b>器技術(shù),方便高效地使用內(nèi)存

    linux驅(qū)動(dòng)程序編譯方法有哪兩種

    Linux驅(qū)動(dòng)程序編譯方法主要可以歸納為兩種: 手動(dòng)編譯 和 使用內(nèi)核構(gòu)建系統(tǒng)(Makefile)自動(dòng)編譯 。 1. 手動(dòng)編譯 手動(dòng)
    的頭像 發(fā)表于 08-30 14:39 ?1469次閱讀

    嵌入式學(xué)習(xí)-靜態(tài)鏈接動(dòng)態(tài)鏈接

    一、靜態(tài)鏈接靜態(tài)鏈接通過(guò)靜態(tài)庫(kù)進(jìn)行鏈接,生成的目標(biāo)程序
    發(fā)表于 08-28 09:33

    靜態(tài)鏈接動(dòng)態(tài)鏈接

    一、靜態(tài)鏈接靜態(tài)鏈接通過(guò)靜態(tài)庫(kù)進(jìn)行鏈接,生成的目標(biāo)程序
    發(fā)表于 08-27 10:20

    嵌入式學(xué)習(xí)-常用編輯器之GCC編譯

    ;匯編:將匯編語(yǔ)言翻譯成二進(jìn)制文件;鏈接:將匯編出來(lái)的多個(gè)二進(jìn)制目標(biāo)文件和庫(kù)文件進(jìn)行鏈接,生成可執(zhí)行文件。我們可以通過(guò)一個(gè)簡(jiǎn)單的hello.c程序編譯過(guò)程對(duì)
    發(fā)表于 08-27 10:17

    常用編輯器之GCC編譯

    ,輸出結(jié)果是一樣的。elf@ubuntu:~/work/example/hello$ gcc hello.c4、GCC編譯過(guò)程GCC編譯器的
    發(fā)表于 08-24 11:05