![x86汇编与逆向工程:软件破解与防护的艺术](https://wfqqreader-1252317822.image.myqcloud.com/cover/730/53287730/b_53287730.jpg)
2.5 内存访问
32位(或64位)的系统只有有限的寄存器。忽略用于追踪栈的特殊寄存器和通用寄存器(如esp和ebp)后,只剩下六个可用于一般计算的寄存器(如eax、ebx、ecx、edx、esi和edi),这就是程序还需要能够读取内存数据和向内存中写入数据的原因。
在x86汇编Intel语法中,内存访问是使用[]符号来表示的。例如,存储在0x12345678地址的数据可以通过[0x12345678]来访问。内存地址也可以存储在寄存器中,如指令[eax]。
指定数据长度
当从内存获取数据时,不仅需要知道数据的存储地址,还需要知道要访问的内存量。例如,指令[0x12345678]并没有指明程序需要一个字节、一个字、一个双字,还是更多。
![](https://epubservercos.yuewen.com/2FAC88/31751360804058606/epubprivate/OEBPS/Images/40_01.jpg?sign=1739614214-fQBKStP6kbtyio2y6ejPtVqkSbXQlJB3-0-cb06b391e7eaec4956090712ac981e77)
图2.7 x64常用的寄存器
来源:Bobmon/Wikimedia Commons/CC BY-SA 4.0.
![](https://epubservercos.yuewen.com/2FAC88/31751360804058606/epubprivate/OEBPS/Images/41_01.jpg?sign=1739614214-sJ8WVa7Ax18yT1PNt7r3nThc3EXNImwy-0-67f1e3295fc08890c6b97e4baaf86fd3)
图2.8 r8寄存器的各个部分
在某些情况下,可以从上下文中推断出需要访问的数据的长度。例如,在指令mov eax,[0x12345678]中,从内存中获取的数据将被储存在eax中。由于eax是一个32位寄存器,程序必然需要请求32位的数据。
事实并非总是这样。例如,考虑指令mov[0x12345678], 1,它会将值1放到内存中的特定地址。但是,这个指令并没有明确被设定的值的长度。我们应该将1看作是一个字节(00000001)、一个字(0000000000000001),还是一个双字(00000000000000000000000000000001)呢?为了明确和精简,我们经常会去除前导零,所以以上都是有效解释。
提示:传统上,32位的x86架构应该有32位的字。然而,为了向后兼容16位的x86架构,所以字的长度是16位,而双字则是32位。
当内存访问的大小没有被隐式地指出时,必须在指令内明确指明。例如,指令byte[100]访问位于地址100的字节,word[ebx]访问ebx指向的字,dword[ax]访问ax指向的双字。图2.9展示了以下三条指令之间的区别。
![](https://epubservercos.yuewen.com/2FAC88/31751360804058606/epubprivate/OEBPS/Images/41_02.jpg?sign=1739614214-fJfSiidbRxBNbBR52CJFZxJoP58xx838-0-b4bbbc7f573b0358c27b6402956f8ac2)
![](https://epubservercos.yuewen.com/2FAC88/31751360804058606/epubprivate/OEBPS/Images/41_03.jpg?sign=1739614214-ZmJuYtbxhdNEm8qeFQgrv8ZQIGq6kD5O-0-03b8dd1e8d3d835dc6d157ddcabd89bb)
图2.9 比较不同大小的mov指令