Einige Fragen zu Dissambly von Microsoft Visual Studio 2010
-
Ich sehe mir in letzter Zeit gerne mal das disassembly meines C++ Codes an und beginne gleichzeitig (möglicherweise unberechtigerweise) das Vertrauen in MS Visual Studio 2010 zu verlieren. Hier ein kleines Beispiel:
// ----------------------------------------- public operator "*=" ---------------------------------------- // This operator multiplies the parametric matrix by this matrix and returns a copy of the result. // Author: Samuel Lörtscher // ------------------------------------------------------------------------------------------------------- Matrix Matrix::operator*=(const Matrix &M){ 00F83430 push ebp 00F83431 mov ebp,esp 00F83433 sub esp,114h // NO SUB ESP,10h fucking hell 00F83439 push ebx 00F8343A push esi 00F8343B push edi // ****** WTF :eek: ****** 00F8343C push ecx 00F8343D lea edi,[ebp-114h] 00F83443 mov ecx,45h 00F83448 mov eax,0CCCCCCCCh 00F8344D rep stos dword ptr es:[edi] 00F8344F pop ecx 00F83450 mov dword ptr [ebp-8],ecx // ************************** // declare and init local variables Matrix m = *this; 00F83453 mov esi,dword ptr [this] 00F83456 mov ecx,10h 00F8345B lea edi,[m] 00F8345E rep movs dword ptr es:[edi],dword ptr [esi]
Ich habe genau eine lokale Variable, eine 4x4 Matrix, das wäre dann sub esp,10h, wieso dann sub esp,114h? Ist der verrückt geworden? Und dann der untere Teil, wieso schreddert der mit das ohnehin bereits viel zu grosse Stackframe voll??
Noch eine frage, ich habe bei den Compileroptions den SSE Befehlssatz aktiviert, kann aber dennoch im ganzen Binary nicht einen einzigen SSE Opcode entdecken?? Auch die Matrizenmultiplikation, welche sich IMHO wirklich perfekt in die 128-Bit SSE Register einfügen lassen würden, wird dennoch munter mit der langsamen FPU berechnet?
Was meint Ihr dazu?
Mfg Samuel
-
der code den du mit 'WTF' Kommentiert hast, wird nur im debug build Erzeugt - im release sollte Dieser nicht mehr erscheinen.
Im weiteren solltes du den verwendeten Datentyp beachten: hierbei handelt es sich sicherlich um double (oder singel) -> 4*4*8 = 128.
Auserdem wird höchst wahrscheinlich Platz für Zwischenergebnisse auf den Stack gemacht.SSE kann man hier verwenden, häng aber vom Compiler, Zeielprozessor und den verwendeten Algorithmus ab (den du hier nich Zeigst!) - So etwas implemetiert man normalerweise Händisch (inline oder externer Assembler), da Compiler sich meistens mit SIMD schwer tuen
-
Welche Optimierungen hast du alle im Compiler aktiviert?
MfG SideWinder
-
@masm
(4*4*4)/4 = (64/4) = 16 -> 10h :pESP ist ja IMHO 32-bit aligned?
Zwischenergebnisse gibt es IMHO keine, resp. werden diese direkt in die Zielmatrix gespeichert (16 Dot Produkte).Ich habe noch gelesen, dass SIMD nur dann sinnvoll sei, wenn man lange streams damit bearbeite, weil dir Initialisierungszeit so extrem hoch sei, ist das korrekt?
@SideWinder
Im Debug Mode keine und im ReleaseMode kann ich keinen Breakpoint setzten um mir das dissembly anzusehen (und im Binary suchen mag ich es auch nicht
-
Ishildur schrieb:
@masm
(4*4*4)/4 = (64/4) = 16 -> 10h :pESP ist ja IMHO 32-bit aligned?
Warum teilst du durch 4? - Wenn es nötig währe, müsste man Aufrunden.
Ishildur schrieb:
Ich habe noch gelesen, dass SIMD nur dann sinnvoll sei, wenn man lange streams damit bearbeite, weil dir Initialisierungszeit so extrem hoch sei, ist das korrekt?
Dem stimme ich nicht zu, zumidest allgmein. In deinem Fall würde es sich auf jedem Fall lohnen.
-
Warum teilst du durch 4? - Wenn es nötig währe, müsste man Aufrunden.
Muss ich nicht?
Was passiert dann wenn ich bspw. sub esp 3 mache? Sind das 3 Bytes? Ich dachte dass sind 3 ints...Hmmm... Was passiert dann wenn ich nach sub esp 3 schliesslich noch ein call auf eine Procedur mache? Findet diese Prozedur dann seine Rücksprungadresse noch? Würde mich sehr wundern...
-
Du solltes dir noch mal die Grundlagen zu Gemüte führen.
Wenn du 3 bytes an Platz brauchst, musst du den Wert auf 4 Aufrunden:
x=3 x_aligned = (x+3)/4
Wenn esp unaligned ist löst der nächste Befehl, der auf den Stack zugreift, eine exeception aus - das Programm stürtzt ab.
Im übrigen währe es etwas Eindeutiger, wenn du statt von int besser von byte,word,doubleword,... redest. (für mich ist z.B. int eine 32Bit Integer (x86-32/64))
-
ups: es muss heißen:
x=3 x_aligned = (x+3)&(-4)
-
@masm
Ja ich kannte Assembler eigentlich mal sehr gut (habe auch mal ein komplettes Game geschrieben, dass ohne Betriebssystem auskam) Ist aber auch schon 2 Jahre her und war im RealMode nur 386er Befehle. Und seither habe ich nie mehr was mit Assembler gemacht (immer nur kurz über die Disassemblies geflogen!
-
Ishildur schrieb:
... Ich habe genau eine lokale Variable, eine 4x4 Matrix, das wäre dann sub esp,10h, wieso dann sub esp,114h? Ist der verrückt geworden? Und dann der untere Teil, wieso schreddert der mit das ohnehin bereits viel zu grosse Stackframe voll?? ...
Ja, das ist interessant. In C++ Pseudo-Code wäre das ungefähr folgendes (wenn ich es richtig sehe):
Matrix Matrix::operator*=(const Matrix &M) { struct _Stackframe { uint32_t saved_ebp; uint32_t data[69u]; uint32_t saved_ebx; uint32_t saved_esi; uint32_t saved_edi; } Stackframe; uint32_t i = 0u; for (i = 0u; i < 69u; ++i) { Stackframe.data[i] = 0xCCCCCCCCu; } ...
Vielleicht versucht der Compiler, auf diese Weise Buffer-Overflows zu erkennen
Ich meine, vielleicht wird am Ende der Funktion geprüft, ob in diesem Stackframe noch lauter 0xCCCCCCCC drin stehen, wenn ja - alles ok, wenn nein - in deiner Funktion wird irgendwo über die Grenzen hinaus geschrieben...
Ishildur schrieb:
Im Debug Mode keine und im ReleaseMode kann ich keinen Breakpoint setzten um mir das dissembly anzusehen (und im Binary suchen mag ich es auch nicht
Gibt es in Visual Studio keine Tools, so was wie objdump?
Man könnte damit so was machen:objdump -D program.exe
Oder, wenn noch so was wie c++filt da wäre:
objdump program.exe | c++filt
Es kann ja nicht sein, dass die Objektdateien und die Exe wie Blackboxes da wären...