C編譯器、連結器、載入器詳解

來源:互聯網
上載者:User
文章目錄
  • 2.1編譯
  •  
  • 2.2彙編
  • 2.3目標檔案(Executable and Linkable Format)
  • 2.4 靜態庫與動態庫
  • 3.1 連結的時機:
  • 3.2 連結的作用(軟體複用):
  • 3.3 靜態庫搜尋路徑(由靜態連結器負責)
  • 3.4 動態庫搜尋路徑(由動態連結器負責)
  • 3.5 靜態連結(編譯時間)
  • 3.6 動態連結(載入、運行時)
一、概述

C語言的編譯連結過程要把我們編寫的一個c程式(原始碼)轉換成可以在硬體上啟動並執行程式(可執行代碼),需要進行編譯和連結。編譯就是把文本形式原始碼翻譯為機器語言形式的目標檔案的過程。連結是把目標檔案、作業系統的啟動代碼和用到的庫檔案進行組織形成最終產生可載入、可執行代碼的過程。

過程圖解如下: 

  1. 前置處理器:將.c 檔案轉化成 .i檔案,使用的gcc命令是:gcc –E,對應於預先處理命令cpp;
  2. 編譯器:將.c/.h檔案轉換成.s檔案,使用的gcc命令是:gcc –S,對應於編譯命令 cc –S;
  3. 彙編器:將.s 檔案轉化成 .o檔案,使用的gcc 命令是:gcc –c,對應於彙編命令是 as;
  4. 連結器:將.o檔案轉化成可執行程式,使用的gcc 命令是: gcc,對應於連結命令是 ld;
  5. 載入器:將可執行程式載入到記憶體並進行執行,loader和ld-linux.so。

 

二、編譯過程

編譯過程又可以分成兩個階段:編譯和彙編。

2.1編譯

編譯是指編譯器讀取來源程式(字元流),對之進行詞法和文法的分析,將進階語言指令轉換為功能等效的彙編代碼

源檔案的編譯過程包含兩個主要階段:

第一個階段是預先處理階段,在正式的編譯階段之前進行。預先處理階段將根據已放置在檔案中的預先處理指令來修改源檔案的內容。

主要是以下幾方面的處理:

  1. 宏定義指令,如 #define a b 對於這種偽指令,先行編譯所要做的是將程式中的所有a用b替換,但作為字串常量的 a則不被替換。還有 #undef,則將取消對某個宏的定義,使以後該串的出現不再被替換。
  2. 條件編譯指令,如#ifdef,#ifndef,#else,#elif,#endif等。 這些偽指令的引入使得程式員可以通過定義不同的宏來決定編譯器對哪些代碼進行處理。先行編譯程式將根據有關的檔案,將那些不必要的代碼過濾掉
  3. 標頭檔包含指令,如#include "FileName"或者#include 等。 該指令將標頭檔中的定義統統都加入到它所產生的輸出檔案中,以供編譯器對之進行處理。
  4. 特殊符號,先行編譯程式可以識別一些特殊的符號。 例如在來源程式中出現的LINE標識將被解釋為當前行號(十進位數),FILE則被解釋為當前被編譯的C來源程式的名稱。先行編譯程式對於在來源程式中出現的這些串將用合適的值進行替換。

標頭檔的目的主要是為了使某些定義可以供多個不同的C來源程式使用,這涉及到標頭檔的定位即搜尋路徑問題。標頭檔搜尋規則如下:

  1. 所有header file的搜尋會從-I開始
  2. 然後找環境變數 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH指定的路徑
  3. 再找預設目錄(/usr/include、/usr/local/include、/usr/lib/gcc-lib/i386-linux/2.95.2/include......)

 

第二個階段編譯、最佳化階段,編譯器所要作得工作就是通過詞法分析和文法分析,在確認所有的指令都符合文法規則之後,將其翻譯成等價的中間代碼錶示或彙編代碼。 

 2.2彙編

彙編實際上指彙編器(as)把組合語言代碼翻譯成目標機器指令的過程。目標檔案中所存放的也就是與來源程式等效的目標的機器語言代碼。目標檔案由段組成。通常一個目標檔案中至少有兩個段:

  • 程式碼片段:該段中所包含的主要是程式的指令。該段一般是可讀和可執行檔,但一般卻不可寫。
  • 資料區段:主要存放程式中要用到的各種全域變數或靜態資料。一般資料區段都是可讀,可寫,可執行檔。

 

2.3目標檔案(Executable and Linkable Format)
  1. 可重定位(Relocatable)檔案:由編譯器和彙編器產生,可以與其他可重定位目標檔案合并建立一個可執行或共用的目標檔案;
  2. 共用(Shared)目標檔案:一類特殊的可重定位目標檔案,可以在連結(靜態共用庫)時加入目標檔案或載入時或運行時(動態共用程式庫)被動態載入到記憶體並執行;
  3. 可執行(Executable)檔案:由連結器產生,可以直接通過載入器載入到記憶體中充當進程執行的檔案。

 

2.4 靜態庫與動態庫

靜態庫(static library)就是將相關的目標模組打包形成的單獨的檔案。使用ar命令。

靜態庫的優點在於:

  • 程式員不需要顯式的指定所有需要連結的目標模組,因為指定是一個耗時且容易出錯的過程;
  • 連結時,串連程式只從靜態庫中拷貝被程式引用的目標模組,這樣就減小了可執行檔在磁碟和記憶體中的大小。

動態庫(dynamic library)是一種特殊的目標模組,它可以在運行時被載入到任意的記憶體位址,或者是與任意的程式進行連結。

動態庫的優點在於:

  • 更新動態庫,無需重新連結;對於大系統,重新連結是一個非常耗時的過程;
  • 運行中可供多個程式使用,記憶體中只需要有一份,節省記憶體。

 

三、連結過程

連結器主要是將有關的目標檔案彼此相串連產生可載入、可執行檔目標檔案。連結器的核心工作就是符號表解析和重定位。

3.1 連結的時機:
  1. 編譯時間,就是原始碼被編譯成機器代碼時(靜態連結器負責);
  2. 載入時,也就是程式被載入到記憶體時(載入器負責);
  3. 運行時,由應用程式來實施(動態連結器負責)。
3.2 連結的作用(軟體複用):
  1. 使得分離編譯成為可能;
  2. 動態綁定(binding):使定義、實現、使用分離
3.3 靜態庫搜尋路徑(由靜態連結器負責)
  1. gcc先從-L尋找;
  2. 再找環境變數LIBRARY_PATH指定的搜尋路徑;
  3. 再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程式內的。
3.4 動態庫搜尋路徑(由動態連結器負責)
  1. 編譯目標代碼時指定的動態庫搜尋路徑-L;
  2. 環境變數LD_LIBRARY_PATH指定的動態庫搜尋路徑;
  3. 設定檔/etc/ld.so.conf中指定的動態庫搜尋路徑;
  4. 預設的動態庫搜尋路徑/lib /usr/lib/ /usr/local/lib
3.5 靜態連結(編譯時間)

連結器將函數的代碼從其所在地(目標檔案或靜態連結庫中)拷貝到最終的可執行程式中。這樣該程式在被執行時這些代碼將被裝入到該進程的虛擬位址空間中。靜態連結庫實際上是一個目標檔案的集合,其中的每個檔案含有庫中的一個或者一組相關函數的代碼。

為建立可執行檔,連結器必須要完成的主要任務:

  1. 符號解析:把目標檔案中符號的定義和引用聯絡起來;
  2. 重定位:把符號定義和記憶體位址對應起來,然後修改所有對符號的引用。

關於符號表和符號解析以及重定位的分析後續學習。

3.6 動態連結(載入、運行時)

在此種方式下,函數的定義在動態連結程式庫或共用對象的目標檔案中。在編譯的連結階段,動態連結程式庫只提供符號表和其他少量資訊用於保證所有符號引用都有定義,保證編譯順利通過。動態連結器(ld-linux.so)連結程式在運行過程中根據記錄的共用對象的符號定義來動態載入共用庫,然後完成重定位。在此可執行檔被執行時,動態連結程式庫的全部內容將被映射到運行時相應進程的虛地址空間。動態連結程式將根據可執行程式中記錄的資訊找到相應的函數代碼。  


四、載入過程

載入器把可執行檔從外存載入到記憶體並進行執行。 Linux中進程運行時的記憶體映像如下:

 

 載入過程如下:

載入器首先建立如所示的記憶體映像,然後根據段頭部表,把目標檔案拷貝到記憶體的資料和程式碼片段中。然後,載入器跳轉到程式進入點(即符號_start 的地址),執行啟動代碼(startup code),啟動代碼的調用順序如所示:

 

五、處理目標的常用工具

UNIX系統提供了一系列工具協助理解和處理目標檔案。GNUbinutils 包也提供了很多協助。這些工具包括:

  • AR :建立靜態庫,插入、刪除、列出和提取成員;
  • STRINGS :列出目標檔案中所有可以列印的字串;
  • STRIP :從目標檔案中刪除符號表資訊;
  • NM :列出目標檔案符號表中定義的符號;
  • SIZE :列出目標檔案中節的名字和大小;
  • READELF :顯示一個目標檔案的完整結構,包括ELF 頭中編碼的所有資訊。
  • OBJDUMP :顯示目標檔案的所有資訊,最有用的功能是反組譯碼.text節中的二進位指令。
  • LDD :列出可執行檔在運行時需要的共用庫。

   

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.