【问题标题】:Endianness inside CPU registersCPU 寄存器中的字节顺序
【发布时间】:2011-05-29 03:12:40
【问题描述】:

我需要帮助了解 x86 处理器的 CPU 寄存器中的字节序。我写了这个小汇编程序:

section .data
section .bss

section .text
    global _start
_start:
    nop
    mov eax, 0x78FF5ABC
    mov ebx,'WXYZ'
    nop  ; GDB breakpoint here.
    mov eax, 1
    mov ebx, 0
    int 0x80

我在 GDB 中运行这个程序,在第 10 行有一个断点(在上面的源代码中注释)。在此断点处,info registers 显示了eax=0x78ff5abcebx=0x5a595857 的值。

由于W、X、Y、Z的ASCII码分别为57、58、59、5A;英特尔是小端,0x5a595857 似乎是正确的字节顺序(最低有效字节在前)。为什么不输出 eax 寄存器 0xbc5aff78(数字 0x78ff5abc 的最低有效字节在前)而不是 0x78ff5abc

【问题讨论】:

    标签: x86 cpu-registers endianness


    【解决方案1】:

    寄存器内部的字节序没有意义,因为字节序描述了字节顺序是从低内存地址到高内存地址还是从高内存地址到低内存地址。寄存器不可字节寻址,因此寄存器内没有低地址或高地址。您所看到的是您的调试器如何打印出数据。

    【讨论】:

    • 感谢您的回复。显然,“WXYZ”确实以相反的顺序存储在 ebx 寄存器中。根据调试器,BL寄存器包含87(十进制值为0x57);当然,这里有字节排序的概念吗?为什么 'W' 不存储在 ebx 的最高 8 位中?
    • 实际上,寄存器部分字节可寻址的。您可以使用 AL 和 AH 访问 EAX 的低两个字节。
    • 这是字节可访问的,而不是字节“可寻址的”。您可以访问该低字节,但仍然无法回答以下问题:“该低字节位于高于还是低于高字节的内存地址中”。 (好吧,您可以争辩说,如果将操作码解释为整数,则该操作码比另一个更大或更小,但这是非常随意的)
    • 所以当我们说 CPU 是 little-endian 时,我们是说 CPU 会按照“little-endian”规则从内存中读取多个字节吗?并且寄存器中的值将始终保存在 Big Endian 中?
    • @KorayTugay:硬盘也是内存:磁内存。由于硬盘驱动器是可逐字节寻址的,所以是的,字节序在磁盘上很重要。
    【解决方案2】:

    汇编器以不同的方式处理这两个常量。在内部,EAX 寄存器中的值以大端格式存储。你可以通过写来看到:

    mov eax, 1
    

    如果你检查寄存器,你会看到它的值是0x00000001

    当您告诉汇编器您想要常量值0x78ff5abc 时,这正是存储在寄存器中的内容。 EAX的高8位将包含0x78,AL寄存器包含0xbc

    现在,如果您要将 EAX 中的值存储到内存中,它将以相反的顺序排列在内存中。也就是说,如果你要写:

    mov [addr],eax
    

    然后检查 [addr] 处的内存,您会看到 0xbc、0x5a、0xff、0x78。

    在 'WXYZ' 的情况下,汇编器假定您要加载该值,这样如果您要将其写入内存,它将被布置为 0x57、0x58、0x59、0x5a。

    查看汇编程序生成的代码字节,您会发现其中的不同。对于mov eax,0x78ff5abc,您将看到:

    <opcodes for mov eax>, 0xbc, 0x5a, 0xff, 0x78
    

    对于mov eax,WXYZ,您会看到:

    <opcodes for mov eax>, 0x57, 0x58, 0x59, 0x5a
    

    【讨论】:

    • 所以当我们说 CPU 是 little-endian 时,我们是说 CPU 会按照“little-endian”规则从内存中读取多个字节吗?并且寄存器中的值将始终保存在 Big Endian 中?
    • @KorayTugay:据我所知,现代处理器确实如此。我不知道旧处理器,但我怀疑这是真的。 “Endianess”只关心 CPU 期望值如何存储在内存中。
    • @JimMischel 我确实意识到这篇文章到现在已经 3 岁了。但是为什么您声称“在内部,EAX 寄存器中的值以大端格式存储”?在您的示例中,AL 寄存器包含 0xbc,这意味着最低有效位存储在 EAX 的低 8 位中。这不就是小端的定义吗?
    • @OliverYoung 不,这不是小端。在 little endian 中,存储在内存中地址 0x12345678 的 32 位值 0xDEADBEEF 的值将在地址 0x12345678 处具有值 0x0F,在地址 0x123456789 处具有值 0x0E,等等。字节从右到左存储。当您查看 CPU 寄存器时,情况并非如此。无论如何,正如其他人指出的那样,字节序仅对记忆有意义。
    【解决方案3】:

    字节序仅对内存有意义,其中每个字节都有一个数字地址。当一个值的 MSByte 被放入比 LSByte 更高的内存地址时,它被称为 Littte endian,这是任何 x86 处理器的字节序。

    虽然对于整数,LSByte 和 MSByte 之间的区别很明显:

        0x12345678
    MSB---^^    ^^---LSB
    

    它不是为字符串字面量定义的! WXYZ 的哪一部分应该被视为 LSB 或 MSB 尚不清楚:

    1) 最明显的方式,

    'WXYZ' ->  0x5758595A
    

    会导致内存顺序ZYXW

    2) 不那么明显的方式,当内存顺序应该与文字顺序匹配时:

    'WXYZ' ->  0x5A595857
    

    汇编器必须选择其中之一,显然它选择了第二个。

    【讨论】:

      【解决方案4】:

      简单来说,将寄存器视为值,它们最终如何存储的字节序并不重要。

      您知道在 eax 上写入会写入 32 位数字,并且您知道从 eax 读取您将读取相同的 32 位数字。在这种情况下,字节顺序无关紧要。

      你知道,在“al”中,值的 8 位有效部分较低,在“ah”中,低 16 位的 8 位有效部分。除了读取整个 32 位值之外,没有办法访问更高 16 位的单个字节。

      【讨论】:

        猜你喜欢
        • 2013-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-25
        • 2019-09-06
        相关资源
        最近更新 更多