x86 64 registos rax/eax/ax / al sobrescrever o conteúdo total do registo [duplicado]

Como é amplamente anunciado, os modernos processadores x86_64 têm registos de 64 bits que podem ser usados de forma compatível com o passado como registos de 32 bits, registos de 16 bits e mesmo registradores de 8 bits, por exemplo:

0x1122334455667788
  ================ rax (64 bits)
          ======== eax (32 bits)
              ====  ax (16 bits)
              ==    ah (8 bits)
                ==  al (8 bits)
([9]} tal esquema pode ser tomado literalmente, isto é, pode-se sempre aceder apenas à parte do registo usando um nome designado para fins de leitura ou escrita, e seria altamente lógico. Na verdade, isso é verdade para tudo até 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)
No entanto, as coisas parecem estranhas assim que chegamos a coisas de 64 bits.
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
Esse comportamento parece - me muito ridículo e ilógico. Parece que estou a tentar escrever. qualquer coisa a eax por qualquer meio leva a limpar de alto 32 bits de registro rax.

Então, tenho duas perguntas:
  1. Eu acredito que este comportamento estranho deve estar documentado em algum lugar, mas eu não consigo encontrar explicação detalhada (de como exatamente 32 bits de registro de 64 bits são apagados) em qualquer lugar. Tenho razão em escrever para apagar sempre, ou é algo mais complicado? Aplica-se a todos os registos de 64 bits, ou há alguns excepções?

    a questão fortemente relacionada menciona o mesmo comportamento, mas, infelizmente, não há mais nenhuma referência exata à documentação.

    Em outras palavras, Eu gostaria de um link para a documentação que especifica este comportamento.

  2. É impressão minha ou tudo isto parece ser muito estranho e ilógico (ou seja, eax-AX-ah-al, rax-ax-ah-al ter um comportamento e rax-eax ter outro)? Talvez me esteja a escapar algum ponto vital sobre o porquê. implementado assim?

    Uma explicação sobre" porquê " seria muito apreciada.

Author: GreyCat, 2014-08-23

1 answers

O modelo do processador documentado no manual do Processador Intel / AMD é um modelo bastante imperfeito para o Real motor de execução de um núcleo moderno. Em particular, a noção dos registros do processador não corresponde à realidade, não existe tal coisa como um registro EAX ou RAX.

Uma tarefa principal do descodificador de instruções é converter as instruções x86/x64 legadas em Micro-ops, Instruções de um processador RISC. Pequenas instruções que são fáceis de executar simultaneamente e ser capaz de tirar vantagem de várias subunidades de execução. Permitindo até 6 instruções para executar ao mesmo tempo.

Para fazer isso funcionar, a noção de registradores de processadores também é virtualizada. O descodificador de instruções atribui um registo de um grande banco de registos. Quando a instrução é aposentada, o valor desse registo dinamicamente atribuído é escrito de volta para qualquer registo que detém actualmente o valor de, digamos,, RAX.

Para que isso funcione de forma suave e eficiente, permitindo que muitas instruções sejam executadas simultaneamente, é muito importante que estas operações não tenham uma interdependência. E o pior tipo que você pode ter é que o valor de registro depende de outras instruções. O registo de EFLAGS é notório, muitas instruções modificam-no.

O mesmo problema com a forma como tu gostas que funcione. Grande problema, ele requer dois valores de registro para ser fundido quando a instrução é Aposentado. Criar uma dependência de dados que vai entupir o núcleo. Ao forçar o 32-bit superior a 0, essa dependência desaparece instantaneamente, não mais uma necessidade de se fundir. Velocidade de execução Warp 9.

 58
Author: Hans Passant, 2014-08-22 21:56:16