《深入理解電腦系統》筆記(三)連結知識【附圖】

來源:互聯網
上載者:User
概述

        ●該章節主要講解的是ELF檔案的結構。    

        ●靜態庫的概念

        ●動態庫(又叫共用庫)的概念,一般用於作業系統,普通應用程式作用不大。

        ●程式的載入過程。

        該書中對連結的解釋也不夠詳細。在章節最後,作者也承認:在電腦系統文獻中並沒有很好的記錄連結。因為連結是處在編譯器、電腦體繫結構和作業系統的交叉點上,他要求理解代碼產生、機器語言編程、程式執行個體化和虛擬儲存空間。它恰好不落在某個通常的電腦系統領域中。

        該章節講述Linux的X86系統,使用標準的ELF目標檔案,無論是什麼樣的作業系統,細節可能不盡相同,但是概念是相同的。

        讀完這一章節後,對“符號”的概念很是模糊。

7.1編譯驅動程式

    這裡再說一下編譯系統。大多數編譯系統提供編譯驅動程式,它代表使用者在需要的時候調用語言預先處理、編譯器、彙編器、和連結器。我自己畫了一個結構圖。

7.2靜態連結

7.3目標檔案    目標檔案有三種:可重定位目標檔案、可執行目標檔案和共用目標檔案(即動態連結程式庫),個個系統上對目標檔案的叫法不一致,Unix叫a.out,Windows NT叫PE(Portable Executable)。現代Unix使用ELF格式(EXecutable and Linkable Format 即可執行和可連結格式)。    下面詳細介紹“可重定位目標檔案”,最左邊的一個圖。    說明了,一個目標檔案產生可執行檔,然後載入到記憶體後的映射等,三個步驟。    ELF頭描述了產生該檔案的系統的字的大小和位元組序。ELF和節頭部表之間每個部分都稱為一個節(section)    .text:已編譯器的機器代碼    .rodada:唯讀資料,比如printf語句中的格式串。    .data:已經初始化的全域C變數。局部變數在運行時儲存在棧中。即不再data節也不在bss節    .bss:未初始化的全域C變數。不佔據實際的空間,僅僅是一個預留位置。所以未初始設定變數不需要佔據任何實際的磁碟空間。C++弱化BSS段。可能是沒有,也可能有。    .symtab:一個符號表,它存放“在程式中定義和引用的函數和全域變數的資訊”。    .rel.text:一個.text節中位置的列表。(將來重定位使用的)    .rel.data:被模組引用或定義的任何全域變數的重定位資訊。    .debug:偵錯符號表,其內容是程式中定義的局部變數和類型定義。    .line:原始C來源程式的行號和.text節中機器指令之間的映射。    .strtab:一個字串表.

可定位目標檔案的結構:讓你深入瞭解程式段,資料區段,bss段,符號表等等。

7.4可重定位目標檔案——參考7.3

7.5符號和符號表

符號表是一個數組,數組裡存放一個結構體。

typedef struct {    int name;/*String table offset*/    int value;/*Section offset, or VM address*/    int size;/*Object size in bytes*/    char type:4,/*Data, fund,section,or src file name (4 bits)*/        binding:4;/* Local of global(4bits)*/    char reserved;/*Unused*/    char section;/*Section header index ABS UNDEF*/}Elf_Symbol;

7.6符號解析

原則是:編譯器只允許每個模組中每個本地符號只有一個定義。而且對全域的符號的解析很棘手,因為多個目標檔案可能會定義相同的符號。C++和Java使用mangling手段來支援重載。

    多重定義的全域符號,請看下面的程式:

/*foo.c*/                      /*bar.c*/#include <stdio.h>             int x;void f(void);                  void f()int x =15213;                  {int main()                         x = 15212;{                               }    f();    printf("x=%d\n",x);    return 0;}

大家能猜到輸出的結果是15212;這是因為:bar.c中的x全域變數沒有初始化,導致函數f中使用的是foo檔案中的x變數。

根據Unix連接器使用下面的規則來處理多重定義的符號:

    ●規則1:不允許有多個強符號。

    ●規則2:如果有一個強符號和多個弱符號,那麼選擇強符號(這就是上面這道題的答案,初始化的int x=15213是強符號,而int x;是弱符號)

    ●規則3:如果有多個弱符號,那麼從這些弱符號中任意選擇一個(多麼可怕啊)

靜態庫

    事先寫好的一些可重定位的目標檔案打包成一個單獨的檔案,它可以用作連接器的輸入。當連接器構造一個輸出的可執行檔時,它只拷貝靜態庫裡被應用程式引用的目標模組。(稍後講解動態連結程式庫,也稱之為共用庫)。

    在Unix系統中,靜態庫以一種成為存檔(archive)的特殊檔案格式存放在磁碟中。封存檔案是一組串連起來的可重定位目標檔案的集合。有一個頭部用來描述每個成員目標檔案的大小和位置。封存檔案的尾碼是.a標識。是否可以這麼理解.a檔案的結構呢?(自己畫圖)

    下面用展示一個靜態庫串連的過程:

7.7重定位

7.8可執行檔

    參考7.3節圖中央部分。可執行檔跟可重定位目標檔案非常相似。只是可執行檔多了“init”和“段頭部表"少了,”.rel.text“和”.rel.data“兩個節。

7.9載入可執行檔。

    從7.3節圖中可以發現,右部是載入後的程式結構。ELF目標檔案被設計的非常容易載入到儲存空間。需要注意的是Unix中,程式總的程式碼片段總是從0x0804800處開始(這就是虛擬儲存空間的作用)。資料區段是在接下來的下一個4KB對齊的地址處。運行時堆在"讀/寫段"之後接下來的第一個4KB對齊的地址處,並通過malloc庫往上增長。而棧總是往下生長。

7.10動態庫(共用庫)

    動態庫是為瞭解決靜態庫的兩個弊端而出現的,靜態庫的兩個弊端:1)靜態庫更新後,程式要獲得該靜態庫然後再編譯。2)不同程式可能使用相同的靜態庫,導致很多靜態庫中的代碼重複被載入到儲存空間中。

    共用庫是致力於解決靜態庫的缺陷而出現的現代創新型產物。共用庫是一塊目標模組,在運行時,可以載入到任意的儲存空間地址,並和一個在儲存其中的程式連結起來。這個過程稱之為”動態連結“,是由一個叫做”動態連結器“的程式來完成的。

    共用庫是以梁總方式來共用的:1)所有引用該庫的程式都共用一個.so檔案中的代碼和資料,而不是靜態庫一樣拷貝一份。2)在儲存空間中,一個共用庫的.text節的一個副本可以被不同正在啟動並執行進城共用,從而節約寶貴的儲存空間資源。(Unix中動態庫以.so尾碼表示。)

    理解動態庫=共用庫的概念非常重要。動態庫一般是大型軟體或者作業系統的最愛,因為對於普通應用來說,沒有那麼多庫給別人使用,絕大多數都是自己用,所以靜態庫就夠了。

7.11從應用程式中載入和連結共用庫

    應用程式還可能從應用程式中載入和連結任意共用庫,而無需編譯時間連結那些庫到應用中(這個牛逼大了)!

    Windows中的更新大部分是這個技術。另外還有構建高效能web伺服器。

    Linux為動態連結器提供了一系列簡單的介面:

    #include <dlfcn.h>    void *dlopen(const char *filename, int flag);//載入共用庫    void *dlsym(void *handle, char *symbol);    //指向一個共用庫的控制代碼和一個符號名字。    int dlclose(void *handle);  //下載共用庫    const char *dlerror(void);  //容錯

    Java定義了一個標準的調用規則,叫做Java本地介面(Java NativeInterface,JNI),它允許Java程式調用本地的C和C++函數。JNI的基本思想是將本地的C函數,如foo,編譯到共用庫中,如foo.so .當一個正在啟動並執行Java程式試圖調用函數foo時,Java解析程式利用dlopen介面(或者類似的介面)動態連結和載入foo.so,然後調用foo。

7.12與位置無關的代碼(PIC)

7.13處理目標檔案的工具  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.