2012-04-13 7 views
-1

Dies ist C++ mit x86-Inline-Assembly [Intel Syntax]Anruf nicht zurückkehr richtig [X86_ASM]

Funktion:

 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 
    } 
} 

Der Zweck dieser Funktion ist es, mehrere Funktionen/Adressen aufrufen, ohne sie einzeln aufrufen .

Warum habe ich Sie debuggen? Ich muss die Schule für den Tag beginnen, und ich muss es bis zum Abend geschafft haben. alot

Danke, iDomo

+0

Welcher Compiler? Visual C++? Außerdem verstehe ich nicht, was du wissen willst. –

+1

Sind Sie sicher, dass das Problem nicht mit der aufgerufenen Funktion verbunden ist? Tritt das Problem beim ersten Anruf oder danach auf? –

+1

Ihre Push/Pop-Paare sind durcheinander ('eax' und' esi'). Es wäre wahrscheinlich schneller zu benutzen 'mov esi, edx; shl esi, 2' statt 'mov esi, 4; imul esi, edx'. Haben Sie die gesamte Funktion demontiert und überprüft? Wie Scott sagte, haben die aufgerufenen Funktionen wirklich die Signatur, die Sie erwarten? – DCoder

Antwort

3

Vielen Dank für ein komplettes kompilierbares Beispiel, das die Problemlösung viel einfacher macht.

Nach Ihrer Call Funktion Signatur, wenn der Stapelrahmen eingerichtet ist, ist die lArgs bei ebp+8, und die Zeiger beginnen bei ebp+C. Und Sie haben ein paar andere Probleme. Hier ist eine korrigierte Version mit einigen Push/Pop-Optimierungen und Bereinigung, getestet auf 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 
    } 
} 

Und vergessen Sie nicht zu delete[] den Speicher von dieser Funktion zurück, nachdem Sie fertig sind.

+0

Danke, ich bin noch nicht vertraut mit den genauen Aufrufkonventionen von C, noch wie das Aufrufen von etwas aus einer Klasse funktioniert. – iDomo

1

Ich stelle fest, dass vor dem Aufruf, Sie drücken EAX, EDX, ESI, ECX (in dieser Reihenfolge), aber nicht in der umgekehrten Reihenfolge Pop nach der Rückkehr. Wenn das erste CALL korrekt zurückkehrt, aber nachfolgende nicht, könnte das Problem sein.

+0

Das ist für die Versuche Jungs, aber nach dem Umkehren der Art und Weise, wie die Register vom Stapel genommen werden (sie sind jetzt korrekt), geht es immer noch um die Elternfunktion nach dem Aufruf der ersten Funktion. – iDomo

+0

@iDomo: Dann könnten Sie uns ein Beispiel zeigen, wie Sie diese Funktion aufrufen - welche Funktionszeiger Sie übergeben, die Funktionen, auf die sie tatsächlich zeigen ... – DCoder

+0

http://pastebin.com/DrXgpBNx Vielen Dank . – iDomo