跳转到内容

x86汇编语言

副标题:从实模式到保护模式

作者: 李忠 王晓波 余洁

第一版:2012 第二版:2022

作者也写过《穿越计算机的迷雾》,计算机原理的基础。

跟王爽的汇编语言一样的好口碑,个人觉得王爽的那本略胜一筹。这本可以作为辅助,以王爽的《汇编语言》为重点阅读资料。

8086寄存器 通用寄存器

8086处理器内部共14个寄存器。都是16位的。

AX / BX / CX / DX / SI / DI / SP / BP / IP / CS / SS / DS / ES / PSW

有8个通用寄存器,都是由16比特组成,并分别被命名为AX、BX、CX、DX、SI、DI、BP、SP。“通用”的意思是,它们之中的大部分都可以根据需要用于多种目的。

因为这8个寄存器都是16位的,所以通常用于进行16位的操作。比如,可以 在这8个寄存器之间互相传送数据,它们之间也可以进行算术逻辑运算;也可以在它们和内存单元之间进行16位的数据传送或者算术逻辑运算。

内存的逻辑分段 段寄存器

对于INTEL x86处理器来说,指令的长度不定,短的指令仅有1字节,而长的指令则有可能达到15字节。在内存中,指令和非指令的普通二进制数是一模一样的,在组成内存的电路中,都是一些高、低电平的组合。因为处理器是自动按顺序取指令并加以执行的,在指令中混杂了非指令的数据会导致处理器不能正常工作。为此,指令和数据要分开存放,分别位于内存中的不同区域,或者说各自形成一个段(Segment),分别叫代码段和数据段。

注意,我们并没有改变内存的物理性质,并不是真的把它分成几块。段的划分是逻辑上的,从本质上来说,是如何看待和组织内存中的数据。

段在内存中的位置并不重要,因为处理器是可控的,我们可以让它从内存的任何位置开始取指令并加以执行。

为了让你写的程序在内存中的任何地方正确执行,就只能在编写程序的时候使用相对地址或者逻辑地址,而不能使用真实的物理地址。当加载程序时,这些相对地址还要根据程序实际被加载的位置重新计算。

x86处理器在访问内存时使用的是段地址和偏移地址,也就是逻辑地址,而不是物理地址。

为了提供对“段地址:偏移地址”内存访问模式的支持,处理器至少要提供两个段寄存器,分别是代码段寄存器(Code Segment, CS)和数据段寄存器(Data Segment, DS)。

对代码段寄存器CS的改变将导致处理器从新的代码段开始执行。同样,在开始访问内存中的数据之前,也必须首先设置好数据段寄存器DS,使之指向数据段。当处理器访问内存时,它把指令中指定的内存地址看成段内的偏移地址,而不是物理地址。这样,一旦处理器遇到一条访问内存的指令,它将把DS中的数据段起始地址和指令中提供的段内偏移相加,来得到访问内存所需要的物理地址。

8086内部有4个段寄存器。其中,CS是代码段寄存器,DS是数据段寄存器, ES是附加段(Extra Segment)寄存器。附加段的意思是,它是额外赠送的礼物,当需要在程序中同时使用两个数据段时,DS指向一个,ES指向另一个。 可以在指令中指定使用DS和ES中的哪一个,如果没有指定,则默认使用DS。 SS是栈段(Stack Segment)寄存器。

为了加快指令执行速度,8086内部有一个6字节的指令预取队列,在处理器忙着执行那些不需要访问内存的指令时,指令预取部件可以趁机访问内存预取指令。这时,多达6字节的指令流可以排队等待解码和执行。

IP是指令指针(Instruction Pointer)寄存器,它只和CS一起使用,而且只有处理器才能直接改变它的内容。当一段代码开始执行时,CS保存代码段的段地址,IP则指向段内偏移。这样,由CS和IP共同形成逻辑地址,并由总线接口部件变换成物理地址来取得指令。然后,处理器会自动根据当前指令的长度来改变IP的值,使它指向下一条指令。如果在指令的执行过程中需要访问内存单元,那么处理器将用DS的值和指令中提供的偏移地址相加,来形成访问内存所需的物理地址。

8086提供20根地址线。

提供20根地址线的原因很简单,16位的物理地址只能访问64KB的内存,地址范围是0000H~FFFFH,共65536字节。这样的容量,即使在那个年代,也显得捉襟见肘。而20位的物理地址则可以访问多达1MB的内存, 地址范围从00000H到FFFFFH。

8086处理器的逻辑分段,起始地址都是16的倍数,这称为是按16字节对齐的。

在通常情况下,段地址的选择取决于内存中哪些区域是空闲的。举个例子来说,假如从物理地址00000H开始,一直到82251H处都被其他程序占用着,而后面一直到FFFFFH的地址空间都是自由 的,那么,你可以从物理内存地址82251H之后的地方加载你的程序。

系统加载过程

从硬盘的主引导扇区读取内容,加到到0x0000:0x7c00(也就是物理地址0x07C00)的内存中,然后jmp指令跳转到这个地址开始执行,驱动整个系统程序。