Sie scheinen zu fragen, emulieren x86, nicht virtualisieren. Seit modern x86 hardware supports virtualization, wo die CPU Gast-Code nativ ausführt und nur für einige privilegierte Anweisungen an den Hypervisor abfängt, das ist, was der Begriff "Virtualisierung" normalerweise bedeutet.
Faul flag evalution ist typisch. Anstatt alle Flags tatsächlich zu berechnen, speichern Sie einfach die Operanden aus dem letzten Befehl, der Flags setzt. Wenn dann tatsächlich die Flags gelesen werden, müssen Sie herausfinden, was die Flag-Werte sein müssen.
Das bedeutet, dass PF und AF nicht jedesmal neu berechnet werden müssen (fast jede Anweisung), nur jedes Mal wenn sie gelesen werden (meistens nur PUSHF oder Interrupts, kaum Code liest jemals PF (außer für FP-Zweige, wo es NaN bedeutet)). Das Berechnen von PF nach jeder Integer-Anweisung ist in reinem C teuer, da es einen Popcount auf den niedrigen 8 Bits der Ergebnisse erfordert. (Und ich denke, dass C-Compiler im Allgemeinen dieses Muster nicht erkennen und setp
selbst verwenden, geschweige denn pushf
oder lahf
, um mehrere Flags zu speichern, wenn sie einen x86-Emulator kompilieren, um auf einem x86-Host zu laufen Muster und emittieren popcnt
Anweisungen, wenn Ziel Host-CPUs, die diese Funktion haben (z. B. -march=nehalem
)).
BOCHS verwendet diese Technik und beschreibt die Implementierung in einigen Details im Abschnitt Lazy Flags dieser kurzen PDF: How Bochs Works Under the Hood 2nd edition.Sie speichern das Ergebnis, so dass sie ZF, SF und PF und den Übertrag von den hohen 2 Bits für CF und OF und von Bit 3 für AF ableiten können. Damit müssen sie nie eine Anweisung wiederholen, um ihre Flag-Ergebnisse zu berechnen.
Es gibt zusätzliche Komplikationen von einigen Anweisungen nicht alle Flaggen zu schreiben (das heißt partial-Flag-Updates) und vermutlich von Anweisungen wie BSF, die ZF auf der Grundlage der Eingang nicht die Ausgabe.
Weiterführende Literatur:
This paper on emulators.com gibt viele Details, wie Flaggen, um effizient genug Zustand zu speichern zu rekonstruieren. Es hat eine "2.1 Lazy Arithmetic Flags für CPU-Emulation".
Einer der Autoren ist Darek Mihocka (lange Emulator Schriftsteller, arbeitet jetzt offensichtlich bei Intel). Er hat viel interessantes darüber geschrieben, wie man Nicht-JIT-Emulatoren schnell laufen lässt, und CPU-Performance-Sachen im Allgemeinen, vieles davon steht auf seiner Seite, http://www.emulators.com/. Z.B. this article über die Vermeidung von Branch-Misprediction in einem Interpreter-Loop des Emulators, die zu Funktionen, die jeden Opcode implementieren, löst, ist sehr interessant. Darek ist auch der Co-Autor des Artikels über die Interna von BOCHS, die ich vorher verlinkt habe.
Eine Google für faule Flagge eval traf auch relevant sein können: https://silviocesare.wordpress.com/2009/03/08/lazy-eflags-evaluation-and-other-emulator-optimisations/
Zuletzt Emulation von x86-wie Flaggen aufkam, beantworten Sie die discussion in comments auf meinen faulen Fahnen einige interessante Sachen hatte: z @ Raymond Chen vorgeschlagen, dass Link zu der Mihocka & Troeger Papier, und @amdn wies darauf hin, dass JIT dynamische Übersetzung schneller Emulation als Interpretation produzieren kann.
Es ist unklar, was Sie tun. – Jester
Uhm, normalerweise hypervisors emulieren nicht einen Instruktions-Pipe-Schritt, aber lassen den Gast-Code (größtenteils) unverändert laufen, fangen im Hypervisor-Kernel ein, wenn die Hardware einen privilegierten Befehl entdeckt. Natürlich ist es in der Praxis viel komplizierter als das, aber der Punkt ist, dass man sich im Allgemeinen nur dann um den Zustand der Flags kümmern muss, wenn man den Hypervisor einsperrt, nicht nach jeder Anweisung. –
@Jester Ich denke, er baut einen Emulator. – fuz