8

したがって、C++ dll から関数を呼び出せるようにしたいと考えています。特定の理由から、C++ コードの __asm ブロックからそれらを呼び出したいと考えています。私の質問は次のとおりです。関数を呼び出す前に、関数の呼び出し規則で指定された順序で引数をスタックにプッシュする必要があることはわかっています。

int a=5;   
double b = 5.0;  
__asm{  
       push b 
       push a  
       call functionAddress  
}

私が心配しているのは、アセンブリの標準のワード サイズが 2 バイトであるのに対し、C++ の int のサイズは通常 4 バイトであり、double の場合は 8 バイトであることを覚えているように見えるという事実です。各変数の完全な値をプッシュしますか、それとも最初の数バイトだけをプッシュしますか? 上記のコードが正しくない場合、正しい方法は何でしょうか? また、呼び出している関数が double を返す場合、この値はどこに保存されますか? 32ビット(4バイト)しか保存できないため、レジスタに入れることはできないと思います。この混乱の助けがあれば大歓迎です:)

4

3 に答える 3

13

PUSHdouble などの 8 バイト値をプッシュするには、通常の命令を使用できません。また、浮動小数点パラメーター (または double) を浮動小数点スタックにプッシュすることもありません。これらのファット パラメータを「手動で」スタックに配置する必要があります。たとえば、π をパラメーターとして関数 f にプッシュするには、次のようにします。

  __asm {
    FLDPI                    // load pi onto FP stack
    SUB ESP,8                // make room for double on processor stack
    FSTP QWORD PTR [ESP]     // store pi in proc stack slot (and pop from FP stack)
    CALL f
    ADD ESP,8                // clean up stack (assuming f is _cdecl)
  }
于 2010-02-23T17:42:44.723 に答える
4

32 ビット x86 アーキテクチャは、スタックにプッシュされる値を 32 ビットに自動的にパディングします。

心に留めておかなければならないことがあります。呼び出している関数が __cdecl 呼び出し規則を使用している場合は、後でプッシュしたものを「ポップ」する必要があります。ただし、__stdcall 関数については、これを行ってはなりません。

extern "C" int    __cdecl   function1(int, double);
extern "C" double __stdcall function2(char, char*);

int a = 5;
double b = 5.0;
int retval1;
char c = '5';
char *d = "Hello";
double retval2;

__asm {
    push b
    push a
    call function1
    add esp, 4*2 // "pop" what we pushed
    mov retval1, eax
    push d
    push c
    call function2
    mov retval2, eax
}
于 2010-02-22T18:58:46.847 に答える
1

一般に、コンピュータ ワードのフル サイズをプッシュすることになります。これはチップによって異なりますが、32 ビット Intel では 4 バイト、64 ビット Intel では 8 になります (コンパイラによって異なりますが、Visual Studio は IA32 アセンブリのみをサポートしているため、4 バイトです)。

最良の答えは、特定のコンパイラのドキュメントを参照することです。

于 2010-02-22T18:57:59.097 に答える