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).
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'). –
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. –
@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