2012-04-13 2 views
-1

이것은 C++ 86 인라인 어셈블리를 사용하여 [인텔 문법]전화는 반환하지 제대로 [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;를 사용하는 것이 더 빠를 것입니다. shl esi, 2'mov esi, 4 대신에; imul esi, edx'. 전체 기능을 분해하고 검토 했습니까? Scott이 말했듯이, 호출 된 함수는 실제로 여러분이 기대하는 서명을 가지고 있습니까? – 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를 밀어 것을 알 수 있지만, 복귀 후 역순으로 팝업하지 않습니다. 첫 x 째 CALL이 올 Y 르게 리턴하지만 후속 호출이 그렇지 않으면,. 제 점이 _ 생할 수 있습니다.

+0

그건 시도 녀석들을위한 것이지만, 레지스터가 스택에서 튕겨져 나오는 방식을 뒤집은 후에 (그들은 이제 정확합니다), 첫 번째 함수를 호출 한 후에도 여전히 부모 함수로 돌아갑니다. – iDomo

+0

@iDomo : 그러면이 함수를 어떻게 호출하는지에 대한 예를 보여줄 수 있습니다. 포인터가 전달하는 함수 포인터, 실제로 가리키는 함수 ... – DCoder

+0

http://pastebin.com/DrXgpBNx 감사합니다. . – iDomo

관련 문제