x86 64 регистры rax/eax/ax / al перезапись полного содержимого регистра [дубликат]


этот вопрос уже есть ответ здесь:

как это широко рекламируется, современные процессоры x86_64 имеют 64-разрядные регистры, которые могут быть использованы в обратной совместимости как 32-разрядные регистры, 16-разрядные регистры и даже 8-битные регистры, например:

0x1122334455667788
  ================ rax (64 bits)
          ======== eax (32 bits)
              ====  ax (16 bits)
              ==    ah (8 bits)
                ==  al (8 bits)

такая схема может быть воспринята буквально, т. е. всегда можно получить доступ только к части регистра, используя Назначенное имя для чтения или записи, и это было бы очень логично. На самом деле, это верно для всего, вплоть до 32-бит:

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)

однако, все кажется довольно неудобным, как только мы добираемся до 64-битных вещей:

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

такое поведение кажется очень смешным и нелогично для меня. Это похоже на попытку написать что-нибудь вообще eax любыми способами приводит к стиранию высоких 32 бит rax зарегистрироваться.

Итак, у меня есть 2 вопроса:

  1. Я считаю, что это неудобное поведение должно быть задокументировано где-то, но я не могу найти подробного объяснения (как именно высокие 32 бита 64-битного регистра стираются) в любом месте. Я прав, что пишу eax всегда салфетки rax, или это что-то более сложное? Применяется ли он ко всем 64-разрядным регистрам, или есть некоторые исключения?

    сильно связанный вопрос упоминает то же самое поведение, но, увы, снова нет точных ссылок на документацию.

    другими словами, Я хотел бы ссылку на документацию, которая определяет такое поведение.

  2. это только у меня или вся эта история выглядит очень странно и нелогично (то есть еах-ах-ах-ал-Ракс-дя-а-а-Аль, имеющий одно поведение и Ракс-еах, имеющих другой)? Может я упускаю какой-то важный момент здесь, почему он был реализован таким образом?

    объяснение "почему" было бы высоко оценено.

1 53

1 ответ:

модель процессора, описанная в руководстве по процессору Intel/AMD, является довольно несовершенной моделью для real двигатель исполнения современного ядра. В частности, понятие регистров процессора не соответствует действительности, нет такого понятия, как регистр EAX или RAX.

одной из основных задач декодера инструкций является преобразование устаревших инструкций x86 / x64 в micro-ops, инструкции RISC-подобного процессора. Небольшие инструкции, которые легки для того чтобы исполнить одновременно и мочь принять преимущество множественных подблоков исполнения. Позволяет одновременно выполнять до 6 инструкций.

чтобы сделать эту работу, понятие регистров процессора также виртуализируется. Декодер команд выделяет регистр из большого банка регистров. Когда инструкция пенсии, значение этого динамически выделенного регистра записывается обратно в любой регистр, который в настоящее время содержит значение ну, скажем, РАКС.

чтобы сделать эту работу плавной и эффективной, позволяя многим инструкциям выполняться одновременно, очень важно, чтобы эти операции не имели взаимозависимости. И самое худшее, что вы можете иметь, это то, что значение регистра зависит от других инструкций. Реестр EFLAGS печально известен, многие инструкции изменяют его.

такая же проблема с тем, как вы как его на работу. Большая проблема, она требует, чтобы два значения регистра были объединены когда инструкция будет удалена. Создание зависимости данных, которая будет засорять ядро. Заставляя верхний 32-бит равняться 0, эта зависимость мгновенно исчезает, больше не нужно сливаться. Скорость выполнения деформации 9.