歡迎您光臨本站 註冊首頁

ELF文件格式(中文)(三)

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
   ==================== Dynamic Linking (動態鏈接) =====================


一個可執行文件可能有一個 PT_INTERP 程序頭元素。在 exec(BA_OS) 的
過程中,系統從 PT_INTERP 段中取回一個路徑名並由解釋器文件的段創建初始的
進程映像。也就是說,系統為解釋器「編寫」了一個內存映像,而不是使用原始
的可執行文件的段映像。此時該解釋器就負責接收系統來的控制並且為應用程序
提供一個環境變數。


解釋器使用兩種方法中的一種來接收系統來的控制。首先,它會接收一個文件描述符
來讀取該可執行文件,定位於開頭。它可以使用這個文件描述符來讀取 並且(或者)
映射該可執行文件的段到內存中。其次,依賴於該可執行文件的格式,系統會載入
這個可執行文件到內存中而不是給該解釋器一個文件描述符。伴隨著可能的文件描述符
異常的情況,解釋器的初始進程聲明應匹配該可執行文件應當收到的內容。解釋器本身
並不需要第二個解釋器。一個解釋器可能是一個共享對象也可能是一個可執行文件。


* 一個共享對象(通常的情況)在被載入的時候是位置無關的,各個進程可能不同;
系統在 mmap(KE_OS) 使用的動態段域為它創建段和相關的服務。因而,一個
共享對象的解釋器將不會和原始的可執行文件的原始段地址相衝突。


* 一個可執行文件被載入到固定地址;系統使用程序頭表中的虛擬地址為其創建段。
因而,一個可執行文件解釋器的虛擬地址可能和第一個可執行文件相衝突;這種
衝突由解釋器來解決。



Dynamic Linker(動態鏈接器)

當使用動態鏈接方式建立一個可執行文件時,鏈接器把一個 PT_INTERP 類型
的元素加到可執行文件中,告訴系統把動態鏈接器做為該程序的解釋器。

注意:由系統提供的動態鏈接器是和特定處理器相關的。

Exec(BA_OS) 和動態鏈接器合作為程序創建進程,必須有如下的動作:

* 將可執行文件的內存段加入進程映像中;
* 將共享對象的內存段加入進程映像中;
* 為可執行文件和它的共享對象進行重定位;
* 如果有一個用於讀取可執行文件的文件描述符傳遞給了動態鏈接器,那麼關閉它。
* 向程序傳遞控制,就象該程序已經直接從 exec(BA_OS) 接收控制一樣。

鏈接器同時也為動態鏈接器構建各種可執行文件和共享對象文件的相關數據。就象
在上面「程序頭」中說的那樣,這些數據駐留在可載入段中,使得它們在執行過程
中有效。(再一次的,要記住精確的段內容是處理器相關的。可以參閱相應處理器
的補充說明來獲得詳盡的信息。)


* 一個具有 SHT_DYNAMIC 類型的 .dynamic section 包含各種數據。駐留在
section 開頭的結構包含了其他動態鏈接信息的地址。

* SHT_HASH 類型的 .hash section 包含了一個 symbol hash table.

* SHT_PROGBITS 類型的 .got 和 .plt section 包含了兩個分離的 table:
全局偏移表和過程鏈接表。 下面的 section 演示了動態鏈接器使用和改變
這些表來為 object file 創建內存映像。


由於每一個遵循 ABI 的程序從一個共享對象庫中輸入基本的系統服務,因此動態
鏈接器分享於每一個遵循 ABI 的程序的執行過程中。


就象在處理器補充說明的「程序載入」所解釋的那樣,共享對象也許會佔用與記錄在
文件的程序頭表中的地址不同的虛擬內存地址。動態鏈接器重定位內存映像,在應用程序
獲得控制之前更新絕對地址。儘管在庫被載入到由程序頭表指定的地址的情況下絕對地址
應當是正確的,通常的情況卻不是這樣。


如果進程環境 [see exec(BA_OS)] 包含了一個非零的 LD_BIND_NOW 變數,
動態鏈接器將在控制傳遞到程序之前進行所有的重定位。舉例而言,所有下面的
環境入口將指定這種行為。


* LD_BIND_NOW=1
* LD_BIND_NOW=on
* LD_BIND_NOW=off

其他情況下, LD_BIND_NOW 或者不在環境中或者為空值。動態鏈接器可以不急於
處理過程鏈接表入口,因而避免了對沒有調用的函數的符號解析和重定位。參閱
"Procedure Linkage Table"獲取更多的信息。



Dynamic Section(動態section)


假如一個object文件參與動態的連接,它的程序頭表將有一個類型為PT_DYNAMIC
的元素。該「段」包含了.dynamic section。一個_DYNAMIC特別的符號,表明了
該section包含了以下結構的一個數組。

+ Figure 2-9: Dynamic Structure

typedef struct {
Elf32_Sword d_tag;
union {
Elf32_Sword d_val;
Elf32_Addr d_ptr;
} d_un;
} Elf32_Dyn;

extern Elf32_Dyn _DYNAMIC[];

對每一個有該類型的object,d_tag控制著d_un的解釋。

* d_val

那些Elf32_Word object描繪了具有不同解釋的整形變數。

* d_ptr

那些Elf32_Word object描繪了程序的虛擬地址。就象以前提到的,在執行時,
文件的虛擬地址可能和內存虛擬地址不匹配。當解釋包含在動態結構中的地址
時是基於原始文件的值和內存的基地址。為了一致性,文件不包含在
重定位入口來糾正在動態結構中的地址。


以下的表格總結了對可執行和共享object文件需要的tag。假如tag被標為
mandatory,ABI-conforming文件的動態連接數組必須有一個那樣的入口。
同樣的,「optional」意味著一個可能出現tag的入口,但是不是必須的。

+ Figure 2-10: Dynamic Array Tags, d_tag

Name Value d_un Executable Shared Object
==== ===== ==== ========== =============
DT_NULL 0 ignored mandatory mandatory
DT_NEEDED 1 d_val optional optional
DT_PLTRELSZ 2 d_val optional optional
DT_PLTGOT 3 d_ptr optional optional
DT_HASH 4 d_ptr mandatory mandatory
DT_STRTAB 5 d_ptr mandatory mandatory
DT_SYMTAB 6 d_ptr mandatory mandatory
DT_RELA 7 d_ptr mandatory optional
DT_RELASZ 8 d_val mandatory optional
DT_RELAENT 9 d_val mandatory optional
DT_STRSZ 10 d_val mandatory mandatory
DT_SYMENT 11 d_val mandatory mandatory
DT_INIT 12 d_ptr optional optional
DT_FINI 13 d_ptr optional optional
DT_SONAME 14 d_val ignored optional
DT_RPATH 15 d_val optional ignored
DT_SYMBOLIC 16 ignored ignored optional
DT_REL 17 d_ptr mandatory optional
DT_RELSZ 18 d_val mandatory optional
DT_RELENT 19 d_val mandatory optional
DT_PLTREL 20 d_val optional optional
DT_DEBUG 21 d_ptr optional ignored
DT_TEXTREL 22 ignored optional optional
DT_JMPREL 23 d_ptr optional optional
DT_LOPROC 0x70000000 unspecified unspecified unspecified
DT_HIPROC 0x7fffffff unspecified unspecified unspecified

* DT_NULL

一個DT_NULL標記的入口表示了_DYNAMIC數組的結束。

* DT_NEEDED

這個元素保存著以NULL結尾的字元串表的偏移量,那些字元串是所需庫的名字。
該偏移量是以DT_STRTAB 為入口的表的索引。看「Shared Object Dependencies」
關於那些名字的更多信息。動態數組可能包含了多個這個類型的入口。那些
入口的相關順序是重要的,雖然它們跟其他入口的關係是不重要的。

* DT_PLTRELSZ

該元素保存著跟PLT關聯的重定位入口的總共位元組大小。假如一個入口類型
DT_JMPREL存在,那麼DT_PLTRELSZ也必須存在。

* DT_PLTGOT

該元素保存著跟PLT關聯的地址和(或者)是GOT。具體細節看處理器補充
(processor supplement)部分。

* DT_HASH

該元素保存著符號哈希表的地址,在「哈希表」有描述。該哈希表指向
被DT_SYMTAB元素引用的符號表。

* DT_STRTAB

該元素保存著字元串表地址,在第一部分有描述,包括了符號名,庫名,
和一些其他的在該表中的字元串。

* DT_SYMTAB

該元素保存著符號表的地址,在第一部分有描述,對32-bit類型的文件來
說,關聯著一個Elf32_Sym入口。

* DT_RELA

該元素保存著重定位表的地址,在第一部分有描述。在表中的入口有明確的
加數,就象32-bit類型文件的Elf32_Rela。一個object文件可能好多個重定位
section。當為一個可執行和共享文件建立重定位表的時候,連接編輯器連接
那些section到一個單一的表。儘管在object文件中那些section是保持獨立的。
動態連接器只看成是一個簡單的表。當動態連接器為一個可執行文件創建一個
進程映象或者是加一個共享object到進程映象中,它讀重定位表和執行相關的
動作。假如該元素存在,動態結構必須也要有DT_RELASZ和DT_RELAENT元素。
當文件的重定位是mandatory,DT_RELA 或者 DT_REL可能出現(同時出現是
允許的,但是不必要的)。


* DT_RELASZ

該元素保存著DT_RELA重定位表總的位元組大小。

* DT_RELAENT

該元素保存著DT_RELA重定位入口的位元組大小。


* DT_STRSZ

該元素保存著字元串表的位元組大小。

* DT_SYMENT

該元素保存著符號表入口的位元組大小。

* DT_INIT

該元素保存著初始化函數的地址,在下面「初始化和終止函數」中討論。

* DT_FINI

該元素保存著終止函數的地址,在下面「初始化和終止函數」中討論。

* DT_SONAME

該元素保存著以NULL結尾的字元串的字元串表偏移量,那些名字是共享
object的名字。偏移量是在DT_STRTAB入口記錄的表的索引。關於那些名字看
Shared Object Dependencies 部分獲得更多的信息。

* DT_RPATH

該元素保存著以NULL結尾的搜索庫的搜索目錄字元串的字元串表偏移量。
在共享object依賴關係(Shared Object Dependencies)中有討論

* DT_SYMBOLIC

在共享object庫中出現的該元素為在庫中的引用改變動態連接器符號解析的演算法。
替代在可執行文件中的符號搜索,動態連接器從它自己的共享object開始。假如
一個共享的object提供引用參考失敗,那麼動態連接器再照常的搜索可執行文件
和其他的共享object。


* DT_REL

該元素相似於DT_RELA,除了它的表有潛在的加數,正如32-bit文件類型的
Elf32_Rel一樣。假如這個元素存在,它的動態結構必須也同時要有DT_RELSZ
和DT_RELENT的元素。

* DT_RELSZ

該元素保存著DT_REL重定位表的總位元組大小。

* DT_RELENT

該元素保存著DT_RELENT重定為入口的位元組大小。

* DT_PLTREL

該成員指明了PLT指向的重定位入口的類型。適當地, d_val成員保存著
DT_REL或DT_RELA。在一個PLT中的所有重定位必須使用相同的轉換。

* DT_DEBUG

該成員被調試使用。它的內容沒有被ABI指定;訪問該入口的程序不是
ABI-conforming的。

* DT_TEXTREL

如在程序頭表中段許可所指出的那樣,這個成員的缺乏代表沒有重置入
口會引起非寫段的修改。假如該成員存在,一個或多個重定位入口可能
請求修改一個非寫段,並且動態連接器能因此有準備。


* DT_JMPREL

假如存在,它的入口d_ptr成員保存著重定位入口(該入口單獨關聯著
PLT)的地址。假如lazy方式打開,那麼分離它們的重定位入口讓動態連接
器在進程初始化時忽略它們。假如該入口存在,相關聯的類型入口DT_PLTRELSZ
和DT_PLTREL一定要存在。

* DT_LOPROC through DT_HIPROC

在該範圍內的變數為特殊的處理器語義保留。除了在數組末尾的DT_NULL元素,
和DT_NEEDED元素相關的次序,入口可能出現在任何次序中。在表中不出
現的Tag值是保留的。


Shared Object Dependencies(共享Object的依賴關係)

當連接器處理一個文檔庫時,它取出庫中成員並且把它們拷貝到一個輸出的
object文件中。當運行時沒有包括一個動態連接器的時候,那些靜態的連接服
務是可用的。共享object也提供服務,動態連接器必須把正確的共享object
文件連接到要實行的進程映象中。因此,可執行文件和共享的object文件之間
存在著明確的依賴性。

當動態連接器為一個object文件創建內存段時,依賴關係(在動態結構的
DT_NEEDED入口中記錄)表明需要哪些object來為程序提供服務。通過
重複的連接參考的共享object和他們的依賴關係,動態連接器可以建造一個
完全的進程映象。當解決一個符號引用的時候,動態連接器以寬度優先搜索
(breadth-first)來檢查符號表,換句話說,它先查看自己的可實行程序
中的符號表,然後是頂端DT_NEEDED入口(按順序)的符號表,再接下來是
第二級的DT_NEEDED入口,依次類推。共享object文件必須對進程是可讀的;
其他許可權是不需要的。

注意:即使當一個共享object被引用多次(在依賴列關係表中),動態連接器
只把它連接到進程中一次。

在依賴關係列表中的名字既被DT_SONAME字元串拷貝,又被建立object文件
時的路徑名拷貝。例如,動態連接器建立一個可執行文件(使用帶DT_SONAME
入口的lib1共享文件)和一個路徑名為/usr/lib/lib2的共享object庫,
那麼可執行文件將在它自己的依賴關係列表中包含lib1和/usr/bin/lib2。

假如一個共享object名字有一個或更多的反斜杠字元(/)在這名字的如何地方,
例如上面的/usr/lib/lib2文件或目錄,動態連接器把那個字元串自己做為路徑名。
假如名字沒有反斜杠字元(/),例如上面的lib1,三種方法指定共享文件的
搜索路徑,如下:

* 第一,動態數組標記DT_RPATH保存著目錄列表的字元串(用冒號(:)分隔)。
例如,字元串/home/dir/lib:/home/dir2/lib:告訴動態連接器先搜索
/home/dir/lib,再搜索/home/dir2/lib,再是當前目錄。

* 第二,在進程環境中(see exec(BA_OS)),有一個變數稱為LD_LIBRARY_PATH
可以保存象上面一樣的目錄列表(隨意跟一個分號(;)和其他目錄列表)。
以下變數等於前面的例子:
LD_LIBRARY_PATH=/home/dir/lib:/home/dir2/lib:
LD_LIBRARY_PATH=/home/dir/lib;/home/dir2/lib:
LD_LIBRARY_PATH=/home/dir/lib:/home/dir2/lib:;
所以的LD_LIBRARY_PATH目錄在DT_RPATH指向的目錄之後被搜索。儘管一些
程序(例如連接編輯器)不同的處理分號前和分號后的目錄,但是動態連接
不會。不過,動態連接器接受分號符號,具體語意在如上面描述。

* 最後,如果上面的兩個目錄查找想要得到的庫失敗,那麼動態連接器搜索
/usr/lib.

注意:出於安全考慮,動態連接器忽略set-user和set-group的程序的
LD_LIBRARY_PATH所指定的搜索目錄。但它會搜索DT_RPATH指明的目錄和
/usr/lib。


Global Offset Table(GOT全局偏移量表)

一般情況下,位置無關的代碼不包含絕對的虛擬地址。全局偏移量表在私有數據
中保存著絕對地址,所以應該使地址可用的,而不是和位置無關性和程序代碼段
共享能力妥協。一個程序引用它的GOT(全局偏移量表)來使用位置無關的地址並且
提取絕對的變數,所以重定位位置無關的參考到絕對的位置。

初始時,GOT(全局偏移量表)保存著它重定位入口所需要的信息 [看第一部分的
「Relocation」]。在系統為一個可裝載的object文件創建內存段以後,動態
連接器處理重定位入口,那些類型為R_386_GLOB_DAT的指明了GOT(全局偏移量表)。
動態連接器決定了相關的標號變數,計算他們的絕對地址,並且設置適當的內存
表入口到正確的變數。雖然當連接編輯器建造object文件的時候,絕對地址
是不知道,連接器知道所以內存段的地址並且能夠因此計算出包含在那裡的
標號地址。

假如程序需要直接訪問符號的絕對地址,那麼這個符號將有一個GOT(全局偏移量表)
入口。因為可執行文件和共享文件有獨立的GOT(全局偏移量表),一個符號地址
可能出現在不同的幾個表中。在交給進程映象的代碼控制權以前,動態連接器處
理所有的重定位的GOT(全局偏移量表),所以在執行時,確認絕對地址是可用的。

該表的入口0是為保存動態結構地址保留的(參考_DYNAMIC標號)。這允許
象動態連接程序那樣來找出他們自己的動態結構(還沒有處理他們的重
定向入口)。這些對於動態連接器是重要的,因為它必要初始化自己而不
能依賴於其他程序來重定位他們的內存映象。在32位Interl系統結構中,在
GOT中的人口1和2也是保留的,具體看以下的過程連接表(Procedure Linkage
Table)。

系統可以為在不同的程序中相同的共享object選擇不同的內存段;它甚至可以
為相同的程序不同的進程選擇不同的庫地址。雖然如此,一旦進程映象被建立
以後,內存段不改變地址。只要一個進程存在,它的內存段駐留在固定的虛擬
地址。

GOT表的格式和解釋是處理器相關的。在32位Intel體系結構下,標號
_GLOBAL_OFFSET_TABLE_可能被用來訪問該表。

+ Figure 2-11: Global Offset Table

extern Elf32_Addr _GLOBAL_OFFSET_TABLE_[];

標號_GLOBAL_OFFSET_TABLE_可能駐留在.got section的中間,允許負的和非負
的下標索引這個數組。


Procedure Linkage Table(PLT過程連接表)

就象GOT重定位把位置無關的地址計算成絕對地址一樣,PLT過程連接表重定位
位置無關的函數調用到絕對的地址。從一個可執行或者共享的object文件到另外的,
連接編輯器不解析執行的傳輸(例如函數的調用)。因此,連接編輯器安排程序
的傳遞控制到PLT中的入口。在SYSTEM V體系下,PLT存在共享文本中,但是它們
使用的地址是在私有的GOT中。符號連接器決定了目標的絕對地址並且修改GOT的
內存映象。因此,在沒有危及到位置無關、程序文本的共享能力的情況下。動態
連接器能重定位人口。


+ Figure 2-12: Absolute Procedure Linkage Table {*}
絕對的過程連接表

.PLT0:pushl got_plus_4
jmp *got_plus_8
nop; nop
nop; nop
.PLT1:jmp *name1_in_GOT
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2_in_GOT
pushl $offset
jmp .PLT0@PC
...

+ Figure 2-13: Position-Independent Procedure Linkage Table
位置無關(或者說位置獨立)的過程連接表
.PLT0:pushl 4(%ebx)
jmp *8(%ebx)
nop; nop
nop; nop
.PLT1:jmp *name1@GOT(%ebx)
pushl $offset
jmp .PLT0@PC
.PLT2:jmp *name2@GOT(%ebx)
pushl $offset
jmp .PLT0@PC
...

注意:如圖所示,PLT的指令使用了不同的操作數地址方式,對絕對代碼和
對位置無關的代碼。但是,他們的界面對於動態連接器是相同的。

以下的步驟,動態連接器和程序協作(cooperate)通過PLT和GOT來解析符號
引用。

1. 當第一次創建程序的內存映象時,動態連接器為在GOT中特別的變數設置
第二次和第三次的入口。下面關於那些變數有更多的解釋。

2. 假如PLT是位置無關的,那麼GOT的地址一定是保留在%ebx中的。每個在進程
映象中共享的object文件有它自己的PLT,並且僅僅在同一個object文件中,
控制傳輸到PLT入口。從而,要調用的函數有責任在調用PLT入口前,設置PLT
地址到寄存器中。

3. 舉例說明,假如程序調用函數name1,它的傳輸控制到標號.PLT1.

4. 第一個指令跳到在GOT入口的name1地址。初始話時,GOT保存著緊跟著的push1
指令的地址,而不是真實的name1的地址。

5. 因此,程序在堆棧中壓入(push)一個重定位的偏移量。重定位的偏移量是
一個32位,非負的位元組偏移量(從定位表算起)。指派的重定位入口將是
一個R_386_JMP_SLOT類型,它的偏移量指明了GOT入口(在前面的jmp指令中
被使用)。該重定位入口也包含一個符號表的索引,因此告訴動態連接器
哪個符號要被引用,在這裡是name1。

6. 在壓入(push)一個重定位的偏移量后,程序跳到.PLT0,在PLT中的第一個入口。
push1指令在堆棧中放置第二個GOT入口(got_plus_4 or 4(%ebx))的值,
因此,給動態連接器一個word的鑒別信息。然後程序跳到第三個GOT入口
(got_plus_8 or 8(%ebx)),它傳輸控制到動態連接器。

7. 當動態連接器接到控制權,它展開堆棧,查看指派的重定位入口,尋找符號的
值,在GOT入口中存儲真實的name1地址,然後傳輸控制想要目的地。

8. PLT入口的併發執行將直接傳輸控制到name1,而不用第二次調用動態連接器
了。所以,在.PLT1中的jmp指令將轉到name1,代替「falling through」
轉到pushl指令。

LD_BIND_NOW環境變數能改變動態連接器的行為。假如這個變數為非空,動態
連接器在傳輸控制到程序前計算PLT入口。換句話說,動態連接器處理重定位
類型為R_386_JMP_SLOT的入口在進程初始化時。否則,動態連接器計算PLT入口
懶惰的,推遲到符號解析和重定位直到一個表入口的第一次執行。


注意:一般來說,以懶惰(Lazy)方式綁定是對全應用程序執行的改進。
因為不使用的符號就不會招致動態連接器做無用功。然而,對一些應用程序,
兩種情況使用懶惰(Lazy)方式是不受歡迎的。

第一 初始的引用一個共享object函數比後來的調用要花的時間長,因為動
態連接器截取調用來解析符號。一些應用程序是不能容忍這樣的。
第二 假如這個錯誤發生並且動態連接器不能解析該符號,動態連接器將終止
程序。在懶惰(Lazy)方式下,這可能發生在任意的時候。一再的,一
些應用程序是不能容忍這樣的。通過關掉懶惰(Lazy)方式,在應用程
序接到控制前,當在處理初始話時發生錯誤,動態連接器強迫程序,使
之失敗。

Hash Table(哈希表)

Elf32_Word object的哈希表支持符號表的訪問。
標號出現在下面幫助解釋哈希表的組織,但是它們不是規範的一部分。

+ Figure 2-14: Symbol Hash Table

nbucket
nchain
bucket[0]
...
bucket[nbucket - 1]
chain[0]
...
chain[nchain - 1]


bucket數組包含了nbucket入口,並且chain數組包含了nchain個入口;索引從0開始。
bucket和chain保存著符號表的索引。Chain表入口類似於符號表。符號表入口的
數目應該等於nchain;所以符號表的索引也選擇chain表的入口。
一個哈希函數(如下的)接受一個符號名並且返回一個可以被計算機使用的bucket索引
的值。因此,假如一個哈希函數返回一些名字的值為X,那麼bucket[x%nbucket]
將給出一個索引y(既是符號表和chain表的索引)。假如符號表入口不是期望的,
chain[y]給出下一個符號表的入口(使用相同的哈希變數)。可以沿著chain
鏈直到選擇到了期望名字的符號表入口或者是碰到了STN_UNDEF的入口。

+ Figure 2-15: Hashing Function

unsigned long
elf_hash(const unsigned char *name)
{
unsigned long h = 0, g;

while (*name) {
h = (h << 4) + *name++;
if (g = h & 0xf0000000)
h ^= g >> 24;
h &= ~g;
}
return h;
}


Initialization and Termination Functions
初始化和終止函數


在動態連接妻建立進程映象和執行重定位以後,每一個共享object得到適當
的機會來執行一些初始話代碼。初始化函數不按特別的順序被調用,但是
所有的共享object初始化發生在執行程序獲得控制之前。

類似地,共享的object可能包含終止函數,它們在進程本身開始它的終止之後
被執行(以atexit(BA_OS)的機制)。

共享object通過設置在動態結構中的DT_INIT和DT_FINI入口來指派它們的初始化
和終止函數,如上動態section(Dynamic Section)部分描述。典型的,那些函數
代碼存在.init和.fini section中,第一部分的「section」已經提到過。

注意:儘管atexit(BA_OS)的終止處理一般可可正常完成,但是不保證在死進程上
被執行。特別的,假如_exit被調用(看exit(BA_OS))或者假如進程死掉,那麼
進程是不執行終止處理的。因為它收到一個信號,該信號可捕獲或忽略。

________________________________________________________________


3. C LIBRARY

________________________________________________________________


========================== C Library ===========================

C庫,libc,包含了所有的符號(包含在libsys),另外,包含在在下面兩個
表中列出的運行函數。第一個表中的運行函數是ANSI C標準的。

+ Figure 3-1: libc Contents, Names without Synonyms

abort fputc isprint putc strncmp
abs fputs ispunct putchar strncpy
asctime fread isspace puts strpbrk
atof freopen isupper qsort strrchr
atoi frexp isxdigit raise strspn
atol fscanf labs rand strstr
bsearch fseek ldexp rewind strtod
clearerr fsetpos ldiv scanf strtok
clock ftell localtime setbuf strtol
ctime fwrite longjmp setjmp strtoul
difftime getc mblen setvbuf tmpfile
div getchar mbstowcs sprintf tmpnam
fclose getenv mbtowc srand tolower
feof gets memchr sscanf toupper
ferror gmtime memcmp strcat ungetc
fflush isalnum memcpy strchr vfprintf
fgetc isalpha memmove strcmp vprintf
fgetpos iscntrl memset strcpy vsprintf
fgets isdigit mktime strcspn wcstombs
fopen isgraph perror strlen wctomb
fprintf islower printf strncat

再加上, libc 保存著以下的服務。

+ Figure 3-2: libc Contents, Names with Synonyms

__assert getdate lockf ** sleep tell **
cfgetispeed getopt lsearch strdup tempnam
cfgetospeed getpass memccpy swab tfind
cfsetispeed getsubopt mkfifo tcdrain toascii
cfsetospeed getw mktemp tcflow _tolower
ctermid hcreate monitor tcflush tsearch
cuserid hdestroy nftw tcgetattr _toupper
dup2 hsearch nl_langinfo tcgetpgrp twalk
fdopen isascii pclose tcgetsid tzset
__filbuf isatty popen tcsendbreak _xftw
fileno isnan putenv tcsetattr
__flsbuf isnand ** putw tcsetpgrp
fmtmsg ** lfind setlabel tdelete

** = Function is at Level 2 in the SVID Issue 3 and therefore at
Level 2 in the ABI.

包括上面同義(Synonyms)表列出的標號,對於<name> 入口已經存在的_<name>
形式(帶一個下劃線,上面沒有列出來)優先權高於它們的名字。所以,例如,
libc同時包含了getopt和_getopt。

在常規的上列中,其他地方以下沒有被定義。

int __filbuf(FILE *f);
This function returns the next input character for f, filling
its buffer as appropriate. It returns EOF if an error occurs.

int __flsbuf(int x, FILE *f);
This function flushes the output characters for f as if
putc(x, f) had been called and then appends the value of x to
the resulting output stream. It returns EOF if an error occurs
and x otherwise.

int _xftw(int, char *, int (*)(char *, struct stat *, int), int);
Calls to the ftw(BA_LIB) function are mapped to this function
when applications are compiled. This function is identical to
ftw(BA_LIB), except that _xftw() takes an interposed first
argument, which must have the value 2.


要了解更多的關於SVID,ANSI C,POSIX的知識,可看該章節其他的庫section部分。
該節「System Data Interfaces」後有更多的描述。

Global Data Symbols
全局數據符號


libc庫需要一些外部的全局數據符號(為了它自己的常規工作而定義的)。
所有向libsys庫請求的數據符號一定要讓libc提供,就象下面表中的數據符號。

正式定義的數據object被他們的符號描述,看System V介面定義,第三版本
或者第6章節的數據定義(Data Definitions)section(在適當的處理器
補充到System V ABI)。

在下面表中的入口有<name>-_<name>的形式。一對符號都代表了一些數據。
下劃線的synonyms假設滿足ANSI C標準。


+ Figure 3-3: libc Contents, Global External Data Symbols

getdate_err optarg
_getdate_err opterr
__iob optind
optopt



[火星人 ] ELF文件格式(中文)(三)已經有435次圍觀

http://coctec.com/docs/program/show-post-72246.html