汇编push、pop、add、sub、lea 指令详解

1. PUSH 指令

功能: 将操作数压入栈顶。
本质: 它是一个“先减后存”的操作。
受影响的标志位: 无。

工作原理(在 32 位模式下):

  1. 首先,栈指针寄存器 ESP 的值会 减去操作数的字节数(例如,在 32 位模式下是 4 字节)。

  2. 然后,将操作数的值 存储到 ESP 寄存器所指向的新内存地址。

语法:

asm

push source

操作数类型:

  • push reg: 将寄存器的值压入栈。

  • push mem: 将内存地址处的值压入栈。

  • push immediate: 将立即数压入栈。

示例:

asm

mov eax, 11223344h  ; EAX = 0x11223344
push eax            ; 1. ESP = ESP - 4
                    ; 2. 将 0x11223344 存入地址 [ESP]

执行后,栈顶([ESP])的内容就是 0x11223344,并且 ESP 指向这个值。


2. POP 指令

功能: 将栈顶的值弹出到指定的操作数。
本质: 它是一个“先取后加”的操作。
受影响的标志位: 无。

工作原理(在 32 位模式下):

  1. 首先,从 ESP 寄存器所指向的内存地址 读取值

  2. 然后,将该值 存入 目标操作数。

  3. 最后,栈指针寄存器 ESP 的值会 加上操作数的字节数(例如,在 32 位模式下是 4 字节)。

语法:

asm

pop destination

操作数类型:

  • pop reg: 将栈顶值弹出到寄存器。

  • pop mem: 将栈顶值弹出到内存地址。

示例:

asm

pop ebx             ; 1. 从 [ESP] 读取值到 EBX
                    ; 2. ESP = ESP + 4

假设执行前 [ESP] 是 0x11223344,执行后 EBX = 0x11223344,并且 ESP 指向栈中下一个位置。

PUSH 和 POP 的典型用途:

  • 保存和恢复寄存器: 在函数开头保存寄存器原有值,在函数结束前恢复它们。

    asm

    MyFunction:
        push ebp        ; 保存旧的栈帧基址
        mov ebp, esp    ; 建立新栈帧
        push ebx        ; 保存 EBX,因为后面我们会修改它
        push esi        ; 保存 ESI
    
        ; ... 函数主体,使用 EBX 和 ESI ...
    
        pop esi         ; 恢复 ESI (注意:顺序与 PUSH 相反!)
        pop ebx         ; 恢复 EBX
        pop ebp         ; 恢复旧的 EBP
        ret
  • 传递函数参数: 在 C 语言的 cdecl 调用约定中,参数从右向左依次压栈。


3. ADD 指令

功能: 将两个操作数相加,结果存回目标操作数。
公式: destination = destination + source
受影响的标志位: OF(溢出标志)SF(符号标志)ZF(零标志)CF(进位标志), AF, PF。

语法:

asm

add destination, source

操作数组合:

  • add reg, reg: eax = eax + ebx

  • add reg, mem: eax = eax + [myVariable]

  • add mem, reg: [myVariable] = [myVariable] + ebx

  • add reg, immediate: eax = eax + 10

  • add mem, immediate: [myVariable] = [myVariable] + 10

示例:

asm

mov eax, 5       ; EAX = 5
mov ebx, 3       ; EBX = 3
add eax, ebx     ; EAX = 5 + 3 = 8
add eax, 10      ; EAX = 8 + 10 = 18

; 标志位变化示例
mov al, 0xFF     ; AL = 255 (0xFF)
add al, 1        ; AL = 0, 同时会设置 ZF=1 (结果为0), CF=1 (最高位有进位)

4. SUB 指令

功能: 从目标操作数中减去源操作数,结果存回目标操作数。
公式: destination = destination - source
受影响的标志位: OF(溢出标志)SF(符号标志)ZF(零标志)CF(进位标志/借位标志), AF, PF。

语法:

asm

sub destination, source

操作数组合: 与 ADD 指令完全相同。

示例:

asm

mov eax, 10      ; EAX = 10
mov ebx, 4       ; EBX = 4
sub eax, ebx     ; EAX = 10 - 4 = 6
sub eax, 2       ; EAX = 6 - 2 = 4

; 标志位变化示例
mov al, 0        ; AL = 0
sub al, 1        ; AL = 255 (0xFF), 同时会设置 SF=1 (结果为负), CF=1 (需要借位)

5. LEA 指令

功能: 将源操作数的 有效地址 加载到目标操作数。
关键点: 它不访问该地址处的内存,只计算地址本身。
受影响的标志位: 无。

语法:

asm

lea destination, source
  • destination: 必须是一个通用寄存器。

  • source: 必须是一个内存操作数。

LEA 的核心用途:

  1. 计算地址(本职工作):

    asm

    mov esi, offset myArray ; ESI 指向 myArray 的地址
    lea edi, [esi + eax*4]  ; 计算 myArray[eax] 的地址(假设是 int 数组),并存到 EDI。
                            ; 这里 EDI 得到的是地址,而不是该地址处的值。
    ; 对比 MOV:
    mov edi, [esi + eax*4]  ; 这是将 myArray[eax] 的值加载到 EDI。
  2. 进行复杂的算术运算(巧妙用法):
    由于 LEA 可以执行 [base + index*scale + displacement] 这种形式的计算,它常被编译器用来快速执行整数乘法与加法,而无需使用 MUL 或 ADD 指令。

    asm

    ; 计算 EAX * 5 + 10
    lea ecx, [eax*4 + eax] ; ECX = EAX*4 + EAX = EAX*5
    lea ecx, [ecx + 10]     ; ECX = ECX + 10
    
    ; 上面两条指令可以合并为一条:
    lea ecx, [eax*4 + eax + 10] ; ECX = EAX*5 + 10

    这比使用 imul 和 add 指令更高效。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值