天天看點

探尋ELF檔案内容,理清符号所在section

受《CSAPP》P453啟發,想實際的看看ELF檔案的内容,是以做了簡單的嘗試,希望不虛此行。

采用的程式demo是:

swap.c

extern int buf[];

int *bufp0 = &buf[0];
int *bufp1;

void swap()
{
    int temp;

    bufp1 = &buf[1];
    temp = *bufp0;
    *bufp0 = *bufp1;
    *bufp1 = temp;
}
           

main.c

#include <stdio.h>


void swap();

int buf[2] = {1, 2};


static int foo = 99;

int f(){
        static int x = 1;
        return x;
}

int g(){
        static int x = 2;
        return x;
}

int main()
{
    swap();
    printf("Hello World.\n");
    return 0;
}
           

下面通過指令readelf指令來探尋ELF内部。

探尋ELF檔案内容,理清符号所在section

可以看到ELF頭的一些資訊:采用補碼,小段序;目标檔案的類型是可重定位目标檔案;機器類型是Intel80386;ELF header的大小是52B;有30個section header,共40B;等等。

探尋ELF檔案内容,理清符号所在section

可以看到ELF中各個section的索引号,起始位址,大小,标志字段。隻讀資料段15,已初始化全局變量24,未初始化全局變量25,符号表28,字元串表29,代碼段13.(其他的現在還不懂)。接下來結合上面的代碼看符号表資訊。

探尋ELF檔案内容,理清符号所在section
探尋ELF檔案内容,理清符号所在section

Ndx清單明每個符号所在的段,其中有三個僞段(pseudo section):ABS表示不該被重定位的符号,UNDEF表示在本子產品引用,卻在其他子產品定義,COMMON表示還未配置設定位置的未初始化對象。

main.c, swap.c代表源檔案名,類型是ABS。

f, g是在main.c中定義的倆函數,type=FUNC, bind=GLOBAL, 表示全局函數,所在的section是13(.text),起始位址分别為80483d4,de,大小都是10B.

變量foo, buf都是初始化的全局變量,在24号段(.data)中,大小分别是4,8B,不同在于foo有static修飾,是以bind=LOCAL,對于buf0,buf1也是類似情況.

特别值得關注的是定義在函數f, g中的有static修飾的同名局部變量x,在符号表中有唯一的local linker symbols:x.1688, x.1691都在全局初始化段中,bind=LOCAL.

接下來看swap.o的ELF資訊:

探尋ELF檔案内容,理清符号所在section

可以看到類型是可重定位目标檔案。(REL)

探尋ELF檔案内容,理清符号所在section

與前面readelf -a a.out很大不同的地方在于這裡多了一些.rel.text  .rel.data等可重定位的section,這是有目标檔案的類型決定的,可重定位目标檔案存在的意義就是被連結到其他目标檔案中,建構可執行目标檔案,是以就需要在ELF中表明哪些符号需要進行位址的修改。調用外部函數或者引用全局變量的指令都需要修改,本地函數調用是相對位址,是以不需要修改。上述代碼段位置清單在這裡顯然表示的就是swap()裡面需要重定位的對象,其中操縱了1次buf符号,3次bufp1, 2次bufp0, 是以出現了對應的條目,并且根據偏移量可以更好的了解。在重定位資料段中就隻有我們引用的外部變量buf。

探尋ELF檔案内容,理清符号所在section

在swap.o的符号表中,bu所在的section是UND Type=NOTYPE,表明其是extern的。bufp0是以初始化的全局變量,32位系統指針大小是4B,所在的section number是3(.data).特别要注意的是bufp1是未初始化未配置設定位置的對象,是以Ndx=COM, value值指明的是對齊要求。

總結:通過以上的分析可以更清晰的了解可執行檔案的記憶體布局, 不同對象所在的section,進而指導自己的程式設計。

繼續閱讀