2011-12-04 2 views
1

memset()과 같이 메모리 블록을 지정된 값으로 설정하는 어셈블리에서 함수를 작성하려고합니다.하지만 스택에서 세 번째 인수를 가져올 때 (fastcall 호출 규칙을 사용함) , 레지스터, ECX는 왜곡 된 값을 얻습니다.__fastcall에서 ESP가 손상되는 것을 어떻게 방지합니까?

인라인 어셈블리를 사용하여 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; 
    } 

 
+0

'#define ret return'? 얼마나 게으른가? – Dani

+0

VS에서 디스 어셈블리 뷰를 활성화하고 코드에서 무엇이 생성되는지 확인할 수 있습니다. –

답변

2

제일 먼저 호출의 반환 주소가됩니다. 두 번째 것은 첫 번째 인수가 될 것입니다.

ESP 변경을 피하고 "잘못된 것을 터뜨리기"문제를 해결하려면 "pop ecx"대신 "mov ecx, [esp + 4]"와 같은 것을 시도하십시오.

+0

__declspec (naked)를 추가 한 후,'mov ecx, [esp + 4]'가 완벽하게 작동했습니다. 감사. – vs49688

2

문제는 이것이 함수에 있다는 사실입니다. 컴파일러는 이미 변수 중 일부를 팝했습니다. gcc는 변수를 참조 할 수있는 방법이 있습니다. MSVC에 대해 모르겠습니다.

+0

컴파일러에 대한 예기치 않은 혼란이 프롤로그/에필로그에서 발생할지 여부를 알 수있는 방법이 없습니다. – Brendan

+0

이것은 __declspec (알몸)으로 선언하는 것을 잊어 버렸습니다. 일단 그렇게하면 컴파일러는 함수가 실행되기 전과 후에 더이상 망가질 수 없습니다. – vs49688

관련 문제