检测点10.5
(1)
-
这里要注意,程序将stack段同时与ss与ds进行了关联,也就是此段既被当作栈使用,同时被当作数据段使用
-
call word ptr ds:[0EH] 的理解
-
IP指向此call指令时,call指令被读取进CPU的指令缓存器
-
IP立第即指向了call指令的后的下一条指令,即本程序中的第1条 inc ax
-
然后,指令缓冲器中的call指令开始正式被执行
-
第1步动作就是push IP,即,将第1条 inc ax的偏移地址,压入栈中,栈顶元素的地址为0EH,共占用2个单元
- 这里有几点需要注意,首先,push,pop都是以word为单位进行操作,在8086CPU中是16位,所以是2个单元
- push动作的第一步,就是将SP=SP-2,即栈指针回退2位,指向新的栈顶元素
- push动作的第二步,就是将IP值,存放进栈顶元素中,此时栈顶元素变为当前IP的值,即第1条inc ax指令的地址
-
完成入栈后,接下来就是跳转的动作,是从目标内存单元中,读取指定的1个word长度的值作为地址,完成从当前IP跳转到这个地址的动作。从word的使用上也可以得知,读取的是16位数据,对应的也就是jmp near ptr s/单元地址
-
而数据段的ds:[0EH]正好是栈段中的栈顶元素,所以最终读取出来的目标跳转地址,就是原来的IP,也正是第1条inc ax自己的偏移地址
-
所以,call指令被执行完毕后,IP=原IP,而原IP就是第1条inc ax,于是开始从inc ax开始执行
-
在这之前,ax值被 mov ax, 0 变更为0,所以经过3次 inc ax 操作后,ax值结果为3
-
(2)
-
这里故意对解题者设置了迷惑,即,故意定义了data段,却将data段作为事实上的栈使用
-
mov word ptr ss:[0],offset s 执行后,是将s的 偏移地址EA 传递给了 data段 的前2个单元,此时data段也就是栈的内容如下:
- mov ss:[2],cs 执行后,data段的第2,3两个单元中,存储了cs的值,data段变为:
-
call dword ptr ss:[0] 的执行过程如下:
-
当IP指向call指令所在内存地址时,先将call指令传送到CPU指令缓冲器,然后IP马上指向它的下一条指令,即nop的地址,此时IP值变为nop的EA。然后执行入栈的动作
-
首先栈指针回退4个单元,指向0CH
-
然后向栈中分别push进2个数据,先入栈CS的值,再入栈IP的值,入栈完成后,data段变为:
-
-
再接下来就是跳转。先从call指令中搭配的内存单元 ss:[0] 中读取目标地址,读取的结果是 s的EA。然后跳转到目标地址 s 处。从这里可以看出,从call指令语句的地址,越过nop,直达标号s的地址了
-
s处第1条指令,mov ax,offset s 是将s的EA,给到ax
-
sub ax,ss:[0cH],参考上图,是将 ax的值即 s的EA,减去 ss:[0cH]中的值,即 nop的EA,因二者相邻,差值也就是 nop 所占的数据长度,而 nop的长度为 1 byte,这是常识,所以,结果就是ax的值变成了1
-
mov bx,cs 执行后,(bx)=(cs)
-
sub bx,ss:[0eH],是从bx中减去cs的值,即 (cs)-(cs)=0,所以此条指令后,bx=0