自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Linux 下靜態(tài)鏈接和動(dòng)態(tài)鏈接的原理及應(yīng)用

系統(tǒng) Linux
我們知道一個(gè).c 文件經(jīng)過(guò)編譯、鏈接最終可以形成一個(gè)可執(zhí)行文件。

我們知道一個(gè).c 文件經(jīng)過(guò)編譯、鏈接最終可以形成一個(gè)可執(zhí)行文件。

鏈接原理

當(dāng)我們的程序包含多個(gè)文件時(shí),那么這些文件是怎么形成一個(gè)目標(biāo)文件的呢?

這就要涉及到鏈接器。

鏈接器的作用就是將多個(gè)目標(biāo)文件鏈接成一個(gè)完整、可加載、可執(zhí)行的目標(biāo)文件。其輸入是一組可以重定位的目標(biāo)文件。

鏈接的主要作用有2個(gè):

符號(hào)解析:將目標(biāo)文件內(nèi)的引用符號(hào)和該符號(hào)的定義聯(lián)系起來(lái)。

將符號(hào)定義與存儲(chǔ)器的位置聯(lián)系起來(lái),修改對(duì)這些符號(hào)的引用。

目標(biāo)文件

典型的目標(biāo)文件有3種形式

  • 可重定位目標(biāo)文件:這種目標(biāo)文件后綴通常為.o,這種文件包含已經(jīng)轉(zhuǎn)換成機(jī)器指令的二進(jìn)制代碼和數(shù)據(jù),但是這種文件還不能直接執(zhí)行,因?yàn)檫@些指令和數(shù)據(jù)中往往還引用其他模塊(目標(biāo)文件)中的符號(hào),這些其他模塊的符號(hào)對(duì)于本模塊來(lái)講還都是未知的,因此這些符號(hào)的解析需要鏈接器對(duì)這些模塊進(jìn)行連接,這種操作也稱為“重定位”。
  • 可執(zhí)行目標(biāo)文件:這種文件同樣包含二進(jìn)制代碼和數(shù)據(jù),區(qū)別就是這些文件已經(jīng)經(jīng)過(guò)鏈接,因此這些文件是可以直接執(zhí)行的。
  • 共享目標(biāo)文件:這是一種特殊類型的可重定位的目標(biāo)文件,可以在需要它的程序運(yùn)行過(guò)程或者加載時(shí),動(dòng)態(tài)的加載到內(nèi)存中運(yùn)行。這種文件的后綴通常為“.so”, 共享目標(biāo)文件又稱為“動(dòng)態(tài)庫(kù)”文件或者“共享庫(kù)”文件。

符號(hào)解析

符號(hào)解析是鏈接的主要任務(wù)之一。只有在正確的解析了符號(hào)之后才能更改引用符號(hào)的位置,從而完成重定位,生成一個(gè)可以被機(jī)器直接加載執(zhí)行的的可執(zhí)行目標(biāo)文件。每個(gè)可重定位目標(biāo)文件都有一個(gè)符號(hào)表。在這個(gè)符號(hào)表中存儲(chǔ)符號(hào)。這些符號(hào)分為3類:

本模塊中引用其他模塊所定義的全局符號(hào)。

本模塊中定義的全局符號(hào)。

本模塊中定義和引用的局部符號(hào)。

重定位

在符號(hào)解析結(jié)束后,每個(gè)符號(hào)的定義位置及大小都是已知的了。重定位操作只需要將這些符號(hào)鏈接起來(lái)。在該步驟中,鏈接器需要將所有參與鏈接的目標(biāo)文件合并,并且為每一個(gè)符號(hào)分配存儲(chǔ)內(nèi)容的運(yùn)行時(shí)地址。

重定位分為2個(gè)步驟進(jìn)行:

  • 重定位段:該步將所有目標(biāo)文件中同類型的段合并,生成一個(gè)大段。比如,將所有參與鏈接的目標(biāo)文件的數(shù)據(jù)段合并,生成一個(gè)大的數(shù)據(jù)段。合并之后,程序中的指令和變量就擁有一個(gè)統(tǒng)一并且唯一的運(yùn)行時(shí)地址了。
  • 重定位符號(hào)引用:由于目標(biāo)文件中相同的段已經(jīng)合并,因此程序中對(duì)符號(hào)的引用位置就都作廢了。這時(shí)鏈接器需要修改這些引用符號(hào)的地址,使其指向正確的運(yùn)行時(shí)地址。

程序庫(kù)

所謂“程序庫(kù)”就是包含了一些通用函數(shù)的數(shù)據(jù)和二進(jìn)制可執(zhí)行機(jī)器碼的文件。這些文件是目標(biāo)文件的一種,其不能單獨(dú)執(zhí)行。但是若與其他的可執(zhí)行程序結(jié)合起來(lái)就可以執(zhí)行了。

從鏈接方式上區(qū)別,程序庫(kù)可分為靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)(共享庫(kù))兩種:

  • 靜態(tài)庫(kù):是在可執(zhí)行程序運(yùn)行前就已經(jīng)加入到執(zhí)行代碼中,成為執(zhí)行程序的一部分來(lái)執(zhí)行的。
  • 動(dòng)態(tài)庫(kù):是在執(zhí)行程序啟動(dòng)時(shí)加載到執(zhí)行程序中,可以被多個(gè)執(zhí)行程序共享使用。

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

靜態(tài)庫(kù)是一些目標(biāo)代碼的集合。Linux下靜態(tài)目標(biāo)文件一般以.a作為目標(biāo)文件的后綴。在Linux環(huán)境下使用ar命令來(lái)創(chuàng)建一個(gè)靜態(tài)庫(kù)。靜態(tài)庫(kù)的優(yōu)點(diǎn)就是在生成時(shí)已經(jīng)編譯成可重定位的目標(biāo)文件,節(jié)省了編譯時(shí)間,并且在編譯時(shí)把代碼復(fù)制到可執(zhí)行代碼段中,這樣可執(zhí)行程序就可以單獨(dú)直接運(yùn)行,但是缺點(diǎn)也是顯而易見的,就是可執(zhí)行文件可能會(huì)變得很臃腫。

靜態(tài)庫(kù)的創(chuàng)建

本文以四則運(yùn)算來(lái)創(chuàng)建一個(gè)靜態(tài)庫(kù),該靜態(tài)庫(kù)中包含四個(gè)函數(shù):加、減、乘、除。

// static_lib.c
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}

生成一個(gè)可重定位的目標(biāo)文件。

# gcc -c static_lib.c

在Linux下使用 ar 命令創(chuàng)建一個(gè)靜態(tài)庫(kù),或者將目標(biāo)文件加入到一個(gè)已經(jīng)存在的靜態(tài)庫(kù)中。其使用方法如下:

ar rcs 靜態(tài)庫(kù)名 目標(biāo)文件1 目標(biāo)文件2 ... 目標(biāo)文件n

該命令表示將目標(biāo)文件1~n加入到指定的靜態(tài)庫(kù)中。若該靜態(tài)庫(kù)不存在,則創(chuàng)建靜態(tài)庫(kù)文件,并將庫(kù)文件的擴(kuò)展名命名為.a, 其中rcs這三個(gè)參數(shù)分別表示:把列表中的目標(biāo)文件加入到靜態(tài)庫(kù)中(r);若指定的靜態(tài)庫(kù)不存在,則創(chuàng)建該庫(kù)文件(c);更新靜態(tài)庫(kù)文件的索引,使之包含新加入的目標(biāo)文件的內(nèi)容(s)。

使用生成的 static_lib.o 目標(biāo)文件創(chuàng)建一個(gè)靜態(tài)庫(kù) static_lib.a

# ar rcs static_lib.a static_lib.o
查看生成的靜態(tài)庫(kù)文件
# ls
static_lib.a static_lib.c static_lib.o

靜態(tài)庫(kù)的使用

創(chuàng)建的靜態(tài)庫(kù)需要鏈接到應(yīng)用程序中才能使用,為了方便引用,我們創(chuàng)建一個(gè)頭文件,使用時(shí)把該頭文件包含到應(yīng)用程序中。

//static_lib.h
extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);

編寫應(yīng)用程序

//test.c#include <stdio.h>
#include "static_lib.h"
int main()
{
int a = 8, b = 4;
printf("the add : %d\n", add(a, b));
printf("the sub : %d\n", sub(a, b));
printf("the mul : %d\n", mul(a, b));
printf("the div : %d\n", div(a, b));
}

編譯

# gcc test.c -o test -L. static_lib.a
或者
#gcc test.c -o test ./static_lib.a運(yùn)行
# ./test
the add :12
the sub :4
the mul :32
the div :2

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

動(dòng)態(tài)庫(kù)又稱為共享庫(kù)或者動(dòng)態(tài)鏈接庫(kù)。在 Linux 環(huán)境下為 so 文件。動(dòng)態(tài)庫(kù)是在程序運(yùn)行時(shí)加載的。當(dāng)一個(gè)應(yīng)用程序裝載了一個(gè)動(dòng)態(tài)庫(kù)后,其他應(yīng)用程序仍可以裝載同一個(gè)動(dòng)態(tài)庫(kù)。這個(gè)被多個(gè)進(jìn)程同時(shí)使用的動(dòng)態(tài)庫(kù)在內(nèi)存中只有一個(gè)副本,因此動(dòng)態(tài)庫(kù)易于程序模塊的更新,更新庫(kù)并不影響應(yīng)用程序使用舊的、非向后兼容的版本。

創(chuàng)建動(dòng)態(tài)庫(kù)

我們依然使用以四則運(yùn)算來(lái)創(chuàng)建一個(gè)動(dòng)態(tài)庫(kù),該動(dòng)態(tài)庫(kù)中包含四個(gè)函數(shù):加、減、乘、除。

// share_lib.c
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int mul(int a, int b)
{
return a * b;
}
int div(int a, int b)
{
return a / b;
}

Linux 下使用 gcc 創(chuàng)建一個(gè)動(dòng)態(tài)庫(kù)。由于動(dòng)態(tài)庫(kù)可以被多個(gè)進(jìn)程共享加載,所以需要生成位置無(wú)關(guān)的目標(biāo)文件。因此需要使用 gcc 編譯器的 -fPIC 選項(xiàng),該選項(xiàng)用于生成位置無(wú)關(guān)的代碼。除了使用 -fPIC 選項(xiàng),還需要使用 -shared 選項(xiàng),該選項(xiàng)將位置無(wú)關(guān)的代碼制作為動(dòng)態(tài)庫(kù)。

創(chuàng)建動(dòng)態(tài)庫(kù)的方法如下:

# gcc -shared -fPIC -o share_lib.so share_lib.c
# ls
share_lib.so share_lib.c

動(dòng)態(tài)庫(kù)的使用

為了使應(yīng)用程序可以正確的引用該庫(kù)中的全局符號(hào),需要制作一個(gè)包含該動(dòng)態(tài)庫(kù)文件中的全局符號(hào)聲明的頭文件。

//share_lib.h
extern int add(int a, int b);
extern int sub(int a, int b);
extern int mul(int a, int b);
extern int div(int a, int b);

編寫一個(gè)應(yīng)用程序使用動(dòng)態(tài)庫(kù)

//main.c#include <stdio.h>
#include "share_lib.h"
int main()
{
int a = 8, b = 4;
printf("the add : %d\n", add(a, b));
printf("the sub : %d\n", sub(a, b));
printf("the mul : %d\n", mul(a, b));
printf("the div : %d\n", div(a, b));
}

運(yùn)行

# gcc main.c ./share_lib.so -o main
# ./main
the add :12
the sub :4
the mul :32
the div :2
責(zé)任編輯:華軒 來(lái)源: 今日頭條
相關(guān)推薦

2017-01-15 15:27:51

Linux軟連接和硬鏈接

2019-11-01 11:06:02

Linux操作系統(tǒng)Windows

2022-07-12 13:23:59

靜態(tài)鏈接庫(kù)可執(zhí)行文件C 目標(biāo)文件

2022-06-08 09:56:46

靜態(tài)鏈接Linux命令

2011-08-24 10:53:41

LinuxLua靜態(tài)

2012-05-04 08:24:14

LinuxUnix

2012-05-08 14:48:23

LinuxUnix動(dòng)態(tài)鏈接庫(kù)

2020-06-01 19:00:42

Linux軟鏈接硬鏈接

2009-07-07 20:57:20

LinuxUnix動(dòng)態(tài)鏈接庫(kù)

2022-02-28 09:44:09

Linux硬鏈接軟鏈接

2009-12-23 16:28:13

Linux GCC

2023-11-15 08:27:46

Linux系統(tǒng)

2022-03-21 07:56:25

動(dòng)態(tài)鏈接Linux操作系統(tǒng)

2024-10-30 09:50:51

WebGo語(yǔ)言

2024-06-06 08:53:13

動(dòng)態(tài)鏈接庫(kù)共享庫(kù)

2022-10-21 08:18:54

Linuxln 命令

2024-04-26 00:31:24

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

2022-07-10 21:20:11

C語(yǔ)言Linux

2018-11-09 10:10:09

Linux硬鏈接軟鏈接

2018-11-09 10:30:05

Linux硬鏈接軟鏈接
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)