2014-01-16 39 views
5

我正在用VC編譯器編譯這個C++代碼。我試圖調用一個函數使用__asm語句,這樣,它有兩個WORD(又名unsigned short)參數:如何在__asm中使用變量?

__declspec(naked) void __stdcall CallFunction(WORD a, WORD b) 
{ 
    __asm { 
     PUSH EBP 
     MOV EBP, ESP 
     PUSH a 
     PUSH b 
     CALL functionAddress 
     LEAVE 
     RETN 
    } 
} 

functionAddress功能只是輸出做a + b的結果。然後打電話CallFuncion(5, 5);打印「64351」或類似的東西。使用ab變量時__asm語句內,因爲這個作品的問題是:

PUSH EBP 
MOV EBP, ESP 
PUSH 5 
PUSH 5 
CALL functionAddress 
LEAVE 

這是在functionAddress功能:

void __stdcall Add(WORD a, WORD b) 
{ 
    WORD c; 
    c = a + b; 
    printf("The result is %d\n", c); 
} 

我怎樣才能做到這一點的正確方法?因此__asm聲明解釋了ab值?

+0

「VC編譯器」出現了很多版本。請對你的環境做更詳細和具體的說明。 –

+0

你說它再次調用'CallFunction',這是無限遞歸,請更清楚。 – 2014-01-16 17:24:31

+0

這是VC 2005編譯器,如果我沒有錯。 @ user9000對不起,我在函數的後面調用函數。 – cdonts

回答

4

由於您使用的是__declspec(naked)並設置了自己的堆棧幀,我不相信編譯器會讓您通過名稱引用ab。使用__declspec(naked)基本上意味着您負責自行處理堆棧幀,參數等。

你可能需要更多的代碼這個一般順序:

__asm { 
    PUSH EBP 
    MOV EBP, ESP 
    mov eax, [ebp+8] 
    mov ebx, [ebp+12] 
    push eax 
    push ebx 
    CALL functionAddress 
    LEAVE 
    RETN 
} 

I'ts已經有一段時間,我的手來處理這樣的事情,所以你可能要重新檢查這些偏移,但如果我沒有記錯,返回地址應該在[ebp+4]。參數(通常)從右向左推,所以最左邊的參數應該是[ebp+8],下一個參數是[ebp+12](記住堆棧向下增長)。

編輯:我應該在函數頭更仔細地看着。]

你標記CallFunction爲使用__stdcall調用約定。這意味着它需要清理傳遞給它的參數。因此,由於它收到8個字節的參數,因此它需要從堆棧中刪除8個字節,因爲它返回:

PUSH EBP 
    MOV EBP, ESP 
    mov eax, [ebp+8] 
    mov ebx, [ebp+12] 
    push eax 
    push ebx 
    CALL Add_f 
    LEAVE 
    RET 8 
+0

謝謝!這樣可行!我對ASM非常陌生。對不起,但有一個小問題:在函數被調用後,我在讀00000005時遇到了「訪問衝突」,而OllyDbg評論了「LEAVE」指令。有任何想法嗎?再次感謝! – cdonts

+0

第一段中的語句不正確 - x86支持'push dword ptr [ebp + 8]'這樣的指令,允許您從內存中讀取值並一次將其全部推送到堆棧上。你的asm代碼破壞'ebx',這通常是被保存的,所以可能會導致問題。改用'ecx'或'edx'。 –

+0

@ChrisDodd:你(可能)在想另一個編譯器和/或64位代碼嗎?對於32位VC++:[使用__asm在C/C++函數中編寫彙編語言時,不需要保留EAX,EBX,ECX,EDX,ESI或EDI寄存器。](http:// msdn。 microsoft.com/en-us/library/k1a8ss06。aspx) –