java中push和pop指令的作用_汇编语言PUSH和POP指令(压栈和出栈)
匯編里把一段內(nèi)存空間定義為一個(gè)棧,棧總是先進(jìn)后出,棧的最大空間為 64K。由于 "棧" 是由高到低使用的,所以新壓入的數(shù)據(jù)的位置更低,ESP 中的指針將一直指向這個(gè)新位置,所以 ESP 中的地址數(shù)據(jù)是動(dòng)態(tài)的。
PUSH 指令
PUSH 指令首先減少 ESP 的值,再將源操作數(shù)復(fù)制到堆棧。操作數(shù)是 16 位的,則 ESP 減 2,操作數(shù)是 32 位的,則 ESP 減 4。PUSH 指令有 3 種格式:
PUSH reg/mem16
PUSH reg/mem32
PUSH inm32
POP指令
POP 指令首先把 ESP 指向的堆棧元素內(nèi)容復(fù)制到一個(gè) 16 位或 32 位目的操作數(shù)中,再增加 ESP 的值。如果操作數(shù)是 16 位的,ESP 加 2,如果操作數(shù)是 32 位的,ESP 加 4:
POP reg/mem16
POP reg/mem32
PUSHFD 和 POPFD 指令
PUSHFD 指令把 32 位 EFLAGS 寄存器內(nèi)容壓入堆棧,而 POPFD 指令則把棧頂單元內(nèi)容彈出到 EFLAGS 寄存器:
pushfd
popfd
不能用 MOV 指令把標(biāo)識(shí)寄存器內(nèi)容復(fù)制給一個(gè)變量,因此,PUSHFD 可能就是保存標(biāo)志位的最佳途徑。有些時(shí)候保存標(biāo)志寄存器的副本是非常有用的,這樣之后就可以恢復(fù)標(biāo)志寄存器原來(lái)的值。通常會(huì)用 PUSHFD 和 POPFD 封閉一段代碼:
pushfd?????????? ;保存標(biāo)志寄存器
;
;任意語(yǔ)句序列
;
popfd?????????? ;恢復(fù)標(biāo)志寄存器
當(dāng)用這種方式使用入棧和出棧指令時(shí),必須確保程序的執(zhí)行路徑不會(huì)跳過(guò) POPFD 指令。當(dāng)程序隨著時(shí)間不斷修改時(shí),很難記住所有入棧和出棧指令的位置。因此,精確的文檔就顯得至關(guān)重要!
一種不容易出錯(cuò)的保存和恢復(fù)標(biāo)識(shí)寄存器的方法是:將它們壓入堆棧后,立即彈出給一個(gè)變量:
.data
saveFlags DWORD ?
.code
pushfd ;標(biāo)識(shí)寄存器內(nèi)容入棧
pop saveFLags ;復(fù)制給一個(gè)變量
下述語(yǔ)句從同一個(gè)變量中恢復(fù)標(biāo)識(shí)寄存器內(nèi)容:
push saveFlags ;被保存的標(biāo)識(shí)入棧
popfd ;復(fù)制給標(biāo)識(shí)寄存器
PUSHAD,PUSHA,POPAD 和 POPA
PUSHAD 指令按照 EAX、ECX、EDX、EBX、ESP(執(zhí)行 PUSHAD 之前的值)、EBP、ESI 和 EDI 的順序,將所有 32 位通用寄存器壓入堆棧。
POPAD 指令按照相反順序?qū)⑼瑯拥募拇嫫鲝棾龆褩!Ec之相似,PUSHA 指令按序(AX、CX、DX、BX、SP、BP、SI 和 DI)將 16 位通用寄存器壓入堆棧。
POPA 指令按照相反順序?qū)⑼瑯拥募拇嫫鲝棾龆褩!T?16 位模式下,只能使用 PUSHA 和 POPA 指令。
如果編寫(xiě)的過(guò)程會(huì)修改 32 位寄存器的值,則在過(guò)程開(kāi)始時(shí)使用 PUSHAD 指令,在結(jié)束時(shí)使用 POPAD 指令,以此保存和恢復(fù)寄存器的內(nèi)容。示例如下列代碼段所示:
MySub PROC
pushad ;保存通用寄存器的內(nèi)容
.
.
mov eax,...
mov edx,...
mov ecx,...
.
.
popad ;恢復(fù)通用寄存器的內(nèi)容
ret
MySub ENDP
必須要指岀,上述示例有一個(gè)重要的例外:過(guò)程用一個(gè)或多個(gè)寄存器來(lái)返回結(jié)果時(shí),不應(yīng)使用 PUSHA 和 PUSHAD。假設(shè)下述 ReadValue 過(guò)程用 EAX 返回一個(gè)整數(shù);調(diào)用 POPAD 將會(huì)覆蓋 EAX 中的返回值:
ReadValue PROC
pushad ;保存通用寄存器的內(nèi)容
.
.
mov eax rreturn_value
.
.
popad ;覆蓋 EAX !
ret
ReadValue ENDP
示例:字符串反轉(zhuǎn)
現(xiàn)在查看名為 RevStr 的程序:在一個(gè)字符串上循環(huán),將每個(gè)字符壓入堆棧,再把這些字符從堆棧中彈出(相反順序),并保存回同一個(gè)字符串變量。由于堆棧是 LIFO(后進(jìn)先出)結(jié)構(gòu),字符串中的字母順序就發(fā)生了翻轉(zhuǎn):
;字符串翻轉(zhuǎn)(Revstr.asm)
.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD
.data
aName BYTE "Abraham Lincoln",0
nameSize = ($-aName)-1
.code
main PROC
;將名字壓入堆棧
mov ecx,nameSize
mov esi,0
L1: movzx eax,aName[esi] ;獲取字符
push eax ;壓入堆棧
inc esi
loop L1
;將名字逆序彈出堆棧
;并存入aName數(shù)組
mov ecx,nameSize
mov esi,0
L2: pop eax ;獲取字符
mov aName[esi],al ;存入字符串
inc esi
loop L2
INVOKE ExitProcess,0
main ENDP
END main
總結(jié)
以上是生活随笔為你收集整理的java中push和pop指令的作用_汇编语言PUSH和POP指令(压栈和出栈)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 用命令实现Win7远程桌面关机和重启
- 下一篇: java 数据截断_java – 数据截