Assembler: Fehlerhafter Stackframe

Pascal, Basic und andere nicht aufgelistete
Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » So Jun 15, 2014 6:53 pm

Naja, bin nicht so vertraut mit Assembler, also hauen mich diese ganzen Informationen natürlich erstmal um. :D
Aber ich wühle mich mal durch. Woher kommt das gute Assembler Wissen? ;)

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von nufan » So Jun 15, 2014 7:07 pm

Architekt hat geschrieben:Woher kommt das gute Assembler Wissen? ;)
Sehr viel davon: http://www.amazon.de/Assembly-Language- ... 470497025/
Ein bisschen von dem: http://www.amazon.de/Hacking-Art-Exploi ... 593271441/
Und vor allem wochenlanges Durchsteppen von fremden, disassemblierten C-Code: https://www.hacking-lab.com/ :D Wenn du mal disassemblierte Netzwerk-Services mit Forks und aktiviertem ASLR exploitest, ist der Assembler-Code schon Nebensache, man sieht nur mehr Hex-Adressen und weiß worum es geht :P

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » So Jun 15, 2014 11:55 pm

Ich werde mir wohl auch demnächst am besten ein entsprechendes Buch zulegen. :)
Aber ich hoffe, bis dahin darf ich dich noch etwas "nerven". :P

Habe auch direkt eine Frage. Von dem folgenden Programm hatte ich die Ausgabe 12 und 32 erwartet. Ich bekomme aber 12 und 48:

Code: Alles auswählen

.text
.globl _prog

_prog:
push	%ebp
movl	%esp, %ebp

subl	$16, %esp

movl	$4, %eax
movl	%eax, (%esp)
movl	$8, %eax
movl	%eax, 4(%esp)
movl	(%esp), %eax
push	%eax
movl	4(%esp), %eax
addl	8(%esp), %eax
addl	$4, %esp
movl	%eax, 8(%esp)
movl	8(%esp), %eax
push	%eax
call	_println_int
addl	$4, %esp
# Hier muss wohl irgendwas gecleart/gepopt werden?!
movl	(%esp), %eax
push	%eax
movl	4(%esp), %eax
imull	12(%esp), %eax
addl	$4, %esp
movl	%eax, 12(%esp)
movl	12(%esp), %eax
push	%eax
call	_println_int
addl	$4, %esp

addl	$16, %esp

pop 	%ebp
ret

.data

Ich kann es mir nur damit erklären, dass der Wert 16 irgendwo im Register noch steht und sich irgendwie auf 32 rauf addiert. Irgendwie komme ich noch nicht ganz hinter die Materie.
Und ja mein Assembler ist in der Regle nicht gut optimiert. Es wird auto-generiert durch meinen "Compiler" und daher muss ich auf einige Optimierungen verzichten, wenn ich noch durchsteigen will. :D

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von nufan » Mo Jun 16, 2014 12:48 am

Architekt hat geschrieben:Ich werde mir wohl auch demnächst am besten ein entsprechendes Buch zulegen. :)
Ersteres aus meinem vorigen Beitrag kann ich dir sehr ans Herz legen.
Architekt hat geschrieben:Ich kann es mir nur damit erklären, dass der Wert 16 irgendwo im Register noch steht und sich irgendwie auf 32 rauf addiert. Irgendwie komme ich noch nicht ganz hinter die Materie.
Ich hab dir mal alle paar Instruktionen den Stack aufgezeichnet, damit sollte das nachvollziehbar sein:

Code: Alles auswählen

    .text
    .globl _prog

    _prog:
    push   %ebp
    movl   %esp, %ebp

    subl   $16, %esp

    movl   $4, %eax
    movl   %eax, (%esp)
    #    +-----+
    #  0 |  4  |
    #  4 |     |
    #  8 |     |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 4
    
    movl   $8, %eax
    movl   %eax, 4(%esp)
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 |     |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 8
    
    movl   (%esp), %eax
    push   %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 4
    
    movl   4(%esp), %eax
    addl   8(%esp), %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 12
    
    addl   $4, %esp
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 |     |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 12
    
    movl   %eax, 8(%esp)
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 12
    
    movl   8(%esp), %eax
    push   %eax
    #    +-----+
    #  0 | 12  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 | 12  |
    # 16 |     |
    #    +-----+
    # eax: 12
    
    call   _println_int    # 12 wird ausgegeben
    addl   $4, %esp
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: ?

    movl   (%esp), %eax
    push   %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 | 12  |
    # 16 |     |
    #    +-----+
    # eax: 4
    
    movl   4(%esp), %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 | 12  |
    # 16 |     |
    #    +-----+
    # eax: 4
    
    imull   12(%esp), %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 | 12  |
    # 16 |     |
    #    +-----+
    # eax: 48
    
    addl   $4, %esp
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 |     |
    # 16 |     |
    #    +-----+
    # eax: 48
    
    movl   %eax, 12(%esp)
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 | 48  |
    # 16 |     |
    #    +-----+
    # eax: 48
    
    movl   12(%esp), %eax
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 | 48  |
    # 16 |     |
    #    +-----+
    # eax: 48
    
    push   %eax
    #    +-----+
    #  0 | 48  |
    #  4 |  4  |
    #  8 |  8  |
    # 12 | 12  |
    # 16 | 48  |
    #    +-----+
    # eax: 48
    
    call   _println_int   # 48 Wird ausgegeben
    addl   $4, %esp
    #    +-----+
    #  0 |  4  |
    #  4 |  8  |
    #  8 | 12  |
    # 12 | 48  |
    # 16 |     |
    #    +-----+
    # eax: ?

    addl   $16, %esp

    pop    %ebp
    ret
Im Browser sieht das wohl nicht ganz so hübsch aus, am besten in einen Editor kopieren (Eine Monospace-Font für Code-Tags wäre wünschenswert).

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » Mo Jun 16, 2014 7:33 am

Nicht ganz. Ich sehe mich bestätigt, dass ich den Stack vollgemüllt habe. Aber leider habe ich keine Ahnung, wie ich das gerade biegen könnte.
Ich muss ja, meiner Meinung nach, den Stack clearen. Aber wie mache ich das?
Eine Änderung von

Code: Alles auswählen

movl	$4, %eax
movl	%eax, (%esp)
zu

Code: Alles auswählen

movl	$4, %eax
movl	%eax, (%esp)
pop		%eax
führt zu einem Fehler. Ich liege doch damit richtig, dass ich den Stack "sauber" halten muss, oder? Oder missverstehe ich das?

edit:
Achso, es müsste

Code: Alles auswählen

imull 8(%esp), %eax
heißen, nicht

Code: Alles auswählen

imull 12(%esp), %eax
Zumindest funktioniert das. Ich hoffe das ist korrekt. :)
Ich dachte imull speichert es in dem ersten Register. :oops:

edit2:
Also während ich bei add und sub stets mit dem höchsten Offset arbeiten kann (also in dem Beispiel 12 -> 12(%esp)) muss ich bei imull darauf achten, mit dem vorherigen, also 8(%esp) zu arbeiten. Kann man das so sagen?

In meiner Assembler Klasse würde dann das ganze folgendermaßen aussehen:

Code: Alles auswählen

	void add() {
		::add(_buf, ESP, EAX, _stackSize);
		::add(_buf, 4, ESP); // restore Stack Pointer - pop ginge auch
	}

	void sub() {
		::sub(_buf, EAX, ESP, _stackSize);
		::pop(_buf, EAX);
	}

	void mul() {
		::mul(_buf, ESP, EAX, _stackSize - 4); // -4 statt wie oben einfach _stackSize
		::add(_buf, 4, ESP); // restore Stack Pointer - pop ginge auch
	}
Die globalen Operationen add, sub, pop und mul leiten einfach die Assembler Entsprechung mit dem jeweiligen Registern in ein std::ostream.
_stackSize wiederum ist der höchste Wert/Offset. Jedesmal wenn wir eine Variable speichern, steigt er um 4, damit wir am Ende vor dem eigentlichen Programm den Speicher mit subl $_stacksize anfordern können (und hinterher natürlich genauso wieder freigeben).

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » Mo Jun 16, 2014 8:14 am

Ok, edit2 war ein Trugschluss. Verdammt. :/ Es klappt nur in dem Anwendungsfall. In anderen führt es dennoch zu Fehlern.

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von nufan » Mo Jun 16, 2014 8:30 am

Architekt hat geschrieben:Eine Änderung von

Code: Alles auswählen

movl	$4, %eax
movl	%eax, (%esp)
zu

Code: Alles auswählen

movl	$4, %eax
movl	%eax, (%esp)
pop		%eax
führt zu einem Fehler.
Damit nimmst du recht umständlich 2 Werte vom Stack. Willst du das?
Architekt hat geschrieben:Ich liege doch damit richtig, dass ich den Stack "sauber" halten muss, oder? Oder missverstehe ich das?
Du musst nicht. Ich würde dir raten genau so viel Platz am Stack zu verwenden damit du sauber programmieren kannst. Nicht mehr aber auch nicht weniger.
Architekt hat geschrieben:Achso, es müsste

Code: Alles auswählen

imull 8(%esp), %eax
heißen, nicht

Code: Alles auswählen

imull 12(%esp), %eax
Zumindest funktioniert das. Ich hoffe das ist korrekt. :)
Dann multiplizierst du 4 * 8, was dein gewünschtes Ergebnis wäre. Allerdings weiß ich ja nichtmal was du versuchst zu programmieren bzw. welchen Code du da gerade in Assembler übersetzt.
Architekt hat geschrieben:Also während ich bei add und sub stets mit dem höchsten Offset arbeiten kann (also in dem Beispiel 12 -> 12(%esp)) muss ich bei imull darauf achten, mit dem vorherigen, also 8(%esp) zu arbeiten. Kann man das so sagen?
Ich bezweifle stark, dass du das mit deiner jetzigen Übersetzung allgemein so sagen kannst. Eine zeilenweise Konvertierung nach Assembler wird dir wohl auch nicht gelingen, du musst dir im C++-Code zumindest einige Ergebnis-Offsets speichern, um später noch darauf zurückgreifen zu können.

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » Mo Jun 16, 2014 8:48 am

Hm, ungut.
Ich kann dir das ganze gerne mal als zip packen und hier hochladen, allerdings sind 300 Zeilen Compiler und 200 Zeilen Assembler Klassen Code. :/ Keine Ahnung, ob du das möchtest. ^^
Ich muss mal sehen, wie ich das am besten mache. :/

nufan
Wiki-Moderator
Beiträge: 2557
Registriert: Sa Jul 05, 2008 3:21 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von nufan » Mo Jun 16, 2014 9:24 am

Ich hätte vorgeschlagen du implementierst dir eine High-Level-Speicherverwaltung und wenns wo Probleme gibt versuche ich zu helfen.

Benutzeravatar
Architekt
Beiträge: 172
Registriert: Sa Mai 24, 2014 12:04 pm

Re: Assembler: Fehlerhafter Stackframe

Beitrag von Architekt » Mo Jun 16, 2014 9:53 am

Klingt komplex. ;) Es muss doch auch so gehen. :D

edit:
In dem Tutorial, auf das ich mich stütze, macht er das so, dass er für Variablen negative Offsets benutzt:
http://magazin.c-plusplus.de/artikel/Compilerbau
Speziell hier in seinem VarManager: http://www.c-plusplus.de/magazin/bilder ... r_man1.cpp

Ist das die Rätsels Lösung?

Antworten