歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> UNIX/Linux 平台可執行文件格式分析

UNIX/Linux 平台可執行文件格式分析

日期:2017/2/28 16:46:52   编辑:Linux教程

  本文討論了 UNIX/LINUX 平台下三種主要的可執行文件格式:a.out(assembler and link editor output 匯編器和鏈接編輯器的輸出)、COFF(Common Object File Format 通用對象文件格式)、ELF(Executable and Linking Format 可執行和鏈接格式)。首先是對可執行文件格式的一個綜述,並通過描述 ELF 文件加載過程以揭示可執行文件內容與加載運行操作之間的關系。隨後依此討論了此三種文件格式,並著重討論 ELF 文件的動態連接機制,其間也穿插了對各種文件格式優缺點的評價。最後對三種可執行文件格式有一個簡單總結,並提出作者對可文件格式評價的一些感想。

  可執行文件格式綜述

  相對於其它文件類型,可執行文件可能是一個操作系統中最重要的文件類型,因為它們是完成操作的真正執行者。可執行文件的大小、運行速度、資源占用情況以及可擴展性、可移植性等與文件格式的定義和文件加載過程緊密相關。研究可執行文件的格式對編寫高性能程序和一些黑客技術的運用都是非常有意義的。

  不管何種可執行文件格式,一些基本的要素是必須的,顯而易見的,文件中應包含代碼和數據。因為文件可能引用外部文件定義的符號(變量和函數),因此重定位信息和符號信息也是需要的。一些輔助信息是可選的,如調試信息、硬件信息等。基本上任意一種可執行文件格式都是按區間保存上述信息,稱為段(Segment)或節(Section)。不同的文件格式中段和節的含義可能有細微區別,但根據上下文關系可以很清楚的理解,這不是關鍵問題。最後,可執行文件通常都有一個文件頭部以描述本文件的總體結構。

  相對可執行文件有三個重要的概念:編譯(compile)、連接(link,也可稱為鏈接、聯接)、加載(load)。源程序文件被編譯成目標文件,多個目標文件被連接成一個最終的可執行文件,可執行文件被加載到內存中運行。因為本文重點是討論可執行文件格式,因此加載過程也相對重點討論。下面是LINUX平台下ELF文件加載過程的一個簡單描述。

  1:內核首先讀ELF文件的頭部,然後根據頭部的數據指示分別讀入各種數據結構,找到標記為可加載(loadable)的段,並調用函數 mmap()把段內容加載到內存中。在加載之前,內核把段的標記直接傳遞給 mmap(),段的標記指示該段在內存中是否可讀、可寫,可執行。顯然,文本段是只讀可執行,而數據段是可讀可寫。這種方式是利用了現代操作系統和處理器對內存的保護功能。著名的Shellcode(參考資料 17)的編寫技巧則是突破此保護功能的一個實際例子。

  2:內核分析出ELF文件標記為 PT_INTERP 的段中所對應的動態連接器名稱,並加載動態連接器。現代 LINUX 系統的動態連接器通常是 /lib/ld-linux.so.2,相關細節在後面有詳細描述。

  3:內核在新進程的堆棧中設置一些標記-值對,以指示動態連接器的相關操作。

  4:內核把控制傳遞給動態連接器。

  5:動態連接器檢查程序對外部文件(共享庫)的依賴性,並在需要時對其進行加載。

  6:動態連接器對程序的外部引用進行重定位,通俗的講,就是告訴程序其引用的外部變量/函數的地址,此地址位於共享庫被加載在內存的區間內。動態連接還有一個延遲(Lazy)定位的特性,即只在"真正"需要引用符號時才重定位,這對提高程序運行效率有極大幫助。

  7:動態連接器執行在ELF文件中標記為 .init 的節的代碼,進行程序運行的初始化。在早期系統中,初始化代碼對應函數 _init(void)(函數名強制固定),在現代系統中,則對應形式為

  void

  __attribute((constructor))

  init_function(void)

  {

  ……

  }

  其中函數名為任意。

Copyright © Linux教程網 All Rights Reserved