Es gibt einige Probleme mit Ihrer Inline-Assembly-Anweisung, von denen die meisten durch die Fehlermeldungen angezeigt werden. Die erste Fehlermeldung Error: operand type mismatch for `push'
entspricht der pushw %eax
Anweisung. Der Fehler ist darauf zurückzuführen, dass das von Ihnen verwendete Operandengrößen-Suffix w
nicht mit der tatsächlichen Größe des Operanden %eax
übereinstimmt. Sie haben ihm gesagt, dass er den Befehl verwenden soll, um einen 16-Bit-Wert auf den Stack zu schieben, stellt aber ein 32-Bit-Register als Operanden zur Verfügung. Sie könnten das beheben, indem Sie pushw %ax
verwenden, aber das ist nicht das, was Sie wollen. Es würde nur die unteren 16 Bits des RAX-Registers beibehalten, nicht das gesamte Register. Eine andere "offensichtliche" Lösung wäre pushl %eax
, aber es gibt zwei Probleme damit Um andere Probleme zu beheben, müssen Sie zuerst das gesamte RAX-Register modifizieren, und das bedeutet, dass Sie alle 64 Bits davon speichern müssen, nicht nur die unteren 32 Bits. Die zweite besteht darin, dass es keine 32-Bit-PUSH-Anweisung im 64-Bit-Modus gibt, so dass Sie gezwungen sind, pushq %rax
10 zu verwenden. Die folgenden zwei Fehlermeldungen sind beide Error: unsupported for `mov'
. Diese Fehlermeldungen entsprechen den Anweisungen movl %cr0,%eax
und movl %eax,%cr0
. und beide sind das Ergebnis desselben Problems. Im 64-Bit-Modus gibt es keine 32-Bit-Operandengrößenversion dieser Anweisungen. Sie müssen einen 64-Bit-Operanden verwenden, daher wird RAX anstelle von EAX verwendet. Dies ist der Punkt, an dem die 64-Bit-RAX-Dateien verschrottet werden und warum ich gesagt habe, dass Sie das gesamte Register behalten müssen.
Die letzte Fehlermeldung lautet Error: operand type mismatch for `pop'
. Dies ist ein Ergebnis eines ähnlichen Problems wie das erste. In diesem Fall haben Sie kein Operandengrößensuffix verwendet, was bedeutet, dass Assembler versuchen wird, die Operandengröße basierend auf den Operanden zu bestimmen. Da Sie einen 32-Bit-Operanden %eax
verwendet haben, wird eine 32-Bit-Operandengröße verwendet. Wie auch bei PUSH gibt es 32-Bit-POP-Anweisungen im 64-Bit-Modus, so dass Sie %eax
entweder nicht verwenden können. In jedem Fall, da der PUSH-Befehl 64-Bit sein muss, muss der POP-Befehl 64-Bit entsprechen, so dass der Fix popq %rax
verwenden soll.
Schließlich ist ein Problem, das nicht durch eine Fehlermeldung angezeigt wird, dass im 64-Bit-Modus die Größe von CR0 zu 64-Bit erweitert wird. Während die zusätzlichen 32 Bits derzeit reserviert sind und auf Null gesetzt werden müssen, könnten sie in zukünftigen Prozessoren definiert werden. Also sollte die orl $0x40000000,%eax
Anweisung die oberen 64 Bits beibehalten. Leider werden die oberen 32-Bit-Bits von RAX nicht gelöscht, was bedeutet, dass dieser Befehl auch unbeabsichtigt irgendwelche der Bits löscht, die zukünftige CPUs Bedeutung geben könnten. So sollte es mit orq $0x40000000,%rax
ersetzt werden.
So ist die festgelegte Abfolge von Anweisungen wäre:
pushq %rax
movq %cr0, %rax
orq $0x40000000, %rax
movq %rax, %cr0
wbinvd
popq %rax
Das ist nicht, was ich werde vorschlagen, aber in Ihrer Inline-Assembly verwenden. Es ist möglich, dies zu vereinfachen, indem GCC das verwendete Register auswählt. Auf diese Weise müssen Sie es nicht bewahren. Hier ist, was ich stattdessen vorschlagen würde:
long long dummy;
asm volatile ("movq %%cr0, %0\n\t"
"orq $0x40000000, %0\n\t"
"movq %0, %%cr0\n\t"
"wbinvd"
: "=r" (dummy) : :);
ist nicht pushw für Wortgröße (16bit)? eax ist 32bit, versuchen 'pushl' – Leeor
Hallo @Leeor, Vielen Dank für Ihren Kommentar! aber pushl meldet Fehler: memory.c: 645: Fehler: ungültiges Befehlssuffix für 'push '; Ich habe auch versucht, pushq, die nicht funktioniert – Mike