AX、AH、AL 如何映射到 EAX?

Posted

技术标签:

【中文标题】AX、AH、AL 如何映射到 EAX?【英文标题】:How do AX, AH, AL map onto EAX? 【发布时间】:2022-01-19 11:31:01 【问题描述】:

我对 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 真正具有什么价值?

【问题讨论】:

不,您的 AX 值是错误的。破解最后 16 位。 AH 只返回 EAX 的第 8 位到第 15 位。 请将位模式替换为在您的问题上下文中更容易理解的内容,例如:0000 0001 0010 0011 ... 相关:Assembly language - Why are characters stored in register as little endian? re:映射到内存。 【参考方案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 会起作用。 (这对于向量寄存器可能会很棘手,请参阅***.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
    EAX - 完整的 32 位值 AX - 低 16 位值 AH - 8 到 15 位 AL - EAX/AX 的低 8 位

【讨论】:

您也可以在 gdb 中使用 p /x $eax 打印寄存器(或省略 /x 以表示十进制)。并使用set $eax = 0xdeadbeef, IIRC 修改它们。另请参阅x86 tag wiki 的底部以获取一些关于 asm 的 gdb 技巧。

以上是关于AX、AH、AL 如何映射到 EAX?的主要内容,如果未能解决你的问题,请参考以下文章

汇编 寄存器

如何在c ++中获取eax寄存器的结构

x86_64寄存器rax/eax/ax/al覆盖完整的寄存器内容[重复]

内核如何获取内存

汇编指令学习(MOV,MOVSX,MOVZX,LEA,XCHG)

汇编命令及OD常用命令及断点设置