【问题标题】:How do AX, AH, AL map onto EAX?AX、AH、AL 如何映射到 EAX?
【发布时间】:2013-02-17 22:16:56
【问题描述】:

我对 x86 寄存器的理解是说每个寄存器都可以被整个 32 位代码访问,并且分成多个可访问的寄存器。

在这个例子中EAX是一个32位寄存器,如果我们调用AX它应该返回前16位,如果我们调用AHAL它应该返回16之后的下8位bits 和 AL 应该返回最后 8 位。

所以我的问题是,因为我并不真正相信这就是它的运作方式。如果我们存储 32 位值,也就是 EAX 存储:

0000 0100 0000 1000 0110 0000 0000 0111

所以如果我们访问AX 它应该返回

0000 0100 0000 1000

如果我们读到AH 它应该返回

0000 0100

当我们读到AL 它应该返回

0000 0111

这是正确的吗?如果是 AH 真正具有什么价值?

【问题讨论】:

标签: assembly x86 cpu-registers


【解决方案1】:

不,这不太对。

EAX is the full 32-bit value
AX is the lower 16-bits
AL is the lower 8 bits
AH is the bits 8 through 15 (zero-based)

所以 AX 由 AH:AL 两半组成,它本身就是 EAX 的低半。 (EAX 的上半部分不能作为 16 位寄存器直接访问;如果需要,可以移位或旋转 EAX。)

为了完整起见,除了上述基于 32 位 CPU 的内容外,64 位 Intel/AMD CPU 也有

RAX, which hold a 64-bit value, and where EAX is mapped to the lower 32 bits.

所有这些也适用于 EBX/RBX、ECX/RCX 和 EDX/RDX。其他寄存器如 EDI/RDI 有 DI 低 16 位部分寄存器,但没有高 8 部分,低 8 DIL 只能在 64 位模式下访问:Assembly registers in 64-bit architecture


由于历史原因,写入 AL、AH 或 AX 会在完整的 AX/EAX/RAX 中保留未修改的其他字节。例如,它必须将一个新的 AL 合并到完整的 RAX 中。 (在 32 位或 64 位代码中,如果您不特别希望这种合并,请首选 movzx eax, byte [mem]movzx eax, word [mem] 加载:Why doesn't GCC use partial registers?

将 EAX 零扩展写入 RAX。 (Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?)

同样,所有这些都适用于每个寄存器,而不仅仅是 RAX。例如写入 DI 或 DIL 会合并到旧 RDI,写入 EDI 零扩展并覆盖整个 RDI。对于 R10B 或 R10W 写入合并相同,写入 R10D 使 R10 独立于旧 R10 值。

【讨论】:

  • 所以你会说我的误解来自 Ax 是前 16 名,而是调用了一个同时包含 Al 和 Ah 的值?
  • 感谢您的帮助,这一切都清楚了。这么愚蠢的错误
  • 如何称呼高 16 位和高 32 位?是否有 EAXH 或 AXH?
  • @user97662:不,没有办法只访问寄存器的上部 - 您必须读取整个寄存器并根据需要进行移位。
  • 感谢 Peter Cordes 大力扩充这个答案。
【解决方案2】:

AX 是 EAX 的低 16 位。 AH 是 AX 的高 8 位(即 EAX 的 8-15 位),AL 是 EAX 和 AX 的最低有效字节(0-7 位)。

示例(十六进制数字):

EAX: 12 34 56 78
AX: 56 78
AH: 56
AL: 78

【讨论】:

    【解决方案3】:
    | 0000 0001 0010 0011 0100 0101 0110 0111 | ------> EAX
    
    |                     0100 0101 0110 0111 | ------> AX
    
    |                               0110 0111 | ------> AL
    
    |                     0100 0101           | ------> AH
    

    【讨论】:

    • 您应该删除手动空格( ),并将整个内容格式化为代码块(每行缩进 4 个空格,它将采用单空格格式,并保留间距)
    【解决方案4】:

    不,你的答案是错误的

    Al 和 Ah 的选择来自 AX 而不是来自 EAX

    例如

    EAX=0000 0000 0000 0000 0000 0000 0000 0111
    

    所以如果我们调用 AX 它应该返回

    0000 0000 0000 0111
    

    如果我们调用 AH 它应该返回

    0000 0000
    

    当我们调用 AL 时它应该返回

    0000 0111
    

    示例编号 2

    EAX: 22 33 55 77
    AX: 55 77
    AH: 55    
    AL: 77
    

    示例 3

    EAX: 1111 0000 0000 0000 0000 0000 0000 0111    
    AX= 0000 0000 0000 0111
    AH= 0000 0000
    AL= 0000 0111  
    

    【讨论】:

    • 字节序有什么关系吗?如果我用GAS 组装movl $0x01 %eax%ax%al 的值是什么?一还是零?
    • @FrozenFlame:不,字节序仅适用于内存(包括mov $imm32, %eax 指令的编码方式,如opcode 01 00 00 00。)。 %al 中的值将是 1。如果您认为寄存器内的 MSB 位于左侧,LSB 位于右侧,则左移 %eax 会起作用。 (这对于向量寄存器可能会很棘手,请参阅stackoverflow.com/questions/41351087/…
    【解决方案5】:

    否 -- AL 是 AX 的 8 个最低有效位。 AX 是 EAX 的 16 个最低有效位。

    如果我们从 eax 中的 04030201h 开始,也许最容易处理。在这种情况下,AX 将包含 0201h,AH 将包含 02h,AL 将包含 01h。

    【讨论】:

      【解决方案6】:

      下面的 sn-p 使用 GDB 检查 EAX。

          (gdb) info register eax
          eax            0xaa55   43605
          (gdb) info register ax
          ax             0xaa55   -21931
          (gdb) info register ah
          ah             0xaa -86
          (gdb) info register al
          al             0x55 85
      
      1. EAX - 完整的 32 位值
      2. AX - 低 16 位值
      3. AH - 8 到 15 位
      4. AL - EAX/AX 的低 8 位

      【讨论】:

      • 您也可以在 gdb 中使用p /x $eax 打印寄存器(或者省略/x 以表示十进制)。并使用set $eax = 0xdeadbeef, IIRC 修改它们。另请参阅x86 tag wiki 的底部以获取一些关于 asm 的 gdb 技巧。
      猜你喜欢
      • 1970-01-01
      • 2016-09-11
      • 1970-01-01
      相关资源
      最近更新 更多