|
板凳

楼主 |
发表于 2009-12-7 23:34:46
|
只看该作者
调用
调用是一种能够返回的跳转。调用指令是 CALL ,它只有一个操作数 --- 跳转到的位置地址:address 操作数引用程序中的标签,它被转换为函数中的第一条指令的内存地址。
调用返回使用 RET 指令,该指令没有操作数。
执行 CALL 指令时,它把 EIP 寄存器的值放到堆栈中,然后修改 EIP 寄存器以指向被调用的函数地址。当被调用函数完成后,它从堆栈获得过去的 EIP 寄存器值,并且把控制权返回给原始程序。过程如下图所示:
![]()
# calltest.s - An example of using CALL instruction
.section .data
output:
.asciz "This is section %d\\n"
.section .text
.global _start
_start:
pushl $1
pushl $output
call printf
add $8, %esp
call overhere
pushl $3
pushl $output
call printf
add $8, %esp
pushl $0
call exit
overhere:
pushl %ebp
movl %esp, %ebp
pushl $2
pushl $output
call printf
add $8, %esp
movl %ebp, %esp
popl %ebp
ret 编译连接生成可执行文件 calltest 后,先 objdump 看一下可执行文件相关内容:080481b8 <_start>:
80481b8: 6a 01 push $0x1
80481ba: 68 ac 92 04 08 push $0x80492ac
80481bf: e8 d4 ff ff ff call 8048198 <printf@plt>
80481c4: 83 c4 08 add $0x8,%esp
80481c7: e8 16 00 00 00 call 80481e2 <overhere>
80481cc: 6a 03 push $0x3 由上知道 output 标签所在的内存地址为: $0x80492ac;call overhere 语句的下一条的地址为 0x080481cc 。
现在用 gdb 对 calltest 进行调试,就在 call overhere 处下断,然后跟到 overhere 函数里的 pushl output 处,这时查看寄存器内容:(gdb) info registers
eax 0x12 18
ecx 0x0 0
edx 0xb560f4 11886836
ebx 0x632fc0 6500288
esp 0xbf9d6110 0xbf9d6110
ebp 0xbf9d6118 0xbf9d6118
esi 0xbf9d612c -1080205012
edi 0x80481b8 134513080
eip 0x80481ec 0x80481ec <overhere+10>
eflags 0x200292 [ AF SF IF ID ]
cs 0x73 115
ss 0x7b 123
ds 0x7b 123
es 0x7b 123
fs 0x0 0
gs 0x33 51 然后再查看一下堆栈:(gdb) x/8x 0xbf9d6110
0xbf9d6110: 0x080492ac 0x00000002 0x00000000 0x080481cc
0xbf9d6120: 0x00000001 0xbf9d78b6 0x00000000 0xbf9d78d4 堆栈内容从 0xbf9d6110 开始,依次为:
0x080492ac : output 标签地址
0x00000002 : 常数 2
0x00000000 : EBP 寄存器的内容
0x080481cc : 正是 call overhere 的下一条指令地址,ret 返回后,就返回到此处。
最后,运行一下程序:[beyes@localhost assembly]$ ./calltest
This is section 1
This is section 2
This is section 3 |
|