Untersuchen von Code, der vom C ++ - Compiler von Visual Studio erstellt wurde, Teil 1 [Duplizieren]

7

Hintergrund

Ich lerne gerade x86 asm, indem ich den vom Compiler generierten Binärcode untersuche.

Code, der mit dem C ++ - Compiler in Visual Studio 2010 Beta 2 kompiliert wurde.

%Vor%

C-Code (sandbox.c)

%Vor%

Kompilieren Sie es mit der Visual Studio-Eingabeaufforderung

%Vor%

Disasm sandbox.exe in OllyDgb

Der folgende beginnt am Einstiegspunkt.

%Vor%

Prüfung

%Vor%

Dieser Teil stört mich:

%Vor%

Sie können alles notieren und die Werte von EAX und ECX bleiben am Ende gleich. Also, was ist der Sinn dieser Anleitung?

    
user200557 01.11.2009, 20:06
quelle

4 Antworten

11

Das Ganze

%Vor%

steht für y /= 2 . Sie sehen, ein eigenständiges SAR würde die Ganzzahl-Division mit Vorzeichen nicht so ausführen, wie es die Autoren des Compilers beabsichtigten. C ++ 98 Standard empfiehlt , dass eine Ganzzahldivision mit Vorzeichen das Ergebnis in Richtung 0 rundet, während SAR allein auf die negative Unendlichkeit abgerundet wird. (Es ist erlaubt, in Richtung der negativen Unendlichkeit zu runden, die Wahl bleibt der Implementierung überlassen). Um eine Rundung auf 0 für negative Operanden zu implementieren, wird der obige Trick verwendet. Wenn Sie einen vorzeichenlosen Typ anstelle eines vorzeichenbehafteten Typs verwenden, generiert der Compiler nur eine einzige Schiebeanweisung, da das Problem mit der negativen Division nicht auftritt.

Der Trick ist ziemlich einfach: für negative y Zeichenerweiterung wird ein Muster von 11111...1 in EDX platziert, was tatsächlich -1 in der Zweierkomplementdarstellung ist. Das folgende SUB addiert effektiv 1 zu EAX , wenn der ursprüngliche y Wert negativ war. Wenn das ursprüngliche y positiv (oder 0) war, behält das EDX 0 nach der Vorzeichenerweiterung und EAX bleibt unverändert.

Mit anderen Worten, wenn Sie y /= 2 mit signierten y schreiben, generiert der Compiler den Code, der mehr wie folgt vorgeht:

%Vor%

oder, besser

%Vor%

Beachten Sie, dass der C ++ - Standard nicht erfordert, dass das Ergebnis der Division auf Null gerundet wird, sodass der Compiler auch für signierte Typen nur eine einzige Verschiebung ausführen kann. Normalerweise folgen Compiler jedoch der Empfehlung , um auf Null zu runden (oder bieten eine Option, um das Verhalten zu steuern).

P.S. Ich weiß nicht genau, was der Zweck dieser Anweisung LEA ist. Es ist in der Tat ein No-Op. Ich vermute jedoch, dass dies nur eine Platzhalteranweisung sein könnte, die in den Code für weiteres Patchen eingefügt wird. Wenn ich mich richtig erinnere, hat der MS-Compiler eine Option, die das Einfügen von Platzhalteranweisungen am Anfang und am Ende jeder Funktion erzwingt. In der Zukunft kann diese Anweisung vom Patcher mit einer Anweisung CALL oder JMP überschrieben werden, die den Patch-Code ausführt. Dieses spezifische LEA wurde nur ausgewählt, weil es den a no-op-Platzhalterbefehl der richtigen Länge erzeugt. Natürlich könnte es etwas ganz anderes sein.

    
AnT 01.11.2009 20:18
quelle
5

Das lea ebx,[ebx] ist nur eine NOP-Operation. Sein Zweck ist es, den Anfang der Schleife im Speicher auszurichten, wodurch sie schneller wird. Wie Sie hier sehen können, beginnt der Anfang der Schleife bei der Adresse 0x00401010, die dank dieser Anweisung durch 16 teilbar ist.

Die Operationen CDQ und SUB EAX,EDX stellen sicher, dass die Division eine negative Zahl in Richtung Null aufrundet - andernfalls würde SAR sie abrunden und falsche Ergebnisse für negative Zahlen liefern.

    
interjay 01.11.2009 20:16
quelle
2

Der Grund, warum der Compiler dies ausgibt:

%Vor%

anstelle des semantisch äquivalenten:

%Vor%

.. ist, dass es für den Prozessor schneller ist, einen 6-Byte-Befehl als sechs 1-Byte-Befehle auszuführen. Das ist alles.

    
caf 02.11.2009 04:13
quelle
1

Dies beantwortet die Frage nicht wirklich, ist aber ein hilfreicher Hinweis. Anstatt mit der OllyDbg.exe-Sache herumzualbern, können Sie Visual Studio veranlassen, die asm-Datei für Sie zu generieren, die den zusätzlichen Bonus hat, dass sie als Kommentare in den ursprünglichen Quellcode eingefügt werden kann. Dies ist keine große Sache für Ihr aktuelles kleines Projekt, aber wenn Ihr Projekt wächst, können Sie am Ende ziemlich viel Zeit damit verbringen, herauszufinden, welcher Assemblercode mit welchem ​​Quellcode übereinstimmt.

Über die Befehlszeile möchten Sie die Optionen / FAs und / Fa ( MSDN ).

Hier ist ein Teil der Ausgabe für Ihren Beispielcode (ich habe Debugcode kompiliert, so dass die .asm länger ist, aber Sie können dasselbe für Ihren optimierten Code tun):

%Vor%

Hoffe das hilft!

    
gdunbar 01.11.2009 21:06
quelle

Tags und Links