Ich spiele mit der Idee, einen JIT-Compiler zu schreiben, und frage mich nur, ob es theoretisch überhaupt möglich ist, das Ganze in verwaltetem Code zu schreiben. Insbesondere, wenn Sie Assembler in ein Byte-Array generiert haben, wie springen Sie hinein, um mit der Ausführung zu beginnen?
84
calli
Opcode aufzurufen.Antworten:
Und für den vollständigen Proof of Concept gibt es hier eine vollständig fähige Übersetzung von Rasmus 'Ansatz für JIT in F #
das führt glücklich nach
quelle
Ja, du kannst. In der Tat ist es mein Job :)
Ich habe GPU.NET vollständig in F # geschrieben (modulo unsere Unit-Tests) - es zerlegt und JITs IL zur Laufzeit, genau wie die .NET CLR. Wir geben nativen Code für jedes zugrunde liegende Beschleunigungsgerät aus, das Sie verwenden möchten. Derzeit unterstützen wir nur Nvidia-GPUs, aber ich habe unser System so konzipiert, dass es mit einem Minimum an Arbeit retargetierbar ist, sodass wir wahrscheinlich in Zukunft andere Plattformen unterstützen werden.
Was die Leistung angeht, muss ich mich bei F # bedanken - wenn unser JIT-Compiler im optimierten Modus (mit Tailcalls) kompiliert wird, ist er wahrscheinlich ungefähr so schnell wie der Compiler in der CLR (die in C ++, IIRC geschrieben ist).
Für die Ausführung haben wir den Vorteil, dass wir die Steuerung an Hardwaretreiber übergeben können, um den angepassten Code auszuführen. Dies wäre jedoch auf der CPU nicht schwieriger, da .NET Funktionszeiger auf nicht verwalteten / nativen Code unterstützt (obwohl Sie die Sicherheit verlieren würden, die normalerweise von .NET bereitgestellt wird).
quelle
Der Trick sollte VirtualAlloc mit dem
EXECUTE_READWRITE
Flag-Flag (benötigt P / Invoke) und Marshal.GetDelegateForFunctionPointer sein .Hier ist eine modifizierte Version des Beispiels für rotierende Ganzzahlen (beachten Sie, dass hier kein unsicherer Code benötigt wird):
Vollständiges Beispiel (funktioniert jetzt sowohl mit X86 als auch mit X64).
quelle
Mit unsicherem Code können Sie einen Delegaten "hacken" und ihn auf einen beliebigen Assemblycode verweisen lassen, den Sie generiert und in einem Array gespeichert haben. Die Idee ist, dass der Delegat ein
_methodPtr
Feld hat, das mit Reflection festgelegt werden kann. Hier ist ein Beispielcode:Dies ist natürlich ein schmutziger Hack, der jederzeit nicht mehr funktioniert, wenn sich die .NET-Laufzeit ändert.
Ich vermute, dass vollständig verwalteter sicherer Code JIT im Prinzip nicht implementieren darf, da dies alle Sicherheitsannahmen verletzen würde, auf die sich die Laufzeit stützt. (Es sei denn, der generierte Baugruppencode enthielt einen maschinenprüfbaren Beweis dafür, dass er nicht gegen die Annahmen verstößt ...)
quelle
AccessViolationException
wenn ich versuche, Ihr Beispiel auszuführen. Ich denke, es funktioniert nur, wenn DEP deaktiviert ist.