x86_64的寄存器RAX / EAX / AX /人全覆盖寄存器的内容 [英] x86_64 registers rax/eax/ax/al overwriting full register contents

查看:5540
本文介绍了x86_64的寄存器RAX / EAX / AX /人全覆盖寄存器的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于它广泛通告,现代x86_64的处理器具有可在向后兼容的方​​式来使用如32位寄存器,16位寄存器,甚至8位寄存器64位寄存器,例如:

  0x1122334455667788
  ================ RAX(64位)
          ======== eax中(32位)
              ====斧(16位)
              ==啊(8位)
                ==人,(8比特)

这种方案可以字面,即一个可使用指定的名称用于读或写的目的总是访问寄存器的仅一部分,并且这将是高度合乎逻辑的。事实上,这是一切多达32位真:

  MOV EAX,0x11112222; EAX = 0x11112222
MOV AX,0x3333; EAX = 0x11113333(作品中,只有低16位改变)
MOV人,0x44进行; EAX = 0x11113344(工程,仅低8位改变)
MOV啊,将0x55; EAX = 0x11115544(工程,仅高8位改变)
XOR啊,啊; EAX = 0x11115500(工程,仅高8位清零)
MOV EAX,0x11112222; EAX = 0x11112222
异人,人; EAX = 0x11110022(工程,仅低8位清零)
MOV EAX,0x11112222; EAX = 0x11112222
异斧,斧; EAX = 0x11110000(作品中,只有低16位清零)

然而,事情似乎只要我们得到64位的东西是相当尴尬的:

  MOV RAX,0x1111222233334444; RAX = 0x1111222233334444
MOV EAX,0x55​​556666;实际:RAX = 0x0000000055556666
                             ;预计:RAX = 0x1111222255556666
                             ;高32位似乎丢失!
MOV RAX,0x1111222233334444; RAX = 0x1111222233334444
MOV AX,0x7777; RAX = 0x1111222233337777(作品!)
MOV RAX,0x1111222233334444; RAX = 0x1111222233334444
XOR EAX,EAX;实际:RAX = 0x0000000000000000
                             ;预计:RAX = 0x1111222200000000
                             ;再次,它消灭整个注册

这样的行为似乎是荒谬的高度和不合逻辑给我。它看起来就像试图以任何方式写在所有任何 EAX 引出 RAX 的高32位寄存器的擦

所以,我有2个问题:


  1. 我认为,这种尴尬的行为必须被记录的地方,但我似乎无法找到详细的解释(64位的32位究竟是如何高的注册得到擦拭)的任何地方。我是不是正确的,写 EAX 总是抹 RAX ,或它在更复杂的东西?它是否适用于所有的64位寄存器,或者也有一些例外?

    A <一个href=\"http://stackoverflow.com/questions/11822646/can-mov-eax-0x1-always-be-used-instead-of-mov-rax-0x1\">strongly相关的问题提到相同的行为,但是,唉,有再次文档没有确切的引用。

    在换句话说,我想一个链接到文件,指定此行为。


  2. 难道只是我还是这整个事情似乎是很奇怪的,不合逻辑的(有一个行为,有另一RAX-EAX即EAX-AX-AH-人,RAX-AX-AH-AL)?也许是我错过了一些重要的点这里为什么却实现这样?

    这是一个解释为什么将是非常美联社preciated。



解决方案

记载于Intel / AMD的处理器手册的处理器型号为的真正的执行引擎pretty不完善模型一个现代化的核心。尤其是,处理器寄存器与现实不符的概念,有一个或EAX寄存器RAX没有这样的事。

指令去codeR的一个主要工作是传统的x86 / x64的指令转换成的微操作的,一类RISC处理器的指令。小的指令,很容易并发执行,并能够采取多个执行子单元的优势。允许多达6指示在同一时间执行。

为使这项工作,处理器寄存器的概念被虚拟为好。指令去codeR从分配寄存器的一家大银行的寄存器。当指令的退休的,即动态分配寄存器的值写回任何寄存器目前持有的,比如说价值,RAX。

为使这项工作顺利且高效,使得很多指令同时执行,这些操作不具有相互依赖性是非常重要的。你可以有最坏的一种是寄存器值依赖于其他指令。该EFLAGS寄存器是臭名昭著,许多指令对其进行修改。

你的喜欢的方式同样的问题的它的工作。大问题,它要求当指令退役合并对两个寄存器的值。创建那将堵塞该芯的数据依赖性。通过强制高32位为0,即依赖瞬间消失,不再需要合并。经9的执行速度。

As it is widely advertised, modern x86_64 processors have 64-bit registers that can be used in backward-compatible fashion as 32-bit registers, 16-bit registers and even 8-bit registers, for example:

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

Such a scheme may be taken literally, i.e. one can always access only the part of the register using a designated name for reading or writing purposes, and it would be highly logical. In fact, this is true for everything up to 32-bit:

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 = 0x11115500 (works, only high 8 bits cleared)
mov  eax, 0x11112222 ; eax = 0x11112222
xor  al, al          ; eax = 0x11110022 (works, only low 8 bits cleared)
mov  eax, 0x11112222 ; eax = 0x11112222
xor  ax, ax          ; eax = 0x11110000 (works, only low 16 bits cleared)

However, things seem to be fairly awkward as soon as we get to 64-bit 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

Such behavior seems to be highly ridiculous and illogical to me. It looks like trying to write anything at all to eax by any means leads to wiping of high 32 bits of rax register.

So, I have 2 questions:

  1. I believe that this awkward behavior must be documented somewhere, but I can't seem to find detailed explanation (of how exactly high 32 bits of 64-bit register get wiped) anywhere. Am I right that writing to eax always wipes rax, or it's something more complicated? Does it apply to all 64-bit registers, or there are some exceptions?

    A strongly related question mentions the same behavior, but, alas, there are again no exact references to documentation.

    In other words, I'd like a link to documentation that specifies this behavior.

  2. Is it just me or this whole thing seems to be really weird and illogical (i.e. eax-ax-ah-al, rax-ax-ah-al having one behavior and rax-eax having another)? May be I'm missing some kind of vital point here on why was it implemented like that?

    An explanation on "why" would be highly appreciated.

解决方案

The processor model as documented in the Intel/AMD processor manual is a pretty imperfect model for the real execution engine of a modern core. In particular, the notion of the processor registers does not match reality, there is no such thing as a EAX or RAX register.

One primary job of the instruction decoder is to convert the legacy x86/x64 instructions into micro-ops, instructions of a RISC-like processor. Small instructions that are easy to execute concurrently and being able to take advantage of multiple execution sub-units. Allowing as many as 6 instructions to execute at the same time.

To make that work, the notion of processor registers is virtualized as well. The instruction decoder allocates a register from a big bank of registers. When the instruction is retired, the value of that dynamically allocated register is written back to whatever register currently holds the value of, say, RAX.

To make that work smoothly and efficiently, allowing many instructions to execute concurrently, it is very important that these operations don't have an interdependency. And the worst kind you can have is that the register value depends on other instructions. The EFLAGS register is notorious, many instructions modify it.

Same problem with the way you like it to work. Big problem, it requires two register values to be merged when the instruction is retired. Creating a data dependency that's going to clog up the core. By forcing the upper 32-bit to 0, that dependency instantly disappears, no longer a need to merge. Warp 9 execution speed.

这篇关于x86_64的寄存器RAX / EAX / AX /人全覆盖寄存器的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆