1-栈介绍
基本栈介绍
栈是一种典型的后进先出 (Last in First Out) 的数据结构,其操作主要有压栈 (push) 与出栈 (pop) 两种操作,如下图所示(维基百科)。两种操作都操作栈顶,当然,它也有栈底。

高级语言在运行时都会被转换为汇编程序,在汇编程序运行过程中,充分利用了这一数据结构。每个程序在运行时都有虚拟地址空间,其中某一部分就是该程序对应的栈,用于保存函数调用信息和局部变量。此外,常见的操作也是压栈与出栈。需要注意的是,程序的栈是从进程地址空间的高地址向低地址增长的。
函数调用栈
核心组件
栈指针 (SP)
- x86: ESP (32位), x64: RSP (64位)
- 始终指向栈顶位置
push/pop指令自动修改 SP
基址指针 (BP)
- x86: EBP, x64: RBP
- 作为当前栈帧的基准点
- 用于定位参数和局部变量
指令指针 (IP)
- x86: EIP, x64: RIP
- 存储下一条执行指令地址
call/ret指令修改 IP
函数调用过程(关键!)
调用者 (Caller) 准备
; 1. 参数压栈(从右向左) |
被调函数 (Callee) 序言
function: |
栈帧内存布局(32位示例)
高地址 |
函数返回过程
; 1. 返回值存入EAX(约定) |
Tip
寄存器的图

需要注意的是,32 位和 64 位程序有以下简单的区别:
x86函数参数在函数返回地址的上方
栈帧布局:
高地址
| 参数N | ← EBP + 4*(N+1)
| ... |
| 参数2 | ← EBP + 12
| 参数1 | ← EBP + 8
| 返回地址 | ← EBP + 4
| 保存的EBP | ← EBP
| 局部变量 | ← EBP - 4
低地址
x64System V AMD64 ABI (Linux、FreeBSD、macOS 等采用) 中前六个整型或指针参数依次保存在 RDI, RSI, RDX, RCX, R8 和 R9 寄存器中,如果还有更多的参数的话才会保存在栈上。
内存地址不能大于 0x00007FFFFFFFFFFF,6 个字节长度,否则会抛出异常。
栈帧布局:
高地址
| 额外参数N | ← RBP + 8*(N+1)
| ... |
| 额外参数1 | ← RBP + 16
| 返回地址 | ← RBP + 8
| 保存的RBP | ← RBP
| 局部变量 | ← RBP - 8
低地址
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Rhea's Blog!
评论
