2014-03-13 86 views
-2

call之後的下一條指令的地址,還是call的指令地址,返回地址(保存在堆棧中的EIP寄存器返回時使用的地址)?ASM函數調用返回地址

編輯:

p call x 
q mov y 

呼喚x()pq當堆棧上的返回地址?

+2

這是'call'後面的指令,'ret'應該返回。下一次請參閱指令集參考。 – Jester

+0

看到這個堆棧溢出帖子:http://stackoverflow.com/questions/17514774/how-do-called-functions-return-to-their-caller-after-being-called –

回答

1

在調用之後 - 這將是子例程終止時執行的下一條指令。

1

處理器將EIP寄存器(包含CALL指令之後的指令的偏移量)的值壓入堆棧(稍後用作返回指令指針)。

由於@Jester發佈,RTFM。

+0

考慮到我什至不知道那裏是一本「手冊」(假設我找到了)閱讀它會有點困難.... – user997112

+1

理查德可能脾氣暴躁,但這些概念上的字面意義實在是太多了。一個更詳細的方式來重述他的snark評論是「如果你寫低層次細節很重要的軟件,暫停在那裏,併成爲你的CPU的指令集參考最好的朋友」。注意這種行爲是由CPU架構決定的,而不是編譯器! –

+0

這個隨機谷歌的第3頁是有用的http://mai.kvk.uni-obuda.hu/documents/tantargy/8086-instruction-set-overview.pdf。請注意PUSH,POP,CALL,RET和IRET –

0

call指令在將執行轉移到被調用函數之前,將返回地址 - 按照您編號爲q的行編號 - 在堆棧中。

ret指令將其彈出 - 您可以說它的確如此pop EIP
但是這也意味着... 之前ret,[ ESP ] == EIP。由於ret對堆棧沒有做任何其他操作,但是調整堆棧指針(即ESP - >ESP + 4),到您返回時,仍然應該有EIP == [ ESP - 4 ]

你可以做的,因此:

call func 
mov EAX, [ ESP - 4 ] 

,並很可能得到的代碼位置爲MOV指令的第一個字節。

爲什麼只有很可能?答案是堆棧未分配部分內的堆棧內容不能保證;在執行堆棧指針調整/ EIP更改但在該指令實際執行之前,會出現異步事件(UN * X信號以及其他操作系統中的類似機制),這些事件可能會中斷正在執行的ret之間的執行。如果發生這種情況,信號幀可能會覆蓋未分配的堆棧部分,從而破壞存儲在那裏的返回地址。

如果您想要可靠地檢索您當前的EIP,請執行一個PC相對調用,它只是「跳過call指令」。然後彈出堆棧上的值。即像:

call +5 ;; the size of a call is 5 bytes, so ... "skip yourself" 
pop EAX ;; EAX now contains the "return address" - its own EIP 

參見Reading Program Counter directly如以前SO回答了。