[C] innline Assembler -> Array



  • Hallo,

    ich hoffe ich hab hier im richtigen Forum gepostet, sonst bitte verschieben.
    Also, ich brauche eure Hilfe. Und zwar bin ich auf der suche danach, wie man ueber den Befehl asm in C aus einem Array die Summe bildet.
    Dabei stellt sich mir die Frage, wie kann ich auf die einzelnen Elemente des Arrays zugreifen, in Assembler gibt es doch nicht die [position] -Notation von C, oder?
    Wie ihr vielleicht gemerkt hab bin ich relativ neu in der Assembler-Programmierung, alles was ich bis noch hingekriegt habe ist die Addtion zweir Zahlen, wie gesagt, mir fehlt der Zugriff auf die Einzelnen Elemente.

    Bitte um Hilfe ...

    vielen dank schon mal im Voraus!

    mfg



  • Tipp: In C implementieren und schauen was dann für Assemblercode raus kommt.

    Gruß



  • Wenn du z.B. in eax die Basisadresse des Arrays lädst und in ecx den Schleifenzähler, kannst du mit [eax + 4*ecx] auf einzelne 32 Bit ints in diesem Array zugreifen. Oder du zählst gleich eax bei jedem Durchlauf um 4 hoch.



  • Hier mal Code-Beispiel wie ich denken würde:

    DWORD meinarray[10];
    __asm {
      mov edx, meinarray      ; ptr auf meinarray laden
      xor ecx, ecx            ; ecx auf 0 setzen
      xor eax, eax            ; eax auf 0 setzen
    _loop:
        add eax, dword ptr [edx+ecx*4]    ; *4 weil sizeof(DWORD) = 4, "dword" ptr = das dword auf welches der ptr zeigt
        inc ecx               ; ecx um einen erhöhen
        cmp ecx, 10           ; prüfen ob 10 erreicht ist
        jnz _loop             ; wenn nein, wieder zurück zur loop
    
      mov meinevariable, eax  ; ergebnis speichern
    }
    

    Ich möchte für die Funktionalität diese Beispiels nicht garantieren. 😉 Aber so ungefähr müsste es meiner Meinung nach aussehen.


  • Mod

    M™ schrieb:

    Hier mal Code-Beispiel wie ich denken würde:

    DWORD meinarray[10];
    __asm {
      mov edx, meinarray      ; ptr auf meinarray laden
      xor ecx, ecx            ; ecx auf 0 setzen
      xor eax, eax            ; eax auf 0 setzen
    _loop:
        add eax, dword ptr [edx+ecx*4]    ; *4 weil sizeof(DWORD) = 4, "dword" ptr = das dword auf welches der ptr zeigt
        inc ecx               ; ecx um einen erhöhen
        cmp ecx, 10           ; prüfen ob 10 erreicht ist
        jnz _loop             ; wenn nein, wieder zurück zur loop
    
      mov meinevariable, eax  ; ergebnis speichern
    }
    

    Ich möchte für die Funktionalität diese Beispiels nicht garantieren. 😉 Aber so ungefähr müsste es meiner Meinung nach aussehen.

    mov edx, meinarray
    

    geht nat. nicht, damit greifts du auf das erste element zu. korrekt wäre

    lea edx, meinarray
    

    (meinarray ist ja auto)
    meinarray ist ja nichts weiter als esp[irgendein offset] - und weil das so ist, kannst du auf das laden auch verzichten (ausserdem sparen wir uns den (in diesem falle sowieso überflüssigen) override):

    DWORD meinarray[10];
    __asm {
      mov ecx, -sizeof meinarray / sizeof DWORD
      xor eax, eax
    _loop:
        add eax, meinarray[ecx*sizeof DWORD + sizeof meinarray]
        inc ecx
        jnz _loop
      mov meinevariable, eax  ; ergebnis speichern
    }
    

    (bin jetzt nicht ganz sicher ob man beim inline assembler sizeof auch so anwenden darf - beim externen geht es jedenfalls)



  • Das "lea edx, meinarray" stimmt, liegt wohl daran, dass ich nie mit statischen Arrays arbeite.

    Wenn du mich fragst verringert dieses ständige sizeof die Leserlichkeit... mein Vorschlag wäre:

    DWORD meinarray[10];
    __asm {
      mov ecx, -10    ; array hat 10 felder, also 10
      xor eax, eax
    _loop:
        add eax, dword ptr [meinarray+40+ecx*4]  ; meinarray+40 = letztes element, ecx*4 von -40 bis 0
        inc ecx
        jnz _loop
      mov meinevariable, eax  ; ergebnis speichern
    }
    

    Naja aber jeder wie ers für richtig hält. Hauptsache es ist gleich schnell. ^^ Diese Art der Aufwärtszählung von ecx ist übrigens besser als meine. 😉



  • DWORD meinarray[10];
    __asm {
             mov si,meinarry   //meinarray Adresse nach si
             mov ecx,10        //für 10 DWORDS addieren
             xor ebx,ebx       
    next:
             lodsd             //Lädt über den Index Si ein DWORD aus meinarry,dach
                               //wird Si um 4 erhöht
             add ebx,eax
             loop next         //schon alle 10 Werte
             mov Ergebniss,ebx  
    }
    

  • Mod

    hermes schrieb:

    DWORD meinarray[10];
    __asm {
             mov si,meinarry   //meinarray Adresse nach si
             mov ecx,10        //für 10 DWORDS addieren
             xor ebx,ebx       
    next:
             lodsd             //Lädt über den Index Si ein DWORD aus meinarry,dach
                               //wird Si um 4 erhöht
             add ebx,eax
             loop next         //schon alle 10 Werte
             mov Ergebniss,ebx  
    }
    

    lodsd impliziert esi. langsamer und brauch mehr register ==> Papierkorb 😉

    M™ schrieb:

    Das "lea edx, meinarray" stimmt, liegt wohl daran, dass ich nie mit statischen Arrays arbeite.

    Wenn du mich fragst verringert dieses ständige sizeof die Leserlichkeit... mein Vorschlag wäre:
    ...
    Naja aber jeder wie ers für richtig hält. Hauptsache es ist gleich schnell. ^^ Diese Art der Aufwärtszählung von ecx ist übrigens besser als meine. 😉

    magische konstanten mitten im code sind doof weil nicht wartbar, dann definier dir wenigstens welche unmittelbar nachdem das feld deklariert wurde. das würde ich auch tun, wenn die funktion länger wäre. wenns wirklich leserlich sein soll, nimmt man sowieso kein inline assembler - wozu gibts std::accumulate 😉



  • lodsd impliziert esi. langsamer und brauch mehr register

    Kann nicht glauben das

    add eax, dword ptr [meinarray+40+ecx*4]  ; meinarray+40 = letztes element, ecx*4 von -40 bis 0
        inc ecx
        jnz _loop
    

    schneller ist als

    next:
             lodsd             //Lädt über den Index Si ein DWORD aus meinarry,dach
                               //wird ESi um 4 erhöht
             add ebx,eax
             loop next         //schon alle 10 Werte
    

    ist.



  • Dann glaub's halt nicht, aber der loop-Befehl allein ist saulangsam. Du kannst es ja empirisch nachweisen, dann wirst auch du überzeugt sein.


  • Mod

    hermes schrieb:

    Kann nicht glauben das

    nicht glauben, messen. 😉
    wie bereits erwähnt, legst du dich auf eine bestimmte registerbelegung fest, das ist schon mal ungünstig. im übrigen sind load-execute befehle expliziten load und executes grundsätzlich vorzuziehen (schneller und brauchen weniger code und führen zu weniger abhängigkeiten). auf allen modernen x86 prozessoren bringt loop keinerlei geschwindigkeitsvorteil; i.allg. ist es langsamer, definitiv zumindest mit intel prozessoren. das geeignete mittel, um hier zu beschleunigen, ist sowieso loop-unrolling und vektorisierung.


Anmelden zum Antworten