程序的鏈接——目標(biāo)文件格式

目標(biāo)文件格式

前言:在講鏈接之前,我們先得說(shuō)說(shuō)痴怨,可重定位目標(biāo)文件格式和可執(zhí)行目標(biāo)文件格式

采用的是 ELF 標(biāo)準(zhǔn)二進(jìn)制文件格式進(jìn)行說(shuō)明

可重定位目標(biāo)文件格式

整個(gè)文件格式如下:

名稱(chēng)
ELF 頭
.text 節(jié)
.rodata 節(jié)
.data 節(jié)
.bss 節(jié)
.symtab 節(jié)
.rel.text 節(jié)
.rel.data 節(jié)
.debug 節(jié)
.line 節(jié)
.strtab 節(jié)
節(jié)頭表
  • ELF 頭
#define EI_NIDENT 16

typedef struct {
        unsigned char   e_ident[EI_NIDENT];
        Elf32_Half      e_type;
        Elf32_Half      e_machine;
        Elf32_Word      e_version;
        Elf32_Addr      e_entry;
        Elf32_Off       e_phoff;
        Elf32_Off       e_shoff;
        Elf32_Word      e_flags;
        Elf32_Half      e_ehsize;
        Elf32_Half      e_phentsize;
        Elf32_Half      e_phnum;
        Elf32_Half      e_shentsize;
        Elf32_Half      e_shnum;
        Elf32_Half      e_shstrndx;
} Elf32_Ehdr;

一共 52 個(gè)字節(jié)屡穗。咋算的呢?Elf32_Half 開(kāi)頭的就是 16 位兩個(gè)字節(jié)

也就是:

16 + 2 + 2 + 4 + 4 + 4 + 4 + 4 + 6 * 2 = 52

每個(gè)的作用如下

成員 含義
e_ident[EI_NIDENT] 前 4 個(gè)字節(jié)成為魔數(shù)字,通常用來(lái)確定文件的類(lèi)型和格式
e_type 文件類(lèi)型:可重定位咆瘟、可執(zhí)行、共享庫(kù)
e_machine 機(jī)器結(jié)構(gòu)類(lèi)型:如 IA-32
e_version 文件版本
e_entry 程序起始虛擬地址诽里,如可重定位文件就是 0
e_phoff 程序頭表的偏移(在可執(zhí)行目標(biāo)文件中才有)
e_shoff 節(jié)頭表的偏移(字節(jié)為單位)
e_flags
e_ehsize ELF 頭大刑徊汀(字節(jié)為單位)
e_phentsize 程序頭表大小(在可執(zhí)行目標(biāo)文件中才有)
e_phnum 程序頭表項(xiàng)數(shù)(在可執(zhí)行目標(biāo)文件中才有)
e_shentsize 節(jié)頭表中一個(gè)表項(xiàng)的大邪啤(每個(gè)表項(xiàng)大小一致灸眼,字節(jié)為單位)
e_shnum 節(jié)頭表的項(xiàng)數(shù)
e_shstrndx .strlab 節(jié)在節(jié)頭表的索引

每種可執(zhí)行文件的格式的開(kāi)頭幾個(gè)字節(jié)都是很特殊的,特別是開(kāi)頭 4 個(gè)字節(jié)墓懂,通常被稱(chēng)為魔數(shù)(Magic Number)焰宣。通過(guò)對(duì)魔數(shù)的判斷可以確定文件的格式和類(lèi)型。如:ELF 的可執(zhí)行文件格式的頭 4 個(gè)字節(jié)為0x7F拒贱、e宛徊、lf逻澳;Java的可執(zhí)行文件格式的頭 4 個(gè)字節(jié)為c闸天、af斜做、e苞氮;如果被執(zhí)行的是 Shell 腳本或 perl、python 等解釋型語(yǔ)言的腳本瓤逼,那么它的第一行往往是 #!/bin/sh#!/usr/bin/perl#!/usr/bin/python笼吟,此時(shí)前兩個(gè)字節(jié) #! 就構(gòu)成了魔數(shù),系統(tǒng)一旦判斷到這兩個(gè)字節(jié)霸旗,就對(duì)后面的字符串進(jìn)行解析贷帮,以確定具體的解釋程序路徑。

假設(shè)你有這樣一個(gè) main.o 的文件诱告,可以用 readelf 看它的 ELF 頭

readelf -h main.o

  • 節(jié)

節(jié)是 ELF 文件中的主體信息撵枢,包含了鏈接過(guò)程中所用的目標(biāo)代碼信息,包括指令、數(shù)據(jù)锄禽、符號(hào)表和重定位信息潜必。

節(jié)名稱(chēng) 用途
.text 節(jié) 目標(biāo)代碼部分(二進(jìn)制)
.rodata 節(jié) 只讀數(shù)據(jù),如 printf 中的格式串沃但、開(kāi)關(guān)語(yǔ)句的跳轉(zhuǎn)表
.data 節(jié) 已經(jīng)初始化的全局變量
.bss 節(jié) 未初始化的全局變量磁滚。由于是未初始化,所以無(wú)需在當(dāng)前目標(biāo)文件中分配用與保存值的空間宵晚。而對(duì)于局部變量來(lái)說(shuō)垂攘,運(yùn)行時(shí)被分配在棧中所以既不出現(xiàn)在 .bss 節(jié)中也不會(huì)出現(xiàn)在 .data 節(jié)中
.symtab 節(jié) 符號(hào)表,程序中定義的函數(shù)名和全局靜態(tài)變量名都屬于符號(hào)坝疼,與這些符號(hào)相關(guān)的信息都保存在符號(hào)表中搜贤。每個(gè)可重定位目標(biāo)文件都有一個(gè) .symtab 節(jié)
.rel.text 節(jié) .text 節(jié)相關(guān)的重定位信息。通常钝凶,調(diào)用外部函數(shù)或者引用全局變量的指令中的地址字段需要修改
.rel.data 節(jié) .data 節(jié)相關(guān)的可重定位信息仪芒。
.debug 節(jié) 調(diào)試用符號(hào)表
.line 節(jié) 源程序中的行號(hào)和 .text 節(jié)中的機(jī)器指令之間的映射
.strtab 節(jié) 字符串表,包括 .symtab 和 .debug 節(jié)中的符號(hào)以及節(jié)頭表中的節(jié)名耕陷。
  • 節(jié)頭表
typedef struct
{
  Elf32_Word sh_name; /* Section name (string tbl index) */
  Elf32_Word sh_type; /* Section type */
  Elf32_Word sh_flags; /* Section flags */
  Elf32_Addr sh_addr; /* Section virtual addr at execution */
  Elf32_Off sh_offset; /* Section file offset */
  Elf32_Word sh_size; /* Section size in bytes */
  Elf32_Word shdebugging sym_link; /* Link to another section */
  Elf32_Word sh_info; /* Additional section information */
  Elf32_Word sh_addralign; /* Section alignment */
  Elf32_Word sh_entsize; /* Entry size if section holds table */
} Elf32_Shdr;

大小 40B = 4 × 10B掂名。

命令:readelf -S main.o

可執(zhí)行目標(biāo)文件格式

鏈接器將相互關(guān)聯(lián)的可重定位目標(biāo)文件中的相同代碼和數(shù)據(jù)節(jié)(.text 節(jié),.rodata 節(jié)哟沫,.data 節(jié)饺蔑,.bss 節(jié))合并。因?yàn)楹喜⒑笫染鳎械奶摷俚刂范寄鼙挥?jì)算出來(lái)猾警。也就能算出每個(gè)符號(hào)的地址。

可執(zhí)行目標(biāo)文件格式包括:

  • ELF 頭
  • 程序頭表
  • 節(jié)頭表
名稱(chēng)
ELF 頭
程序頭表
.init隆敢、.fini 節(jié)
.text 節(jié)
.rodata 節(jié)
.data 節(jié)
.bss 節(jié)
.symtab 節(jié)
.debug 節(jié)
.line 節(jié)
.strtab 節(jié)
節(jié)頭表

與可重定義目標(biāo)文件格式類(lèi)似发皿,主要不同點(diǎn)有:

  • ELF 頭中 e_entry 不再是 0。而是執(zhí)行代碼的第一條指令的地址
  • 多了 .init 節(jié)和 .fini 節(jié)拂蝎,其中 .init 節(jié)中定義了一個(gè) _init 函數(shù)穴墅,用于可執(zhí)行目標(biāo)文件執(zhí)行時(shí)初始化工作。.fini 包含進(jìn)程終止時(shí)要執(zhí)行的指令代碼
  • 少了 .rel.text 和 .rel.data 節(jié)等重定位信息節(jié)温自。
  • 多了一個(gè)程序頭表也叫作段頭表

整個(gè)文件有兩個(gè)重要的段

  • 只讀代碼段:(ELF 頭 + 程序頭表 + .init .fini 節(jié) + .text 節(jié) + .rodata 節(jié) )
  • 可讀寫(xiě)數(shù)據(jù)段:(.data 節(jié) + .bss 節(jié))玄货,由于在執(zhí)行文件時(shí)這兩個(gè)段必須分配空間所以又可以叫做 可裝入段

下面隆重介紹程序頭表:

為了在可執(zhí)行文件執(zhí)行時(shí)能夠訪在內(nèi)存中訪問(wèn)到代碼和數(shù)據(jù),必須將可執(zhí)行文件中這些連續(xù)的悼泌,具有相同訪問(wèn)屬性的代碼和數(shù)據(jù)段映射到存儲(chǔ)空間(通常是虛擬地址)松捉。程序頭表就用于描述這種映射關(guān)系,一個(gè)表項(xiàng)對(duì)應(yīng)一個(gè)連續(xù)的存儲(chǔ)段或特殊節(jié)馆里。

typedef struct {
        Elf32_Word      p_type;
        Elf32_Off       p_offset;
        Elf32_Addr      p_vaddr;
        Elf32_Addr      p_paddr;
        Elf32_Word      p_filesz;
        Elf32_Word      p_memsz;
        Elf32_Word      p_flags;
        Elf32_Word      p_align;
} Elf32_Phdr;

成員 含義
p_type 短的類(lèi)型或者節(jié)的類(lèi)型惩坑,列入是否為可裝入段
p_offset 本段的首字節(jié)在文件中的偏移地址
p_vaddr 本字段的虛擬地址
p_paddr 本段首字節(jié)的物理地址
p_filesz 本段所占字節(jié)數(shù)
p_memsz 在存儲(chǔ)器中所占字節(jié)數(shù)
p_flags 存取權(quán)限
p_align 對(duì)齊方式

輸入 readelf -l main

程序頭:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x00000034 0x00000034 0x00120 0x00120 R   0x4
  INTERP         0x000154 0x00000154 0x00000154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x00000000 0x00000000 0x00730 0x00730 R E 0x1000
  LOAD           0x000edc 0x00001edc 0x00001edc 0x0012c 0x00130 RW  0x1000
  DYNAMIC        0x000ee4 0x00001ee4 0x00001ee4 0x000f8 0x000f8 RW  0x4
  NOTE           0x000168 0x00000168 0x00000168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x0005d0 0x000005d0 0x000005d0 0x00044 0x00044 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000edc 0x00001edc 0x00001edc 0x00124 0x00124 R   0x1

這里只是大概介紹了一些知識(shí)掉盅,具體怎么運(yùn)用要看接下來(lái)的文章。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末以舒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子慢哈,更是在濱河造成了極大的恐慌蔓钟,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卵贱,死亡現(xiàn)場(chǎng)離奇詭異滥沫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)键俱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)兰绣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人编振,你說(shuō)我怎么就攤上這事缀辩。” “怎么了踪央?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵臀玄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我畅蹂,道長(zhǎng)健无,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任液斜,我火速辦了婚禮累贤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘少漆。我一直安慰自己臼膏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布检疫。 她就那樣靜靜地躺著讶请,像睡著了一般。 火紅的嫁衣襯著肌膚如雪屎媳。 梳的紋絲不亂的頭發(fā)上夺溢,一...
    開(kāi)封第一講書(shū)人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音烛谊,去河邊找鬼风响。 笑死,一個(gè)胖子當(dāng)著我的面吹牛丹禀,可吹牛的內(nèi)容都是我干的状勤。 我是一名探鬼主播鞋怀,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼持搜!你這毒婦竟也來(lái)了密似?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤葫盼,失蹤者是張志新(化名)和其女友劉穎残腌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體贫导,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抛猫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了孩灯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闺金。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖峰档,靈堂內(nèi)的尸體忽然破棺而出败匹,到底是詐尸還是另有隱情,我是刑警寧澤面哥,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布哎壳,位于F島的核電站,受9級(jí)特大地震影響尚卫,放射性物質(zhì)發(fā)生泄漏归榕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一吱涉、第九天 我趴在偏房一處隱蔽的房頂上張望刹泄。 院中可真熱鬧,春花似錦怎爵、人聲如沸特石。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)姆蘸。三九已至,卻和暖如春芙委,著一層夾襖步出監(jiān)牢的瞬間逞敷,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工灌侣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留推捐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓侧啼,卻偏偏與公主長(zhǎng)得像牛柒,于是被迫代替她去往敵國(guó)和親堪簿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容