摘要:在 x86 汇编语言 中,"PUSH" 指令用于 将数据压入栈(Stack),栈是一种 后进先出(LIFO) 的数据结构,常用于 保存寄存器值、传递参数、临时存储数据 等场景。
在 x86 汇编语言 中,"PUSH" 指令用于 将数据压入栈(Stack),栈是一种 后进先出(LIFO) 的数据结构,常用于 保存寄存器值、传递参数、临时存储数据 等场景。
***
1. "PUSH" 指令的基本用法
语法
PUSH 源操作数
- 源操作数 可以是:
- 16位/32位寄存器(如 "AX", "EAX", "BX", "EBX")。
- 16位/32位内存地址(如 "[BX]", "[ESI]")。
- 立即数(如 "PUSH 1234h")。
功能
1. 栈指针("ESP" 或 "SP")递减(栈向低地址增长)。
2. 将数据存入栈顶("[ESP]" 或 "[SP]" 指向的位置)。
***
2. "PUSH" 的具体示例
(1)压入寄存器
PUSH EAX ; 32位模式:ESP -= 4,EAX 存入 [ESP]
PUSH AX ; 16位模式:SP -= 2,AX 存入 [SP]
- 32位模式下:
- "ESP" 减少 4 字节(因为 "EAX" 是 32 位)。
- "EAX" 的值存入 "[ESP]"。
- 16位模式下:
- "SP" 减少 2 字节(因为 "AX" 是 16 位)。
- "AX" 的值存入 "[SP]"。
(2)压入内存数据
PUSH [EBX] ; 将 EBX 指向的内存数据(32位)压栈
PUSH WORD [SI] ; 将 SI 指向的内存数据(16位)压栈
(3)压入立即数
PUSH 1234h ; 16位模式下:压入 0x1234
PUSH DWORD 5678h ; 32位模式下:压入 0x5678
- 注意:
- 在 16位模式 下,"PUSH 1234h" 默认是 16位操作。
- 在 32位模式 下,需显式指定 "DWORD" 或 "WORD"。
***
3. "PUSH" 的底层操作
32位模式("PUSH EAX")
SUB ESP, 4 ; ESP -= 4(栈指针下移)
MOV [ESP], EAX ; 将 EAX 存入栈顶
- 等价于:PUSH EAX
16位模式("PUSH AX")
SUB SP, 2 ; SP -= 2(栈指针下移)
MOV [SP], AX ; 将 AX 存入栈顶
- 等价于:PUSH AX
***
4. "PUSH" 的常见用途
(1)保存寄存器值
PUSH EAX
PUSH EBX
; ...(其他操作)
POP EBX ; 恢复 EBX
POP EAX ; 恢复 EAX
- 用途:在函数调用或中断处理时,保护寄存器不被修改。
(2)传递函数参数
PUSH 3 ; 第三个参数
PUSH 2 ; 第二个参数
PUSH 1 ; 第一个参数
CALL my_func ; 调用函数
ADD ESP, 12 ; 清理栈(stdcall 调用约定)
- 用途:在 C 调用约定(cdecl) 或 stdcall 中,参数通过栈传递。
(3)临时存储数据
MOV EAX, 1234h
PUSH EAX ; 临时保存 EAX
; ...(其他操作)
POP EAX ; 恢复 EAX
***
5. 注意事项
1. 栈对齐:
- 在 32/64位模式 下,栈通常需要 4/8 字节对齐(如 "ESP % 4 == 0")。
- 不对齐可能导致性能下降或错误(如 SSE 指令要求 16 字节对齐)。
2. 栈溢出:
- 如果 "PUSH" 次数过多,可能导致 栈溢出("ESP" 超出栈空间)。
- 典型错误:"Stack Overflow" 或访问非法内存。
3. 与 "POP" 配对使用:
- "PUSH" 和 "POP" 必须成对出现,否则会导致栈不平衡。
- 示例错误:PUSH EAX
; 忘记 POP EAX
RET ; 错误!ESP 指向错误地址
4. 16位 vs 32位模式:
- 16位模式:"PUSH" 操作 16位数据("SP -= 2")。
- 32位模式:"PUSH" 操作 32位数据("ESP -= 4")。
- 64位模式:"PUSH" 操作 64位数据("RSP -= 8")。
***
6. 示例代码
32位模式(保存并恢复寄存器)
section .text
global _start
_start:
MOV EAX, 1234h
MOV EBX, 5678h
; 保存寄存器
PUSH EAX
PUSH EBX
; ...(其他操作)
; 恢复寄存器
POP EBX
POP EAX
; 退出程序
MOV EAX, 1
INT 0x80
16位模式(DOS 程序)
org 100h
start:
MOV AX, 1234h
PUSH AX ; 保存 AX
; ...(其他操作)
POP AX ; 恢复 AX
; 返回 DOS
MOV AH, 4Ch
INT 21h
***
7. 总结
| 操作 | 功能 | 栈指针变化 |
||||
| "PUSH reg" | 将寄存器值压栈 | "ESP -= 4"(32位) |
| "PUSH [mem]" | 将内存数据压栈 | "ESP -= 4"(32位) |
| "PUSH imm" | 将立即数压栈 | "ESP -= 4"(32位) |
| "PUSHAD" | 压入所有通用寄存器(32位) | "ESP -= 32" |
| "PUSHF" | 压入标志寄存器(EFLAGS) | "ESP -= 4"(32位) |
- "PUSH" 会 减少栈指针(栈向低地址增长)。
- 必须与 "POP" 配对使用,避免栈不平衡。
- 在 函数调用 和 中断处理 中广泛使用。
希望这份详细指南能帮你掌握 "PUSH" 指令的用法!
来源:敏敏课堂