linux 文件格式elf,linux ELF 文件格式 | ZION
ELF 文件類型
ELF (Executable Linkable Format) 是linux下的可執(zhí)行文件格式,與windows下的PE (Portable Executable) 格式一樣,都是COFF (Common File Format)文件格式的變種。在linux下除了可執(zhí)行文件,編譯過程中產(chǎn)生的目標(biāo)文件(.o 文件),動(dòng)態(tài)鏈接文件(.so文件),靜態(tài)鏈接庫文件(.a 文件) ,核心轉(zhuǎn)儲(chǔ)文件(Core Dump File)都按照 ELF 格式存儲(chǔ)。查看ELF文件類型可以用file命令
[code language="bash"]
$ file /lib/libc-2.11.2.so
/lib/libc-2.11.2.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
[/code]
ELF 文件結(jié)構(gòu)
ELF文件結(jié)構(gòu)在 /usr/include/elf.h 中有完整定義
一些有用的命令:
file elf_ile 輸出ELF各個(gè)段的size
readelf [options] elf_file
-S 輸出 section header
-t 輸出符號(hào)表 symbol table
-h 輸出ELF文件頭信息
objdump [options] elf_file
-h 輸出文件基本ELF信息
-d 反匯編代碼段
-s 輸出完整內(nèi)容
-r 查看重定位表
-D 反匯編所有段內(nèi)容
-S 輸出內(nèi)容包含源代碼(需要gcc -g 參數(shù)支持)
ELF結(jié)構(gòu)中比較重要的幾個(gè)段:
.data 數(shù)據(jù)段,存放已經(jīng)初始化的全局/靜態(tài)變量
.bss(Block Started by Symbol) 存放未初始化的全局變量和靜態(tài)變量,因?yàn)檫@些變量
在程序加載的時(shí)候都會(huì)被初始化為零,所以不需要存放實(shí)際的數(shù)據(jù),只需要預(yù)留位置
就可以了。
.text 代碼段,存放源代碼編譯后的機(jī)器指令
.rodata 只讀數(shù)據(jù)段,存放只讀變量
.symtab(Symbol Table) 符號(hào)表
.strtab(String Table) 字符串表
.plt(Procedure Linkage Table) 動(dòng)態(tài)鏈接跳轉(zhuǎn)表
.got(Global Offset Table) 動(dòng)態(tài)鏈接全局入口表
動(dòng)態(tài)鏈接和靜態(tài)鏈接
在靜態(tài)鏈接過程中,編譯器將需要重定位的符號(hào)寫在ELF結(jié)構(gòu)中的重定位表(Relocation Table)內(nèi),之后鏈接器(Linker)分析重定位表,從全局符號(hào)表中找到相應(yīng)符號(hào)的地址,完成重定位
如果希望某個(gè)代碼文件生成的對象文件可以被動(dòng)態(tài)的鏈接,需要在編譯時(shí)給GCC指定 -fPIC 參數(shù),PIC(Position Independent Code)即位置無關(guān)代碼
[code language="C"]
/***** echo.c *******/
#include
extern int global_variable;
int echo(){
printf("%dn",global_variable);
return 0;
}
[/code]
[code language="C"]
/******* main.c *******/
#include
extern int echo();
int global_variable = 0;
int main() {
echo();
return 0;
}
[/code]
[code language="bash"]
$ g++ -fPIC -shared echo.cc -o libecho.so
$ g++ -c main.cc -o main.o
$ g++ main.o -o dynamic -lecho -L.
$ g++ main.cc echo.cc -o static
$ objdump -d main.o
00000000 :
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: e8 fc ff ff ff call 7
b: b8 00 00 00 00 mov $0x0,%eax
10: 89 ec mov %ebp,%esp
12: 5d pop %ebp
13: c3 ret
$ objdump -d dynamic
08048584 :
8048584: 55 push %ebp
8048585: 89 e5 mov %esp,%ebp
8048587: 83 e4 f0 and $0xfffffff0,%esp
804858a: e8 11 ff ff ff call 80484a0
804858f: b8 00 00 00 00 mov $0x0,%eax
8048594: 89 ec mov %ebp,%esp
8048596: 5d pop %ebp
8048597: c3 ret
8048598: 90 nop
$ objdump -d static
080484c8 :
80484c8: 55 push %ebp
80484c9: 89 e5 mov %esp,%ebp
80484cb: 83 e4 f0 and $0xfffffff0,%esp
80484ce: e8 d1 ff ff ff call 80484a4
80484d3: b8 00 00 00 00 mov $0x0,%eax
80484d8: 89 ec mov %ebp,%esp
80484da: 5d pop %ebp
80484db: c3 ret
80484dc: 90 nop
PIC sample
$ g++ echo.cc -shared -o libecho.so
0000051c :
51c: 55 push %ebp
51d: 89 e5 mov %esp,%ebp
51f: 83 ec 18 sub $0x18,%esp
522: a1 00 00 00 00 mov 0x0,%eax
527: 89 44 24 04 mov %eax,0x4(%esp)
52b: c7 04 24 94 05 00 00 movl $0x594,(%esp)
532: e8 fc ff ff ff call 533
537: b8 00 00 00 00 mov $0x0,%eax
53c: c9 leave
53d: c3 ret
53e: 90 nop
53f: 90 nop
$ g++ echo.cc -shared -fPIC -o libecho.so
0000052c :
52c: 55 push %ebp
52d: 89 e5 mov %esp,%ebp
52f: 53 push %ebx
530: 83 ec 14 sub $0x14,%esp
533: e8 ef ff ff ff call 527 <__i686.get_pc_thunk.bx>
538: 81 c3 e4 11 00 00 add $0x11e4,%ebx
53e: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax
544: 8b 00 mov (%eax),%eax
546: 89 44 24 04 mov %eax,0x4(%esp)
54a: 8d 83 a8 ee ff ff lea -0x1158(%ebx),%eax
550: 89 04 24 mov %eax,(%esp)
553: e8 f0 fe ff ff call 448
558: b8 00 00 00 00 mov $0x0,%eax
55d: 83 c4 14 add $0x14,%esp
560: 5b pop %ebx
561: 5d pop %ebp
[/code]
GOT 和 PLT
[code language="C"]
#include
void foo() {
printf("test 0x%06xn", 10);
return;
}
int main () {
foo();
return 0;
}
[/code]
編譯后查看ELF的信息
[code language="bash"]
gcc -g test.c -o test
objdump -S test
[/code]
以下為部分段的內(nèi)容:
[code language="C"]
080482cc :
80482cc: ff 35 c8 95 04 08 pushl 0x80495c8
80482d2: ff 25 cc 95 04 08 jmp *0x80495c
80482d8: 00 00 add %al,(%eax)
080482fc :
80482fc: ff 25 d8 95 04 08 jmp *0x80495d8
8048302: 68 10 00 00 00 push $0x10
8048307: e9 c0 ff ff ff jmp 80482cc
int main () {
80483f0: 55 push %ebp
80483f1: 89 e5 mov %esp,%ebp
80483f3: 83 ec 08 sub $0x8,%esp
80483f6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
foo();
80483fd: e8 ce ff ff ff call 80483d0
8048402: b8 00 00 00 00 mov $0x0,%eax
return 0;
8048407: 83 c4 08 add $0x8,%esp
804840a: 5d pop %ebp
804840b: c3 ret
void foo() {
80483d0: 55 push %ebp
80483d1: 89 e5 mov %esp,%ebp
80483d3: 83 ec 08 sub $0x8,%esp
80483d6: 8d 05 d0 84 04 08 lea 0x80484d0,%eax
printf("testn");
80483dc: 89 04 24 mov %eax,(%esp)
80483df: e8 18 ff ff ff call 80482fc
return;
80483e4: 89 45 fc mov %eax,-0x4(%ebp)
80483e7: 83 c4 08 add $0x8,%esp
80483ea: 5d pop %ebp
80483eb: c3 ret
80483ec: 0f 1f 40 00 nopl 0x0(%eax)
[/code]
總結(jié)
以上是生活随笔為你收集整理的linux 文件格式elf,linux ELF 文件格式 | ZION的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 文件系统只读方案
- 下一篇: 文献管理工具——Zotero教程