2012-04-13 10 views
-1

これはC++のx86インラインアセンブリを使用して、[インテル構文]コールは戻らない正しく[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++?また、私はあなたが知りたいことを理解していません。 –

+1

関数が呼び出されていないという問題はありますか?問題は最初の呼び出しで発生するか、それ以降に発生しますか? –

+1

プッシュ/ポップペアが混在しています( 'eax'と' esi')。おそらく 'mov esi、edx;を使うほうが速いでしょう。 'mov esi、4;の代わりに' shl esi、2'を使います。 imul esi、edx'。機能全体を逆アセンブルしてレビューしましたか?スコット氏のように、呼び出される関数は実際にあなたが期待するシグネチャを持っていますか? – DCoder

答えて

3

コンパイル可能な完全な例をありがとうございました。問題をもっと簡単に解決できます。

スタックフレームが設定されているあなたのCall関数のシグネチャ、によると、lArgsebp+8であり、かつポインタがebp+Cから始まります。そしてあなたにはいくつかの問題があります。ここMSVC 2010(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

1

は私が呼ぶ前に、あなたがEAX、EDX、ESI、ECX(順番に)を押しますが、帰国後、逆の順序でポップしていない、ということに気づきます。最初のCALLが正常に戻っても、それ以降のCALLは戻らなければ、それが問題になる可能性があります。

+0

それは試みの人のためですが、レジスタがスタックからポップされた(今は正しい)方法を逆にした後、最初の関数を呼び出した後も親関数に変わりません。 – iDomo

+0

@iDomo:この関数をどのように呼び出すのか、どの関数ポインタを渡しているか、実際に指し示す関数の例を私たちに示すことができます。 – DCoder

+0

http://pastebin.com/DrXgpBNxありがとう。 – iDomo

関連する問題