2017-09-14 3 views
0

Ich erstelle einen x86-Decoder und ich habe Mühe zu verstehen und eine effiziente Möglichkeit zur Berechnung der Mnemonik einer Anweisung zu finden.x86 Dekodierung Befehl Opcode Byte

Ich weiß, dass die Opcode 6 MSBs die Opcode-Bits sind, aber ich kann nirgends finden, dass diese 6 Bits in einer Mnemoniktabelle verwenden. Die einzige Mnemonic-Tabelle, die ich finde, ist für das ganze Opcode-Byte selbst und nicht nur für die 6 MSBs.

Ich wollte fragen, was sind einige effiziente Möglichkeiten, die Decodierung der Mnemotechniken im Opcode-Byte weitermachen kann, und wenn es Tabellenverweise mit den 6 MSBs und nicht das ganze Opcode-Byte.

+0

Die unteren 2 Bits sind auch Teil des Opcodes ... Zum Beispiel haben die ['jcc'] (http://felixcloutier.com/x86/Jcc.html) Anweisungen unterschiedliche Mnemotechniken für jeden Opcode-Wert von 0x70 bis 0x7F. Manchmal ist auch das '/ r'-Feld aus dem ModR/M-Byte Teil des Opcodes. (z.B. 'shl' vs.' shr'). –

+0

Das Problem mit dem modernen x86-Maschinencode ist, dass es * keine * effiziente/einfache Möglichkeit gibt, sie zu dekodieren. Beispielsweise dekomprimiert "rep nop" tatsächlich als "Pause" oder "rep bsf" dekodiert als "tzcnt" (wenn BMI1 unterstützt wird, andernfalls dekodiert es als "bsf"). Sie müssen also nach den Vorsilben anderer Anweisungen suchen. –

+0

@PeterCordes Eine der Ressourcen, die ich verwendete, ist http://www.c-jump.com/CIS77/CPU/x86/X77_0050_add_opcode.htm Ich weiß, dass es Ausnahmen gibt, wenn nicht die einzigen 6 MSBs des Opcodes Byte steht für die Mnemonic, aber für eine regelmäßige Anweisung scheint es so, je nachdem, was sie sagen. Ich frage, wie ich für diese regelmäßigen Fälle diese 6 MSBs verwenden könnte, um die Gedächtnisstütze wie in ihrem Beispiel zu bestimmen. – Jorayen

Antwort

1

Aber gibt es keine effiziente Möglichkeit, eine Tabelle für die Mnemonik ohne Duplikate zu speichern?

Dies ist zu einer Frage von Algorithmen und Datenstrukturen geworden.

Wie Sie weisen darauf hin, viele der Opcode-Tabelleneinträge (zumindest für die Tabelle ohne 0f escape Byte: http://sparksandflames.com/files/x86InstructionChart.html) DO wiederholen in Gruppen von 4 oder 2, also mit dem gleichen 6 oder 7-Bit-Präfix der Auswahl dieselbe mnemonic.

Offensichtlich ist eine 256-Entry-Tabelle von Strukturen einfach, aber dupliziert Dinge. Es ist sehr schnell und einfach zu benutzen, da es wahrscheinlich immer noch klein genug ist, um nicht oft zu cachen. (Vor allem, da die gemeinsamen Einträge im Cache heiß bleiben; x86-Code verwendet die gleichen Opcodes sehr oft.)

Sie können Einfachheit/Leistung für Platz tauschen.

könnten Sie haben eine 64-Eintragstabelle von structs wo ein Mitglied, ein Zeiger auf eine Sekundärtabelle ist mit den niedrigen 2 Bits indexiert werden. Wenn der Zeiger NULL ist, bedeutet dies, dass der Befehl dem Muster von add//usw. folgt, wobei die niedrigen 2 Bits Ihnen 8 Bit mitteilen, unabhängig von der Operandengröße und Richtung (r/m, reg oder reg, r/m).

Ihre Struktur würde auch Einträge für die Umwandlung in andere Anweisungen benötigen, wenn bestimmte Präfixe vorhanden sind (z. B. rep nop ist pause). AVX VEX-Präfixe verwenden auch eine ungültige Codierung einer anderen Anweisung. x86 ist ziemlich verrückt zu dekodieren, wenn Sie für alle aktuellen Erweiterungen einen kompletten Job machen wollen.

Eigentlich könnte es am einfachsten (und auch effizient) sein, nur eine Tabelle mit Funktionszeigern zu verwenden. Oder eine Struktur mit einer const char* mnemonic und einer int (*decode)(const char*mnemonic, const char *insn_bytes, unsigned prefix_bitmap) Funktion, so dass viele Opcodes auf die gleiche Dekodier-Funktion zeigen können, aber immer noch unterschiedliche Mnemotechniken erhalten. Manchmal ignoriert die Funktion die übergebene Mnemonik, aber zu anderen Zeiten ist das alles, was sie braucht. Sie hätten eine gemeinsame Funktion zum Decodieren von Adressierungsmodi, die viele der Decodierungsfunktionen aufrufen würden.

Dies ähnelt der Implementierung eines x86-Emulators, der eine dynamische Neukompilierung durchführt. Eine gemeinsame Dekodierschleife und dann durch Funktionszeiger.


Eine noch kompliziertere Datenstruktur Sie verwenden könnte, ist ein radix trie aka Präfixbaums. Siehe auch https://en.wikipedia.org/wiki/Trie#Bitwise_tries.

Dies wird in alberne Jahreszeit, weil die Dichte so hoch ist, dass eine Nachschlagetabelle viel mehr Sinn macht.(Es gibt sehr wenige undefinierte Opcodes).

+0

Also wenn Ich ziele auf Leistung (Geschwindigkeit) Würden Sie sagen, nur eine 256 Eintragstabelle speichern wäre die beste Wahl? Auch warum brauche ich eine Struktur? Ich dachte, vielleicht ein Enum aller Mnemonics zu erstellen und dann eine 256-Tabelle als Index-Tabelle zu diesem Enum erstellen, was sind Ihre Gedanken? – Jorayen

+0

Ja, ich würde vermuten, dass eine Tabelle mit 256 Einträgen am besten funktioniert. Eine zusätzliche Verzweigung zur Auswahl zusätzlicher Dekodierschritte ist wahrscheinlich nicht sinnvoll. –

+0

@Jorayen: Sofern Sie keine separate Tabelle für andere Sonderfälle haben, verwenden Sie eine Struktur, um die Mnemonic zu halten und Ihnen zu sagen, wie Sie die verbleibenden Bytes in Operanden dekodieren. (z. B. 'jcc' /' call' gegen 'add' gegen' mulr/m32' gegenüber 'imulr, r/m32, imm32' gegenüber anderen Sonderfällen). Und für spezielle Fälle, wo drei weitere Opcode-Bits aus dem '/ r'-Feld in ModR/M kommen, um dies anzuzeigen (z.B. mit einem Zeiger auf eine andere Tabelle). Wenn Sie eine Struktur verwenden, in der Sie die meisten Mitglieder bei jedem Zugriff verwenden, ergibt sich eine gute räumliche Lokalität, so dass sie gut zwischengespeichert wird. –