Inline Assembler in C



  • Hallo zusammen,

    ich beschäftige mich gerade mit Inline Assembler in C und bin dabei auf ein komisches Phänomen gestoßen. Seht euch bitte mal diesen Code an:

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void) {
    
    	int a, b;
    	int inv[4] = {1,2,3,4};
    	asm( 	
    //		"pushl $0;"	
    		"movups (%%esi), %%xmm0;" //inv in SSE Register xmm0 laden
    		"addps %%xmm0, %%xmm0;" //Jede Zahl mit sich selbst addieren
    		"movups %%xmm0, (%%esi);" //Ergebnis wieder in inv schreiben
    		:
    		:"S" (inv) //inv in %esi laden
    		:"%esi"
    	);
    
    	for(int i = 0; i < 4; i++) {
    		 printf("%d\n", inv[i]);
    	}
    
    	return EXIT_SUCCESS;
    }
    

    Das Programm macht genau das, was es tun soll: Es gibt Folgendes aus:

    2
    4
    6
    8

    Nun habe ich zwei Fragen:

    1.) Das %esi Register ist 32 Bit groß. Wie kann dort aber ein ganzes Array, nämlich inv, passen? Warum funktioniert das?

    2.) Wenn ich die auskommentierte Zeile mitausführe, so wird folgendes ausgeben:

    -1219730907
    4
    6
    8

    Die erste Zahl wird also durch Speichermüll ersetzt? Aber warum? Ich lege die Anfangsadresse des Arrays "inv" doch nur auf den Stack und ändere nichts am %esi-Register. Woher kommt diese Änderung?

    Vielen Dank
    LG, freakC++

    PS.: Falls dieser Thread doch ins Assembler-Forum soll, dann verschiebt ihn bitte dorthin.



    1. In esi steht die Adresse von inv.
    2. Keine Ahnung. Lass dich in Assembler-Forum verschieben, das hat mit C nichts zu tun.


  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C (C89 und C99) in das Forum Assembler verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • 1.) Das bedeutet, dass ein Offset, beispielsweise 4(%esi) nur bedeutet, dass ich auf die Adresse des Arrays 4 addiere? Ok, das leuchtet mir ein.

    2.) Hier suche ich noch eine Antwort 🙂

    Vielen Dank
    LG, freakC++



  • freakC++ schrieb:

    2.) Hier suche ich noch eine Antwort 🙂

    1. Auf jedes PUSH muss auch ein POP folgen.
    2. GCC bekommt von der Veränderung des Stacks nichts mit und belegt ihn für printf nach dem Vor-ASM-Stand.

    Edit: 3. Du legst die Konstante 0 auf den Stack und nicht [inv].

    viele grüße
    ralph



  • Ahh :). Vielen Dank. Das leuchtet mir ein.

    Ich habe noch eine andere Frage:

    Warum wird hier in das komplette Array 0 geschrieben?

    int arr[4] = {1,2,3,4};
    
    	asm(
    		"movups (%%esi), %%xmm0;"
    		"mulps %%xmm0, %%xmm0;" //Ohne diese Zeile wird 1 2 3 4 ausgegeben. Mit dieser Zeile jedoch 0 0 0 0
    		"movups %%xmm0, (%%esi);"
    
    		:
    		:"S"(arr)
    
    	);
    
    	for(int i=0; i<4; i++)
    		printf("%d ", arr[i]);
    

    Ich verstehe nicht, warum hier 0 0 0 0 ausgegeben wird. Der mulps Befehl müsste doch 1*1 2*2 3*3 4*4, also 1 4 9 16 bewirken!?

    Vielen Dank
    LG, freakC++



  • freakC++ schrieb:

    int arr[4] = {1,2,3,4};
            ...
    
    		"mulps %%xmm0, %%xmm0;" //Ohne diese Zeile wird 1 2 3 4 ausgegeben. Mit dieser Zeile jedoch 0 0 0 0
    
    		printf("%d ", arr[i]);
    

    Ich verstehe nicht, warum hier 0 0 0 0 ausgegeben wird. Der mulps Befehl müsste doch 1*1 2*2 3*3 4*4, also 1 4 9 16 bewirken!?

    MULPS verarbeitet Floats. Ändere mal das Int-Array in ein Float-Array und den Formatstring bei printf gleich mit.

    viele grüße
    ralph



  • Ohh! Super, du hast mir sehr geholfen. Jetzt funktioniert. Kennst Du denn einen Befehl, wie ich ints in floats umwandeln kann? Es wäre ja doof, wenn ich nur float-Arrays benutzen könnte.

    Vielen Dank für die Hilfe
    LG, freakC++



  • freakC++ schrieb:

    Kennst Du denn einen Befehl, wie ich ints in floats umwandeln kann? Es wäre ja doof, wenn ich nur float-Arrays benutzen könnte.

    Ich bin auch nicht sooo der SSE-Crack. So funktionierts schon mal:

    #include <stdio.h>
    
    int main ( void )
    {
        float arr[4] = {1,2,3,4};
        int irr[4] = {1,2,3,4};
        asm
        (
            "movups (%%esi), %%xmm0\n"
            "mulps %%xmm0, %%xmm0;"
            "movups %%xmm0, (%%esi)\n"
    
            "movdqu (%%edi), %%xmm0\n"
            "cvtdq2ps %%xmm0, %%xmm0;"      // 4 Integer zu 4 Single Floats
            "mulps %%xmm0, %%xmm0;"
            "cvttps2dq %%xmm0, %%xmm0;"     // 4 Single Floats zu 4 Integer
            "movdqu %%xmm0, (%%edi)\n"
            :
            : "S" (arr), "D" (irr)          // %%esi = [arr], %%edi = [irr]
        );
        puts ("float:");
        for (int i = 0; i < 4; i++) printf("%f\n", arr[i]);
        puts ("\ninteger:");
        for (int i = 0; i < 4; i++) printf("%i\n", irr[i]);
    
        return 0;
    }
    

    viele grüße
    ralph



  • Ich werds ausprobieren. Danke für deine Mühe!

    LG, freakC++


Anmelden zum Antworten