在研究如何在程序crash定位出错函数,补充的计算机系统基础知识。此篇主要是介绍IA32中重要的几个汇编指令(以AT&T为例),详情请参考《深入计算机系统2》第三章第三节。
PUSH 和 POP指令图解:最近在研究如何在程序crash定位出错函数,补充的计算机系统基础知识。此篇主要是介绍IA32中重要的几个汇编指令(以AT&T为例),详情请参考《深入计算机系统2》第三章第三节。
PUSH 和 POP
指令的汇编格式:PUSH SRC ;POP DST
指令的基本功能:PUSH指令在程序中常用来暂存某些数据,而POP指令又可将这些数据恢复。
PUSH 等价于:
subl $4, %esp
movl %ebp (%esp)
POP 等价于:
movl (%esp), %ead
addl $4, %esp
CALL,RET和LEAVE
CALL指令的步骤:首先是将返回地址(也就是call指令要执行时EIP的值)压入栈顶,然后是将程序跳转到当前调用的方法的起始地址。执行push和jump指令。
RET指令则是将栈顶的返回地址弹出到EIP,然后按照EIP此时指示的指令地址继续执行程序。
LEAVE指令是将栈指针指向帧指针,然后POP备份的原帧指针到%EBP。
Leave等价于:
movl %ebp %esp
popl %ebp
通常在函数调用中使用堆栈来传递参数,保存函数返回地址和为自动变量分配内存。
通常在进入函数中时有两条命令,如下:
push ebp ; 保存上一个函数的栈帧基地址
mov ebp,esp ; 设置新的函数栈帧基地址
在返回函数前通常有如下两条指令:
mov esp,ebp ; 将当前函数栈帧基地址保存到esp中
pop ebp ; 恢复上一个函数的栈帧基地址
这是前奏。。之后Intel又设计了两条指令来简化上面的两个步骤,那就是ENTER和LEAVE指令。
我先说LEAVE指令吧。。这条指令就相当于 mov esp,ebp 和 pop ebp 两条指令的执行效果。
而ENTER指令要麻烦一点。我先将它的指令格式列出来:
ENTER A,B
A表示的是在栈上分配的临时变量的空间大小,B表示词法嵌套级(我英文不好,原英文是:lexical nesting level)
A很容易理解,就是sub esp,N之类的指令,用来给当前函数的栈帧分配局部变量空间。
B我也不太明白啥意思。不过没关系,一般这个值为0。
举个例子吧,例如:ENTER 4,0 相当于如下三条指令:
push ebp
mov ebp,esp
sub esp,4
就这么简单!但是这条enter指令也有一个先天上的不足,那就是速度慢。所以一般编译器生成代码时很少使用enter指令。还是用以前的老方法,倒是LEAVE指令经常被用到。
联系客服