汇编指令执行过程分析
一、编写C程序,并编译
// main.c
int g(int x)
{
return x + 1;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(1) + 1;
}
$ gcc –S –o main.s main.c -m32
编译后
删除以“.”开头的辅助信息后
g:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
addl $1, %eax
popl %ebp
ret
f:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call g
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl $1, (%esp)
call f
addl $1, %eax
leave
ret
二、下面分析过程
1.首先执行main函数,
pushl %ebp
保存调用函数的基址(ebp中)到栈中,压栈操作此时esp自动下移一个地址空间(4个字节)
movl %esp, %ebp
将esp的内容放到ebp中,设置ebp为当前被调用函数的基址指针,即当前栈顶
subl $4, %esp
esp下移一个地址空间(4个字节),为当前函数分配1个栈空间(4个字节)用于存储局部变量
movl $1, (%esp)
将1放到esp当前指向的位置
call f
=pushl %eip(*) movl f %eip(*)
将此时eip中的值(下一条指令addl $1, %eax
)压栈,然后将f函数的地址放到eip中,这样程序转而执行f函数。
2.执行f函数
pushl %ebp
保存调用函数的基址(ebp中)到栈中,压栈操作此时esp自动下移一个地址空间(4个字节)
movl %esp, %ebp
将esp的内容放到ebp中,设置ebp为当前被调用函数的基址指针,即当前栈顶
subl $4, %esp
esp下移一个地址空间(4个字节),为当前函数分配1个栈空间(4个字节)用于存储局部变量
movl 8(%ebp), %eax
ebp中的地址上移2个(8个字节)地址空间的内容放到eax中,也就是将数字1放到eax中
movl %eax, (%esp)
将eax中的内容放到esp当前指向的位置
call g
=pushl %eip(*) movl g %eip(*)
将此时eip中的值(下一条指令leave
)压栈,然后将g函数的地址放到eip中,这样程序转而执行g函数。
3.执行g函数
pushl %ebp
保存调用函数的基址(ebp中)到栈中,压栈操作此时esp自动下移一个地址空间(4个字节)
movl %esp, %ebp
将esp的内容放到ebp中,设置ebp为当前被调用函数的基址指针,即当前栈顶
movl 8(%ebp), %eax
将ebp上移2个地址空间的内容放到eax中,就是数字1
addl $1, %eax
将1与eax中的数相加,也就是2放到eax中
popl %ebp
恢复ebp为调用函数基址
ret
=popl %eip(*)
就是f函数中的leave
4.返回执行f函数
leave
=movl %ebp,%esp popl %ebp
将ebp中的那内容放到esp,将回复ebp为调用函数基址
ret
=popl %eip(*)
就是main函数中的addl $1, %eax
5.返回执行main函数
addl $1, %eax
将1与eax中的内容相加,也就是1+2=3,将3放到eax中
leave
=movl %ebp,%esp popl %ebp
将ebp中的那内容放到esp,将回复ebp为调用函数基址
ret
返回main函数之前的堆栈