x86 汇编语言 中,“PUSH” 指令用法

B站影视 日本电影 2025-09-03 17:39 1

摘要:在 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" 指令的用法!

来源:敏敏课堂

相关推荐