2012-04-13 116 views
-1

這是C++使用x86的內聯組件[Intel語法]呼叫沒有返回正確[X86_ASM]

功能:

 DWORD *Call (size_t lArgs, ...){ 

    DWORD *_ret = new DWORD[lArgs]; 

    __asm { 
     xor edx, edx 
     xor esi, esi 
     xor edi, edi 
     inc edx 
start: 
     cmp edx, lArgs 
     je end 
     push eax 
     push edx 
     push esi 
     mov esi, 0x04 
     imul esi, edx 
     mov ecx, esi 
     add ecx, _ret 
     push ecx 
     call dword ptr[ebp+esi] //Doesn't return to the next instruction, returns to the caller of the parent function. 
     pop ecx 
     mov [ecx], eax 
     pop eax 
     pop edx 
     pop esi 
     inc edx 
     jmp start 
end: 
     mov eax, _ret 
     ret 
    } 
} 

此功能的目的是調用多個功能/地址,而不單獨地調用它們。

爲什麼我要讓你調試它? 我必須開始上課,我需要在晚上完成。

非常感謝,iDomo

+0

哪個編譯器? Visual C++?另外,我不明白你想知道什麼。 – 2012-04-13 12:39:55

+1

你確定問題不在於被調用的函數嗎?第一個電話會發生問題,還是之後呢? – 2012-04-13 12:46:43

+1

您的推/拉對混合在一起('eax'和'esi')。使用'mov esi,edx可能會更快; shl esi,2'而不是'mov esi,4; imul esi,edx'。你有沒有反彙編和審查整個功能?像Scott說的那樣,被調用的函數真的有你期望的簽名嗎? – DCoder 2012-04-13 13:00:07

回答

3

感謝您提供完整的可編譯示例,它使得解決問題變得更容易。

根據您的Call函數簽名,當堆棧幀成立,lArgsebp+8,且指針在ebp+C開始。而且還有其他一些問題。這裏有一個修正版本,一些PUSH/POP優化和清理,2010年MSVC(16.00.40219.01)測試:

DWORD *Call (size_t lArgs, ...) { 

    DWORD *_ret = new DWORD[lArgs]; 

    __asm { 
     xor edx, edx 
     xor esi, esi 
     xor edi, edi 
     inc edx 
     push esi 
start: 
     cmp edx, lArgs 
     ; since you started counting at 1 instead of 0 
     ; you need to stop *after* reaching lArgs 
     ja end 
     push edx 
     ; you're trying to call [ebp+0xC+edx*4-4] 
     ; a simpler way of expressing that - 4*edx + 8 
     ; (4*edx is the same as edx << 2) 
     mov esi, edx 
     shl esi, 2 
     add esi, 0x8 
     call dword ptr[ebp+esi] 
     ; and here you want to write the return value 
     ; (which, btw, your printfs don't produce, so you'll get garbage) 
     ; into _ret[edx*4-4] , which equals ret[esi - 0xC] 
     add esi, _ret 
     sub esi, 0xC 
     mov [esi], eax 
     pop edx 
     inc edx 
     jmp start 
end: 
     pop esi 
     mov eax, _ret 
     ; ret ; let the compiler clean up, because it created a stack frame and allocated space for the _ret pointer 
    } 
} 

大功告成後,不要忘了delete[]從這個函數返回的內存。

+0

謝謝,我還不熟悉C的確切調用約定,也不知道如何從類中調用某些東西。 – iDomo 2012-04-13 14:25:11

1

我注意到,在調用之前,你推EAX,EDX,ESI,ECX(按順序),但在相反的順序返回後不彈出。如果第一個CALL正確地返回,但後來的CALL沒有,那可能是問題。

+0

這是爲了嘗試球員,但是在顛倒寄存器從堆棧彈出的方式(它們現在是正確的)之後,它在調用第一個函數後仍然是父函數。 – iDomo 2012-04-13 13:16:34

+0

@iDomo:那麼你可以告訴我們一個如何調用這個函數的例子 - 你傳遞給它的函數指針,它們實際指向的函數... – DCoder 2012-04-13 13:18:30

+0

http://pastebin.com/DrXgpBNx謝謝。 – iDomo 2012-04-13 13:19:52