- Was heißt
rep; nop
das - Ist es dasselbe wie
pause
Anweisung? - Ist es dasselbe wie
rep nop
(ohne das Semikolon)? - Was ist der Unterschied zu der einfachen
nop
Anweisung? - Verhält es sich auf AMD- und Intel-Prozessoren anders?
- (Bonus) Wo ist die offizielle Dokumentation für diese Anweisungen?
Motivation für diese Frage
Nach einigen Diskussionen in den Kommentaren einer anderen Frage wurde mir klar, dass ich nicht weiß, was rep; nop;
in x86- (oder x86-64-) Assembly bedeutet. Außerdem konnte ich im Web keine gute Erklärung finden.
Ich weiß, dass dies rep
ein Präfix ist, das "die nächsten Befehlszeiten wiederholen cx
" bedeutet (oder zumindest in einer alten 16-Bit-x86-Assembly). Nach dieser Übersichtstabelle auf Wikipedia , scheint es rep
nur mit verwendet werden movs
, stos
, cmps
, lods
, scas
(aber vielleicht diese Begrenzung auf neueren Prozessoren entfernt wurde). Daher würde ich denken rep nop
(ohne Semikolon) würde eine nop
Operation cx
mal wiederholen .
Nach weiterer Suche wurde ich jedoch noch verwirrter. Es scheint, dass rep; nop
und pause
Karte auf genau den gleichen Opcode und pause
hat ein etwas anderes Verhalten als nur nop
. Einige alte Mails aus dem Jahr 2005 sagten verschiedene Dinge:
- "Versuche nicht zu viel Strom zu verbrennen"
- "Es ist gleichbedeutend mit 'nop', nur mit 2-Byte-Codierung."
- "Es ist Magie auf Intel. Es ist wie 'Nein, aber lassen Sie die anderen HT-Geschwister laufen'"
- "Es ist eine Pause für Informationen und eine schnelle Polsterung für Athlon."
Mit diesen unterschiedlichen Meinungen konnte ich die richtige Bedeutung nicht verstehen.
Es wird im Linux-Kernel (sowohl auf i386 als auch auf x86_64 ) zusammen mit diesem Kommentar verwendet: /* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
Es wird auch in BeRTOS mit demselben Kommentar verwendet.
Antworten:
rep; nop
ist in der Tat das gleiche wie diepause
Anweisung (OpcodeF390
). Es kann für Assembler verwendet werden, die diepause
Anweisung noch nicht unterstützen . Auf früheren Prozessoren hat dies einfach nichts bewirkt, genau wienop
in zwei Bytes. Auf neuen Prozessoren, die Hyperthreading unterstützen, wird dies als Hinweis für den Prozessor verwendet, dass Sie einen Spinloop ausführen, um die Leistung zu steigern. Aus Intels Anweisungsreferenz :quelle
pause
ist Ihre Spin-Schleife effektiv eine Pipeline langsamer, um die Zustandsänderung des von einem anderen Kern geschriebenen Speicherorts zu bemerken.rep nop
= F3 90 = die Codierung fürpause
sowie die Dekodierung auf älteren CPUs, die dies nicht unterstützenpause
.Präfixe (außer
lock
), die nicht für eine Anweisung gelten, werden in der Praxis von vorhandenen CPUs ignoriert.In der Dokumentation heißt es, dass die Verwendung
rep
mit Anweisungen, für die sie nicht gilt, "reserviert ist und unvorhersehbares Verhalten verursachen kann", da zukünftige CPUs sie möglicherweise als Teil einer neuen Anweisung erkennen. Sobald sie eine bestimmte neue Befehlskodierung mit erstellt habenf3 xx
, dokumentieren sie, wie sie auf älteren CPUs ausgeführt wird. (Ja, der x86-Opcode-Speicherplatz ist so begrenzt, dass sie solche verrückten Sachen machen, und ja, das macht die Decoder kompliziert.)In diesem Fall bedeutet
pause
dies, dass Sie in Spinloops verwenden können, ohne die Abwärtskompatibilität zu beeinträchtigen . Alte CPUs, die nichts davon wissenpause
, dekodieren es als NOP, ohne Schaden zuzufügen, wie durch Intels ISA-Referenzhandbuch fürpause
garantiert . Bei neuen CPUs profitieren Sie von Energieeinsparung / HT-Freundlichkeit und vermeiden Fehlerspekulationen bei der Speicherreihenfolge , wenn sich der Speicher, auf dem Sie sich drehen, ändert und Sie die Spin-Schleife verlassen.Links zu Intels Handbüchern und vielen anderen guten Dingen auf der x86-Tag-Wiki-Infoseite
Ein weiterer Fall, in dem ein bedeutungsloses
rep
Präfix zu einer neuen Anweisung für neue CPUs wird:lzcnt
istF3 0F BD /r
. Auf CPUs, die diese Anweisung nicht unterstützen (das LZCNT-Feature-Flag fehlt in ihrer CPUID), wird sie als dekodiertrep bsr
, was genauso ausgeführt wird wiebsr
. Auf alten CPUs erzeugt es also32 - expected_result
und ist undefiniert, wenn die Eingabe Null war.Aber
tzcnt
undbsf
das gleiche tun mit Nicht-Null - Eingänge, so Compiler kann und verwenden ,tzcnt
auch wenn es nicht garantiert ist , dass die Ziel - CPU als ausgeführt wirdtzcnt
. AMD-CPUs sind schnelltzcnt
, langsambsf
und bei Intel sind beide schnell. Solange es für die Korrektheit keine Rolle spielt (Sie verlassen sich nicht auf das Setzen von Flags oder darauf, dass das Zielverhalten im Fall input = 0 unveränderttzcnt
bleibt ), ist es hilfreich , es wie auf CPUs dekodieren zu lassen, die es unterstützen.Ein Fall eines bedeutungslosen
rep
Präfixes, das wahrscheinlich nie anders dekodiert wird: Wirdrep ret
standardmäßig von gcc verwendet, wenn auf "generische" CPUs abgezielt wird (dh keine bestimmte CPU mit-march
oder-mtune
anvisiert wird und AMD K8 oder K10 nicht anvisiert werden). Es wird Jahrzehnte vor irgendjemandem sein könnte eine CPU machen, dierep ret
als etwas anderes dekodiert alsret
, weil sie in den meisten Binärdateien in den meisten Linux-Distributionen vorhanden ist. Siehe Was bedeutet "rep ret"?quelle
rep
Präfix wurde auch von Intel verwendet, um die Sperrentfernung hinzuzufügen.F2H
undF3H
) reserviert sind und zu unvorhersehbarem Verhalten in Tabelle 11-3 führen können. Auswirkung von Präfixen auf SSE-, SSE2- und SSE3-Anweisungen . Daher wird die Präfixanwendung für einige Anweisungen ignoriert, nicht für alle. Wird diese Funktion als undokumentiert betrachtet?f3 xx
, dokumentieren sie, wie sie auf älteren CPUs ausgeführt wird.rep movbe
Ursachen#UD
, sorep
wird nicht immer ignoriert. Auch wenn es nicht für eine Anweisung in dem Sinne gilt, wie es imREP/REPE/REPZ/REPNE/REPNZ
manuellen Eintrag angegeben ist.