1

memset()のように、メモリのブロックを指定された値に設定する関数をアセンブリで書き込もうとしていますが、スタックから3番目の引数を取得しようとすると(fastcall呼び出し規約を使用します)、レジスタECXは、文字化けした値を取得します。

インラインアセンブリを使用してコードをVisualStudioに配置すると、関数が呼び出されたときにESPが大幅に変更されることがわかります。最初の2つの引数は問題なくECXとEDXに入れられており、問題を引き起こしているのは3番目の引数にすぎません。

VSでデバッグしているときにレジスタに値を手動で設定すると、コードが機能することを知っています。メモリのブロックは正しい値で満たされます。

私はアセンブリに比較的慣れていないので、私のコードはおそらく少し危険ですが、誰かがこの問題を修正する方法を知っていますか?

コードは以下のとおりです。



    #ifdef __GNUC__
    #define __fastcall  __attribute__((fastcall)) // 'Cause I'm a M$ fanboy
    #endif

    void __fastcall memset(void *pDest, int iValue, int iSize)
    {
        __asm
        {
            ; Assume the pointer to the memory is stored in ECX
            ; Assume the value is stored in EDX
            ; Assume the size of the block is stored on the stack

                mov eax, esi        ; Put ESI somewhere it won't be touched (I think)

                mov esi, ecx        ; Move the address of the memory into ESI
                xor ecx, ecx        ; Zero ECX

                pop ecx             ; Get the size of the block into ECX. ECX is our loop counter

            memset_count:
                cmp ecx, 0          ; If we are at the end of the block,
                jz memset_return    ; Jump to return

                mov [esi], edx      ; Move our value into the memory
                inc esi             ; Otherwise, increment out position in the memory
                dec ecx             ; Decrement out counter
                jmp memset_count    ; Start again

            memset_return:
                mov esi, eax        ; Restore ESI
                add esp, 4          ; Remove our third argument from the stack
                ret
        }
    }

    #define ret return

    int main(int argc, char **argv)
    {
        char szText[3];

        /*
        __asm
        {
            push 3
            mov edx, 65
            lea ecx, szText2
            call memset
        }
        */
        memset(&szText, 'A', 3);

        ret 42;
    }


4

2 に答える 2

2

呼び出されたコードのスタックの最初のものは、呼び出しのリターンアドレスになります。2番目は最初の引数になります。

ESPの変更を回避し、「間違ったものをポップする」問題を修正するには、(「pop ecx」の代わりに)「mov ecx、[esp+4]」のようなものを試してください。

于 2011-12-04T04:43:25.283 に答える
2

問題は、これが関数内にあり、コンパイラーがすでにいくつかの変数をポップしているという事実です。gccには変数を参照する方法があります。MSVCについてはわかりません。

于 2011-12-04T04:45:55.453 に答える