一 堆栈
栈是一种后进先出的结构, 这是因为最后压入栈的值总是最先被取出,
1.运行时栈
运行时栈由CPU直接管理,它使用两个寄存器, SS和ESP, 在保护模式下, SS寄存器存放的段选择子, 用户模式应对它进行修改,。ESP是指向堆栈内某
个特定的位置
压栈操作
32位的压栈操作首先将栈指针减4, 然后把值直接复制到指针所指向的位置,
出栈操作
出栈操作从堆栈顶端一走一个值并将其复制到寄存器或内存变量中,弹出值后,堆栈指针相应的增加,
2.堆栈的应用
堆栈可以方便的作为临时区域,在寄存器使用完毕后, 可以通过堆栈恢复其原始值
CALL指令执行时, CPU用堆栈保存当前调用过程的返回地址
调用过程中,可以通过压栈传入参数
过程内的局部变量在堆栈上创建, 过程结束时, 这些变量被丢弃
二 PUSH和POP指令
1.PUSH指令
PUSH执行压栈操作, 先将ESP的值减小, 然后把一个16位或者32位的源操作数复制到堆栈上, 对于16位操作数, ESP值将减小, 对于32位操作数, ESP将减4, 有以下3中格式
PUSH r/m16
PUSH r/m32
push imm32
2.POP指令
先将ESP的值复制到目的操作数中, 然后增加ESP的值
pop r/m16
pop r/m32
3. PUSHFD , POPFD
PUSHFD 指令在堆栈上压入32位的EFLAGS寄存器的值,POPFD指令将堆栈顶部的值弹出送到EFLAGS寄存器中
MOV指令不能复制标志寄存器中的值到变量或者寄存器中, 使用pushfd 和 POPFD注意要成对使用, 不要跳过POPFD
4. PUSHAD, PUSHA, POPAD, POPA
PUSHAD 指令在堆栈上按顺序压入32位寄存器:EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI,
POPAD以相反的顺序弹出这些通用的寄存器,PUSHA和POPA则是16位的操作
三过程的定义与使用
1.PROC指令
可以把过程非正式的定义为以返回语句结束的明明语句块, 过程使用PROC和ENDP伪指令来声明, 另外还可以给过程定义一个名字。
sample PROC
.
.
ret
samp ENDP
四 CALL和RET指令
1.CALL指令 只是处理器在新的内存地址执行指令, 以实现对过程的调用, 过程使用RET指令使处理器返回到被调用的地方继续执行, 从底层细节来讲,
call指令把返回地址压入堆栈并把新地址复制到指令寄存器EIP中。RET指令弹出返回地址EIP
2.向过程传递寄存器参数
五. 流程图
流程图以图形化的方式描述程序逻辑。流程图每个图形都代表了一个逻辑步骤, 用带箭头的线将图形连接起来表示了逻辑步骤:
我们为数组求和画一个流程图:
六 保存和恢复寄存器
1.USES 操作符
与PROC伪指令配套使用的USES操作符允许列出被过程修改的所有寄存器, 它指示编译器做两件事, 首先, 在过程开始处PUSH列出的寄存器, 其次在过程结束处POP列出的寄存器。
ArraySum PROC USES esi, ecx
mov eax, 0
L1:
add eax, [esi]
inc esi
loop L1
ret
ArraySum ENDP
但是如果过程将某些寄存器作为返回值是不要使用USES列出该寄存器
一个数组求和的例子
INCLUDE Irvine32.inc INTEGER_COUNT = 3 .data str1 BYTE "Enter a signed integer:", 0 str2 BYTE "the sum integer is:", 0 array DWORD INTEGER_COUNT DUP(?) .code main PROC call Clrscr mov esi, OFFSET array mov ecx, INTEGER_COUNT call PromptForIntegers call ArraySum call DisplaySum exit main ENDP PromptForIntegers PROC uses ecx edx esi mov edx, OFFSET str1 L1:call WriteString call ReadInt call Crlf mov [esi], eax add esi, TYPE DWORD loop L1 ret PromptForIntegers ENDP ArraySum PROC USES esi ecx mov eax, 0 L1: add eax, [esi] add esi, TYPE DWORD loop L1 ret ArraySum ENDP DisplaySum PROC USES edx mov edx, OFFSET str2 call WriteString call WriteInt call Crlf ret DisplaySum ENDP END main