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 :p 😉 ESP 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 :p 😉 ESP 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... 🙂


Anmelden zum Antworten