3 Stimmen

8086 Assembly Frage, was macht dieser Code

Ich habe diese Frage in meinem Montagekurs gestellt bekommen:

Was bewirkt dieses Verfahren?
und wie sie genannt werden sollte?

push ebp
mov ebp, esp    
push esi

mov esi, [ebp+4]
mov eax, [esi]
sub eax, [esi+4]
add esi, 8
mov [ebp+4], esi

pop esi
pop ebp
ret

es sieht so aus [ebp+4] ist ein Argument und nicht die Rücksprungadresse, daher sollte es mit "jmp" und nicht mit "call" aufgerufen werden. Ich verstehe nicht wirklich, was auf [esi+4] und weiter esi+8 (die Absenderadresse) hmm, ich bin wirklich verwirrt, ich hoffe, Sie können mir helfen
vielen Dank im Voraus.

2voto

Thomas Pornin Punkte 70790

Wie Sie richtig bemerken, wird diese Routine, wenn sie mit einer call dann [ebp+4] ist die Absenderadresse. Das heißt aber nicht, dass dies eine schlechte Idee ist.

Angenommen, die Routine wird mit einer call . Zu diesem Zeitpunkt ist die "Rücksprungadresse", die auf den Stapel geschoben wird, die Adresse des Bytes, das unmittelbar auf die call Opcode. Nennen wir diese Adresse x . Die Routine extrahiert dann aus der Adresse x zwei 32-Bit-Worte, eines an der Adresse x und einer unter der Adresse x+4 . Es subtrahiert das zweite Wort vom ersten Wort und speichert das Ergebnis in eax . Schließlich speichert die Routine den Wert zurück x+8 im Stapelplatz [ebp+4] , was zur Folge hat, dass die ret erreicht ist, wird die Ausführung an der Adresse x+8 . Mit dieser Hypothese sieht die Routine wie eine Möglichkeit aus, ganze Zahlen zu subtrahieren, die sich in der Mitte des Codes befinden, etwa so:

call yourroutine
dd   56478634
dd   18943675
mov  ebx, eax  ; an example instruction

Hier ist die call kehrt zum mov Anweisung, und zu diesem Zeitpunkt eax enthält den Wert 37534959 (das ist 18943675 subtrahiert von 56478634).

Als Code-Routine ist sie nicht sonderlich nützlich, da sie eine komplizierte Methode zum Laden von eax mit einem konstanten Wert, der fest kodiert ist (der Codebereich ist während der Ausführung normalerweise schreibgeschützt). Man könnte sich vorstellen, dass eine solche Routine als Teil der Laufzeitunterstützung für dynamische Verknüpfung auf einer bestimmten Architektur erscheinen könnte (dynamische Verknüpfung ist ein heikles Thema).

Nehmen wir nun stattdessen an, dass die Routine mit einer jmp . [ebp+4] bezeichnet nun das, was sich zu diesem Zeitpunkt oben auf dem Stapel befand. Die Routine nimmt diesen Wert (nennen wir ihn y ), erhalten Sie die beiden Wörter unter Adressen yy+4 berechnet das Subtraktionsergebnis in eax und speichert dann y+8 zurück in die [ebp+4] Steckplatz. Schließlich ist die ret interpretiert diesen Slot als Rücksprungadresse, d.h. die Adresse eines Codes, zu dem die Ausführung springen soll. Es spielt keine Rolle, dass keine call Opcode an der Erzeugung dieser Adresse beteiligt war; ret wird sich dennoch darauf stürzen. Dieses Mal könnte der Aufrufcode wie folgt aussehen:

    push   foobar
    jmp    yourroutine
    ...  ; unreached code

foobar:
    dd 56478634
    dd 18943675
    mov  ebx, eax  ; an example instruction

Diesmal sieht es nach einem parametrisierten Sprung mit einer inhärenten Belastung von eax . Ein solcher Code kann in der Implementierung von einigen Interpreter für Threaded Code . Als Hausaufgabe bin ich mir jedoch ziemlich sicher, dass dies nicht beabsichtigt war (Interpreter für threaded Code sind noch haariger als dynamisches Linking).

1voto

Henno Brandsma Punkte 2026

Wenn Sie diese Funktion aufrufen, wird die Rücksprungadresse (eip der Adresse der Anweisung nach dem Aufruf) auf den Stack geschoben, und zwar nach der ersten Funktionspräambel, [ebp+4] verweist auf diese Absenderadresse. Der Körper der Funktion betrachtet diese Adresse dann als 2 Ganzzahlen, die subtrahiert werden, das Ergebnis wird in eax und dann wird die Rücksprungadresse um 8 erhöht, d. h. die Größe dieser 2 Ganzzahlen um add esi,8mov [ebp+4], esi . Die ret bringt uns einfach zu der neuen Absenderadresse zurück (die hoffentlich eine gültige Anweisung ist....).

Eine merkwürdige Funktion, die in einem sich selbst modifizierenden Code vorkommt...

1voto

paxdiablo Punkte 809679

Nein, es sollte auf jeden Fall aufgerufen werden mit call - es hat eine ret am Ende.

Sie sollten sich mit einem Blatt Papier und einer Liste der Register hinsetzen und sich den Code in Einzelschritten durch den Kopf gehen lassen, wobei Sie die Register nach und nach aktualisieren. Dann sollte es offensichtlich sein, was vor sich geht:

eax:
esp:
ebp:
esi:

sowie anderer relevanter Speicher (z. B. der Bereich um den Stapelanfang).

Dies ist ein idealer Weg, um das Programmieren zu lernen (für kleine Programme sowieso), da man lernt, Dinge im Detail zu analysieren und tatsächlich verstehen. sie. Und ich fürchte, mehr Hilfe werde ich für eine Hausaufgabe nicht geben :-)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X