Assembler und C (short int addition)



  • Hallo,

    ich muss (musste) für mein Studium in einer Aufgabe ein Programm in C schreiben, dass zwei short int addiert, und damit erkannt werden kann, ob das ergebnis korrekt ist, soll dies in assembler geschehen, und die flags zurückgegeben werden.
    das problem das ich habe: es funktioniert.
    nach meiner kenntnis aber sollte (im asm teil) die adressen nicht stimmen (stimmen aber)
    ich tipp mal wie ich mir das denke:
    c ruf die funktion addition auf, legt dafür auf den stack die beiden summanden und die adresse von ergebnis.
    die beiden short int sind 16bit lang (2 byte) die adresse 32bit (4byte)
    nun sollte der offset für den ersten summand (da der basepointer auf den stack gepusht wird) bei 6 liegen. funktioniert aber nur mit 8.
    wo liegt mein denkfehler?
    hier die codes:

    #include <stdio.h>
    
    extern int addition(short int summand1, short int summand2, short int *ergebnis);
    
    int main()
    {
    int flaguebergabe;
    short int summand1;
    short int summand2;
    short int ergebnis;
    
    while(summand1 != 1212)
    {
    	printf("Geben Sie den ersten Summanden ein:");
    	scanf("%hd", &summand1);   //liest short int
    	printf("Erhalten: %d\n", summand1);
    
    	printf("Geben Sie den zweiten Summanden ein:");
    	scanf("%hd", &summand2); //liest short int
    	printf("Erhalten: %d\n", summand2);
    
    	printf("short int:%d\n", sizeof(short int)); // short int größe
    	printf("Adresse 1:%p\n", &summand1); //adressen ausgabe
    	printf("Adresse 2:%p\n", &summand2);
    
    	printf("Ergebnis aus C:\t\t %d + %d = %d\n", summand1, summand2, summand1 + summand2); //"normal" berechnet"
    
    	flaguebergabe = addition(summand1, summand2, &ergebnis); //assembler programm
    	printf("Ergebnis aus ASM:\t %d + %d = %d\n", summand1, summand2, ergebnis);
    	printf("Ergebnis aus ASM:\t %d + %d = %d\n", (unsigned)summand1, (unsigned)summand2, (unsigned)ergebnis);
    
            // den erhaltenen int (aus eax) bitweise ausgeben
    	int i;
    	printf("                      ODIT SZ A P C\n");
    	for(i = sizeof(flaguebergabe)*8-1;i>=0;--i)
    	{
    	printf("%ld%s",(flaguebergabe>>i) & 1, (i%8==0) ? " " : "");
    	}
    	printf("\n");
    
    }
    
    return 0;
    
    }
    
    global addition	
    addition: 
    	push ebp		;basepointer auf stack retten
    	mov ebp, esp            ;basepointer auf stack setzen
    	mov bx, [ebp+8]         ;hier ist meine erste frage
                                    ;summand 1 bekommen
                                    ;da es short int ist, müssten es doch nur
                                    ;4(ebp) + 2(16bit) offset sein?
    	add bx, [ebp+12]        ; summand 2 bekommen
                                    ; hier die gleiche frage
    	mov ecx, [ebp+16]       ; adresse von ergebnis
                                    ;wieder die gleiche frage, wobei hier es ja
                                    ;logisch ist, wenn die vorrigen werte klar sind
    	mov [ecx], bx           ; ergebnis auf die int adresse schreiben
    
    	pushfd		        ; flags auf stack	
    	pop eax                 ; flags in eax (müsste hier 
    		                ; nicht angegeben werden, das er 32bit
                                    ; popen soll)
    	pop ebp			;basepointer zurücksetzen
    	ret
    


  • Dafür braucht man doch kein Assembler

    int main() {
      short lhs = SHRT_MAX;
      short rhs = 1;
      short res;
    
      int t = lhs + rhs;
      if(t > SHRT_MAX || t < SHRT_MIN) {
        puts("overflow");
      }
      else {
        res = t;
        printf("%hd\n", res);
      }
    }
    

    edit: Casts entfernt.



  • int t = (int)lhs + (int)rhs;
    

    Werden beim Rechnen mit Zahlen nicht sowieso alle short's zu int's gemacht? Dann könnte man sich nämlich die beiden Casts sparen.



  • µngbd schrieb:

    int t = (int)lhs + (int)rhs;
    

    Werden beim Rechnen mit Zahlen nicht sowieso alle short's zu int's gemacht? Dann könnte man sich nämlich die beiden Casts sparen.

    Oh, hast recht. Man braucht die Casts nicht, da es zu int promoted wird.



  • Der Stack wird standardmäßig auf 4 Byte ausgerichtet. Also belegt jeder Wert mindestens 32 Bit. Das dürfte den Compilern einiges an Arbeit sparen, da sie sich nur die Zahl der Parameter merken müssen und nicht noch deren Größe. Laut der GCC Doku wird sobald man long long oder double benutzt das ganze sogar auf 8 Byte erhöht, da es ansonsten deutliche Performance Einbußen entstehen.

    Und bei "pop eax" weiß der Assembler das der 32 Bit Befehl gemeint ist, weil mit eax ein 32 Bit Register angegeben ist. Bei "pop ax" würde er entsprechend den 16 Bit Befehl wählen.



  • Tobiking2 schrieb:

    Der Stack wird standardmäßig auf 4 Byte ausgerichtet. Also belegt jeder Wert mindestens 32 Bit. Das dürfte den Compilern einiges an Arbeit sparen, da sie sich nur die Zahl der Parameter merken müssen und nicht noch deren Größe. Laut der GCC Doku wird sobald man long long oder double benutzt das ganze sogar auf 8 Byte erhöht, da es ansonsten deutliche Performance Einbußen entstehen.

    Und bei "pop eax" weiß der Assembler das der 32 Bit Befehl gemeint ist, weil mit eax ein 32 Bit Register angegeben ist. Bei "pop ax" würde er entsprechend den 16 Bit Befehl wählen.

    perfekt, danke!


Anmelden zum Antworten