wrx*_*xyz 9 x86 endianness cpu-registers
我需要帮助理解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
Run Code Online (Sandbox Code Playgroud)
我在GDB中使用第10行的断点运行此程序(在上面的源代码中注释).在此断点,info registers显示的数值eax=0x78ff5abc和ebx=0x5a595857.
由于W,X,Y,Z的ASCII码分别为57,58,59,5A; 并且intel是小端,0x5a595857似乎是正确的字节顺序(最低有效字节优先).那么为什么不是eax寄存器的输出0xbc5aff78(数字0x78ff5abc的最低有效字节)而不是0x78ff5abc?
sle*_*man 19
寄存器内的字节顺序没有意义,因为字节顺序描述字节顺序是从低存储器地址到高存储器地址还是从高存储器地址到低存储器地址.寄存器不是字节可寻址的,因此寄存器中没有低地址或高地址.您看到的是调试器打印数据的方式.
Jim*_*hel 13
汇编程序以不同方式处理这两个常量.在内部,EAX寄存器中的值以big-endian格式存储.你可以通过写:
mov eax, 1
Run Code Online (Sandbox Code Playgroud)
如果你检查寄存器,你会看到它的值是0x00000001.
当您告诉汇编程序您想要常量值时0x78ff5abc,这正是存储在寄存器中的内容.EAX的高8位将包含0x78,AL寄存器包含0xbc.
现在,如果您要将EAX中的值存储到内存中,它将以相反的顺序布置在内存中.也就是说,如果你要写:
mov [addr],eax
Run Code Online (Sandbox Code Playgroud)
然后在[addr]检查内存,你会看到0xbc,0x5a,0xff,0x78.
在'WXYZ'的情况下,汇编程序假定您要加载该值,以便在将其写入内存时,它将被布局为0x57,0x58,0x59,0x5a.
看看汇编程序生成的代码字节,你会看到差异.在这种情况下mov eax,0x78ff5abc,你会看到:
<opcodes for mov eax>, 0xbc, 0x5a, 0xff, 0x78
Run Code Online (Sandbox Code Playgroud)
在这种情况下mov eax,WXYZ,你会看到:
<opcodes for mov eax>, 0x57, 0x58, 0x59, 0x5a
Run Code Online (Sandbox Code Playgroud)
字节序仅对内存有意义,每个字节都有一个数字地址.当一个值的MSByte被放入比LSByte更高的内存地址时,它被称为Littte endian,这是任何x86处理器的字节顺序.
而对于整数,LSByte和MSByte之间的区别很明显:
0x12345678
MSB---^^ ^^---LSB
Run Code Online (Sandbox Code Playgroud)
它没有为字符串文字定义!WXYZLSB或MSB应该被视为哪个部分并不明显:
1)最明显的方式,
'WXYZ' -> 0x5758595A
Run Code Online (Sandbox Code Playgroud)
会导致记忆秩序ZYXW.
2)当内存顺序与文字顺序相匹配时,并非如此明显的方式:
'WXYZ' -> 0x5A595857
Run Code Online (Sandbox Code Playgroud)
汇编程序必须选择其中一个,显然它选择了第二个.
简而言之,将寄存器视为只是值,它们最终如何存储的字节序并不重要。
您知道在 eax 上写入您写入的是一个 32 位数字,并且您知道从 eax 读取您将读取相同的 32 位数字。从这个角度来说,字节序并不重要。
您知道,在“al”中,您拥有该值的较低有效 8 位部分,而在“ah”中,您拥有较低 16 位的最高有效 8 位部分。无法访问高 16 位上的单个字节,当然读取整个 32 位值除外。