内存
X86CPU 和 AMD64(X86-64)CPU 的区别:
通用寄存器的位宽不同:AMD64 通用寄存器是 64 位,而 X86 通用寄存器是 32 位,所以 AMD64 一次能处理 64 位数据,而 X86 一次只能处理 32 位数据。
支持的寻址空间不同:操作内存的最小单位是字节,每个内存地址(内存编号)指向一个字节,2^32 = 4294967296,所以 X86 支持的最大寻址空间就是 4294967296 字节,也就是 4GB。
AMD65 兼容 32 位操作系统,而 X86 不支持 64 位操作系统。
- 32 位操作系统 内存地址是 32 位
- 64 位操作系统 内存地址是 64 位
寄存器与内存
寄存器与内存的区别:
寄存器位于 CPU 内部,执行速度快,但比较贵。
内存速度相对较慢,但成本较低,所以可以做的很大。
寄存器和内存没有本质区别,都是用于存储数据的容器,都是定宽的。
寄存器常用的有 8 个:EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI。
计算机中的几个常用计量单位:BYTE WORD DWORD
1
2
3BYTE 字节 8bit
WORD 字 16bit
DWORD 双字 32bit内存的数量特别庞大,无法每个内存单元都起一个名字,所以用编号来代替,我们称计算机 CPU 是 32 位或者 64 位,主要指的就是内存编号的宽度,而不是寄存器的宽度。有很多书上说之所以叫 32 位计算机是因为寄存器的宽度是 32 位,是不准确的,因为还有很多寄存器是大于 32 位的。
计算机内存的每一个字节会有一个编号(即内存编号的单位是字节),如下图:
内存编号 编号对应的字节字节 0x00000000 第 0 个字节 0x00000001 第 1 个字节 0x00000002 第 2 个字节 …. …. …. 0xFFFFFFFF 第 2^32 个字节,2^32=4294967296,4294967296BYTE = 4GB 32 位操作系统最多识别内存 4G,对吗?不对,通过 PAE 物理内存扩展技术,可以使处理器能够从 32 位寻址提升到 36 位,也就是说理论上最大的物理内存可达 64GB。
内存编号
内存格式
- 每个内存单元的宽度为 8
- [编号]称为地址
- 地址的作用:当我们想从内存中读取数据或者想向内存中写入数据,首先应该找到要读、写的位置。就像写信要写地址一样。
从指定内存中写入/读取数据
1 | mov dword ptr ds:[0x0012FF34],0x12345678 |
dword ptr:要读/写多少 此时是 4 字节 byte == 1 字节 word == 2 字节
- ptr:代表后面是一个指针 (指针的意思就是里面存的不是普通的值,而是个地址)
[]:中括号表示里面的数据是一个地址值,和 ptr 的作用一样
ds:段寄存器 先不用管 记住就行
0x0012FF34:内存编号,必须是 32 位的 前面 0 可以省略
注意:地址编号不要随便写,因为内存是有保护的,并不是所有的内存都可以直接读写(需要特别处理)
建议地址编号写成 esp 的值
内存读写的 5 个公式
深刻理解内存寻址方式
寻址公式一 [立即数]
读取内存的值
1 | MOV EAX,DWORD PTR DS:[0x13FFC4] ; 将0x13FFC4中的值读出来,写到EAX中 |
向内存中写入数据
1 | MOV DWORD PTR DS:[0x13FFC4],eax ; 将eax中的值读出来,写到eax中 |
获取内存编号
1 | LEA EAX,DWORD PTR DS:[0X13FFC4] ; 将0X13FFC4这个内存编号(也就是0X13FFC4本身)写到EAX中 |
寻址公式二 [reg]
reg 代表寄存器,可以是 8 个通用寄存器中的任何一个
这种方式相比第一种,只是要先读取 reg
寻址公式三 [reg+立即数]
寻址公式四 [reg+reg*{1,2,4,8}]
用来寻址数组,有些数组元素占用不止一个内存单元,所以在计算数组元素的地址时需要用这种方式来计算:
1 | 数组元素地址 = 数组首地址 + 元素索引 * 数组元素占用空间 |
比如一个字形的数组,它的首地址是 6000H,那么它的第 4 个(索引从 0 开始)元素的地址就是:
1 | 6000H + 4 * 2 = 6008H |
在高级的 CPU 中,这种比例因子的寻址方式是在指令级别上提供支持的,所以可以直接用这种方式寻址:
1 | mov ebx,offset a |