我需要帮助理解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=0x78ff5abc
和ebx=0x5a595857
的值。
由于W,X,Y,Z的ASCII码分别为57,58,59,5A;并且intel是小端,0x5a595857似乎是正确的字节顺序(最低有效字节优先)。那么为什么不是eax寄存器0xbc5aff78
的输出(首先是0x78ff5abc的最低有效字节)而不是0x78ff5abc
?
答案 0 :(得分:16)
寄存器中的字节顺序没有意义,因为字节顺序描述字节顺序是从低存储器地址到高存储器地址还是从高存储器地址到低存储器地址。寄存器不是字节可寻址的,因此寄存器中没有低地址或高地址。您所看到的是调试器打印数据的方式。
答案 1 :(得分:11)
汇编程序以不同方式处理这两个常量。在内部,EAX寄存器中的值以big-endian格式存储。你可以通过写:
来看到mov eax, 1
如果您检查注册表,您会看到其值为0x00000001
。
当您告诉汇编程序您想要常量值0x78ff5abc
时,这正是存储在寄存器中的内容。 EAX的高8位将包含0x78
,AL寄存器包含0xbc
。
现在,如果您将
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
答案 2 :(得分:5)
Endianness仅对内存有意义,其中每个字节都有一个数字地址。当一个值的MSByte被放入比LSByte更高的内存地址时,它被称为Littte endian,这是任何x86处理器的字节顺序。
对于整数,LSByte和MSByte之间的区别很明显:
0x12345678
MSB---^^ ^^---LSB
没有为字符串文字定义! WXYZ
的哪一部分应被视为LSB或MSB并不明显:
1)最明显的方式,
'WXYZ' -> 0x5758595A
会导致内存顺序ZYXW
。
2)当内存顺序与文字顺序相匹配时,并非不那么明显:
'WXYZ' -> 0x5A595857
汇编程序必须选择其中一个,显然它会选择第二个。
答案 3 :(得分:2)
用简单的话来说,将寄存器视为值,对它们最终存储方式的字节序并不重要。
您知道在eax上写会写一个32位数字,并且从eax上读会读到相同的32位数字。用这个术语,字节顺序并不重要。
比您知道,在“ al”中,值的有效8位部分较少,而在“ ah”中,低16位的含义最为显着的8位部分。除了读取整个32位值之外,无法访问更高16位的单个字节。