2025年08月03日
帐号 密码


8086CPU寻址范围的思考与研究

文章作者:duckgaga

  给定段地址为0001H,仅通过变化偏移地址寻址,CPU的寻址范围为()到()? 

  这个小题的关键点在于,求出偏移的变化范围,再利用公式“段地址*16+偏移地址=物理地址”即可求得CPU的寻址范围。 
关于这个小题的偏移变化范围,据我所知,好像有两种,一个是0~FFFFH,另一种则是0~15。那么两种答案到底谁对谁错呢?或者说,哪一个答案更加合理呢?为此,笔者设计了一个实验对此进行测试,具体情况如下: 

一、设计思路: 
  两个答案中,一个是0~15,另一个是0~FFFFH,两个答案中都包含0~15这个部分,因此只要验证超出15部分(即16~FFFFH)能否正确寻址,就可以达到检测的目的。如果偏移使用16~FFFFH范围内的值进行寻址时出错,则说明答案0~FFFFH是不合理的;反之亦然。 

二、实现方案介绍: 
  1)背景知识:在系统中,0:200h~300h空间的内容为空,值默认为0,即是没有值的。而系统1000:0~1000:200h空间的内容也为空,值也默认为0。这一点可自行验证,方法是进入CMD后,输入debug回车,然后分别用d 0:200和d 1000:0查看即可。 
  2)方法步骤: 
  i.在0:200h~300h空间的内容为空,我们先给从0:200H开始的16个字节赋值,值分别是0,1,2……,15.即从0:200h~20fh的值分别为0~15; 
  ii.设置DS,ES的段值为0001H,分别设置SI,DI初始值为0fff0h,1f0h。通过公式“段地址*16+偏移地址=物理地址”可以得知,ds:si初始时指向的物理地址为10000H,而es:di初始时指向的物理地址则为00200H,es:di与0:200H所指向的物理地址是相同的。 
  iii.将ds:si所指向物理地址开始的16个内存单元中的内容复制到es:di所指向的物理地址开始的16个内存单元中,这其中复制了16个字节。复制完毕后0:200h开始的16个内存单元中的内容应该跟ds:si所指向的内存单元中的值一样,即为0. 
iv.在debug跟踪观察ds,es,si,di的值,并且看程序是否能够正确执行。 

三、测试程序的代码: 
assume cs:code 
code segment 
start: 
        mov cx,16 
        mov ax,0 
        mov es,ax 
       mov si,200h 
     s:   mov es:[si],al 
        inc al 
        inc si 
        loop s        ;将0:200h开始的16个内存单元的值设置为0~15. 

        mov ax,0001 
        mov ds,ax 
        mov es,ax    ;设置ds,es段值都为0001H 
        mov si,0fff0h 
        mov di,1f0h 
        mov cx,16 
        cld 
        rep movsb    ;将ds:si指向开始的16个内存单元复制到es:di所指向的16个内存单元中 

        mov ax,4c00h 
        int 21h 
code ends 
end start 

编译情况:编译时没有提示出错,成功通过编译和连接。 

四、debug跟踪情况 

1.装载test.exe后: 
-u 
0B68:0000 B91000        MOV     CX,0010 
0B68:0003 B80000        MOV     AX,0000 
0B68:0006 8EC0          MOV     ES,AX 
0B68:0008 BE0002        MOV     SI,0200 
0B68:000B 26            ES: 
0B68:000C 8804          MOV     [SI],AL 
0B68:000E FEC0          INC     AL 
0B68:0010 46            INC     SI 
0B68:0011 E2F8          LOOP    000B 
0B68:0013 B80100        MOV     AX,0001 
0B68:0016 8ED8          MOV     DS,AX 
0B68:0018 8EC0          MOV     ES,AX 
0B68:001A BEF0FF        MOV     SI,FFF0 
0B68:001D BFF001        MOV     DI,01F0 
0B68:0020 B91000        MOV     CX,0010 
0B68:0023 FC            CLD 
0B68:0024 F3            REPZ 
0B68:0025 A4            MOVSB 
0B68:0026 B8004C        MOV     AX,4C00 
0B68:0029 CD21          INT     21 

2.在开始跟踪运行test.exe之前,先查看内存0:200h处的内容: 
-d 0:200 
0000:0200  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0210  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0220  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0230  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0240  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0250  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0260  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0270  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
由此可以看出,程序执行前,0:200开始的内容为空。 

3.直接用g 13命令,使程序执行到mov ax,0001处停止(此时mov ax,0001并未执行,它是下一条待执行的指令),则有: 

-g13 

AX=0010  BX=0000  CX=0000  DX=0000  SP=0100  BP=0000  SI=0210  DI=0000 
DS=0B58  ES=0000  SS=0B68  CS=0B68  IP=0013   NV UP EI PL NZ AC PO NC 
0B68:0013 B80100        MOV     AX,0001 

4.此时,我们再去查看0:200h处的内容,按照预计,0:200H开始的16个内存单元中的内容应该被修改了,好,我们此时用d 0:200命令进行查看,结果为: 
-d 0:200 
0000:0200  00 01 02 03 04 05 06 07-08 09 0A 0B 0C 0D 0E 0F   ................ 
0000:0210  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0220  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0230  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0240  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0250  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
由上面,我们可以清楚地看到,0:200h~20fh处的内容如我们所想的,被修改了。它们的值分别是0,1……14,15. 

5.好,我们继续下一步,用g 20命令使程序直接运行至mov cx,16处停止,此时,我们的程序应该已经执行完了给ds,es,si,di赋值。 

-g20 

AX=0001  BX=0000  CX=0000  DX=0000  SP=0100  BP=0000  SI=FFF0  DI=01F0 
DS=0001  ES=0001  SS=0B68  CS=0B68  IP=0020   NV UP EI PL NZ AC PO NC 
0B68:0020 B91000        MOV     CX,0010 
由上可以看到,ds,es分别被设置为0001,而si,di分别被设置为fff0,01f0。 

6.经过给ds,es,si,di赋值后没有出错,说明偏移大于15时是合法的(此时SI,DI的内容为偏移),好,我们继续下步,看程序是否能成功运行。我们用g 26命令,使程序直接运行止mov ax,4c00h处停止(中间的rep movsb是循环执行的,为避免烦琐,故直接跳至此处), 
-g 26 

AX=0001  BX=0000  CX=0000  DX=0000  SP=0100  BP=0000  SI=0000  DI=0200 
DS=0001  ES=0001  SS=0B68  CS=0B68  IP=0026   NV UP EI PL NZ AC PO NC 
0B68:0026 B8004C        MOV     AX,4C00 
我们可以看到ds,es的内容还是0001,没有改变,即段地址的值没有发生改变。而si,di在加上0fh之后,分别变为0000h,0200h了。 


7.程序执行到mov ax,4c00h处时,此时程序已经完成了将DS:SI指向内存单元开始的16个字节复制到ES:DI所指向内存单元的指令。我们再来查看结果,用d 0:200命令进行查看,看其中的内容是否如我们所想,又重新变为空了(因为1000:0h开始处的内容为空,复制到0:200h处后,0:200h的数据被覆盖,因此变成与1000:0h处的内容一样,即为空,值为0): 

-d 0:200 
0000:0200  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0210  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0220  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0230  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0240  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 
0000:0250  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00   ................ 

  大家可以清晰地看到:0:200h~20fH处的内容又全部变成0了!说明此程序成功执行了! 

  这也就说明,在给定段地址为0001H的情况下,仅通过变化偏移地址寻址时,使用16~ffffH范围内的偏移(这里我们分别使用了0fff0~0ffffh和1f0~1ffh)进行寻址是合法的,也即偏移地址的变化范围仍然为0~ffffH,而不会被局限为0~15. 

五、结论 
  OK,我们通过上面的实验证实偏移地址的变化范围仍然是0~FFFFH的。但是题目要求的是CPU的寻址范围,即求其物理地址范围。因此,我们还得用“段地址*16+偏移地址=物理地址”这个公式进行求解一次。 

  ∵段地址=0001,偏移地址变化范围为0~FFFFH,由“段地址*16+偏移地址=物理地址”有: 
物理地址=0001*16+0~FFFFH 
          =00010H+0~FFFFH 
          =00010~1000FH 
  综上所述,我个人认为,检测2.2的第一小题的答案应为(00010H)到(1000FH)。 



六、题外探讨 

  那么,许多人以为问题到此已经解决了,但大家是否会想想:为什么有人会得出偏移变化范围为0~15的答案呢? 

  个人见解: 
  我想之所以有人会得出0~15的答案来,这与是否真正理解了“段地址*16+偏移地址=物理地址”的本质含义密切相关的。 

  好,我们进行一次错误(个人认为是错误的,请指教)的思维过程: 
  1)由“给定段地址0001H,仅通过变化偏移地址进行寻址”+“段地址*16+偏移地址=物理地址”有: 
段地址*16=0001H*16=00010H 
  2)又由关键字眼“给定段地址”,“仅通过变化偏移地址进行寻址”则有: 
CPU寻址的范围只能从00010H~0001fH,因为如果再加1的话,就变为00020H了,就不再是00010h这个“给定的段地址”了,就不符合题目的要求了!所以答案应为:0到15. 

  OK,错误思维旅程结束,我们跳出来(不要掉进这个陷阱出不来了,否则我罪过就大了)探讨上面错误思维产生的原因。不难看出,这是由于对“段地址*16+偏移地址=物理地址”的本质含义没有真正理解,并且没有真正理解“段”概念、物理地址及其之间关系的缘故。 

七、结语 
  王爽老师的《汇编语言》看起来虽然简单,但是里面讲述的都是一些原理性的、本质性的东西,因此希望大家认真理解、深入研究和探讨,只有这样才能真正达到学习的目的。就像本题,虽然“段地址*16+偏移地址=物理地址”这个公式看起来是很简单,但是又有多少人掉进了这个“陷阱”? 


八、题外话 
  学完一遍,感觉轻松了不少,因为不用再像以前一样,不再急着往下学(以前就算不赶进度,但还是要考虑时间关系的),所以就想找点事做。所谓“三人必有我师”,故决定从第一章开始,把论坛里所有章节的帖子都看完,然后再逛别人的博客,呵呵。这几天都在逛论坛,今天把第1章的所有帖子看完了。感觉这几天学习到了不少东西,大多是与课本学习密切相关,但课本上没有的基础类的东西或者是从课本上来,但又高于课本的一些思考类的东西。 
虽然是重新回头读《汇编语言》这本书,但还是从中发掘到了许多东西,因此速度愈放愈慢(所以更新博客会比较慢),自己也逐渐感到有一种研究性学习的精神在自己身上慢慢产生,虽然是一点点,但是有了开头,只要坚持,一定会有所成的。 
每当看到谁谁说自己速度多快,一下子看了几十页时,心里不知作何感想。如果他真的是个牛人,我羡慕他,佩服他;但是如果单纯是为了进度而不求甚解的话,我又会为其担心,这样子学下去又能学到什么实质性的东西呢?不管怎么都好吧,希望大家都能克制浮躁的心情,同时希望学得快的人都是比我理解能力强的人。 
虽然自己有点笨,不像他们那样能一飞冲天,但是贵在坚持吧。许三多说得对:“不抛弃,不放弃!”

发表日期:08/06/26 00:00

网友评论(1)

【游客 发表于:18/02/02 21:08】

妙哉

当前1/1页 首页 上一页下一页 尾页

我也跟评:

     验证码 验证码... [看不清]