|
板凳

楼主 |
发表于 2010-12-5 22:48:48
|
只看该作者
可执行ELF文件分析
将上面的目标文件链接成可执行文件后再用 readelf 查看其中的输出信息: ELF Header:
Magic: 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
Class: ELF32
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Intel 80386
Version: 0x1
Entry point address: 0x8048074
Start of program headers: 52 (bytes into file)
Start of section headers: 260 (bytes into file)
Flags: 0x0
Size of this header: 52 (bytes)
Size of program headers: 32 (bytes)
Number of program headers: 2
Size of section headers: 40 (bytes)
Number of section headers: 6
Section header string table index: 3
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .text PROGBITS 08048074 000074 000038 00 AX 0 0 4
[ 2] .data PROGBITS 080490ac 0000ac 000031 00 WA 0 0 4
[ 3] .shstrtab STRTAB 00000000 0000dd 000027 00 0 0 1
[ 4] .symtab SYMTAB 00000000 0001f4 0000b0 10 5 7 4
[ 5] .strtab STRTAB 00000000 0002a4 000040 00 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)
There are no section groups in this file.
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x08048000 0x08048000 0x000ac 0x000ac R E 0x1000
LOAD 0x0000ac 0x080490ac 0x080490ac 0x00031 0x00031 RW 0x1000
Section to Segment mapping:
Segment Sections...
00 .text
01 .data
There is no dynamic section in this file.
There are no relocations in this file.
There are no unwind sections in this file.
Symbol table '.symtab' contains 11 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048074 0 SECTION LOCAL DEFAULT 1
2: 080490ac 0 SECTION LOCAL DEFAULT 2
3: 080490ac 0 NOTYPE LOCAL DEFAULT 2 string1
4: 080490d8 0 NOTYPE LOCAL DEFAULT 2 length
5: 080490dc 0 NOTYPE LOCAL DEFAULT 2 string2
6: 080480a0 0 NOTYPE LOCAL DEFAULT 1 notfound
7: 08048074 0 NOTYPE GLOBAL DEFAULT 1 _start
8: 080490dd 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
9: 080490dd 0 NOTYPE GLOBAL DEFAULT ABS _edata
10: 080490e0 0 NOTYPE GLOBAL DEFAULT ABS _end
No version information found in this file.
文件类型 Type 已经改为 EXEC 。入口点地址 Entry point address 变为 0x8048074 而不是原来的 0x0。这个地址就是加载到内存时第一条指令所在的地址,也是 _start 标签所在的地址,且为虚拟地址。有趣的是,连接器在对编译时没有添加 -g (可调试) 选项的目标文件链接生成的可执行文件,它们的入口地址是一样的(0x8048074),如果是添加了 -g 选项,那么会是另外一个入口地址,如 0x80481b8 。
在 Section Headers 可以看到,.bss 和 .rel.tex 已经被删掉。这是因为,程序中不存在任何未初始化的变量,所以无需 .bss ;而 .rel.text 在链接过程中使用,在链接完成后,也将被删除。
现在具体看下 .rel.text 如何提供重定位信息:
首先比对一下目标文件 *.o 和 可执行文件的反汇编信息。下面是目标文件的反汇编:
# objdump -d sca.o
sca.o: file format elf32-i386
Disassembly of section .text:
00000000 <_start>:
0: 90 nop
1: 8d 3d 00 00 00 00 lea 0x0,%edi #00000003
7: 8d 35 30 00 00 00 lea 0x30,%esi #00000009
d: 8b 0d 2c 00 00 00 mov 0x2c,%ecx #0000000f
13: ac lods %ds:(%esi),%al
14: fc cld
15: f2 ae repnz scas %es:(%edi),%al
17: 75 13 jne 2c <notfound>
19: 66 2b 0d 2c 00 00 00 sub 0x2c,%cx #0000001c
20: 66 f7 d9 neg %cx
23: b8 01 00 00 00 mov $0x1,%eax
28: 89 cb mov %ecx,%ebx
2a: cd 80 int $0x80
0000002c <notfound>:
2c: b8 01 00 00 00 mov $0x1,%eax
31: bb 00 00 00 00 mov $0x0,%ebx
36: cd 80
可执行文件的反汇编:
# objdump -d sca
sca: file format elf32-i386
Disassembly of section .text:
08048074 <_start>:
8048074: 90 nop
8048075: 8d 3d ac 90 04 08 lea 0x80490ac,%edi
804807b: 8d 35 dc 90 04 08 lea 0x80490dc,%esi
8048081: 8b 0d d8 90 04 08 mov 0x80490d8,%ecx
8048087: ac lods %ds:(%esi),%al
8048088: fc cld
8048089: f2 ae repnz scas %es:(%edi),%al
804808b: 75 13 jne 80480a0 <notfound>
804808d: 66 2b 0d d8 90 04 08 sub 0x80490d8,%cx
8048094: 66 f7 d9 neg %cx
8048097: b8 01 00 00 00 mov $0x1,%eax
804809c: 89 cb mov %ecx,%ebx
804809e: cd 80 int $0x80
080480a0 <notfound>:
80480a0: b8 01 00 00 00 mov $0x1,%eax
80480a5: bb 00 00 00 00 mov $0x0,%ebx
80480aa: cd 80 int $0x80
对比两个反汇编,可以看到,在目标文件的反汇编输出中,第一列为指令的偏移值;而在对可执行文件的反汇编输出中,第一列都改为了绝对地址。
在指令码部分,目标文件中的粉红色加亮部分被可执行文件中的蓝色加亮部分所替代。那么,这些替代信息是依据什么来做呢?答案就是 .rel.text 中输出的信息: 00000003 00000201 R_386_32 00000000 .data
00000009 00000201 R_386_32 00000000 .data
0000000f 00000201 R_386_32 00000000 .data
0000001c 00000201 R_386_32 00000000 .data
可以看到,上面的红色部分就是要重新定位(relocate)的内容的偏移。这也就是为什么说,还未链接成可执行文件的目标文件就是可重定位文件了。
在 Program Headers 中所显示的 PhysAddr 是没有意义的,因为在用户态,面对的都是虚拟地址,而不是物理地址(x86 平台至少如此,但 MIPS 平台则不一定,因为在 MIPS 平台,在 linux 内核里,可以选择是否允许用户态直接访问内核态)。
还有,我们看到 Align 的值为 0x1000,即 4K,这正是 x86 物理页面的大小。程序在加载时,也会按照这 4K 页面对其方式来加载。在上面,程序段 .text 被加载在从 0x08048000 开始的 4K 的页里,而 .data 段则被加载到 0x08049000 开始的 4K 大小的页里。但这里要注意的是,.data 段的加载并不会直接就从 0x08049000 加载,而是从 0x080490ac 这里加载。这是因为为了简化链接器和加载器的实现,规定文件在文件页面里偏移多少,那么在加载到内存里时也同样要偏移多少。
|
|