x86_64 регистры rax / eax / ax / al перезаписывают полное содержимое регистра [дубликаты]
На этот вопрос уже есть ответ:
Почему инструкции x86-64 для 32-разрядных регистров обнуляют верхнюю часть полного 64-разрядного регистра? 2 ответаКак это широко рекламируется, современные процессоры 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 вопроса:
Я считаю, что это неуклюжее поведение должно быть где-то задокументировано, но я не могу найти подробного объяснения (как точно стираются 32-битные 64-битные регистры). Я прав, что пишуeax
всегда вытираетrax
, или это что-то более сложное? Это относится ко всем 64-битным регистрам или есть некоторые исключения?
A сильно связанный вопрос упоминает то же поведение, но, увы, нет точных ссылок на документацию.
Другими словами, мне нужна ссылка на документацию, в которой указано это поведение.
Это только я или вся эта вещь кажется действительно странной и нелогичной (то есть eax-ax-ah-al, rax-ax-ah-al с одним поведением и rax-eax с другим)? Может быть, я упускаю какой-то важный момент, почему это так реализовано?
Объяснение «почему» будет высоко оценено.