堆棧的概念
堆棧 是在內存RAM中開闢的一段空間,利用“先進後出”或“後進先出”原則存取數據。
如果把數據壓入堆棧,則堆棧指針的值是減少的,即所謂的向下生成堆棧。
由SS:SP(16位)或SS:ESP(32位)指向棧底(棧空)或棧頂(棧不空)地址。
利用數據入棧指令PUSH和數據出棧指令POP操作堆棧。
1.數據入棧指令
指令格式:PUSH OPS
功能:將OPS中的數據壓入堆棧中。若壓入堆棧中的OPS是16位,則SP(16位CPU)或ESP(32位CPU)減2;若OPS是32位,ESP(32位CPU)減4。
PUSH一般有如下三種:
PUSH reg16/32
; 寄存器reg必須是16或32位
PUSH seg
PUSH mem16/32
; 內存中的數據必須是16或32位
PUSH imm16/32
; 將16位或32位立即數壓入堆棧
2.數據出棧指令
指令格式:POP OPD
功能:將棧頂元素彈出送到某一寄存器、段寄存器(CS除外)或內存中。注意OPS一定是16或32位。彈出棧的數據若是16位,SP或ESP加2;若數據是32位,ESP加4。
POP一般有如下三種:
POP reg16/32
; 寄存器reg必須是16或32位
POP seg
; seg不能為CS、SS
POP mem 16/32
; 存儲器長度必須是16或32位
彈出肯定是從棧頂開始:LIFO原先的ax在下面,要等到原先的Bx彈出再彈出ax。
AX,BX入棧後原來的數據還在;只不過經過出棧後原來的數據被修改了,結果是交換了數據。
棧實際上是個中轉站。
數據的交換必須要通過第三方中轉。
MOV CX,AX
MOV DX,BX
MOV AX,DX
MOV BX,CX
這段指令實際上是利用CX,DX做中轉站交換AX,BX;道理是一樣的;
只不過棧的操作原則是LIFO。
PUSH/POP相關的其他指令
(1)存儲器操作數入棧與出棧
PUSHW mem
; 16位存儲器操作數入棧
PUSHD mem
; 32位存儲器操作數入棧
或
PUSH WORD PTR mem(16)
PUSH DWORD PTR mem(32)
POP WORD PTR mem(16)
POP DWORD PTR mem (32)
(2)多個16位通用寄存器入棧和出棧
16位數據入棧/出棧配對使用指令:PUSHA/POPA。
PUSHA:
將AX、BX、CX、DX、SP、BP、SI、DI這8個16位通用寄存器的值依次壓入堆棧(指針減),其中SP的值是在此條指令未執行之前的值,該指令執行後,SP-16(字節)→SP。
POPA:
依次彈出堆棧中的16位字節到DI、SI、BP、SP、DX、CX、BX、AX中,該指令執行後,SP+16→SP。
(3)多個32位通用寄存器入棧與出棧
PUSHAD
將EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI這8個32位通用寄存器的值依次壓入堆棧,其中ESP的值是在此條指令未執行之前的值,指令執行後,ESP-32→ESP。
POPAD
依次彈出堆棧中的32位字到EDI、ESI、EBP、ESP、EBX、EDX、ECX、EAX中,彈出完成後,ESP+32→ESP。
上述兩組指令用於過程設計時,PUSHA和PUSHAD在過程開始時暫存通用寄存器的當前值,POPA和POPAD在過程結束時恢復通用寄存器的值,必須配對使用。
(4)16位標誌寄存器F的入棧和出棧。
PUSHF
; 將16位標誌寄存器F的值入棧
POPF
; 將棧頂彈出2個字節送給16位標誌寄存器F,
; 或彈出送到32位標誌寄存器的低16位中。
操作碼POPF的含義是:pop flags off stack。
(5)32位標誌寄存器入棧和出棧
PUSHFD
; 是將32位標誌寄存器EFLAGS的值
; 入棧
POPFD
; 從堆棧棧頂處連續彈出4字節送
; 給32位的標誌寄存器EFLAGS
當從堆棧中彈出4字節送給32位標誌寄存器時,只有在當前特權級為0時,才能從堆棧中彈出4字節標誌送給EFLAGS,使得EFLAGS中的I/O特權級標誌位IOPL才能被替換。
(6)ENTER和LEAVE指令
ENTER/LEAVE指令把EBP寄存器內容入棧/出棧,並在堆棧中為局部變量分配/釋放存儲空間,通常在子程序調用時使用該組指令。
閱讀更多 又將如何存在 的文章