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:

  1. 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 essuie rax , 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.

  2. 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é.

53
demandé sur GreyCat 2014-08-23 00:57:47

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.

58
répondu Hans Passant 2014-08-22 21:56:16