2010-05-16 76 views
1

這可能很簡單,但由於某種原因,我無法工作。它應該是一個簡單的函數,它將雙字的最後一個字節更改爲「AA」(10101010),但是當我調用該函數時沒有任何反應。它只是返回我的原始雙字。嵌入在C++中的x86彙編中的調用/ Ret

__declspec(naked) long 
    function(unsigned long inputDWord, unsigned long *outputDWord) 
    { 
     _asm{ 
     mov ebx, dword ptr[esp+4] 

    push ebx 
    call SET_AA 
    pop ebx 

    mov eax, dword ptr[esp+8] 
    mov dword ptr[eax], ebx 
     } 
} 

__declspec(naked) unsigned long 

SET_AA(unsigned long inputDWord) 

{ 

     __asm{ 
      mov eax, [esp+4] 
       mov al, 0xAA //10101010 didn't work either 
       ret 
      } 
} 
+0

我的錯誤。我嘗試了10101010,感到沮喪,然後把0xAA(我以爲我之前看到過?)。 (不,不,你不需要) – SP658 2010-05-16 06:36:56

+1

(不,不,你沒關係,我把'AA'看作一個字符串文字,而不是讀取你之後放置的二進制文件。)然而(自從16位處理器開始以來,我試過閱讀程序集),它看起來像是在返回eax中的值而不是使用它(也就是說,你用一個指向[esp + 8]的指針覆蓋它),而且你似乎沒有這樣做即使你推動並彈出它,任何帶有ebx的東西。儘管我可能完全錯誤(就像我說的,這已經有一段時間了)。 – 2010-05-16 06:44:07

回答

0

你的功能SET_AA修改在EAX值(和寄存器只),但你call SET_AA後,您將另一個值到EAX在你的第一個功能,從而覆蓋從SET_AA調用的結果。因此,以不覆蓋EAX(如答案中所示)的方式更改您對寄存器的使用可解決您的問題。

4

你似乎很容易混淆返回一個值,並有一個變量。

這裏:

push ebx 
call SET_AA 
pop ebx 

你像個ebx是一個不折不扣的變量。

這裏:

mov eax, [esp+4] 
mov al, 0xAA //10101010 didn't work either 
ret 

你只是寫東西到eax兩次(一次帶有參數,那麼你覆蓋它與您和0xAA)。 eax傳統上是返回值寄存器。你需要選擇你想使用哪一個。

如果你希望它是你需要做的是這樣的一個out變量:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) { 
    _asm{ 
     mov ebx, dword ptr[esp+4] 

     push ebx 
     call SET_AA 
     pop ebx 

     mov eax, dword ptr[esp+8] 
     mov dword ptr[eax], ebx 
    } 
} 

__declspec(naked) void SET_AA(unsigned long inputDWord) { 
    __asm{ 
     mov [esp+4], 0xAA // put 0xAA into the variable passed on the stack 
     ret 
    } 
} 

如果你想有一個返回值,你可以做這樣的事情:

__declspec(naked) long function(unsigned long inputDWord, unsigned long *outputDWord) { 
    _asm{ 
     mov ebx, dword ptr[esp+4] 

     call SET_AA 
     mov ebx, eax 

     mov eax, dword ptr[esp+8] 
     mov dword ptr[eax], ebx 
    } 
} 

__declspec(naked) unsigned long SET_AA(/* input param not needed, we are just returning a value */) { 
    __asm{ 
     mov eax, 0xAA // return 0xAA via the eax register 
     ret 
    } 
} 
2

我覺得這更像你的意思。一個重要的事情:爲MSDN說,

裸體功能必須提供自己的 序言...和收尾

SET_AA()是好的。它將結果留在eax。 (你能逃脫沒有序言/結尾處理,因爲你是從_asm調用它,而不是C.)

__declspec(naked) unsigned long 
SET_AA(unsigned long inputDWord) 
{ 
    __asm 
    { 
     mov eax, [esp+4] 
     mov al, 0xAA 
     ret    // final value is in eax 
    } 
} 

function()應該返回void,因爲你想要的結果*outputDWord。此外,你還不如用inputDWord而非[ESP + 4]:

__declspec(naked) void 
function(unsigned long inputDWord, unsigned long *outputDWord) 
{ 
    _asm 
    { 
    // you need a prolog/epilog to make C happy 
    // here's the prolog: 
    push ebp 
    mov ebp, esp 

    mov ebx, inputDWord // the value you're going to change 
    mov ecx, outputDWord // address of where to put the result 

    push ebx 
    call SET_AA // puts the result in eax 
    pop ebx 

    // copy the result to the thing ecx points to (*outputDWord) 
    mov [ecx], eax 

    // epilog to keep C happy 
    pop ebp 
    ret 
    } 
} 
0

我與其他哪些用戶同意說。

  1. SET_AA將返回值存儲在EAX寄存器中。但是,不要返回它,而是返回通過它的參數(EBX)。
  2. 您的function最後沒有RET指令。您無法手動將代碼返回給調用者。

此外,我想指出,在function您覆蓋EBX寄存器的值,但不保存(在堆棧中),並在結束時恢復。

您不指定您爲function假設哪種呼叫約定。 (既然你甚至不使用RETRET(8)指令,我不能猜到它是什麼)。 但是根據我所知道的大多數調用約定,它是非法覆蓋EBX寄存器而不在最後恢復它。

函數使用的寄存器(在大多數約定中)是EAX,ECX,EDX。所有其他寄存器也可以隨意使用,但它們必須恢復。

+0

他*確定*調用約定:'裸體'。我不知道你在哪裏提出**「非法」**。除了偶爾的「非法操作」之外,裝配中沒有什麼是「非法」的。 – egrunin 2010-05-16 23:59:39

+0

「裸體」是** NOT **的調用約定。這是編譯器不生成標準函數prolog/epilog代碼的指令。 約定是主叫方和被叫方之間的「協議」。所提供的代碼不符合任何有效的協議。其實這個代碼不會返回它肯定會導致一個未定義的行爲。 – valdo 2010-05-31 22:11:28

0

除非您使用__cdecl作爲調用對話,否則您的函數都會丟失堆棧清理,這將在返回展開堆棧幀時導致問題,以及寄存器未正確保存的事實。

使用的東西多一點的結構,簡潔明瞭的:

__declspec(naked) unsigned long __stdcall SET_AA(unsigned long inputDWord) 
{ 
    __asm 
    { 
     mov eax, [esp+4] 
     mov al, 0xAA 
     retn 4 
    } 
} 

__declspec(naked) void __fastcall function(unsigned long inputDWord, unsigned long *outputDWord) 
{ 
    _asm 
    { 
    push ecx //push inputDWord 
    call SET_AA // puts the result in eax 

    // copy the result to the thing ecx points to (*outputDWord) 
    mov [edx], eax 
    retn//fastcall has no cleaup for the first 2 args 
    } 
} 
0

爲什麼不直接寫C++函數?它高興地提供位操作。

+2

大概這是一個簡單的例子來說明問題。 – 2010-05-16 17:58:08

+0

如果OP有更廣泛的問題,那麼我的答案也是完全可擴展的。在彙編中他可能需要哪些操作,而C++中沒有這些操作? – Puppy 2010-05-16 19:25:00

+3

我確信他只是在自學會議,這是一個完全合理的項目,而且這是一個非常合理的開始。 – egrunin 2010-05-16 23:55:05