Как остановить ESP от повреждения в __fastcall? - PullRequest
1 голос
/ 04 декабря 2011

Я пытаюсь написать функцию в ассемблере, которая устанавливает блок памяти в указанное значение, очень похоже на memset (), однако, когда я собираюсь получить третий аргумент из стека (он использует соглашение о вызовах fastcall ), регистр ECX получает искаженное значение.

Поместив код в Visual Studio с использованием встроенной сборки, я вижу, что ESP значительно изменяется при вызове функции. Первые два аргумента вводятся в ECX и EDX без каких-либо проблем, только третий вызывает проблемы.

Я знаю, что код работает, блок памяти заполняется правильным значением, когда я вручную устанавливаю значение в регистр во время отладки в 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;
    }


Ответы [ 2 ]

2 голосов
/ 04 декабря 2011

Проблема в том, что это функция, компилятор уже выдал некоторые переменные. У gcc есть способ обращения к переменным, я не знаю насчет MSVC

2 голосов
/ 04 декабря 2011

Первым делом в стеке вызываемого кода будет адрес возврата для вызова.Второй аргумент будет первым аргументом.

Чтобы избежать изменения ESP и исправить проблему «высовывания неправильной вещи», попробуйте что-то вроде «mov ecx, [esp + 4]» (вместо «»pop ecx ").

...