鉴于汇编语言和处理器之间的紧密关系,学习汇编语言的过程,实际上也是洞悉处理器内部构造和工作方式的过程。
在本章中,我们要借助一款早已淘汰的处理器INTEL 8086来了解x86汇编语言编程的基本环境。不要小看这款处理器,它是整个INTEL x86处理器家族的起点和基础。本章的目标是:
1.了解INTEL 8086处理器的通用寄存器和段地址加偏移地址的内存访问方式;
2.了解分段机制对程序重定位的好处;
3.理解INTEL 8086处理器内存分段的本质,充分认识到这种分段机制的灵活性。
为什么处理器能够自动计算,这个问题已经在第2章里做了介绍。处理器的工作依赖其内部的寄存器。早期的处理器,它的寄存器只能保存4比特、8比特或16比特,分别叫作4位、8位和16位寄存器。现在的处理器,寄存器一般都是32位、64位甚至更多。
如图3-1所示,8位寄存器可以容纳8比特,或者说1字节。为了方便,我们还要为该字节的每一位编上号,编号是从右往左进行的,从0开始,分别是0、1、2、3、4、5、6、7。在这里,位0(第1位)是最低位,在最右边;位7(第8位)是最高位,在最左边。
图3-1 寄存器数据宽度示意
为了更好地理解上面这些概念,图3-1假定8位寄存器里存放的是二进制数10001101,即十六进制的8D。这时,它的最低位和最高位都是1。
在第2章里我们提到了处理器的位数,它是指寄存器和算术逻辑部件的数据宽度,这个宽度也叫作处理器的字长。因此,8位处理器、16位处理器、32位处理器和64位处理器的字长也分别是8位、16位、32位和64位。
16位寄存器可以存放2字节,这称为1个字(word),各个比特的编号分别是0~15,其中0~7是低字节,8~15是高字节。
32位寄存器可以存放4字节,这称为1个双字(double word),各个数位的编号分别是0~31,其中,0~15是低字,16~31是高字。
尽管图中没有画出,但是64位寄存器可以容纳更多的比特,也就是8字节,或者4个字,简称四字(quad word)。位数越多,寄存器所能保存的数越大,这是显而易见的。
如图3-2所示,和寄存器不同,内存用于保存更多的比特。对于用得最多的个人计算机来说,内存按字节来组织,单次访问的最小单位是1字节,这是最基本的存储单元。如图3-2所示,每个存储单元中,各位的编号分别是0~7。
图3-2 内存和内存访问示意图
内存中的每字节都对应着一个地址,如图3-2所示,第1字节的地址是0000H,第2字节的地址是0001H,第3字节的地址是0002H,其他依次类推。注意,图中采用的是十六进制表示法。作为一个例子,因为这个内存的容量是65536字节,所以最后一字节的地址是FFFFH。
为了访问内存,处理器需要给出一个地址。访问包括读和写,为此,处理器还要指明,本次访问是读还是写。如果是写,还要给出待写入的数据。
处理器在工作时,需要在内存和寄存器之间交换数据。尽管内存的最小组成单位是字节,但是,经过精心的设计和安排,它能够按字节、字、双字和四字进行访问。换句话说,仅通过单次访问就能处理8位、16位、32位或者64位的二进制数。注意,这里说的是单次访问,而不是一个一个地取出各字节,然后加以组合。
如图3-2所示,处理器发出字长控制信号,以指示本次访问的字长是8、16、32还是64。如果字长是8,而且给出的地址是0002H,那么,本次访问只会影响到内存的1字节;如果字长是16,给出的地址依然是0002H,那么实际访问的将是地址0002H处的一个字。对于INTEL处理器来说,如果访问内存中的一个字,那么,它规定高字节位于高地址部分,低字节位于低地址部分,这称为低端字节序(Little Endian)。因此,低8位在0002H中,高8位在0003H中。至于其他公司的处理器,则可能情况正好相反,称为高端字节序。
◆ 检测点3.1
1.一个字含有( )字节和( )比特?一个双字含有( )字节、( )个字和( )比特?
2.二进制数10000000中,位( )的那个比特是“1”,也就是第( )位。它是最低位还是最高位?
3.一个存储器的容量是16字节,地址范围为( )~( )。用该存储器保存字数据时,可存放( )个字,这些字的地址分别是( ),保存双字呢?
任何时候,一旦提到INTEL公司的处理器,就不能不说8086。8086是INTEL公司第一款16位处理器,诞生于1978年,所以说它很古老。
但是,在INTEL公司的所有处理器中,它占有很重要的地位,是整个INTEL 32位架构处理器(IA-32)的开山鼻祖。
首先,最重要的一点是,它是一款非常成功的产品,设计先进,功能很强,卖得很好。
其次,8086的成功使得市场上出现了大量针对它开发的软件产品。这样,当INTEL公司要设计新的处理器时,它不得不考虑兼容性的问题。要使得老的软件也能在新的处理器上很好地运行,必须要具备指令集和工作模式上的兼容性和一致性。INTEL公司很清楚,如果新处理器和老处理器不兼容,那么,新处理器越多,它扔掉的拥趸也就越多,要不了多久,这公司就不用再开了。
所以,当我们讲述处理器的时候,必须要从8086开始;另外,要学习汇编语言,针对8086的汇编技术也是必不可少的。
如图3-3所示,8086处理器内部有8个16位的通用寄存器,都是由16比特组成的,并分别被命名为AX、BX、CX、DX、SI、DI、BP、SP。“通用”的意思是,它们之中的大部分都可以根据需要用于多种目的。
因为这8个寄存器都是16位的,所以通常用于进行16位的操作。比如,可以在这8个寄存器之间互相传送数据,它们之间也可以进行算术逻辑运算;也可以在它们和内存单元之间进行16位的数据传送或者算术逻辑运算。
图3-3 8086的通用寄存器
同时,如图3-3所示,这8个寄存器中的前4个,即AX、BX、CX和DX,又各自可以拆分成两个8位的寄存器来使用,总共可以提供8个8位的寄存器AH、AL、BH、BL、CH、CL、DH和DL。这样一来,当需要在寄存器和寄存器之间,或者寄存器和内存单元之间进行8位的数据传送或者算术逻辑运算时,使用它们就很方便。
将一个16位的寄存器当成两个8位的寄存器来用时,对其中一个8位寄存器的操作不会影响到另一个8位寄存器。举个例子来说,当你操作寄存器AL时,不会影响到AH中的内容。
如图3-3所示,以寄存器AX为例,它可以分成两个独立的寄存器AH和AL。寄存器AX有16比特,但是,位0到位7这8比特属于寄存器AL;位8到位15这8比特属于寄存器AH。因此,我们说,寄存器AH是寄存器AX的高字节部分;寄存器AL是寄存器AX的低字节部分。同时,寄存器AX的内容也是由寄存器AH的内容和寄存器AL的内容组合而成的。
如果寄存器AH的内容是00111110(3EH),寄存器AL的内容是00101111(2FH),那么,寄存器AX的内容就是0011111000101111(3E2FH)。
接着,如果我们改变了寄存器AH的内容,将它修改成00000000(00H),那么,这对寄存器AL没有任何影响,还是00101111(2FH)。但是,寄存器AX的内容也跟着改变,变成0000000000101111(002FH)。
最后,如果我们改变了寄存器AL的内容,将它修改成01011010(5AH),那么,这对寄存器AH没有任何影响,还是00000000(00H),但是寄存器AX的值也跟着改变,变成0000000001011010(005AH)。
◆ 检测点3.2
1.INTEL 8086有哪几款通用寄存器?这些寄存器的长度是几比特?几字节?
2.如果向寄存器DH写入数字08H,向寄存器DL写入数字3CH,则寄存器DX的内容是什么?
我们知道,处理器的设计者用某些数字来指示处理器所进行的操作,这些数字代表指令,或者叫机器指令,因为只有处理器才认得它们。指令是集中存放在内存里的,一条接着一条,处理器的工作是自动按顺序取出并加以执行。处理器内部有寄存器和算术逻辑部件,还有控制器部件,控制器部件“分析”一条条指令,然后确定在哪个时间点让哪些部件进行工作。
对于INTEL x86处理器来说,指令的长度不定,短的指令仅有1字节,而长的指令则有可能达到15字节。在内存中,指令和非指令的普通二进制数是一模一样的,在组成内存的电路中,都是一些高、低电平的组合。因为处理器是自动按顺序取指令并加以执行的,在指令中混杂了非指令的数据会导致处理器不能正常工作。为此,指令和数据要分开存放,分别位于内存中的不同区域,或者说各自形成一个段(Segment),分别叫代码段和数据段。
注意,我们并没有改变内存的物理性质,并不是真的把它分成几块。段的划分是逻辑上的,从本质上来说,是如何看待和组织内存中的数据。
段在内存中的位置并不重要,因为处理器是可控的,我们可以让它从内存的任何位置开始取指令并加以执行。这里有一个例子,如图3-4所示,我们有一大堆数字,现在想把它们加起来求出总和。
图3-4 程序的代码段和数据段示例
假定我们有16个数要相加,这些数都是16位的二进制数,分别是0005H、00A0H、00FFH、…。为了让处理器把它们加起来,我们应该先在内存中定义一个数据段,将这些数字写进去。数据段可以起始于内存中的任何位置,既然如此,我们将它定在0100H处。这样一来,第一个要加的数位于地址0100H,第二个要加的数位于地址0102H,最后一个数的地址是011EH。
一旦定义了数据段,我们就知道了每个数的内存地址。然后,紧挨着数据段,我们从内存地址0120H处定义代码段。严格地说,数据段和代码段是不需要连续的,但这里把它们挨在一起更自然一些。为了区别数据段和代码段,我们使用了不同的底色。
代码段是从内存地址0120H处开始的,第一条指令是A1 00 01。其中,A1是操作码,意思是从指定的内存地址处取出一个字,传送到寄存器AX;后面的00 01是采用低端字节序存放的数字0100H,代表一个内存地址。所以这条指令的功能是将内存单元0100H里的字传送到寄存器AX。指令执行后,AX的内容为0005H。
第二条指令是03 06 02 01,其中,03 06是操作码,02 01是采用低端字节序存放的数字0102H,这条指令的功能是将AX中的内容和内存单元0102H里的字相加,结果在AX中。由于AX的内容为0005H,而内存地址0102H里的数是00A0H,这条指令执行后,AX的内容为00A5H。
第三条指令是03 06 04 01,其中,03 06是操作码,04 01是采用低端字节序存放的数字0104H,这条指令的功能是将AX中的内容和内存单元0104H里的字相加,结果在AX中。此时,由于AX里的内容是00A5H,内存地址0104H里的数是00FFH,本指令执行后,AX的内容为01A4H。
后面的指令没有列出,但和前2条指令相似,依次用AX的内容和下一个内存单元里的字相加,一直到最后,在AX中得到总的累加和。在这个例子中,我们没有考虑寄存器AX容纳不下结果的情况。当累加的总和超出了AX所能表示的数的范围(最大为FFFFH,即十进制的65535)时,就会产生进位,但这个进位被丢弃。
在内存中定义了数据段和代码段之后,我们就可以命令处理器从内存地址0120H处开始执行。当所有的指令执行完后,就能在寄存器AX中得到最后的结果。看起来没有什么问题,一切都很完美,不是吗?那本节标题中所说的难题又从何而来呢?
这里确实有一个难题。
在前面的例子中,所有在执行时需要访问内存单元的指令,使用的都是真实的内存地址。比如A1 00 01,这条指令的意思是从地址为0100H的内存单元里取出一个字,并传送到寄存器AX中。这里,0100H是一个真实的内存地址,又称物理地址。
整个程序(包括代码段和数据段)在内存中的位置,是由我们自己定的。我们把数据段定在0100H,把代码段定在0120H。
问题是,大多数时候,整个程序(包括代码段和数据段)在内存中的位置并不是我们能够决定的。请想一想你平时是怎么使用计算机的,你所用的程序,包括那些用来调整计算机性能的工具、小游戏、音乐和视频播放器等,都是从网上下载的,位于你的硬盘、U盘或光盘中。即使有些程序是你自己编写的,那又如何?当你双击它们的图标,使它们在Windows里启动之前,内存已经被塞了很多东西,就算你是刚刚打开计算机,Windows自己已经占用了很多内存空间,不然的话,你怎么可能在它上面操作呢?
在这种情况下,你所运行的程序,在内存中被加载的位置是完全随机的,哪里有空闲的地方,它就会被加载到哪里,并从那里开始被处理器执行。所以,前面那段程序不可能恰好如你所愿,被加载到内存地址0100H,它完全可能被加载到另一个不同的位置,如1000H。但是,同样是那个程序,一旦它在内存中的位置发生了改变,灾难就出现了。
如图3-5所示,因为程序现在是从内存地址1000H处被加载的,所以,数据段的起始地址为1000H。这就是说,第一个要加的数,其地址为1000H,第二个则为1002H,其他依次类推。代码段依然紧挨着数据段之后,起始地址相应地是1020H。
图3-5 在指令中使用绝对内存地址的程序是不可重定位的
只要所有的指令都是连续存放的,代码段位于内存中的什么地方都可以正常执行。所以,处理器可以按你的要求,从内存地址1020H处连续执行,但结果完全不是你想要的。
请看第一条指令A1 00 01,它的意思是从内存地址0100H处取得一个字,将其传送到寄存器AX中。但是,由于程序刚刚改变了位置,它要取的那个数,现在实际上位于1000H,它取的是别人地盘里的数!
这能怪谁呢?发生这样的事情,是因为我们在指令中使用了绝对内存地址(物理地址),这样的程序是无法重定位的。为了让你写的程序在卖给别人之后,可以在内存中的任何地方正确执行,就只能在编写程序的时候使用相对地址或者逻辑地址,而不能使用真实的物理地址。当加载程序时,这些相对地址还要根据程序实际被加载的位置重新计算。
在任何时候,程序的重定位都是非常棘手的事情。当然,也有好几种解决的办法。在8086处理器上,这个问题特别容易解决,因为该处理器在访问内存时使用的是段地址和偏移地址,也就是逻辑地址,而不是物理地址。
从传统的视角来看,内存的组织是线性的,是一个由大量内存单元组成的序列,就像长长的纸条。每个内存单元都有自己的物理地址,它是相对于内存起始处的绝对位置。但是请想象一下,如果我们把内存从逻辑上划分为若干部分,也就是分成段,会怎样呢?
如图3-6所示,根据需要,段可以开始于内存中的任何位置,比如图中的内存地址A532H处,这个起始地址就是段地址。
段的长度不是固定的。图3-6中的这个段包含了6个存储单元。在分段之前,这些单元在整个内存空间里的物理地址分别是A532H、A533H、A534H、A535H、A536H、A537H。但是,在分段之后,它们的地址可以只相对于自己所在的段。这样,它们相对于段开始处的距离分别为0、1、2、3、4、5,这叫作段内偏移,或者叫偏移地址。
于是,当采用分段策略之后,一个内存单元的地址实际上就可以用“段:偏移”或者“段地址:偏移地址”来表示,这就是通常所说的逻辑地址。比如,在图3-6中,段内第1个存储单元的地址为A532H:0000H,第3个存储单元的地址为A532H:0002H,而本段最后一个存储单元的地址是A532H:0005H。
图3-6 段地址和偏移地址示意图
为了在硬件一级提供对“段地址:偏移地址”内存访问模式的支持,处理器至少要提供两个段寄存器,分别是代码段寄存器(Code Segment,CS)和数据段寄存器(Data Segment,DS)。
对代码段寄存器CS的改变将导致处理器从新的代码段开始执行。同样,在开始访问内存中的数据之前,也必须首先设置好数据段寄存器DS,使之指向数据段。
除此之外,最重要的是, 当处理器访问内存时,它把指令中指定的内存地址看成段内的偏移地址 ,而不是物理地址。这样,一旦处理器遇到一条访问内存的指令,它将把DS中的数据段起始地址和指令中提供的段内偏移相加,来得到访问内存所需要的物理地址。
如图3-7所示,代码段的段地址为1020H,数据段的段地址为1000H。在代码段中有一条指令A1 02 00,它的功能是将地址0002H处的一个字传送到寄存器AX中。在这里,处理器将0002H看成段内的偏移地址,段地址在DS中,应该在执行这条指令之前就已经用别的指令传送到DS中了。
当执行指令A1 02 00时,处理器将把DS中的内容和指令中指定的偏移地址0002H相加,得到1002H。这是一个物理地址,处理器用它来访问内存,就可以得到所需要的数00A0H。
如果下次执行这个程序时,代码段和数据段在内存中的位置发生了变化,只要把它们的段地址分别传送到CS和DS,它也能够正确执行。
图3-7 从逻辑地址到物理地址的转换过程
前面讲了如何从逻辑地址转换到物理地址,以使程序的运行和它在内存中的位置无关。这种策略在很多处理器中得到了支持,包括8086处理器。但是,由于8086自身的局限性,它的做法还要复杂一些。
如图3-8所示,8086内部有8个16位的通用寄存器,分别是AX、BX、CX、DX、SI、DI、BP、SP。其中,前4个寄存器中的每个寄存器都还可以当成2个8位的寄存器来使用,分别是AH、AL、BH、BL、CH、CL、DH、DL。
图3-8 8086处理器内部组成框图
在进行数据传送或者算术逻辑运算的时候,使用算术逻辑部件(ALU)。比如,将AX的内容和CX的内容相加,结果仍在AX中,那么,在相加的结果返回到AX之前,需要通过一个叫数据暂存器的寄存器中转。
处理器能够自动运行,这是控制器的功劳。为了加快指令执行速度,8086内部有一个6字节的指令预取队列,在处理器忙着执行那些不需要访问内存的指令时,指令预取部件可以趁机访问内存预取指令。这时,多达6字节的指令流可以排队等待解码和执行。
8086内部有4个段寄存器。其中,CS是代码段寄存器,DS是数据段寄存器,ES是附加段(Extra Segment)寄存器。附加段的意思是,它是额外赠送的礼物,当需要在程序中同时使用两个数据段时,DS指向一个,ES指向另一个。可以在指令中指定使用DS和ES中的哪一个,如果没有指定,则默认使用DS。SS是栈段(Stack Segment)寄存器,以后会讲到,而且非常重要。
IP是指令指针(Instruction Pointer)寄存器,它只和CS一起使用,而且只有处理器才能直接改变它的内容。当一段代码开始执行时,CS保存代码段的段地址,IP则指向段内偏移。这样,由CS和IP共同形成逻辑地址,并由总线接口部件变换成物理地址来取得指令。然后,处理器会自动根据当前指令的长度来改变IP的值,使它指向下一条指令。
当然,如果在指令的执行过程中需要访问内存单元,那么,处理器将用DS的值和指令中提供的偏移地址相加,来形成访问内存所需的物理地址。
8086的段寄存器和IP寄存器都是16位的,如果按照原先的方式,把段寄存器的内容和偏移地址直接相加来形成物理地址的话,也只能得到16位的物理地址。麻烦的是,8086却提供了20根地址线。换句话说,它提供的是20位的物理地址。
提供20根地址线的原因很简单,16位的物理地址只能访问64KB的内存,地址范围是0000H~FFFFH,共65536字节。这样的容量,即使在那个年代,也显得捉襟见肘。
所以,65536字节就是64KB,而20位的物理地址则可以访问多达1MB的内存,地址范围从00000H到FFFFFH。问题是,16位的段地址和16位的偏移地址相加,只能形成16位的物理地址,怎么得到这20位的物理地址呢?
有些内存地址的十六进制形式是以0结尾的,如00000H、00010H、00010H、00020H、A0000H、FFFF0H等。如果我们将这些地址末尾的0去掉,剩下的部分就可以放到段寄存器里了,将来恢复段的物理地址时,只需要添加一个0就可以了。
给定一个以0结尾的内存地址,如3C7F0H,将它末尾的0去掉,剩下一个16位的部分3C7FH,这相当于将段的物理地址除以16(10H),也相当于将这个地址的二进制形式整体右移4位。
将3C7F0H除以16,得到一个十六进制的结果3C7FH,这很容易理解。至于右移4位,是这样的:3C7F0H的二进制形式为00111100011111110000,右移4位的意思是将所有比特同时向右移动4次。移动之后,最右边的4比特被挤掉,结果是一个16位的二进制数0011110001111111,换算成十六进制是3C7FH。
显然,在8086系统中,由于段寄存器长度的限制,段不能起始于任意位置,也不是所有内存地址都可以作为段地址,段只能起始于那些能够被16整除的物理内存地址。对8086处理器来说,将这样的内存地址除以16或者右移4位,得到的结果就是逻辑段地址,简称段地址。要访问一个段,需要将段地址传送到段寄存器。
反过来,在用段寄存器的内容访问内存时,只需要在其十六进制形式的内容后面加0,就可以还原到原先的20位物理地址,这相当于乘以16,或者左移4位。如果段地址是3C7FH,它的二进制形式为0011110001111111。左移4位的意思是将所有比特同时向左移动4次,右边空出来的位置用4个0填充。因此,结果是一个16位的二进制数00111100011111110000,换算成十六进制是3C7F0H,这就是段的物理地址。
处理器访问内存时,光有段地址不行,还需要有偏移地址,它们共同组成了逻辑地址,而且处理器的总线接口部件负责把逻辑地址转换为物理地址。8086处理器在形成物理地址时,先将段寄存器的内容乘以16或者左移4位,形成20位的段地址,然后再同16位的偏移地址相加,得到20位的物理地址。比如,对于逻辑地址F000H:052DH,处理器在形成物理地址时,将段地址F000H左移4位,变成F0000H,再加上偏移地址052DH,就形成了20位的物理地址F052DH。
这样,因为段寄存器是16位的,在段不重叠的情况下,最多可以将1MB的内存分成65536个段,段地址分别是0000H、0001H、0002H、0003H,…,FFFFH。在这种情况下,如图3-9所示,每个段正好16字节,偏移地址从0000H到000FH。
同样在不允许段之间重叠的情况下,每个段的最大长度是64KB,因为偏移地址也是16位的,从0000H到FFFFH。在这种情况下,1MB的内存,最多只能划分成16个段,每段长64KB,段地址分别是0000H、1000H、2000H、3000H,…,F000H。
以上所说的只是两种最典型的情况。在通常情况下,段地址的选择取决于内存中哪些区域是空闲的。举个例子来说,假如从物理地址00000H开始,一直到82251H处都被其他程序占用着,而后面一直到FFFFFH的地址空间都是自由的,那么,你可以从物理内存地址82251H之后的地方加载你的程序。
图3-9 1MB内存可以划分为65536个16字节的段
接着,你的任务是定义段地址并设置处理器的段寄存器,其中最重要的是段地址的选取。因为偏移地址总是要求从0000H开始,而82260H是第一个符合该条件的物理地址,它恰好对应着逻辑地址8226H:0000H,符合偏移地址的条件,所以完全可以将段地址定为8226H。
但是,举个例子来说,如果你从物理内存地址82255H处加载程序,由于它根本无法表示成一个偏移地址为0000H的逻辑地址,所以不符合要求,段不能从这里开始划分。这里面的区别在于,82260H可以被16(10H)整除,而82255H不能。通过这个例子可以看出,8086处理器的逻辑分段,起始地址都是16的倍数,这称为是按16字节对齐的。
段的划分是自由的,它可以起始于任何16字节对齐的内存地址,也可以是任意长度,只要不超过64KB。比如,段可以起始于物理地址82260H,段的长度可以是3字节(此时,该段所对应的逻辑地址范围是8226H:0000H~8226H:0002H,对应的物理地址范围是82260H~82262H)、2KB(此时,该段所对应的逻辑地址范围是8226H:0000H~8226H:07FFH,对应的物理地址范围是82260H~82A5FH),甚至最多可以达到64KB(此时,该段所对应的逻辑地址范围是8226H:0000H~8226H:FFFFH,对应的物理地址范围是82260H~9225FH)。
同时,正是由于段的划分非常自由,使得8086的内存访问也非常随意。同一个物理地址,或者同一片内存区域,根据需要,可以随意指定一个段来访问它,前提是那个物理地址位于该段的64KB范围内。也就是说,同一个物理地址,实际上对应多个逻辑地址。比如说,对于一个物理地址C0533H,它可以用逻辑地址C053H:0003H来表示,也可以用逻辑地址C000H:0530H来表示,还可以用逻辑地址C050H:0030H来表示,甚至用逻辑地址BFFFH:0540H来表示,等等。
如图3-10所示,对于上述的各种表示方法,实际上说明我们认为物理地址C0533H位于不同的段中,段地址分别为C053H、C050H、C000H和BFFFH。
图3-10 以不同的段来划分逻辑地址
◆ 检测点3.3
1.INTEL 8086处理器有( )个16位通用寄存器,分别是( )。其中,有些还可以分开来作为两个独立的8位寄存器来用,这几个8位寄存器分别是( )。
2.选择题(可多选):INTEL 8086处理器取指令时,使用段寄存器( )和指令指针寄存器( )。方法是,将段寄存器的值( ),加上指令指针寄存器的当前值,形成物理地址访问内存。
A.CS B.DS C.IP D.左移4位 E.右移4位 F.乘以16 G.除以10H
3.物理地址132FEH对应的逻辑地址是(可多选):
A.132FH:000EH B.1300H:02FEH C.1000H:32FEH D.1320H:00FEH
E.102FH:03E0H F.0FE0H:34FEH
1.在段与段之间互不重叠的前提下,1MB内存可以完整地划分为多少个16KB的段?
2.数据段寄存器DS的值为25BCH时,计算INTEL 8086可以访问的最大物理地址范围。