2013-01-07 56 views
2

我一直在學習IA-32彙編程序設計。所以我想在彙編中編寫一個函數,並從C++中調用它。從IA-32的程序集訪問C++中的函數參數

我正在遵循的教程實際上是爲x64程序集。但我正在研究IA-32。 在x64上,它說函數參數存儲在像RCX,RDX,R8,R9等

寄存器但在搜索一點點,我能理解在IA-32 ,參數存儲在堆棧中,不在寄存器中。

下面是我的C++代碼:

#include <iostream> 
#include <conio.h> 

using namespace std; 
extern "C" int PassParam(int a,int b); 

int main() 
{ 
    cout << "z is " << PassParam(15,13) << endl; 
    _getch(); 
    return 0; 
} 

下面是PassParam()函數的彙編代碼(它只是增加兩個參數,這一切都只是爲了學習的目的。):

PassParam()彙編:

.model C,flat 
.code 
PassParam proc 
    mov eax,[ebp-212] 
    add eax,[ebp-216] 
    ret 
PassParam endp 
end 

在我assembl y代碼,你可以看到我把第一個參數從[ebp-212]移到了eax。該值如下獲得:

我在C++本身編寫了PassParam()函數,並對它進行反彙編。然後檢查ebp在哪裏,第二個參數存儲在哪裏(參數從右向左存儲)。我可以看到有212的差異,所以這就是我得到這個價值的方式。然後像往常一樣,第一個參數存儲在4個字節之後。它工作正常。

問:

這是從裝配訪問參數的正確方法是什麼?我的意思是,它是否永遠[ebp-212]參數存儲在哪裏?

如果沒有,任何人都可以解釋從C++傳遞參數到彙編的正確方法嗎?

注:

我用Visual C++ 2010的工作時,Windows 7機器上。

+0

我認爲它通常是像esp + 4這樣的東西,但我很難成爲這方面的專家,尤其是在涉及VC++時。 –

+0

看起來你已經複製粘貼的程序集。這不是它的工作原理。 – 2013-01-07 13:42:40

+0

@Tinctorius:未複製粘貼。這是我經過大量搜索後得出的最終工作解決方案。但我自己覺得這是錯誤的方法(好吧,ebp-212對我沒有任何意義)。 –

回答

8

在32位架構,這取決於調用約定,Windows爲例如既有__fastcall__thiscall那些使用登記和堆棧ARGS,並__cdecl__stdcall使用堆棧ARGS但不同之處誰做清理。 MSDN有一個很好的列表here(或更多assembly orientated version)。請注意,FPU/SSE操作也有它們的own conventions

爲了方便和簡單,嘗試使用__stdcall的一切,這使您可以使用堆棧幀通過MOV r32,[EBP+4+(arg_index * 4)]訪問指定參數時,或者如果你不使用棧幀,可以使用MOV r32,[ESP+local_stack_offset+(arg_index * 4)]。註釋的C++ - > x86彙編示例here應該有所幫助。


因此,作爲一個簡單的例子,讓我們說我們有功能MulAdd組裝,用C++原型int __stdcall MulAdd(int base, int mul, int add),它看起來是這樣的:

MOV EAX,[ESP+4] //get the first arg('base') off the stack 
MOV ECX,[ESP+8] //get the second arg('mul') off the stack 
IMUL EAX,ECX //base * mul 
MOV ECX,[ESP+12] //get arg 3 off the stack 
ADD EAX,ECX 
RETN 12 //cleanup the 3 args and return 

或者,如果您使用的是棧幀:

PUSH EBP 
MOV EBP,ESP //save the stack 
MOV EAX,[EBP+8] //get the first arg('base') off the stack 
MOV ECX,[EBP+12] //get the second arg('mul') off the stack 
IMUL EAX,ECX //base * mul 
MOV ECX,[EBP+16] //get arg 3 off the stack 
ADD EAX,ECX 
MOV ESP,EBP //restore the stack 
POP EBP 
RETN //return to caller 

使用堆棧幀避免需要調整用於通過PUSH到堆棧製成「荷蘭國際集團args來變化,溢出或吉斯ters或堆棧分配爲局部變量。它的缺點是它減少了你必須使用的寄存器的數量。

+0

+1 - 嗨,第一種方法工作正常。爲什麼[ESP + 4]?爲什麼不只是[ESP]? –

+1

@AbidRahmanK:因爲'[ESP]'持有通過'CALL'指令被壓入堆棧的返回地址。 – Necrolis

+0

+1 - 哦...我忘了那部分。謝謝。你有任何推薦的書籍或教程,以更好地瞭解這部分? –