Assembler Simulieren



  • Um aus deinem Asm-Code ein Programm zu machen benötigst du Assembler + Linker. Normalerweise würde ich hier auf NASM verweisen, aber der kennt nur seine Intel-Syntax.
    Für dich dürfte "as" aus dem GCC-Toolset als Assembler taugen und der "ld" als Linker, welcher ebenfalls beim GCC dabei sind.



  • Ich hab jetzt mal versucht das in intel Code umzuwandeln

    .text
    
    main:
    	push	ebp
    	mov	ebp, esp
    	and	esp, 8
    	sub	esp, 24
    	mov	[esp+20], 5
    	mov	eax, [esp+20]
    	mov	esp, eax
    	call	square
    	mov	[esp+16], eax
    	mov	eax, 0
    ;	leave
    	ret
    
    square:
    	push	ebp
    	mov	esp, ebp 
    	sub	 esp, 16
    	mov	 eax, [ebp+8]
    	imul	 eax, [ebp+8]
    	mov	edx, 0
    	mov	[ebp-8], eax 
    	mov	[ebp-4], edx
    	mov	eax, [ebp-8]
    	mov	edx, [ebp-4]
    ;	leave
    	ret
    

    Da wird dann aber ständig Speichterunterlauf/überlauf gemeckert ...



  • Wobei ich eigentlich nur zwei Fragen habe ...

    Was macht folgender Teil und brauche ich ihn wirklich?

    mov    [ebp-8], eax
        mov    [ebp-4], edx
        mov    eax, [ebp-8]
        mov    edx, [ebp-4]
    

    Und, wie kommt die "5" in diese Speicherzelle?

    [ebp+8]
    

    Ohne, dass die "5" in dieser Zelle ist, macht

    mov eax, [ebp+8]
    imul eax, [ebp+8]

    nämlich keinen Sinn ...



  • Versuch lieber das Original zu verstehen, dir sind da beim Übersetzen anscheinend ein paar Fehler passiert...



  • Beim Original wird ja in

    movl    $5, 20(%esp)
    

    die 5 auf den Stack gespeichert.
    Wie kommt es jetzt, dass man eben diese später über

    8(%ebp)
    

    erreicht?

    Und wofür ist der

    movl    %eax, -8(%ebp)
        movl    %edx, -4(%ebp)
        movl    -8(%ebp), %eax
        movl    -4(%ebp), %edx
    

    Block ... wird hier einmal in die eine Richtung gespeichert und dann das selbe noch einmal in die andere?



  • ; Funktion: int square(int x)
        pushl    %ebp            ; stack frame
        movl    %esp, %ebp       ; 
        subl    $16, %esp        ; lokale Variablen (werden nicht benötigt!)
    
        movl    8(%ebp), %eax    ; eax = Argument = x
        imull    8(%ebp), %eax   ; eax = eax * x = x * x
        movl    $0, %edx         ; edx = 0
    
        movl    %eax, -8(%ebp)   ; Sinnlos
        movl    %edx, -4(%ebp)   ; 
        movl    -8(%ebp), %eax   ; 
        movl    -4(%ebp), %edx   ; 
        leave 
        ret 
    
        ; Programmeintritspunkt
    main: 
        pushl    %ebp            ; stack frame
        movl    %esp, %ebp       ;
        andl    $-8, %esp        ; lokale Variablen: align 8 , size = 24 Byte
        subl    $24, %esp        ; Auserdem wird hier Platz für das Funktionsargument gemacht  (square(int x))
    
        movl    $5, 20(%esp)     ; Verschwendung -> mov $5,%eax
        movl    20(%esp), %eax   ; 
    
        movl    %eax, (%esp)     ; Argument auf den Stack (=5)
        call    square
        movl    %eax, 16(%esp)   ; Ergebniss in lokaler Variable speichern
    
        movl    $0, %eax         ; Rückgabewert = 0
        leave 
        ret
    


  • Die 5 wird nicht nur in [esp+20] gespeichert, sondern danach nach eax geschoben und von dort nach [esp]. Dann gibts einen call und ein push, d.h. esp wird um 8 erniedrigt. Dann wird esp nach ebp kopiert und auf [ebp+8] zugegriffen, und das ist natürlich die gleiche Speicherstelle wie die, die vorher mal [esp] war.

    Zu der zweiten Frage: Keine Ahnung. Das Programm sieht aus wie von einem Compiler ohne Optimierung erzeugt. Da wird wohl das Ergebnis nochmal in eine lokale Variable geschrieben, obwohl die gar nicht mehr gebraucht wird.



  • Danke, danke^^



  • Wenn's dich interessiert, es dürfte sich dabei um das unoptimierte Kompilat von etwas ähnlichem wie diesem C-Programm handeln:

    long long square(int v)
    {
      long long ret=v*v;
      return ret;
    }
    
    int main(void)
    {
      int a=5;
      int s=square(a);
      return 0;
    }
    


  • Man könnte das sinnvollerweise mit dem gas und gdb unter Linux untersuchen, aber gerade um des Verständniswillens würde ich vorschlagen, das ganze mit Bleistift und kariertem Papier(Speicherbereich) aufzuzeichnen.

    Dem Stackpointer kann man die Adresse FFFFFFFFh geben, und -8 für den AND-Befehl wäre FFFFFFF8h. Sollte der Stackpointer zufälligerweise auf FEEDDEADh zeigen, dann wird nach dem AND Befehl FEEDDEA8h daraus.


Anmelden zum Antworten