鱼C论坛

 找回密码
 立即注册
查看: 3159|回复: 1

为什么当用T命令会出现出人意料的答案呢?

[复制链接]
发表于 2011-3-21 21:41:34 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 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=0000  BX=0000  CX=0029  DX=0000  SP=0010  BP=0000  SI=0000  DI=0000
DS=14EE  ES=14DE  SS=14EE  CS=14EF  IP=000D   NV UP EI PL NZ NA PO NC
14EF:000D FF160E00      CALL    [000E]                             DS:000E=0E9B

-d ds:0
14EE:0000  00 00 00 00 00 00 00 00-00 00 0D 00 EF 14 (9B 0E)   ................
14EE:0010  B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E   ................
14EE:0020  00 40 40 40 B8 00 4C CD-21 00 00 00 00 00 00 00   .@@@..L.!.......
执行call命令后:
-t

AX=0000  BX=0000  CX=0029  DX=0000  SP=000E  BP=0000  SI=0000  DI=000
DS=14EE  ES=14DE  SS=14EE  CS=14EF  IP=3302   NV UP EI PL NZ NA PO NC
14EF:3302 0000          ADD     [BX+SI],AL                         DS

-d ds:0
14EE:0000  00 00 00 00 00 00 00 00-02 33 EF 14 9B 0E (11 00)
14EE:0010  B8 EE 14 8E D0 BC 10 00-8E D8 B8 00 00 FF 16 0E
14EE:0020  00 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:[0eh]即将ds:[0eh]这个内存单元的地址赋给IP,又因为ds:[0eh]也就是ss:[0eh],所以程序又将0011赋给IP 即去执行了INC AX ,执行了三次 即AX=3
但是执行完call之后ip的值到底是怎样?以及为什么不能通过单步执行得到呢???????求解释!谢谢

补充:(1)CPU将call word ptr ds:[0EH]指令载入,IP指向call word ptr ds:[0EH]后的指令(inc ax),然后CPU执行call word ptr ds:[0EH]指令,,将当前的IP值(第一个inc ax指令的偏移地址)压栈,并将IP值改变为ds:[0EH]的值。
    由于先压栈,所以ds:[0EH]=SS:[0EH]=17,call word ptr ds:[0EH]指令执行后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:[0eH]
我觉得这是一种解释方法 也就是让我们觉得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:[0eh]
       inc ax
       inc ax
       inc ax
       mov ax,4c00H
       int 21H
codesg ends
end start
刚刚装载时:
AX=0000  BX=0000  CX=002B  DX=0000  SP=0000
DS=14DE  ES=14DE  SS=14EE  CS=14EF  IP=0001
14EF:0001 B8EE14        MOV     AX,14EE                   -------------CX=002B--------------------
而跳到mov ax,4c00h时:
AX=0003  BX=0000  CX=002C  DX=0000  SP=00
DS=14EE  ES=14DE  SS=14EE  CS=14EF  IP=00
14EF:0015 B8004C        MOV     AX,4C00                  -------------CX=002c---------------------
真的好像有在执行一遍inc cx!!!!!
{{{{{{{{那位哥们说:
1) 读入ss:[0e]=0, 把命令翻译成 call 0
2) push ip, sp=sp-2, ss[0e]=ip=12h
3) jmp 0
从头执行, sp=16, 第二次到call,
1) 读入ss:[0e]=12h 把命令翻译成 call 12h
2) push ip, sp=sp-2=000e, ss[0e]=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语句看两者的时间差!但是这个有点难于执行啊!!还不知道怎么计时啊!!希望有前辈指点下,即执行一条语句需要多少时刻????膜拜!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
发表于 2011-3-25 11:18:40 | 显示全部楼层
哈哈,朋友很细心的学习,不过文章显得有点长,看了半天~
最后,我觉得第一种方案更可靠些,也验证了一下,可行。
第二种可能性不高,不同CPU执行指令的时间差不同,也算不了吧~数值太小了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 03:21

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表