真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Linux動(dòng)態(tài)庫與靜態(tài)庫-創(chuàng)新互聯(lián)

Linux動(dòng)態(tài)庫與靜態(tài)庫

十載的平橋網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整平橋建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)公司從事“平橋網(wǎng)站設(shè)計(jì)”,“平橋網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。文章目錄
  • Linux動(dòng)態(tài)庫與靜態(tài)庫
    • 1.庫的概念、種類與使用
    • 2.鏈接簡(jiǎn)述
      • 2.1 鏈接過程理解
      • 2.2 靜態(tài)鏈接與動(dòng)態(tài)鏈接概念
      • 2.3 靜態(tài)鏈接與動(dòng)態(tài)鏈接的例子
    • 3.動(dòng)態(tài)庫與靜態(tài)庫的生成方法
      • 3.1 靜態(tài)庫的生成
      • 3.2 靜態(tài)庫的打包
      • 3.2 靜態(tài)庫的使用
      • 3.3 動(dòng)態(tài)庫的生成
      • 3.4 動(dòng)態(tài)庫的打包
      • 3.5 動(dòng)態(tài)庫的使用

1.庫的概念、種類與使用

庫的概念:一組.o文件的集合,或者說.obj文件(windows下)的集合,也就是鏈接生成可執(zhí)行文件時(shí)用到的文件

請(qǐng)?zhí)砑訄D片描述

在我的理解里,庫就是別人寫的代碼,比如庫函數(shù),第三方庫,包括之后會(huì)用到的網(wǎng)絡(luò)庫,這些都是別人寫的,我們只是拿過來使用而已

那為什么我們要使用別人的代碼呢?

因?yàn)椋簽榱碎_發(fā)效率和代碼的健壯性

那我們要如何使用別人的庫?

  • 借助庫、開源代碼、和網(wǎng)絡(luò)。下面我們主要了解庫的使用
  • 如果別人要用我們的功能,我們又不想給源碼,就可以把源碼打包成一個(gè)庫給對(duì)方用

庫的種類:

鏈接分為動(dòng)態(tài)鏈接和靜態(tài)鏈接,庫分為動(dòng)態(tài)庫和靜態(tài)庫。靜態(tài)鏈接是一個(gè)過程,這個(gè)過程中用到的庫就是靜態(tài)庫,動(dòng)態(tài)鏈接同理

使用三方庫時(shí)的鏈接過程:
請(qǐng)?zhí)砑訄D片描述


2.鏈接簡(jiǎn)述 2.1 鏈接過程理解

鏈接過程簡(jiǎn)單概括為地址和空間分配,符號(hào)解析和代碼重定位

符號(hào)指的是變量,函數(shù)名等,符號(hào)解析則是將符號(hào)的定義和符號(hào)的引用建立聯(lián)系

重定位我簡(jiǎn)單理解為可以準(zhǔn)確的運(yùn)行我們的程序,比如一個(gè)函數(shù),我們可以精準(zhǔn)的找到函數(shù)入口的地址并進(jìn)行運(yùn)行

符號(hào)解析后生成符號(hào)表,linux下查看符號(hào)表命令:readelf -s 文件名.o

請(qǐng)?zhí)砑訄D片描述

代碼的重定位:我們運(yùn)行的指令都有其對(duì)應(yīng)的地址,比如我們進(jìn)入一個(gè)函數(shù)就是跳到一個(gè)表示函數(shù)入口的地址,代碼變化指令也會(huì)跟著變化,地址自然就變化了,比如前面一開始有4條代碼,修改后有5條,那對(duì)應(yīng)的指令和地址可能都要發(fā)生變化,函數(shù)入口就變化了,此時(shí)的代碼里重新計(jì)算地址的過程就叫做重定位。如果有多個(gè)模塊,成千上萬行代碼,修改這個(gè)地址的工作就是龐大的,早期還是人工改,現(xiàn)在都交給鏈接器了


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

靜態(tài)鏈接概念:

  • 靜態(tài)鏈接:是指編譯階段把靜態(tài)庫的代碼加入到可執(zhí)行文件中,或者說把用到的函數(shù)的全部鏈接到可執(zhí)行文件中(但是鏈接器是以文件為單位進(jìn)行操作的,比如要用printf就得鏈接所有包含printf的文件)。這樣生成的可執(zhí)行文件不需要借助外部的庫,生成后可以直接使用,這就是靜態(tài)鏈接。缺點(diǎn)是文件比較大,每次更新都得重新編譯,優(yōu)點(diǎn)是運(yùn)行較快
  • 簡(jiǎn)言之:把需要的代碼和數(shù)據(jù)從庫全拷貝到當(dāng)前代碼

動(dòng)態(tài)鏈接概念:

  • 動(dòng)態(tài)鏈接:是什么時(shí)候要用到庫里的東西就什么時(shí)候去找,存的也只是索引和相關(guān)的部分信息,所以占用空間不大。好處是占用空間小,所有的程序可以共用同一個(gè)庫,更新也比較方便,缺點(diǎn)就是比較慢。如果我們有及時(shí)上百個(gè)進(jìn)程都用了同一個(gè)庫,那相比靜態(tài)鏈接就大大節(jié)省了空間
  • 簡(jiǎn)言之:動(dòng)態(tài)庫可以被多個(gè)進(jìn)程共享,與進(jìn)程地址空間里的共享區(qū)有關(guān)

2.3 靜態(tài)鏈接與動(dòng)態(tài)鏈接的例子

gcc -o 命令默認(rèn)動(dòng)態(tài)鏈接,加上-static選項(xiàng)就表示靜態(tài)鏈接,可通過file命令查看鏈接屬性

#includeint main()
{int a=1;
  printf("%d\n",a);
  return 0;
}

請(qǐng)?zhí)砑訄D片描述

ldd命令,查看程序或者庫文件所依賴的共享庫,即打印動(dòng)態(tài)鏈接依賴的庫列表

下圖中:libc.so.6,把lib和so去掉,中間剩下的c就是庫名,.so就表示動(dòng)態(tài)庫,.a表示靜態(tài)庫,.6是主版本號(hào)

請(qǐng)?zhí)砑訄D片描述

對(duì)于靜態(tài)鏈接與動(dòng)態(tài)鏈接的總結(jié):

  1. 靜態(tài)鏈接會(huì)拷貝代碼和數(shù)據(jù),再將其鏈接進(jìn)可執(zhí)行文件,因?yàn)殒溄悠鞯牟僮鲉卧质俏募造o態(tài)的鏈接的文件一般都較大,優(yōu)點(diǎn)是快(不用去庫里找東西自然快),不需要依賴外部(庫丟失了也能跑)。但是不好更新,每次更新都得重新編譯,比如包含了這個(gè)庫里的某個(gè)函數(shù)的文件就全得更新
  2. 動(dòng)態(tài)鏈接就是啥時(shí)候要就啥時(shí)候找,鏈接器看到動(dòng)態(tài)鏈接的符號(hào)也會(huì)去找,只不過不分配地址,重定位的操作等到了程序裝載時(shí)才做。但因?yàn)槭峭ㄟ^索引去找,所以多個(gè)進(jìn)程可以共享一個(gè)庫(庫丟失就跑不了了),一些場(chǎng)景下可以大大節(jié)省空間資源,更新時(shí)也方便,只用編譯相對(duì)應(yīng)的模塊

3.動(dòng)態(tài)庫與靜態(tài)庫的生成方法

下面的動(dòng)靜態(tài)庫生成剖析通過下面四個(gè)函數(shù)來驗(yàn)證:

add.h

#pragma once 
int add(int x,int y);

add.c

#include"add.h"
int add(int x,int y)
{return x+y;
}

sub.h

#pragma once 
int sub(int x,int y);

sub.c

#include"sub.h"
int sub(int x,int y)
{return x-y;
}

3.1 靜態(tài)庫的生成

下面以一個(gè)例子說明生成靜態(tài)庫的操作,我們利用ar工具把兩個(gè)C文件打包成一個(gè)靜態(tài)庫。靜態(tài)庫里放.o文件,可以做到不暴露源碼,再建一個(gè)目錄放頭文件,告訴使用者里面有哪些方法可以用
請(qǐng)?zhí)砑訄D片描述


3.2 靜態(tài)庫的打包

靜態(tài)庫的打包過程:

關(guān)于ar命令的補(bǔ)充:

ar命令是gnu的歸檔工具,常用于將目標(biāo)文件打包為靜態(tài)庫,下面我們使用ar命令的-r選項(xiàng)和-c選項(xiàng)進(jìn)行打包

  • -r(replace):若靜態(tài)庫文件當(dāng)中的目標(biāo)文件有更新,則用新的目標(biāo)文件替換舊的目標(biāo)文件
  • -c(create):建立靜態(tài)庫文件
  • -t:列出靜態(tài)庫中的文件
  • -v(verbose):顯示詳細(xì)的信息

打包流程:

  1. 第一步:讓所有源文件生成對(duì)應(yīng)的目標(biāo)文件,即gcc -c add.c -o add.o等操作
  2. 第二步:使用ar命令將所有目標(biāo)文件打包為靜態(tài)庫,即ar -rc …等操作
  3. 第三步:將頭文件和生成的靜態(tài)庫組織起來,即cp add.h sub.h …等操作
  4. 第四步(可有可無):編寫Makefile后,只需一個(gè)make就能生成所有源文件對(duì)應(yīng)的目標(biāo)文件進(jìn)而生成靜態(tài)庫

請(qǐng)?zhí)砑訄D片描述

生成的靜態(tài)庫名為libmymath.a.1,后面的1表示版本號(hào),建議我們自己打包庫的時(shí)候去掉版本號(hào),不然后面使用的時(shí)候會(huì)顯示找不到庫…(也不知道為啥會(huì)找不到,網(wǎng)上查閱資料后發(fā)現(xiàn)靜態(tài)庫一般都把版本號(hào)寫在文件里,再通過strings+文件里添加字符串version來標(biāo)識(shí)文件是哪個(gè)版本,也有利用命令行參數(shù)來打印版本號(hào)的)


3.2 靜態(tài)庫的使用
gcc -o main main.c  -I ./include -L ./lib -lmymath -static
//-I指定去哪找頭文件,-L指定去哪找?guī)煳募?l+庫名表示去找哪個(gè)庫
//因?yàn)槟J(rèn)路徑的緣故,gcc編譯C代碼都不用加-I -L -l等選項(xiàng)

請(qǐng)?zhí)砑訄D片描述


3.3 動(dòng)態(tài)庫的生成

多個(gè)進(jìn)程可以共享一個(gè)多態(tài)庫,如下圖:

請(qǐng)?zhí)砑訄D片描述

動(dòng)態(tài)庫上面提到是要的時(shí)候再去找,所以多個(gè)進(jìn)程用動(dòng)態(tài)庫時(shí)用的都是同一份代碼,合理的節(jié)省了資源

請(qǐng)?zhí)砑訄D片描述

-fPIC作用于編譯時(shí)期,產(chǎn)生與位置無關(guān)的代碼,編譯后的代碼用的是相對(duì)地址

用相對(duì)地址的原因共享庫加載進(jìn)內(nèi)存的位置是不確定的,如果不加-fPIC選項(xiàng),可能生成帶有絕對(duì)位置的代碼,那鏈接器鏈接時(shí)可能就需要去重新定位各個(gè)符號(hào)的位置,那共享庫的代碼可能就發(fā)生了變化,我們的程序此時(shí)就要去維護(hù)這段發(fā)生了變化的代碼,維護(hù)進(jìn)行的操作就是拷貝一份,那動(dòng)態(tài)鏈接的作用就不大了(動(dòng)態(tài)鏈接本來是要用的時(shí)候直接用庫里的,現(xiàn)在我程序自身要維護(hù)一份更改后的代碼,顯然是不合理的),所以與位置無關(guān)的代碼其實(shí)就是使用了相對(duì)地址的代碼,這么做與elf文件的格式有關(guān)(借助了elf文件里面的“段”)??梢院?jiǎn)單理解為規(guī)定了一根線,關(guān)于地址的坐標(biāo)都是相對(duì)于這根線的,不管我程序加載到內(nèi)存的哪個(gè)位置,只要通過計(jì)算這根線到當(dāng)前位置的距離就可以獲取到(算出)正確的位置。真正清晰的理解需要了解elf文件的格式,編譯原理、鏈接器的相關(guān)知識(shí)

請(qǐng)?zhí)砑訄D片描述


3.4 動(dòng)態(tài)庫的打包

動(dòng)態(tài)庫的打包相對(duì)于靜態(tài)庫來說有一點(diǎn)點(diǎn)差別,但大致相同,我們還是利用上面的四個(gè)文件進(jìn)行打包演示:

動(dòng)態(tài)庫的打包流程:

第一步:讓所有源文件生成對(duì)應(yīng)的目標(biāo)文件

  • 此時(shí)用源文件生成目標(biāo)文件時(shí)需要攜帶-fPIC選項(xiàng)

  • -fPIC(position independent code):產(chǎn)生位置無關(guān)碼

請(qǐng)?zhí)砑訄D片描述

說明一下:

  • -fPIC作用于編譯階段,告訴編譯器產(chǎn)生與位置無關(guān)的代碼,此時(shí)產(chǎn)生的代碼中沒有絕對(duì)地址,全部都使用相對(duì)地址,從而代碼可以被加載器加載到內(nèi)存的任意位置都可以正確的執(zhí)行。這正是共享庫所要求的,共享庫被加載時(shí),在內(nèi)存的位置不是固定的
  • 如果不加-fPIC選項(xiàng),則加載.so文件的代碼段時(shí),代碼段引用的數(shù)據(jù)對(duì)象需要重定位,重定位會(huì)修改代碼段的內(nèi)容,這就造成每個(gè)使用這個(gè).so文件代碼段的進(jìn)程在內(nèi)核里都會(huì)生成這個(gè).so文件代碼段的拷貝,并且每個(gè)拷貝都不一樣,取決于這個(gè).so文件代碼段和數(shù)據(jù)段內(nèi)存映射的位置
  • 不加-fPIC編譯出來的.so是要在加載時(shí)根據(jù)加載到的位置再次重定位的,因?yàn)樗锩娴拇aBBS位置無關(guān)代碼。如果該.so文件被多個(gè)應(yīng)用程序共同使用,那么它們必須每個(gè)程序維護(hù)一份.so的代碼副本(因?yàn)?so被每個(gè)程序加載的位置都不同,顯然這些重定位后的代碼也不同,當(dāng)然不能共享)
  • 我們總是用-fPIC來生成.so,但從來不用-fPIC來生成.a。但是.so一樣可以不用-fPIC選項(xiàng)進(jìn)行編譯,只是這樣的.so必須要在加載到用戶程序的地址空間時(shí)重定向所有表目

第二步:使用-shared選項(xiàng)將所有目標(biāo)文件打包為動(dòng)態(tài)庫

  • 與生成靜態(tài)庫不同的是,生成動(dòng)態(tài)庫時(shí)我們不必使用ar命令,我們只需使用gcc的-shared選項(xiàng)即可
gcc -shared -o libcal.so add.o sub.o

請(qǐng)?zhí)砑訄D片描述


第三步:將頭文件和生成的動(dòng)態(tài)庫組織起來

  • 與生成靜態(tài)庫時(shí)一樣,為了方便別人使用,在這里我們可以將add.hsub.h這兩個(gè)頭文件放到一個(gè)名為include的目錄下,將生成的動(dòng)態(tài)庫文件libcal.so放到一個(gè)名為lib的目錄下,然后將這兩個(gè)目錄都放到mlib下,此時(shí)就可以將mlib給別人使用了

請(qǐng)?zhí)砑訄D片描述


第四步:使用Makefile

  • 當(dāng)然,生成動(dòng)態(tài)庫也可以將上述所要執(zhí)行的命令全部寫到Makefile當(dāng)中,后續(xù)當(dāng)我們要生成動(dòng)態(tài)庫以及組織頭文件和庫文件時(shí)就可以一步到位了

請(qǐng)?zhí)砑訄D片描述

  • 編寫Makefile后,只需一個(gè)make就能生成所有源文件對(duì)應(yīng)的目標(biāo)文件進(jìn)而生成動(dòng)態(tài)庫

請(qǐng)?zhí)砑訄D片描述

  • 一個(gè)make output就能將頭文件和動(dòng)態(tài)庫組織起來

請(qǐng)?zhí)砑訄D片描述


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

我們使用下面main.c的代碼作為例子:

//main.c
#include#include"add.h"
#include"sub.h"
int main()
{int a=add(0,1);
  printf("%d\n",a);

  return 0;
}

請(qǐng)?zhí)砑訄D片描述
請(qǐng)?zhí)砑訄D片描述
請(qǐng)?zhí)砑訄D片描述

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購,新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


分享文章:Linux動(dòng)態(tài)庫與靜態(tài)庫-創(chuàng)新互聯(lián)
文章分享:http://weahome.cn/article/dsgpdc.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部