ELF文件解析和反汇编

首先来看一段Unix/Linux下的汇编代码:

#PURPOSE: This program finds the maximum number of a

# set of data items.

##VARIABLES: The registers have the following uses:

## %edi - Holds the index of the data item being examined

# %ebx - Largest data item found

# %eax - Current data item

## The following memory locations are used:

## data_items - contains the item data. A 0 is used

# to terminate the data

#

.section .data

data_items:  

.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

.section .text

.globl _start

_start:

movl $0, %edi

movl data_items(,%edi,4), %eax

movl %eax, %ebx

start_loop:

cmpl $0, %eax 

je loop_exit

incl %edi 

movl data_items(,%edi,4), %eax

cmpl %ebx, %eax 

jle start_loop

movl %eax, %ebx 

jmp start_loop

loop_exit: 

movl $1, %eax

int $0x80

被红色注释的部分就是汇编代码,先大概的解释一下这段代码的意思。.section .data表示的是数据段。

data_items:  

.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

表示的是定义的一个long型的数组。

.section .text 表示的是代码区段。下面的部分就是真正的代码部分。

.globl _start 表示的定义了一个全局的标识符_start,相当C语言中的标签作用,_start要被链接器使用,相当C语言中的main函数一样,是整个程序的入口。

用%edi寄存器中的值表示数组下标

movl data_items(,%edi,4), %eax

movl %eax, %ebx

表示把取数组data_items中的第%edi的值,存放至寄存器%eax,同时%ebx表示的是数组中的最大值,初始化为数组的第一个元素。

start_loop,loop_exit都属于标签性质。

cmpl $0, %eax 

je loop_exit

因为我们定义数组的时候,最后一个元素为0,即0为哨兵,比较%eax和0,如果相等的话,表示程序已经完成,跳转至loop_exit处执行。

incl %edi 

movl data_items(,%edi,4), %eax

cmpl %ebx, %eax

否则移动数组下标,取数组的下一个元素值,与%ebx进行比较,若%eax中的值比%ebx值大,则将%eax值给%ebx,保持%ebx维持是数组的最大值。

movl $1, %eax

int $0x80

表示exit退出,并且退出码为1.

上面所讲的就是该段汇编代码的涵义。.

把上述的汇编代码编辑在test.s文档中,然后执行下面的命令:

as test.s -o test.o

ld test.o -o test

 

Unix/Linux中的可执行文件都是采用的ELF文件格式标准,但是有3中不同的类型:

<1>.可重定位的目标文件(Relocatable Object file)

<2>.可执行文件(Executable file)

<3>.共享库(Shared library)

我们通过分析ELF文件的组成,来了解编译和链接的过程。

我们用Linux下带的工具来查看elf文件,用下述命令即可:

$ readelf -a test.o

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: REL (Relocatable file)

Machine: Intel 80386

Version: 0x1

Entry point address: 0x0

Start of program headers: 0 (bytes into file)

Start of section headers: 200 (bytes into file)

Flags: 0x0

Size of this header: 52 (bytes)

Size of program headers: 0 (bytes)

Number of program headers: 0

Size of section headers: 40 (bytes)

Number of section headers: 8

Section header string table index: 5

...

上面的就是被解读出来的elf文件信息。
ELF Header中描述了操作系统是UNIX,体系结构是80386。Section Header Table中有8个Section Header,在文件中的位置(或者叫文件地址)从200(0xc8)开始,每个40字节,共320字节,到文件地址0x207结束。这个目标文件没有Program Header。

 

如果想要从目标文件反汇编的话,可以执行下述命令即可。

$ objdump -d test.o

test.o: file format elf32-i386

Disassembly of section .text:

00000000 <_start>:

0: bf 00 00 00 00           mov $0x0,%edi

5: 8b 04 bd 00 00 00 00     mov 0x0(,%edi,4),%eax

c: 89 c3                    mov %eax,%ebx

0000000e <start_loop>:

e: 83 f8 00                 cmp $0x0,%eax

11: 74 10                   je 23 <loop_exit>

13: 47                      inc %edi

14: 8b 04 bd 00 00 00 00    mov 0x0(,%edi,4),%eax

1b: 39 d8                   cmp %ebx,%eax

1d: 7e ef                   jle e <start_loop>

1f: 89 c3                   mov %eax,%ebx

21: eb eb                   jmp e <start_loop>

00000023 <loop_exit>:

23: b8 01 00 00 00           mov $0x1,%eax

28: cd 80                    int $0x80

 上面右边的代码就是反汇编后生成的代码,对比一下本身的代码和反汇编后的有何区别,会发现很多该出现地址的地方都是0,这是因为程序只有在链接的时候才会真正的把函数以及变量的地址加载进代码中来。

 

我们对可执行程序反汇编一下,就知道结果了:

$ objdump -d test

test: file format elf32-i386

Disassembly of section .text:

08048074 <_start>:

8048074: bf 00 00 00 00                  mov $0x0,%edi

8048079: 8b 04 bd a0 90 04 08            mov 0x80490a0(,%edi,4),%eax

8048080: 89 c3                           mov %eax,%ebx

08048082 <start_loop>:

8048082: 83 f8 00                        cmp $0x0,%eax

8048085: 74 10                           je 8048097 <loop_exit>

8048087: 47                              inc %edi

8048088: 8b 04 bd a0 90 04 08            mov 0x80490a0(,%edi,4),%eax

804808f: 39 d8                           cmp %ebx,%eax

8048091: 7e ef                           jle 8048082 <start_loop>

8048093: 89 c3                           mov %eax,%ebx

8048095: eb eb                           jmp 8048082 <start_loop>

08048097 <loop_exit>:

8048097: b8 01 00 00 00                  mov $0x1,%eax

804809c: cd 80                           int $0x80
现在反汇编的代码中已经把绝对地址都加在进程序中了。从这个角度来理解编译和链接应该更深入一些,编译只是检查语法错误,对应的地址都是虚拟地址(即被MMU单元截获了地址),链接时,把虚拟地址转化为绝对地址,加载进可执行文件中。

 

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值