1. 程式人生 > >linux下elf重定位理解

linux下elf重定位理解

準備:可重定位檔案(Relocatable file),可執行檔案(Executable file),共享檔案(Shared object file)。

  • Relocatable file: an object file that holds code and data suitable for linking with other object files to create an executable or a shared object file. In other word, you can say that relocatable file is a foundation for creating executables and libraries.

    This is kind of file you get if you compile a source code like this:

    $ gcc -c test.c

    That will produce test.o, which is a relocatable file.

    Kernel module (either suffixed with .o or .ko) is also a form of relocatable file.

  • Executable file: object file that holds a program suitable for execution. Yes, that means, your XMMS mp3 player, your vcd software player, even your text editor are all ELF executable files.

    This is also a familiar file if you compile a program:

    $ gcc -o test test.c

    After you make sure the executable bit of "test" is enabled, you can execute it. The question is, what about shell script? Shell script is NOT ELF executable, but the interpreter IS.

  • Shared object file: This file holds code and data suitable for linking in two contexts:

    1. The link editor may process it with other relocatable and shared shared object file to create another object file.
    2. The dynamic linker combines it with an executable file and other shared objects to create a process image.

    In simple words, these are the files that you usually see with suffix .so (normally located inside /usr/lib on most Linux installation).



重定位:就是把符號的value進行重新定位,value可是地址也可是其他型別值.要重點理解
編譯器、聯結器和裝載器各個職能,熟悉編譯、連線和載入過程、符號(symbol)、段(section)等概念

符號:高階語言經編譯處理後,在binary層面上,統一以符號表示各個變數、函式實體。是連線和重定位橋 
    樑。不同編譯器有不同的地符號影射,比如c語言中,以前有的編譯器固定變數前加下劃線 int a ==>_a

段:binary層面對指令和資料的組織,方便管理、理解。深入參考彙編中有關段概念。
符號和段都是屬於ELF表示範疇,是對binary層面的描述。深入可參考ELF或者coff相關文件


重定位分為兩大類:普通和動態。普通就是連線時候重定位,動態是指載入、執行時
                  重定位,一般有程式啟動時動態載入符號來重定位,和函式符號被呼叫時候動態載入。

重定位過程要用到一些表,來輔助定位,有.rel.text、 .rel.dyn和.rel.plt、.plt.下面根據他們來展開說明。

.rel.text 
  重定位的地方在.text段內,以offset指定具體要定位位置。在連線時候由聯結器完成。注意比較.text段前後變化。指的是比較.o檔案和最終的執行檔案(或者動態庫檔案)。就是重定位前後比較,以上是說明了具體比較物件而已。

.rel.dyn 
  重定位的地方在.got段內。主要是針對外部資料變數符號。例如全域性資料。重定位在程式執行時定位,一般是在.init段內。定位過程:獲得符號對應value後,根據rel.dyn表中對應的offset,修改.got表對應位置的value。另外,.rel.dyn 含義是指和dyn有關,一般是指在程式執行時候,動態載入。區別於rel.plt,rel.plt是指和plt相關,具體是指在某個函式被呼叫時候載入。

.rel.plt  
  重定位的地方在.got.plt段內(注意也是.got內,具體區分而已)。 主要是針對外部函式符號。一般是函式首次被呼叫時候重定位。可看彙編,理解其首次訪問是如何重定位的,實際很簡單,就是初次重定位函式地址,然後把最終函式地址放到.got.plt內,以後讀取該.got.plt就直接得到最終函式地址(參考過程說明)。  所有外部函式呼叫都是經過一個對應樁函式,這些樁函式都在.plt段內。

 過程說明:呼叫對應樁函式--->樁函式取出.got表(具體是.got.plt)表內地址--->然後跳轉到這個地址.如果是第一次,這個跳轉地址預設是樁函式本身跳轉處地址的下一個指令地址(目的是通過樁函式統一集中取地址和載入地址),後續接著把對應函式的真實地址載入進來放到.got.plt表對應處,同時跳轉執行該地址指令.以後樁函式從.got.plt取得地址都是真實函式地址了。

 .plt段,存放重定位樁函式的。

重要區別  
.rel.text屬於普通重定位輔助段 ,他由編譯器編譯產生存在於obj檔案內。聯結器連線時,他 用於最終可執行檔案或者動態庫的重定位。通過它修改原obj檔案的.text段後,和並      到 最終可執行檔案或者動態檔案的.text段。
注:readelf -r a.o 檢視 .rel.text。其型別一般為R_386_32和R_386_PC32


.rel.dyn和.rel.plt是動態定位輔助段。由聯結器產生存在於可執行檔案或者動態庫檔案內。藉助這兩個輔助段可以動態修改對應.got和.got.plt段,從而實現執行時重定位。
.rel.dyn 對應地點在.got表內;.rel.plt  在.got.plt,注意不是在.text,這點和普通不同,也是重要點。

.rel.text由編譯器產生,然後在連線時候,由連結器負責根據.rel.text對.text段進行修改,從而達到重定位目的;

.rel.dyn和.rel.plt由聯結器產生,然後在執行時候,動態載入符號地址。
對於資料,根據.rel.dyn找到.got中的offset位置;
對於函式則通過.plt樁函式和.rel.plt段來獲取函式真實地址,然後存在於.got.plt。
要理解動態連線中訪問外部符號是通過.got和.got.plt
注1:規律:.rel.plt和.got.plt偏移 有對應,另外和.dynsym好似有次序對應關係(不很確定)。通過這可方便解析函式符號地址,詳細可參考聯結器解析函式(聯結器一般是動態載入,像全域性資料符號那樣,程式啟動時載入)。

注2:readelf -r a.out 檢視 .rel.dyn 和.rel.plt.其中 .rel.dyn 型別一般為R_386_GLOB_DAT和R_386_COPY;.rel.plt為R_386_JUMP_SLOT


例子在此不舉了,分析這個重定位過程,最好還是自己動手寫個例子來,比單純看文章好理解。
分析沒多久,還有好多問題需要慢慢分析透徹,大家多多指正。參考http://blog.chinaunix.net/space.php?uid=52437&do=blog&id=2108840 和
http://blog.chinaunix.net/space.php?uid=52437&do=blog&id=2108843



附註:
  • .text – contains the module code
  • .data – initialized variables
  • .bss – non-initialized variables
  • .symtab – the module symbols: functions and static variables
  • .strtab – the names for module symbols
  • .rel.text –the relocation for functions (for statically linked modules)
  • .rel.data – the relocation for static variables (for statically linked modules)
  • .rel.plt – the list of elements in the PLT (Procedure Linkage Table), which are liable to the relocation during the dynamic linking (if PLT is used)
  • .rel.dyn – the relocation for dynamically linked functions (if PLT is not used)
  • .got – Global Offset Table, contains the information about the offsets of relocated objects
  • .debug –the debug information