汇编语言:基于x86处理器-学习笔记-第八章

《汇编语言:基于x86处理器(原书第7版)》
第八章学习笔记

堆栈帧

《汇编语言:基于x86处理器(原书第7版)》 Page 227

堆栈帧 (stack frame)(或活动记录 (activation record))是一块堆栈保留区域,用于存放被传递的实际参数子程序的返回值局部变量以及被保存的寄存器。堆栈帧的创建步骤如下所示:

  1. 被传递的实际参数。如果有,则压入堆栈。
  2. 当子程序被调用时,使该子程序的返回值压入堆栈。
  3. 子程序开始执行时,EBP 被压入堆栈。
  4. 设置 EBP 等于 ESP。从这时开始,EBP 就变成了该子程序所有参数的引用基址。
  5. 如果有局部变量,修改 ESP 以便在堆栈中为这些变量预留空间。
  6. 如果需要保存寄存器,就将它们压入堆栈。
  • ESP 用于寻址堆栈(一种系统内存结构)数据。它极少用于一般算术运算和数据传输,通常被称为扩展堆栈指针 (extended stack pointer) 寄存器。
  • 高级语言通过 EBP 来引用堆栈中的函数参数和局部变量。除了高级编程,它不用于一般算术运算和数据传输。它常常被称为扩展帧指针 (extended frame pointer) 寄存器。

程序内存模式和对参数传递规则的选择直接影响到堆栈帧的结构。

学习用堆栈传递参数有个好理由:几乎所有的高级语言都会用到它们。比如如果想要在 32 位 Windows 应用程序接口(API)中调用函数,就必须用堆栈传递参数。而 64 位程序可以使用另一种不同的参数传递规则。

访问堆栈参数

高级语言有多种方式来对函数调用的参数进行初始化和访问。以 C 和 C++ 语言为例,它们以保存 EBP 寄存器并使该寄存器指向栈顶的语句为开始 (prologue)。然后,根据实际情况,它们可以把某些寄存器入栈,以便在函数返回时恢复这些寄存器的值。在函数结尾 (epilogue) 部分,恢复 EBP 寄存器,并用 RET 指令返回调用者。

ENTER 指令

ENTER 指令为被调用过程自动创建堆栈帧。它为局部变量保留堆栈空间,把 EBP 入栈。具体来说,它执行三个操作:

  • 把 EBP 入栈(push EBP
  • 把 EBP 设置为堆栈帧的基址(mov EBP, ESP
  • 为局部变量保留空间(sub ESP, numbytes

ENTER有两个操作数:第一个是常数,定义为局部变量保存的堆栈空间字节数;第二个定义了过程的词法嵌套级。
$$
ENTER \space \space numbytes, \space nestinglevel
$$
这两个操作数都是立即数。Numbytes 总是向上舍入为 4 的倍数,以便 ESP 对齐双字边界。Nestinglevel 确定了从主调过程堆栈帧复制到当前帧的堆栈帧指针的个数。

示例

ENTER 指令为局部变量保留了 8 个字节的堆栈空间:

1
2
MySub PROC
enter 8, 0

它与如下指令等效:

1
2
3
4
MySub PROC
push ebp
mov ebp, esp
sub esp, 8

下图为执行 ENTER 指令前后的堆栈示意图。

LEAVE 指令

LEAVE 指令结束一个过程的堆栈帧。它反转了之前的 ENTER 指令操作:恢复了过程被调用时 ESP 和 EBP 的值。再次以 MySub 过程为例,现在可以编码如下:

1
2
3
4
5
6
7
MySub PROC
enter 8,0
.
.
leave
ret
MySub ENDP

下面是与之等效的指令序列,其功能是在堆栈中保存和删除 8 个字节的局部变量:

1
2
3
4
5
6
7
8
9
10
MySub PROC
push ebp
mov ebp, esp
sub esp, 8
.
.
mov esp, ebp
pop ebp
ret
MySub ENDP

LOCAL 指令

不难想象,Microsoft 创建 LOCAL 伪指令是作为 ENTER 指令的高级替补。

LOCAL 声明一个或多个变量名,并定义其大小属性。(另一方面,ENTER 则只为局部变量保留一块未命名的堆栈空间。)如果要使用 LOCAL 伪指令,它必须紧跟在 PROC 伪指令的后面。其语法如下所示:

$$
LOCAL \space \space varlist
$$
$varlist$ 是变量定义列表,用逗号分隔表项,可选为跨越多行。每个变量定义采用如下格式:
$$
label: \space type
$$
其中,标号可以为任意有效标识符,类型既可以是标准类型(WORD、DWORD等),也可以是用户定义类型。

示例

1
2
BubbleSort PROC
LOCAL temp: DWORD, SwapFlag: BYTE

汇编语言:基于x86处理器-学习笔记-第八章
https://luoyuy.top/posts/19271da3fc19/
作者
LuoYu-Ying
发布于
2023年1月3日
许可协议