0%

汇编与栈帧1

转自:

参考以上博文的内容,写了一个简单的程序,说明一下汇编调用过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// 源程序 test1.c
#include<stdio.h>
int add(int a, int b){
int c = a + b;
return c;
}
int main()
{
int a = -1;
int b = 0;
int sum = add(a, b);
}
// 我的环境为64位linux系统,需要加上-m32指定以32位方式编译
$ gcc -m32 -g test1.c
$ gdb a.out
(gdb) b main
Breakpoint 1 at 0x80483f7: file test1.c, line 8.
(gdb) b add
Breakpoint 2 at 0x80483e1: file test1.c, line 3.
(gdb) r
Breakpoint 1, main () at test1.c:8
8 int a = -1;
(gdb) disas main
Dump of assembler code for function main:
0x080483f1 <+0>: push %ebp // ebp寄存器存储当前main栈帧栈底, 将ebp入栈,esp减去4字节
0x080483f2 <+1>: mov %esp,%ebp // 把esp的数值赋给ebp
0x080483f4 <+3>: sub $0x10,%esp // 把esp减去16个字节
=> 0x080483f7 <+6>: movl $0xffffffff,-0xc(%ebp) // ebp减去12字节的位置保存直接数-1
0x080483fe <+13>: movl $0x0,-0x8(%ebp) // ebp减去8字节的位置保存直接数0
0x08048405 <+20>: pushl -0x8(%ebp) // ebp减去8字节的位置的值(b的数值)入栈 同时esp减去4字节
0x08048408 <+23>: pushl -0xc(%ebp) // ebp减去12字节的位置的值入栈(a的数值) 同时esp减去4字节 说明参数是按照从右向左的顺序入栈的
0x0804840b <+26>: call 0x80483db <add> // 调用add函数 call指令将返回地址0x0804840b压入栈顶,esp减去4字节,然后程序跳转到add函数的起始地址
0x08048410 <+31>: add $0x8,%esp // esp加上8 清除局部变量占用的空间
0x08048413 <+34>: mov %eax,-0x4(%ebp)
0x08048416 <+37>: mov $0x0,%eax
0x0804841b <+42>: leave
0x0804841c <+43>: ret
End of assembler dump.
(gdb) p $esp
$1 = (void *) 0xffffcc68
(gdb) p $ebp
$2 = (void *) 0xffffcc78
(gdb) disas add
Dump of assembler code for function add:
0x080483db <+0>: push %ebp // ebp寄存器存储当前main栈帧栈底, 将ebp入栈,esp减去4字节
0x080483dc <+1>: mov %esp,%ebp // 把esp的数值赋给ebp
0x080483de <+3>: sub $0x10,%esp // 把esp减去16个字节
=> 0x080483e1 <+6>: mov 0x8(%ebp),%edx // ebp加上8个字节的位置的值 存入寄存器edx
0x080483e4 <+9>: mov 0xc(%ebp),%eax // // ebp加上12个字节的位置的值 存入寄存器eax
0x080483e7 <+12>: add %edx,%eax // edx的数值加上eax的数值存入eax
0x080483e9 <+14>: mov %eax,-0x4(%ebp) // ebx减去4字节的位置保存eax的值
0x080483ec <+17>: mov -0x4(%ebp),%eax //
0x080483ef <+20>: leave // LEAVE指令是将ebp的数值赋给esp,然后popl ebp, 即esp加上4字节
0x080483f0 <+21>: ret // RET指令则是将栈顶的返回地址弹出到EIP,esp+4 然后按照EIP此时指示的指令地址继续执行程序
(gdb) p $ebp
$6 = (void *) 0xffffcc58
(gdb) p $esp
$5 = (void *) 0xffffcc48