为什么当用T命令会出现出人意料的答案呢?
本帖最后由 jueqingsizhe66 于 2011-3-21 22:14 编辑《汇编语言》- 王爽 - 检测点10.5 - 详细解答
--------------------------------------------------------------------------------
检测点10.5(第183页)
----------------------
(1)答:ax中的数值为3
提示:不能利用T命令进行调试,则改用U和G命令来调试。可用U命令先查看指令"mov ax,4c00h"处的偏移地址,然后用G命令直接执行到指令"mov ax,4c00h"的偏移地址处。
准备进入call命令:
AX=0000BX=0000CX=0029DX=0000SP=0010BP=0000SI=0000DI=0000
DS=14EEES=14DESS=14EECS=14EFIP=000D NV UP EI PL NZ NA PO NC
14EF:000D FF160E00 CALL DS:000E=0E9B
-d ds:0
14EE:000000 00 00 00 00 00 00 00-00 00 0D 00 EF 14 (9B 0E) ................
14EE:0010B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E ................
14EE:002000 40 40 40 B8 00 4C CD-21 00 00 00 00 00 00 00 .@@@..L.!.......
执行call命令后:
-t
AX=0000BX=0000CX=0029DX=0000SP=000EBP=0000SI=0000DI=000
DS=14EEES=14DESS=14EECS=14EFIP=3302 NV UP EI PL NZ NA PO NC
14EF:3302 0000 ADD ,AL DS
-d ds:0
14EE:000000 00 00 00 00 00 00 00-02 33 EF 14 9B 0E (11 00)
14EE:0010B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E
14EE:002000 40 40 40 B8 00 4C CD-21 00 00 00 00 00 00 00
为什么会单步call执行之后IP值会出现那么大的区别 ip不是等于0吗? 不是要返回mov ax,stack的那个地方吗?
网上有这样解释:
首先IP进栈 此时IP的值是0011H不是0012H (连指令占多少个字节都数不清楚还在牛逼哄哄的),进栈后sp指针指到0EH ,然后进行JMP WORD PTR DS:即将ds:这个内存单元的地址赋给IP,又因为ds:也就是ss:,所以程序又将0011赋给IP 即去执行了INC AX ,执行了三次 即AX=3
但是执行完call之后ip的值到底是怎样?以及为什么不能通过单步执行得到呢???????求解释!谢谢
补充:(1)CPU将call word ptr ds:指令载入,IP指向call word ptr ds:后的指令(inc ax),然后CPU执行call word ptr ds:指令,,将当前的IP值(第一个inc ax指令的偏移地址)压栈,并将IP值改变为ds:的值。
由于先压栈,所以ds:=SS:=17,call word ptr ds:指令执行后IP=17
(2)inc ax运行3次后,ax=3
但是执行完call之后ip的值到底是怎样?以及为什么不能通过单步执行得到呢???????求解释!谢谢
诶这个挺有理的:
没有循环,直接下来了inc3次,刚开始(我也以为是个死循环.暴堆栈的操作.),分析很对,word call=1.push ip,2.jmp 地址.......原来地址为0,后来push ip后,地址=ip了,ip=下一条指令.所以等于没call.
要知道call执行了两个步骤:其中必须说明的是【当call送入指令缓冲器中ip已经加了,所以此时(call没执行时)ip是指向inc ax】
1:push ip
2:jmp word ptr ds:
我觉得这是一种解释方法 也就是让我们觉得push和jump是存在先后,也是课本上说的那样!
当然网上还有一种说法就是push 和jmp其实是同时双线开工的,我觉得也是有理
证据如下:
assume cs:codesg
stack segment
dw 8 dup (0)
stack ends
codesg segment
start: inc cx
mov ax,stack
mov ss,ax
mov sp,16
mov ds,ax
mov ax,0
call word ptr ds:
inc ax
inc ax
inc ax
mov ax,4c00H
int 21H
codesg ends
end start
刚刚装载时:
AX=0000BX=0000CX=002BDX=0000SP=0000
DS=14DEES=14DESS=14EECS=14EFIP=0001
14EF:0001 B8EE14 MOV AX,14EE -------------CX=002B--------------------
而跳到mov ax,4c00h时:
AX=0003BX=0000CX=002CDX=0000SP=00
DS=14EEES=14DESS=14EECS=14EFIP=00
14EF:0015 B8004C MOV AX,4C00 -------------CX=002c---------------------
真的好像有在执行一遍inc cx!!!!!
{{{{{{{{那位哥们说:
1) 读入ss:=0, 把命令翻译成 call 0
2) push ip, sp=sp-2, ss=ip=12h
3) jmp 0
从头执行, sp=16, 第二次到call,
1) 读入ss:=12h 把命令翻译成 call 12h
2) push ip, sp=sp-2=000e, ss=ip=12h
3) jmp 12h
执行3个inc ax, 最后ax=3
所以第一次call后, 应该从头执行
个人觉得出现开始段被执行两次是因为现代CPU引入了流水线技术,call指令被分为push和jmp操作,在push ip执行后数据写入堆栈还未完成,CPU已经开始执行 jmp 指令,这时堆栈中的数据还没有被修改,仍为0,所以会跳转到程序开始段再次执行,再次执行到call指令此时push操作已经完成,就会跳转到inc ax执行下去}}}}}}}
我觉得也是挺有道理的!为了增加可信度 顺便再把inc bx放在inc cx之后debug之后bx=0002而不是bx=0001也就是说应该是运行了两次吧!!
也就是说push 和jmp其实是同时执行的吧!!也许要知道这个,我觉得可以用时间来解决!去掉call语句然后得到一个程序的运行时间然后加上call语句看两者的时间差!但是这个有点难于执行啊!!还不知道怎么计时啊!!希望有前辈指点下,即执行一条语句需要多少时刻????膜拜! 哈哈,朋友很细心的学习,不过文章显得有点长,看了半天~
最后,我觉得第一种方案更可靠些,也验证了一下,可行。
第二种可能性不高,不同CPU执行指令的时间差不同,也算不了吧~数值太小了。
页:
[1]