Ich beabsichtige, meinen eigenen JIT-Interpreter als Teil eines Kurses über VMs zu schreiben. Ich habe viel Wissen über Hochsprachen, Compiler und Interpreter, aber wenig oder kein Wissen über x86 Assembly (oder C für diese Angelegenheit).
Eigentlich weiß ich nicht, wie ein JIT funktioniert, aber hier ist meine Ansicht: Lies das Programm in einer Zwischensprache ein. Kompiliere das zu x86-Anweisungen. Stellen Sie sicher, dass der letzte Befehl an einen beliebigen Ort im VM-Code zurückkehrt. Bewahren Sie die Anweisungen irgendwo im Speicher auf. Machen Sie einen unbedingten Sprung zum ersten Befehl. Voila!
In diesem Sinne habe ich folgendes kleines C-Programm:
%Vor%}
Okay, meine Absicht ist, dass dieses Programm den NOP-Befehl irgendwo im Speicher speichert, zu diesem Ort springt und dann wahrscheinlich abstürzt (weil ich keine Möglichkeit eingerichtet habe, dass das Programm zum Hauptfenster zurückkehrt).
Frage: Bin ich auf dem richtigen Weg?
Frage: Könnten Sie mir ein modifiziertes Programm zeigen, das es schafft, irgendwo in main zurückzufinden?
Frage: Andere Probleme, vor denen ich mich hüten sollte?
PS: Mein Ziel ist es, Verständnis zu bekommen, nicht unbedingt alles richtig zu machen.
Danke für das Feedback. Der folgende Code scheint der Ort zu sein, an dem ich mit meiner Linux-Box anfangen und arbeiten kann:
%Vor%Frage: Bin ich auf dem richtigen Weg?
Ich würde ja sagen.
Frage: Könnten Sie mir ein modifiziertes Programm zeigen, das es schafft, irgendwo innerhalb von main zurückzufinden?
Ich habe keinen Code für Sie, aber ein besserer Weg, um zum generierten Code und wieder zurück zu gelangen, ist die Verwendung eines Paares von call
/ ret
Anweisungen, da diese automatisch die Rückgabeadresse verwalten / p>
Frage: Andere Probleme, vor denen ich mich hüten sollte?
Ja - Viele Betriebssysteme würden als Sicherheitsmaßnahme die Ausführung von Code auf dem Heap verhindern, ohne dass spezielle Vorkehrungen getroffen werden müssen. Diese speziellen Vereinbarungen erfordern normalerweise, dass Sie die relevanten Speicherseiten als ausführbar markieren müssen.
Unter Linux geschieht dies mit mprotect()
mit PROT_EXEC
.
Wenn Ihr generierter Code der richtigen Aufrufkonvention folgt, können Sie einen Zeiger-zu-Funktion-Typ deklarieren und aufrufen die Funktion so:
%Vor%