分享

linux ELF 文件格式 | ZION

 astrotycoon 2013-08-21
  • ELF 文件类型

ELF (Executable Linkable Format) 是linux下的可执行文件格式,与windows下的PE (Portable Executable) 格式一样,都是COFF (Common File Format)文件格式的变种。在linux下除了可执行文件,编译过程中产生的目标文件(.o 文件),动态链接文件(.so文件),静态链接库文件(.a 文件) ,核心转储文件(Core Dump File)都按照 ELF 格式存储。查看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 文件结构

ELF文件结构在 /usr/include/elf.h 中有完整定义

一些有用的命令:

file elf_ile 输出ELF各个段的size

readelf [options] elf_file
        -S 输出 section header
        -t 输出符号表 symbol table
        -h 输出ELF文件头信息

objdump [options] elf_file
        -h 输出文件基本ELF信息
        -d 反汇编代码段
        -s 输出完整内容
        -r 查看重定位表
        -D 反汇编所有段内容
        -S 输出内容包含源代码(需要gcc -g 参数支持)

ELF结构中比较重要的几个段:

.data 数据段,存放已经初始化的全局/静态变量
.bss(Block Started by Symbol) 存放未初始化的全局变量和静态变量,因为这些变量
     在程序加载的时候都会被初始化为零,所以不需要存放实际的数据,只需要预留位置
     就可以了。
.text 代码段,存放源代码编译后的机器指令
.rodata 只读数据段,存放只读变量
.symtab(Symbol Table) 符号表
.strtab(String Table) 字符串表
.plt(Procedure Linkage Table) 动态链接跳转表
.got(Global Offset Table) 动态链接全局入口表
  • 动态链接和静态链接

在静态链接过程中,编译器将需要重定位的符号写在ELF结构中的重定位表(Relocation Table)内,之后链接器(Linker)分析重定位表,从全局符号表中找到相应符号的地址,完成重定位

如果希望某个代码文件生成的对象文件可以被动态的链接,需要在编译时给GCC指定 -fPIC 参数,PIC(Position Independent Code)即位置无关代码

[code language="C"]
/***** echo.c *******/
#include <stdio.h>
extern int global_variable;
int echo(){
printf("%dn",global_variable);
return 0;
}
[/code]

 

[code language="C"]
/******* main.c *******/
#include <stdio.h>
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 <main>:
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 <main+0x7>
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 <main>:
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 <echo@plt>
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 <main>:
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 <echo>
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 <echo>:
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 <echo+0x17>
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 <echo>:
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 <printf@plt>
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]

以下为部分段的内容:

[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]

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约