2016-11-03 24 views
1

首先,我想說我在裝配中有足夠的背景知道大部分需要知道的功能組裝程序員。不幸的是,我不明白Windows API調用的返回地址是如何工作的。如何在Windows函數調用中設置堆棧?

下面是使用被寫入氣體裝置用於Windows的某些示例代碼的MinGW的作爲作爲彙編和MinGW的LD作爲接頭...

.extern [email protected] 
    .text 
    .globl _main 
_main: 
    pushl $0 
    call [email protected] 

此代碼編譯和組裝後運行...

as program.s -o program.o 

和聯繫吧...

ld program.o -o program.exe -lkernel32 

從我的理解中,Windows API通過推送指令調用參數,如上所述。然後在通話過程中;

call [email protected] 

函數的返回地址放在堆棧上。然後,這就是我困惑的地方,函數將所有參數從堆棧中彈出。

我很困惑,因爲,由於堆棧是最後一個先出,在我腦海中彈出堆棧上的參數時,它會首先彈出返回地址。論點首先出現,接下來的回覆地址就是這樣,所以技術上首先會彈出。

我的問題是,通過推送操作將參數傳遞給函數調用和放置在堆棧上的返回地址之後,堆棧的佈局是什麼樣的?當函數執行時,參數和返回地址如何從堆棧中彈出?最後,返回地址如何從堆棧中彈出,函數調用返回到返回地址中指定的地址?

+0

不好的例子,ExitProcess()根本不應該返回。 –

+0

它不會返回值,但它在堆棧上有返回地址。當它通過ret指令返回時(最後一次檢查爲\ xc3),它會將返回值從堆棧中彈出並將執行流程指向Windows API,然後再次將執行指向執行到下一條指令,該指令位於開始函數調用的調用指令之後第一名。 – August

+0

正如Turbo J所說,ExitProcess永遠不會返回。堆棧中有一個返回地址,但它從來沒有使用過,並且該函數從不執行RET指令。正如函數的名稱所示,該函數會導致進程退出,這意味着它無法返回給調用方,因爲調用方將不再存在。 –

回答

6

幾乎所有的Windows API函數都使用stdcall calling convention。這與普通的「cdecl」約定一樣,除非你看到被調用函數負責在返回時去除參數。它使用RET指令執行此操作,該指令採用可選的立即操作數。此操作數是首次彈出返回值後彈出堆棧的字節數。

在cdecl和stdcall調用約定中,函數的參數在函數執行時不會從堆棧彈出。它們留在堆棧上並使用ESP或EBP相對尋址進行訪問。所以當ExitProcess需要訪問它的參數時,它使用如mov 4(%esp), %eaxmov 4(%ebp), %eax的指令。

+0

不,我的意思是,如果函數的參數在返回地址之前被壓入堆棧,那麼函數如何彈出參數而不彈出返回地址? – August

+4

@八月它不會彈出的參數,直到它返回。 –

+0

啊,所以它會彈出返回地址,然後在返回之前彈出這些參數? – August

相關問題