Gre*_*Cat 70 assembly x86-64 cpu-registers zero-extension
正如广泛宣传的那样,现代x86_64处理器具有64位寄存器,可以以向后兼容的方式用作32位寄存器,16位寄存器甚至8位寄存器,例如:
0x1122334455667788
================ rax (64 bits)
======== eax (32 bits)
==== ax (16 bits)
== ah (8 bits)
== al (8 bits)
Run Code Online (Sandbox Code Playgroud)
这样的方案可以从字面上理解,即,总是可以使用指定的名称仅访问寄存器的一部分用于读取或写入目的,并且这将是高度逻辑的.实际上,对于高达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)
Run Code Online (Sandbox Code Playgroud)
但是,一旦我们得到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
Run Code Online (Sandbox Code Playgroud)
这种行为对我来说似乎非常荒谬和不合逻辑.看起来试图eax通过任何方式写任何东西导致擦除高32位rax寄存器.
所以,我有两个问题:
我相信这种尴尬的行为必须记录在某处,但我似乎无法找到详细的解释(64位寄存器的高32位是如何被擦除的).写作eax总是擦拭我是对的rax,还是更复杂的东西?它是否适用于所有64位寄存器,或者有一些例外?
一个强烈相关的问题提到了相同的行为,但是,唉,再次没有对文档的确切引用.
换句话说,我想要指向此行为的文档链接.
它只是我或整个事情似乎真的很奇怪和不合逻辑(即eax-ax-ah-al,rax-ax-ah-al有一种行为,而rax-eax有另一种行为)?可能是我在这里错过了一些重要的观点,为什么它会像那样实现?
对"为什么"的解释将受到高度赞赏.
Han*_*ant 71
英特尔/ AMD处理器手册中记录的处理器模型对于现代核心的真实执行引擎来说是一个非常不完美的模型.特别是,处理器寄存器的概念与现实不匹配,没有EAX或RAX寄存器这样的东西.
指令解码器的一个主要工作是将传统的x86/x64指令转换为微操作,类似RISC的处理器的指令.易于同时执行并能够利用多个执行子单元的小指令.允许多达6条指令同时执行.
为了实现这一目标,处理器寄存器的概念也是虚拟化的.指令解码器从一大堆寄存器中分配寄存器.当指令退出时,该动态分配的寄存器的值被写回到当前保存的值,例如RAX.
为了使这项工作顺利有效,允许许多指令同时执行,这些操作没有相互依赖性是非常重要的.最糟糕的是,寄存器值取决于其他指令.EFLAGS寄存器是臭名昭着的,许多指令修改它.
你喜欢它的工作方式也有同样的问题.很大的问题,它需要在指令退役时合并两个寄存器值.创建一个阻碍核心的数据依赖.通过强制高32位为0,该依赖性立即消失,不再需要合并.Warp 9执行速度.
| 归档时间: |
|
| 查看次数: |
50724 次 |
| 最近记录: |