日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

c语言书籍elf文件,扒一扒ELF文件

發(fā)布時(shí)間:2025/3/20 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c语言书籍elf文件,扒一扒ELF文件 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

ELF文件(Executable Linkable Format)是一種文件存儲(chǔ)格式。Linux下的目標(biāo)文件和可執(zhí)行文件都按照該格式進(jìn)行存儲(chǔ),有必要做個(gè)總結(jié)。

1. 鏈接舉例

2. ELF文件類型2.1 可重定位目標(biāo)文件(.o文件)

2.2 可執(zhí)行目標(biāo)文件(a.out文件)

2.3 共享對(duì)象文件(.so文件)

3. ELF文件作用

4. ELF文件格式4.1 從編譯和鏈接角度看ELF文件(可重定位目標(biāo)文件)

4.2 從程序執(zhí)行角度看ELF文件(可執(zhí)行文件)

5.總結(jié)

1. 鏈接舉例

在介紹ELF文件之前,我們先看下,一個(gè).c程序是如何變成可執(zhí)行目標(biāo)文件的。下面舉個(gè)例子。

該程序由main.c和sum.c兩個(gè)模塊組成。sum.c接收數(shù)組和數(shù)組長(zhǎng)度兩個(gè)參數(shù),最后將數(shù)組求和的結(jié)果返回。main.c調(diào)用sum函數(shù),并傳遞一個(gè)兩元素的int數(shù)組array,將計(jì)算結(jié)果保存在val中。//main.c

int?sum(int?*a,?int?n);

int?array[2]?=?{1,?2};

int?main(int?argc,?char**?argv){

int?val?=?sum(array,?2);

return?val;

}//sum.c

int?sum(int?*a,?int?n){

int?i,?s?=?0;

for?(i?=?0;?i?

s?+=?a[i];

}

return?s;

}

讓我們來(lái)看看如果我們使用GCC編譯兩個(gè)模塊會(huì)發(fā)生什么?

main.c和sum.c將分別通過(guò)翻譯器將源文件處理為可重定位的目標(biāo)文件main.o和sum.o。翻譯器處理的過(guò)程包括了預(yù)處理(ccp)、編譯(ccl)、匯編(as)?三個(gè)過(guò)程。最后,鏈接器(ld)?將可重定位的目標(biāo)文件main.o和sum.o以及一些必要的系統(tǒng)文件組合起來(lái),創(chuàng)建一個(gè)可執(zhí)行目標(biāo)文件prog。具體過(guò)程如下圖所示。

鏈接過(guò)程

由上面的過(guò)程,我們可以看出在經(jīng)過(guò)匯編器后會(huì)輸出一個(gè).o文件,這個(gè)叫做可重定位的目標(biāo)文件。將main.o和sum.o輸入鏈接器后,鏈接器輸出的prog文件叫做可執(zhí)行目標(biāo)文件。那這兩個(gè)目標(biāo)文件有什么樣的區(qū)別呢?

2. ELF文件類型

2.1 可重定位目標(biāo)文件(.o文件)

包含二進(jìn)制代碼和數(shù)據(jù),其形式可以和其他目標(biāo)文件進(jìn)行合并,創(chuàng)建一個(gè)可執(zhí)行目標(biāo)文件。例如lib*.o文件。

2.2 可執(zhí)行目標(biāo)文件(a.out文件)

包含二進(jìn)制代碼和數(shù)據(jù),可直接被加載器加載執(zhí)行。例如編譯好的可執(zhí)行文件a.out。

2.3 共享對(duì)象文件(.so文件)

用于和其他共享目標(biāo)文件或者可重定位文件一起生成ELF目標(biāo)文件或者和執(zhí)行文件一起創(chuàng)建進(jìn)程映像,例如lib*.so文件。

3. ELF文件作用

ELF文件參與程序的連接(建立一個(gè)程序)和程序的執(zhí)行(運(yùn)行一個(gè)程序),所以可以從不同的角度來(lái)看待ELF格式的文件:

1.如果用于編譯和鏈接(可重定位文件),則編譯器和鏈接器將把ELF文件看作是節(jié)頭表描述的節(jié)的集合,程序頭表可選。

2.如果用于加載執(zhí)行(可執(zhí)行文件),則加載器則將把ELF文件看作是程序頭表描述的段的集合,一個(gè)段可能包含多個(gè)節(jié),節(jié)頭表可選。

4. ELF文件格式

4.1 從編譯和鏈接角度看ELF文件(可重定位目標(biāo)文件)

從編譯和鏈接角度看ELF文件

ELF頭

每個(gè)ELF文件都必須存在一個(gè)ELF_He ader,這里存放了很多重要的信息用來(lái)描述整個(gè)文件的組織,如: 版本信息,入口信息,偏移信息等。程序執(zhí)行也必須依靠其提供的信息。

段頭表

段頭表。存放的是所有不同段將在內(nèi)存中的位置。

.text section

代碼段。存放已編譯程序的機(jī)器代碼,一般是只讀的。

.rodata?section

只讀數(shù)據(jù)段。此段的數(shù)據(jù)不可修改,存放常量。比如,printf中的格式化語(yǔ)句。

.data?section

數(shù)據(jù)段。存放已初始化的全局變量、常量。

.bss?section

bss段。未初始化全局變量,僅是占位符,不占據(jù)任何實(shí)際磁盤(pán)空間。目標(biāo)文件格式區(qū)分初始化和非初始化是為了空間效率。

從編譯和鏈接角度看ELF文件

.symtab?section

符號(hào)表,它存放在程序中定義和引用的函數(shù)和全局變量的信息。

.rel.txt?section

.text節(jié)的重定位信息,用于重新修改代碼段的指令中的地址信息。

.rel.data?section

.data節(jié)的重定位信息,用于對(duì)被模塊使用或定義的全局變量進(jìn)行重定位的信息。

.debug?section

調(diào)試用的符號(hào)表。

.strtab section

包含 symtab和 debug節(jié)中符號(hào)及節(jié)名。

節(jié)頭部表

每個(gè)節(jié)的節(jié)名、偏移和大小。

以下是32位系統(tǒng)對(duì)應(yīng)的節(jié)頭表數(shù)據(jù)結(jié)構(gòu),說(shuō)明了每個(gè)節(jié)的節(jié)名、在文件中的偏移、大小、訪問(wèn)屬性、對(duì)齊方式等。typedef?struct?{

Elf32_Word?sh_name;???//節(jié)名字符串在.strtab節(jié)(字符串表)中的偏移

Elf32_Word?sh_type;???//節(jié)類型:無(wú)效/代碼或數(shù)據(jù)/符號(hào)/字符串/...

Elf32_Word?sh_flags;??//節(jié)標(biāo)志:該節(jié)在虛擬空間中的訪問(wèn)屬性

Elf32_Addr?sh_addr;???//虛擬地址:若可被加載,則對(duì)應(yīng)虛擬地址

Elf32_Off??sh_offset;?//在文件中的偏移地址,對(duì).bss節(jié)而言則無(wú)意義

Elf32_Word?sh_size;???//節(jié)在文件中所占的長(zhǎng)度

Elf32_Word?sh_link;???//sh_link和sh_info用于與鏈接相關(guān)的節(jié)(如?.rel.text節(jié)、.rel.data節(jié)、.symtab節(jié)等)

Elf32_Word?sh_info;

Elf32_Word?sh_addralign;?//節(jié)的對(duì)齊要求

Elf32_Word?sh_entsize;???//節(jié)中每個(gè)表項(xiàng)的長(zhǎng)度,0表示無(wú)固定長(zhǎng)度表項(xiàng)

}?Elf32_Shdr;

使用readelf命令命令查看節(jié)頭表內(nèi)容[ubuntu@localhost?interpositioning]$?readelf?-S?main.o

There?are?13?section?headers,?starting?at?offset?0x3f8:

Section?Headers:

[Nr]?Name??????????????Type?????????????Address???????????Offset

Size??????????????EntSize??????????Flags??Link??Info??Align

[?0]???????????????????NULL?????????????0000000000000000??00000000

0000000000000000??0000000000000000???????????0?????0?????0

[?1]?.text?????????????PROGBITS?????????0000000000000000??00000040

0000000000000071??0000000000000000??AX???????0?????0?????1

[?2]?.rela.text????????RELA?????????????0000000000000000??000002d0

0000000000000090??0000000000000018???I??????11?????1?????8

[?3]?.data?????????????PROGBITS?????????0000000000000000??000000b1

0000000000000049??0000000000000000??WA???????0?????0?????1

[?4]?.bss??????????????NOBITS???????????0000000000000000??000000b1

000000000000000c??0000000000000000??WA???????0?????0?????1

[?5]?.rodata???????????PROGBITS?????????0000000000000000??000000b1

0000000000000019??0000000000000000???A???????0?????0?????1

[?6]?.comment??????????PROGBITS?????????0000000000000000??000000ca

0000000000000035??0000000000000001??MS???????0?????0?????1

[?7]?.note.GNU-stack???PROGBITS?????????0000000000000000??000000ff

0000000000000000??0000000000000000???????????0?????0?????1

[?8]?.eh_frame?????????PROGBITS?????????0000000000000000??00000100

0000000000000058??0000000000000000???A???????0?????0?????8

[?9]?.rela.eh_frame????RELA?????????????0000000000000000??00000360

0000000000000030??0000000000000018???I??????11?????8?????8

[10]?.shstrtab?????????STRTAB???????????0000000000000000??00000390

0000000000000061??0000000000000000???????????0?????0?????1

[11]?.symtab???????????SYMTAB???????????0000000000000000??00000158

0000000000000150??0000000000000018??????????12?????9?????8

[12]?.strtab???????????STRTAB???????????0000000000000000??000002a8

0000000000000023??0000000000000000???????????0?????0?????1

Key?to?Flags:

W?(write),?A?(alloc),?X?(execute),?M?(merge),?S?(strings),?l?(large)

I?(info),?L?(link?order),?G?(group),?T?(TLS),?E?(exclude),?x?(unknown)

O?(extra?OS?processing?required)?o?(OS?specific),?p?(processor?specific)

可重定位目標(biāo)文件中,每個(gè)可裝入節(jié)的起始地址總是0。

.bss節(jié)應(yīng)占0x0c大小,但只有裝入內(nèi)存時(shí)才會(huì)分配。

4.2 從程序執(zhí)行角度看ELF文件(可執(zhí)行文件)

從程序執(zhí)行角度看ELF文件

與可重定位目標(biāo)文件不同:

1.ELF頭中,字段 e_entry給出執(zhí)行程序時(shí)第一條指令的地址,而在可重定位文件中,此字段為0。

2.多一個(gè)init節(jié),用于定義init函數(shù),該函數(shù)用來(lái)進(jìn)行可執(zhí)行目標(biāo)文件開(kāi)始執(zhí)行時(shí)的初始化工作。

3.少兩個(gè).rel節(jié)(無(wú)需重定位)。

4.多一個(gè)程序頭表,也稱段頭表,是一個(gè)結(jié)構(gòu)數(shù)組。

使用readelf命令查看ELF頭的內(nèi)容:[ubuntu@localhost?interpositioning]$readelf?-h?main.o

ELF?Header:

Magic:???7f?45?4c?46?02?01?01?00?00?00?00?00?00?00?00?00

Class:?????????????????????????????ELF64

Data:??????????????????????????????2's?complement,?little?endian

Version:???????????????????????????1?(current)

OS/ABI:????????????????????????????UNIX?-?System?V

ABI?Version:???????????????????????0

Type:??????????????????????????????REL?(Relocatable?file)

Machine:???????????????????????????Advanced?Micro?Devices?X86-64

Version:???????????????????????????0x1

Entry?point?address:???????????????0x0

Start?of?program?headers:??????????0?(bytes?into?file)

Start?of?section?headers:??????????1064?(bytes?into?file)

Flags:?????????????????????????????0x0

Size?of?this?header:???????????????64?(bytes)

Size?of?program?headers:???????????32?(bytes)?????????//程序頭表每項(xiàng)32B

Number?of?program?headers:?????????8??????????????????//程序頭表共8項(xiàng)

Size?of?section?headers:???????????64?(bytes)

Number?of?section?headers:?????????13

Section?header?string?table?index:?10????????????????//.strtab在節(jié)頭表中的索引

裝入內(nèi)存時(shí),ELF頭、程序頭表、.init節(jié)、.rodata節(jié)會(huì)被裝入只讀代碼段。.data節(jié)和.bss節(jié)會(huì)被裝入讀寫(xiě)數(shù)據(jù)段。

段頭表能夠描述可執(zhí)行文件中的節(jié)與虛擬空間中的存儲(chǔ)段之間的映射關(guān)系。一個(gè)表項(xiàng)32B,說(shuō)明虛擬地址空間中一個(gè)連續(xù)的片段或一個(gè)特殊的節(jié)。以下是32位系統(tǒng)對(duì)應(yīng)的段頭表數(shù)據(jù)結(jié)構(gòu):typedef?struct?{

Elf32_Word?p_type;???//此數(shù)組元素描述的段的類型,或者如何解釋此數(shù)組元素的信息。

Elf32_Off?p_offset;??//此成員給出從文件頭到該段第一個(gè)字節(jié)的偏移

Elf32_Addr?p_vaddr;??//此成員給出段的第一個(gè)字節(jié)將被放到內(nèi)存中的虛擬地址

Elf32_Addr?p_paddr;??//此成員僅用于與物理地址相關(guān)的系統(tǒng)中。System V忽略所有應(yīng)用程序的物理地址信息。

Elf32_Word?p_filesz;?//此成員給出段在文件映像中所占的字節(jié)數(shù)。可以為0。

Elf32_Word?p_memsz;??//此成員給出段在內(nèi)存映像中占用的字節(jié)數(shù)。可以為0。

Elf32_Word?p_flags;??//此成員給出與段相關(guān)的標(biāo)志。

Elf32_Word?p_align;??//此成員給出段在文件中和內(nèi)存中如何對(duì)齊。

}?Elf32_phdr;

使用readelf命令查看某可執(zhí)行目標(biāo)文件的程序頭表。[ubuntu@localhost?interpositioning]$readelf?-l?main

Elf?file?type?is?EXEC?(Executable?file)

Entry?point?0x400550

There?are?9?program?headers,?starting?at?offset?64

Program?Headers:

Type???????????Offset?????????????VirtAddr???????????PhysAddr

FileSiz????????????MemSiz??????????????Flags??Align

PHDR???????????0x0000000000000040?0x0000000000400040?0x0000000000400040

0x00000000000001f8?0x00000000000001f8??R?E????8

INTERP?????????0x0000000000000238?0x0000000000400238?0x0000000000400238

0x000000000000001c?0x000000000000001c??R??????1

[Requesting?program?interpreter:?/lib64/ld-linux-x86-64.so.2]

LOAD???????????0x0000000000000000?0x0000000000400000?0x0000000000400000

0x00000000000008ac?0x00000000000008ac??R?E????200000

LOAD???????????0x0000000000000e10?0x0000000000600e10?0x0000000000600e10

0x0000000000000240?0x0000000000000248??RW?????200000

DYNAMIC????????0x0000000000000e28?0x0000000000600e28?0x0000000000600e28

0x00000000000001d0?0x00000000000001d0??RW?????8

NOTE???????????0x0000000000000254?0x0000000000400254?0x0000000000400254

0x0000000000000044?0x0000000000000044??R??????4

GNU_EH_FRAME???0x0000000000000780?0x0000000000400780?0x0000000000400780

0x0000000000000034?0x0000000000000034??R??????4

GNU_STACK??????0x0000000000000000?0x0000000000000000?0x0000000000000000

0x0000000000000000?0x0000000000000000??RW?????10

GNU_RELRO??????0x0000000000000e10?0x0000000000600e10?0x0000000000600e10

0x00000000000001f0?0x00000000000001f0??R??????1

程序頭表信息有9個(gè)表項(xiàng),其中兩個(gè)為可裝入段(即Type=LOAD):

第一可裝入段:第0x0000 0~0x0x8ab的長(zhǎng)度為0x8ac字節(jié)的ELF頭、程序頭表、.init、.text和.rodata節(jié),映射到虛擬地址0x400000開(kāi)始長(zhǎng)度為0x8ac字節(jié)的區(qū)域 ,按0x200000=2MB對(duì)齊,具有只讀/執(zhí)行權(quán)限(Flg=RE),是只讀代碼段。

第二可裝入段:第0xe10 ~0x104f的長(zhǎng)度為0x240字節(jié)的.data節(jié)和磁盤(pán)中不占存儲(chǔ)空間的.bss節(jié),映射到虛擬地址0x600e10開(kāi)始長(zhǎng)度為0x248字節(jié)的存儲(chǔ)區(qū)域,在0x248=584B存儲(chǔ)區(qū)中,前0x240= 576B用.data節(jié)內(nèi)容初始化,后面584-576= 8B對(duì)應(yīng).bss節(jié),初始化為0 ,按0x200000 =2MB對(duì)齊,具有可讀可寫(xiě)權(quán)限(Flg=RW),是可讀寫(xiě)數(shù)據(jù)段。

由此看出.bss節(jié)在文件中不占用磁盤(pán)空間,但在存儲(chǔ)器中需要給它分配相應(yīng)大小的空間。

5.總結(jié)

1.鏈接處理涉及到三種目標(biāo)文件格式:可重定位目標(biāo)文件、可執(zhí)行目標(biāo)文件和共享目標(biāo)文件。共享庫(kù)文件是一種特殊的可重定位目標(biāo)。

2.ELF目標(biāo)文件格式可以從編譯鏈接角度和程序執(zhí)行角度兩個(gè)角度看,前者是可重定位目標(biāo)格式,后者是可執(zhí)行目標(biāo)格式。從編譯鏈接角度看,可重定位目標(biāo)文件中包含ELF頭、各個(gè)節(jié)以及節(jié)頭表。可執(zhí)行目標(biāo)文件中包含ELF頭、程序頭表(段頭表)以及各種節(jié)組成的段。

3.bss段在可執(zhí)行目標(biāo)文件中不會(huì)有它的空間,只有當(dāng)可執(zhí)行目標(biāo)文件裝載運(yùn)行時(shí),才會(huì)被分配內(nèi)存(并且位于data段內(nèi)存塊之后),并且初始化為0。

總結(jié)

以上是生活随笔為你收集整理的c语言书籍elf文件,扒一扒ELF文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。