`
zzc1684
  • 浏览: 1221861 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

学 Win32 汇编[18]: 关于压栈(PUSH)与出栈(POP) 之二

 
阅读更多

由于 "栈" 是由高到低使用的, 所以新压入的数据的位置更低.
ESP 中的指针将一直指向这个新位置, 所以 ESP 中的地址数据是动态的.

每次 PUSH, ESP = ESP - x; 每次 POP, ESP = ESP + x;
其中的 x 只能是 4 或 2, 因为 Win32 的 PUSH 只可以压入 32 位(默认)或 16 位的数据.

ESP 有个名字叫 "栈顶", 其实它指向的是栈中最低位置的数据.



实例查看 ESP 的变化:


; Test18_1.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.data
    ddVal1 dd 1
    ddVal2 dd 2
    dwVal1 dw 3
    dwVal2 dw 4
.code
main proc
    PrintHex esp  ;0012FFA4
    
    push ddVal1
    PrintHex esp  ;0012FFA0
    push ddVal2
    PrintHex esp  ;0012FF9C
    push dwVal1
    PrintHex esp  ;0012FF9A
    push dwVal2
    PrintHex esp  ;0012FF98
    
    pop dwVal2
    PrintHex esp  ;0012FF9A
    pop dwVal1
    PrintHex esp  ;0012FF9C
    pop ddVal2
    PrintHex esp  ;0012FFA0
    pop ddVal1
    PrintHex esp  ;0012FFA4
    ret
main endp
end main


使用参数压栈的方式调用函数, 同时揭示 invoke 的本质:


; Test18_2.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
;include    masm32.inc
;include    debug.inc
includelib kernel32.lib
;includelib masm32.lib
;includelib debug.lib

include    user32.inc
includelib user32.lib

.data
    szMsg     db 'Hello World!', 0
    szCaption db 'Hi', 0
.code
main proc
    ;invoke MessageBox, NULL, addr szMsg, addr szCaption, MB_OK
    ;用压栈的方式调用 MessageBox 函数; 本来就是如此, invoke 只是简化了这个步骤
    push MB_OK ;C 函数和系统函数读取参数的顺序是: 从右到左; 最左边的参数最后使用, 要先压入
    push offset szCaption
    push offset szMsg
    push NULL  ;一个常数会默认当作 32 位数据压入
    call MessageBox
    pop edx    ;随便出栈到一个地方, 已经没用了, 相当于进回收站
    pop edx    ;尽管没用, 不出是不行的, 因为 push 和 pop 要成对出现
    pop edx
    pop edx
    
    ;invoke ExitProcess, NULL
    ;用压栈的方式调用 ExitProcess 函数
    push NULL
    call ExitProcess
    pop edx
main endp
end main


从上面的例子看出, 函数调用是需要先压栈(PUSH)参数的;

PUSH 另一重要作用是保护数据, 调用函数前, 最先需要保护的就是 EIP, 这是执行完函数后的下一条指令的地址.
call 指令会先把 EIP 传给 ESP; ret 指令最后把 ESP 恢复给 EIP. 所以, 压栈出栈保护的是 ESP.
但因 ESP 是动态的, 所以一般先 mov ebp, esp, 然后 push ebp ... 像这样:



mov ebp, esp
push ebp
;...函数或子过程
pop ebp
mov esp, ebp
;leave ;可以使用 leave 指令代替上面两行, 它是对上面两行的简化


从调试器中查看编译器添加的保护 ESP 的代码:


; Test18_3.asm; 这是用于调试的例子
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
;求和函数
sumProc proc v1:dword, v2:dword, v3:dword
    mov eax, v1
    add eax, v2
    add eax, v3
    ret
sumProc endp
;
main proc
    invoke sumProc, 11, 22, 33
    PrintDec eax ;66
    ret
main endp
end main
;--------------------------

;Ctrl + T 是设置或取消断点
;Ctrl + D 是调试运行
;从调试器中看到 sumProc 函数的代码变成了:

PUSH EBP
MOV EBP,ESP
MOV EAX,DWORD PTR SS:[EBP+8]
ADD EAX,DWORD PTR SS:[EBP+C]
ADD EAX,DWORD PTR SS:[EBP+10]
LEAVE

;看来保护 ESP 的工作是由编译器做的
;从这里也看出了 EBP 寄存器的主要用途就是中转 ESP 中的数据


利用 ESP 的地址偏移读取栈中的数据:


; Test18_4.asm
.386
.model flat, stdcall

include    windows.inc
include    kernel32.inc
include    masm32.inc
include    debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib

.code
main proc
    push 111
    push 222
    push 333
    push 444
    
    mov eax, [esp]
    PrintDec eax     ;444
    mov eax, [esp+4]
    PrintDec eax     ;333
    mov eax, [esp+12]
    PrintDec eax     ;111
    
    pop edx
    pop edx
    pop edx
    pop edx
    ret
main endp
end main


总结 PUSH 和 POP 的主要用途: 1、暂存与恢复数据; 2、处理函数参数.



压栈、出栈指令汇总:



PUSH(PUSHWPUSHD)  / POP   ;进出 16 位或 32 位操作数, 默认 32 位

PUSHAD              / POPAD ;进出 EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI
PUSHA               / POPA  ;进出  AX、 CX、 DX、 BX、 SP、 BP、 SI、 DI

PUSHFD              / POPFD ;进出 EFLAGS
PUSHF               / POPF  ;进出 EFLAGS 的低 16 位
分享到:
评论

相关推荐

    汇编言语——进栈出栈指令PPT学习教案.pptx

    本PPT学习教案主要讲解汇编语言中的进栈出栈指令,包括PUSH指令和POP指令的格式、功能、说明和使用方法。下面是本教案的详细知识点: 1. PUSH指令: * 格式:PUSH d * 功能:先将SP的值减去2,然后将操作数d指定的...

    汇编语言之 两个多位十进制数相加

    汇编语言之两个多位十进制数相加 本实验旨在学习数据传送和算术运算指令的用法,并熟悉在 PC 机上建立、汇编、链接、调试和运行 8086 汇编语言程序的过程。 一、实验目的: * 了解数据传送和算术运算指令的用法 *...

    汇编指令大全 汇编语言的学习

    - `PUSHA` 和 `POPA` / `PUSHAD` 和 `POPAD`:快速压栈和出栈一组寄存器,简化数据管理。 - `BSWAP`:用于交换32位寄存器内的字节顺序,常用于字节序转换。 - `XCHG`:交换两个操作数的值,可以是寄存器或存储器...

    常用汇编指令(常用汇编指令)

    汇编语言基础知识点 汇编语言是基于 CPU 指令集的低级编程语言,它使用符号表示来表示机器语言指令,从而使得编程更加灵活和高效。下面是常用的汇编指令分类: 1. 通用数据传送指令 MOV:传送字或字节 MOVSX:先...

    汇编语言中山大学本科教学课件

    - 堆栈操作:PUSH和POP用于数据的压栈和出栈,常用于函数调用保存现场和恢复现场。 7. **输入输出** - 输入/输出(I/O)指令:如IN和OUT,用于与外部设备通信。 - BIOS和DOS中断:通过INT指令调用,提供系统服务...

    汇编指令查询器

    4. 存储操作指令:如PUSH(压栈)、POP(出栈)、LEA(取地址)等,用于管理内存中的数据。 二、汇编指令查询的重要性 1. 学习理解:汇编指令查询器可以帮助初学者快速查找和理解各种指令的功能和用法,深入学习...

    汇编语言第三版 王爽

    - 处理器控制指令:如PUSH(压栈)、POP(出栈)、MOV(移动数据)等。 4. 实模式与保护模式: - 实模式:早期的8086处理器工作模式,无内存保护,程序可以直接访问所有内存。 - 保护模式:引入了段机制和特权级...

    单片机设计案列单片机汇编例程学习

    堆栈操作指令如PUSH、POP用于数据压栈和出栈。 四、流程控制与循环 汇编语言中的流程控制包括条件跳转(如JZ、JNE)、无条件跳转(如AJMP、SJMP)、子程序调用(LCALL)和返回(RET)。通过这些指令,可以实现循环...

    汇编语言程序设计(钱晓捷)课后答案

    * 堆栈的基本操作:压栈和出栈 知识点4:Flags 和状态标志 * AL 寄存器的赋值,如 AL = 89h 等 * CF、ZF、SF、OF、PF 等标志的概念和使用 * 如何根据 AL 寄存器的值设置状态标志 知识点5:算术逻辑操作 * 加减...

    易语言汇编动态堆栈调用

    在汇编语言中,堆栈操作通常通过PUSH(压栈)和POP(出栈)指令实现。PUSH将数据压入堆栈,而POP则将堆栈顶部的数据弹出,恢复到原来的变量或寄存器。在动态堆栈调用中,程序员需要精确控制这些指令,以确保数据正确...

    新版汇编语言程序设计钱晓捷习题答参照.pdf

    堆栈的两种基本操作是压栈和出栈,对应的指令是 PUSH 和 POP。 堆栈的工作原则 在习题 2.4 中,我们可以看到堆栈的工作原则是先进后出。例如,push ax 指令将 AX 寄存器的值压栈,pop bx 指令将堆栈顶部的值弹出到...

    AT&T汇编语言手册2005老版本

    - 存储和内存访问指令:如`mov`(移动数据)、`push`(压栈)、`pop`(出栈)等。 - 控制流程指令:如`call`(调用子程序)、`ret`(返回)等。 4. **汇编程序设计**: - 静态链接和动态链接:静态链接在编译时...

    AT & T汇编语言

    它与Intel汇编语言有所不同,在语法和寄存器命名上有其独特之处。这本书《Professional Assembly Language》由Richard Blum编写,是市面上少见的专门讲解AT&T格式汇编语言的书籍之一。 #### 二、AT&T汇编语言特点 -...

    汇编语言指令大全和王爽教程

    4. **处理器控制指令**:如PUSH(压栈)、POP(出栈)、MOV(移动)等,用于管理寄存器和内存。 王爽的《汇编语言》第二版则更注重理论与实践的结合,书中可能会详细讲解: 1. **基本概念**:如地址、寄存器、指令...

    8080汇编手册.pdf

    - `PUSH`和`POP`:用于数据入栈和出栈,常用于保存和恢复寄存器的状态。 - `PUSHA`和`POPA`:一次性将一组寄存器压入或弹出堆栈,节省了单独操作每个寄存器的时间。 - `PUSHAD`和`POPAD`:类似于`PUSHA`和`POPA`...

    汇编指令查询器(汇编)

    4. **处理内存和寄存器的指令**:如MOV(移动数据)、LEA(获取内存地址)、PUSH(压栈)、POP(出栈),用于数据的存储和传输。 5. **输入/输出指令**:如IN(从端口读取数据)、OUT(向端口写入数据),用于与...

    部分8086汇编指令集

    8086汇编指令集速查手册 8086汇编指令集是一个广泛使用的汇编指令集,主要应用于 Intel 8086 微处理器。这些指令可以分为四大类:数据传输指令、输入输出端口传送指令、目的地址传送指令和标志传送指令。 数据传输...

    80x86汇编指令大全总结珍藏版

    - `PUSHA` 和 `POPA`:一次性将所有通用寄存器压栈或出栈,简化了数据保存和恢复过程。 - `PUSHAD` 和 `POPAD`:与`PUSHA`和`POPA`类似,但针对32位寄存器。 - `BSWAP`:用于交换32位寄存器中的字节顺序,例如在...

Global site tag (gtag.js) - Google Analytics