第3章 分段机制和逻辑地址
该章节主要介绍了寄存器的字长、如何访问内存、内存中的字节序以及8086的分段机制。
寄存器和字长
早期寄存器可以保存4比特、8比特、16个比特。现在的一般都是32位和64位。为了方便区分有一些常用叫法。
汇编里看到这样的指令:db、dw、dd、dq其实就是对应上面英文首字母的。
- db:分配1个字节的空间;
- dw:分配1个字(2个字节)的空间;
- dd:分配2个字(4个字节)的空间;
- dq:分配4个字(8个字节)的空间;
内存访问和字节序
如果要保存更多的数据,寄存器就不太够了,所以有了内存这玩意,可以保存大量的数据,现在家用电脑一般内存都8G、16G了,还有的更多。服务器级别上百GB也见过,非常牛B。
搜下现在的CPU,下面是酷睿i7 14代系列,二级和三级缓存都还是MB单位。
内存中的内每个字节都对应一个地址。
内存每个地址只对应1个字节,那么如果需要取出1个字(2个字节),那么是怎么取的呢?这个就涉及到字节序的问题了。
- 如果访问内存中的一个字,那么,它规定高字节位于高地址部分,低字节位于低地址部分,这称为低端字节序(Little Endian)。
- 高字节位于低地址部分,低字节位于高地址部分,这称为高端字节序(Big Endian)。
例子:往内存0x8000的位置写入一个双字(4字节)。
mov dword [0x8000],0x87654321 ;写一个双字
低端字节序就是存数的低位存储在低位、存数的高位存储内存的高位。(以字节为单位)
高端字节序就是存数的低位存储在高位、存数的高位存储内存的低位。(以字节为单位)
低端字节序更符合计算机的计算逻辑,但是人眼看起来不太习惯,比如用Bochs查看内存分布(低端字节序),要从右向左读:
Bochs查看内存分布
古老的INTEL 8086处理器
8086是历史上很经典的一款产品,卖的多,往后的产品基于商业考虑,都要兼容之前的模式,所以要学习处理器,就要从8086开始。
8086的通用寄存器
8086的通用寄存器:
8086是16位的处理器,寄存器都是16位的,可以拆成两个8位的寄存器,就可以向下兼容。同样往后的80386 32位处理器也是这样处理兼容性的。
程序的重定位难题
书中一开始提及到段(Segment)的概念,因为不管是指令还是数据都是存放在内存中,而处理器又是按顺兴执行指令的,如果指令和数据混杂在一起那么就会导致处理器无法正常工作。如果分成数据段和代码段问题就可以解决了。
后面又阐述了程序重定位的难题主要是在于:
- 每个电脑上都可以执行若干程序,每个程序的内存地址是随机分配的;
- 如果程序开发者使用绝对内存地址那么就无法实现重定位;
所以就需要一种机制可以方便实现程序的重定位。在8086上访问内存使用段地址和偏移地址,也就是逻辑地址,而不是实际物理地址。
这里其实也可以理解为多加了一层,想起《计算机组原理》成课程里面的系统复杂性管理的其中一个方法:层次化(Hierachy)。
逻辑地址
书中介绍了段地址和偏移地址的概念,为后面一个小结引出8086的分段机制提供前置知识。
- 段地址可以理解为起始地址;
- 偏移地址就是相对于起始地址的偏移量;
一个指令在当前程序内的偏移地址不管哪台计算上都是固定的,也就是说如果使用这种机制,只要在不同的电脑上可以定位到段地址(程序起始地址)就可以了。
如此,当这个程序被安装到不同的计算机上运行时,只需要修改段地址 A532 即可,管理上就方便了很多。
8086的内存分段机制
该章节一开始介绍了8086的内部结构。
8086内部有4个段寄存器:
- CS:Code Segment 代码段寄存器,16位。
- DS:Data Segment 数据段寄存器,16位。
- ES:Extra Segment 附加段寄存器,16位。
- SS:Stack Segment 栈段寄存器,16位。
IP是指令指针(Instruction Pointer)寄存器,它只和CS一起使用,也是16位的。
::: tip
值的一提的是8086有一个6字节的指令预取队列,这个在几十年就有这种设计,真的是非常牛B。
:::
8086的寻址方式是:(CS) * 0x10 + (IP) = 物理地址。(CS)表示CS中存储的值,(IP)表示IP中存储的值。
例如 0xA532:0x0002 寻址示例图:
为什么这么寻址呢?书中说明了理由:
- 8086有20根地址线,意味着可以寻址的空间:2^20=1024*1024=1MB。
- 8086通过CS和IP共同寻址,两个寄存器都是16位的,相加最多17位,无法达到20位。
- 如果只有16位的寻址空间,那么最大只有:2^16=64KB,不够用。
所以通过 (CS)*0x10,就可以把寻址空间提高到20位。
另外书中有一句话提到:
16位的段地址和16位的偏移地址相加,只能形成16位的物理地址,怎么得到这20位的物理地址呢?
这句话存在一点瑕疵:16位的段地址和16位的偏移地址相加,理论上最大可以有17位。例如:0xFFFF + 0xFFFF = 0x1FFFE,但确实无法得到20位的物理地址。
其他段寄存器:DS、ES和SS也是类似。