x86 64 registres rax/eax/ax/al écrasement complet le contenu d'un registre [dupliquer]
cette question a déjà une réponse ici:
comme il est largement annoncé, les processeurs x86_64 modernes ont des registres 64 bits qui peuvent être utilisés dans à la mode rétrocompatible comme des registres 32 bits, des registres 16 bits et même des registres 8 bits, par exemple:
0x1122334455667788
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
un tel schéma peut être pris au pied de la lettre, c'est-à-dire qu'on ne peut toujours accéder qu'à la partie du registre utilisant un nom désigné à des fins de lecture ou d'écriture, et ce serait très logique. En fait, cela est vrai pour tout jusqu'à 32 bits:
mov eax, 0x11112222 ; eax = 0x11112222
mov ax, 0x3333 ; eax = 0x11113333 (works, only low 16 bits changed)
mov al, 0x44 ; eax = 0x11113344 (works, only low 8 bits changed)
mov ah, 0x55 ; eax = 0x11115544 (works, only high 8 bits changed)
xor ah, ah ; eax = 0x11110044 (works, only high 8 bits cleared)
mov eax, 0x11112222 ; eax = 0x11112222
xor al, al ; eax = 0x11112200 (works, only low 8 bits cleared)
mov eax, 0x11112222 ; eax = 0x11112222
xor ax, ax ; eax = 0x11110000 (works, only low 16 bits cleared)
Cependant, les choses semblent être assez maladroit dès que nous arrivons à 64 bits stuff:
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
mov eax, 0x55556666 ; actual: rax = 0x0000000055556666
; expected: rax = 0x1111222255556666
; upper 32 bits seem to be lost!
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
mov ax, 0x7777 ; rax = 0x1111222233337777 (works!)
mov rax, 0x1111222233334444 ; rax = 0x1111222233334444
xor eax, eax ; actual: rax = 0x0000000000000000
; expected: rax = 0x1111222200000000
; again, it wiped whole register
un tel comportement me semble hautement ridicule et illogique. Cela ressemble à essayer d'écrire n'importe quoi du tout à eax
par n'importe quel moyen conduit à l'essuyage de 32 bits de haut de rax
registre.
donc, j'ai 2 questions:
-
je crois que ce comportement étrange doit être documenté quelque part, mais je ne semble pas trouver d'explication détaillée (de la façon dont exactement 32 bits de registre de 64 bits se essuient) n'importe où. Est-ce que j'ai raison d'écrire
eax
toujours essuierax
, ou c'est quelque chose de plus compliqué? Il ne s'applique pas à tous les registres 64 bits, ou il y a des exceptions?A strongly related question mentionne le même comportement, mais, hélas, il n'y a encore aucune référence exacte à la documentation.
en d'autres termes, j'aimerais un lien vers la documentation qui spécifie ce comportement.
-
est-ce que c'est juste moi ou tout ça semble vraiment bizarre et illogique (i.e. eax-ax-ah-al, rax-ax-ah-al ayant un comportement et rax-eax en ayant un autre)? Peut-être que je manque un point vital sur la raison pour laquelle il a été mis en œuvre comme ça?
, Une explication sur le "pourquoi" serait fortement apprécié.
1 réponses
le modèle de processeur tel que décrit dans le manuel de processeur Intel/AMD est un modèle assez imparfait pour le vrai moteur d'exécution d'un noyau moderne. En particulier, la notion de registres de processeur ne correspond pas à la réalité, il n'existe pas de registre EAX ou RAX.
l'une des tâches principales du décodeur d'instructions est de convertir les instructions x86/x64 héritées en micro-ops , instructions de type RISC processeur. Petites instructions faciles à exécuter en même temps et pouvant profiter de plusieurs sous-unités d'exécution. Permettant 6 instructions à exécuter en même temps.
Pour faire ce travail, la notion de registres du processeur est virtualisé. Le décodeur d'instructions attribue un registre à partir d'une grande banque de registres. Lorsque l'instruction est retirée , la valeur de ce registre attribué dynamiquement est réécrit à n'importe quel registre qui possède actuellement la valeur de, disons, RAX.
pour que cela fonctionne sans heurts et efficacement, ce qui permet à de nombreuses instructions d'être exécutées simultanément, il est très important que ces opérations n'aient pas d'interdépendance. Et la pire chose que vous pouvez avoir est que la valeur du registre dépend d'autres instructions. Le registre EFLAGS est notoire, de nombreuses instructions le modifient.
même problème avec la façon dont vous comme ça marche. Gros problème, il faut que deux valeurs de Registre soient fusionnées lorsque l'instruction est retirée. Créer une dépendance de données qui va obstruer le noyau. En forçant le 32-bit supérieur à 0, cette dépendance disparaît instantanément, plus besoin de fusionner. Vitesse d'exécution de distorsion 9.