lib檔案格式

2021-08-15 03:15:36 字數 3709 閱讀 7183

from:

如果你試著做乙個應用程式的聯結器(linker),就會發現,僅僅有目標檔案是不夠的。我們在連線程式時,不僅僅要用到目標檔案,庫檔案也是必不可少的。

庫檔案是怎麼樣的結構呢?

其實,庫檔案的結構也很簡單。它就是「一堆」目標檔案的集合。把目標檔案做成庫以後,我們在使用目標檔案中所實現的功能時,連線程式會自動在庫檔案裡查詢相應的目標檔案,並使用它。這大大減少了我們對目標檔案的管理工作,減輕了**重用的負擔。

lib檔案中的節

coff格式中所用到的「節」的概念再次出現在lib格式中。不過,lib檔案的節要簡單得多。先讓我們來看看它的整體結構:

如右圖所示:

lib格式只有四種型別的節(section),即first sec,second sec,longname sec和obj sec;其中second sec與longname sec是可選節,很多lib檔案中都沒有。而開頭的singature只是乙個標識,它相當於coff目標檔案中的魔法數字。它是乙個長度為8的字串,值為「!/n」。

first sec,顧名思義,就是第乙個節。它包含了庫中所有的符號名以及這些符號所在的目標檔案在庫中的位置(絕對偏移)。

second sec就是第二節。它的內容和first sec是相同的。不同的是,second sec是乙個有序表,通過它來查詢庫中的符號比通過first sec來查詢要快很多。

signature

first sec

second sec

longname sec

obj sec1

obj sec2……

longname sec是長名稱節。這一節是乙個字串表。它包含了所有長目標檔名。如果後面的obj sec中沒有給出相應的目標檔名,我們就要到這一節中來查詢。

obj sec就是目標檔案節。這些節中儲存著不同的目標檔案的原始資料。

在庫檔案中,每一節都有兩個部分。乙個部分是頭,另乙個部分才是該節的資料;資料緊跟在頭的後面。頭描述了該節資料的型別、長度等資訊。這些頭的格式都是相同的。其結構用c語言描述如下:

typedef struct sectionheader;

可以看到,頭中的資料全都是字串。用字串的好處是可以提高格式的相容性,因為在不同的機器上,資料的排列方式是不同的。有的機器是以little-endian方式工作,還有的是以big-endian方式工作,它們互不相容(這兩種方式的區別!?請看我的《coff格式》一文,其中的檔案頭一節有說明)。用字串就不會有這種問題(後面我們將會遇到)。但它也有不方便的地方,就是必須把字串轉換成數值,多了乙個步驟。

在這個結構中,最常用的name、size以及endofheader三個成員。name就是節的名稱啦!size也很好理解,就是該節資料的長度。現在要注意的就是這個endofheader成員了!這個成員標誌著頭的結束,其內容為「`/n」(注意,這裡沒有打錯,是兩個字元「`」和「/n」)。怎麼樣?有點奇怪吧?為什麼要有這個結束符?每一節的頭長度一定,每節中的資料長度也知道。按順序向下讀不行嗎?答案是:不行!因為每一節之間存在間隙!通常是乙個位元組或零個位元組。如果是零個位元組倒好,按順序向下讀是ok的。可是如果不為零的話,這樣讀就要錯位了。要知道錯位沒有,只好用乙個結束符來定位了。如果在讀頭的時候發現結束符不對,那就要乙個位元組乙個位元組地向下查詢,直到找到結束符,才能算是對齊了。切記!切記!

當然,通過first sec或second sec中給出的偏移來讀資料就不存在這個問題。不會發生錯位,放心讀吧!

現在讓我們來看看每一節中的資料是什麼樣子。

first sec

第一節,通常就是lib中的每乙個小節。它的名稱是「/」。其資料部分的結構如下:

typedef struct firstsec;

第乙個成員symbolnum是符號的數量。注意!它是以big-endian方式儲存的(x86平台上的資料是以little-endian方式儲存的。這裡應該注意轉換。後面給出的convert函式可以在little-endian格式與big-endian格式之間進行相互轉換)。

第二個成員symboloffset是乙個陣列,它的長度n就是符號的數量,也就是symbolnum。這個陣列儲存了每乙個符號所在的目標節的偏移。我們可以方便地通過它來查詢符號所在的目標檔案。注意!它也是以big-endian格式儲存的。

第三個成員strtable是乙個字串表,它的長度m就是sectionheader.size的值減去(symbolnum+1)*4。其結構很簡單,就是一堆以『/0』結尾的字串(和coff檔案中的字串表結構相同)。在有的系統中,它還可能是以「//n」這兩個字元結尾的字串的集合。

很簡單的乙個結構,不過有兩個成員的長度是不定的。怎麼才能方便地從lib中讀出這些資料,留給大家自己想吧!下面我只給出乙個進行little-endian與big-endian互轉的函式。

inline void convert(void * p          // 要轉換的資料的指標

,size_t size = 4  // 資料的長度,long為4,short為2

) secondsec;

第乙個成員objnum是庫中obj sec的數量。

第二個成員objoffset是乙個偏移表,它記錄了庫中所有obj sec的偏移。這個表的記錄數x就是objnum。

第三個成員symbolnum與first sec中的symbolnum意義相同。

第四個成員symbolidx變成了乙個索引,它記錄了相應名稱字串在objoffset這個表中的位置,我們要通過兩次索引才能找到我們所要符號的obj sec位置。它的專案數n為symbolnum。但請注意,這個索引是unsigned short型,不再是unsigned long型。

第五個成員strtable結構與first sec中的一樣。不過,它的長度m為sectionheader.size的值減去((objnum+1)*4+(symbolnum+2)*2)。

值得注意的是,這裡的所有資料都是little-endian格式的。千萬不要弄錯了!

longname sec

這個小節就是乙個字串表,它的名稱為「//」,其結構同firstsec.strtable。這裡就不多說了。

obj sec

這一節中的資料就是coff檔案的原始資料,把它讀出來存成檔案,就是乙個coff檔案。它的格式請參考《coff格式》一文。

要指出的是它的命名方式有些特殊。如果obj檔案的名稱少於16個字元,它就會被儲存在sectionheader的name成員中,以『/』字元結尾。如果無法儲存在name成員中,則name成員的第乙個字元就為『/』,之後再跟上這個名稱在longname sec中的偏移。

例如

!/n ……

longname sec:

this_is_long_name0001/0

this_is_long_name0002/0 ……

obj sec1:

name[16]:「shortname/」 ……

obj sec2:

name[16]:「/0」  // 這裡使用了第乙個長檔名this_is_long_name0001 ……

obj sec3:

name[16]:「/22」  // 這裡使用了第二個長檔名this_is_long_name0002 ……

ok!現在已經介紹完了lib檔案的結構。大家的聯結器可以加新功能了。不過這裡只給出了最基本的lib檔案結構,動態連線庫(dll)的匯出庫有點特別,我將在pe檔案格式中進行詳細介紹

lib檔案格式

如果你試著做乙個應用程式的聯結器 linker 就會發現,僅僅有目標檔案是不夠的。我們在連線程式時,不僅僅要用到目標檔案,庫檔案也是必不可少的。庫檔案是怎麼樣的結構呢?其實,庫檔案的結構也很簡單。它就是 一堆 目標檔案的集合。把目標檔案做成庫以後,我們在使用目標檔案中所實現的功能時,連線程式會自動在...

Oracle 控制檔案格式ctl檔案格式

options skip 1,errors 10 load data characterset zhs16gbk infile into table table name truncate fields terminated by optionally enclosed by trailing nu...

檔案格式 gff格式

gff檔案格式 gff格式是 sanger 研究所定義,是一種簡單的 方便的對於 dna rna以及蛋白質序列的特徵進行描述的一種資料格式,已經成為序列注釋的通用格式,比如基因組的基因 許多軟體都支援輸入或者輸出gff格式。前格式定義的最新版本是版本3。原始定義見 song websitegff是存...