首页
社区
课程
招聘
[旧帖] 恳请高手回答我的问题,请相信在此之前,我已在网上找了无数答案,苦想了许多天仍不能弄懂,怕以请高手们给详细地说说 0.00雪花
发表于: 2011-1-28 12:27 7939

[旧帖] 恳请高手回答我的问题,请相信在此之前,我已在网上找了无数答案,苦想了许多天仍不能弄懂,怕以请高手们给详细地说说 0.00雪花

2011-1-28 12:27
7939
恳请高手回答我的问题,请相信在此之前,我已在网上找了无数答案,苦想了许多天仍不能弄懂,怕以请高手们给详细地说说

我在学汇编语言,可每本书都到CPU执行一条命令过程说得不清不楚,差不多都是这样说的:“8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行,取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令”。我就不明白了,既然“任意时刻,CPU将CS:IP指向的内容当作指令执行,取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令”,那我们为什么还可以用debug调试程度,在用debug调试程序时,CS:IP里的值不应该是指向debug的下一条指令吗?为什么我们还可以看到原程序执行时CS:IP里面的值?还有CPU如何知道CS:IP指向的命令有多长,应该读入多少字节的数据?搞了好久都没有想明白,

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 0
支持
分享
最新回复 (21)
雪    币: 179
活跃值: (26)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
2
debug是调试器,和被调试的进程是不同的两个进程。 楼主想必知道不同的进程之间是完全隔离的,包括内存和寄存器等等。所以IP指向的地址是被调试进程中的地址,而不是调试器的。  
至于为什么debug可以调试其他进程,楼主可以看看windows的调试原理方面的知识。

CPU指令有固定的格式,只要知道开始就可以算出此条指令的长度。所以CPU很清楚当前指令是多长。指令格式楼主可以参考下这个,里面讲的很详细,应该可以解决你的疑惑。
http://www.mouseos.com/x64/format.html
2011-1-28 12:40
0
雪    币: 723
活跃值: (81)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
3
ip 是指向下条指令的地址,不是当前指令的地址。
ip 值在 processor 的解码逻辑解码的是时候早已经确定的,连下几条指令的 IP 都已经确定的,数条指令的指令边界早已确定下来,现在的processor 解码逻辑都是批量解码的。并不是在执行的时候确定 IP 值。
很多人被调试器迷惑了,IP 是当前指令地址还是下条指令的地址,在步进执行调试时,会误认为IP是当前指令地址,仔细想一想就知道了:此时 IP 值指向的指令还没被执行的,它是下一条将要被执行的,当步进时它才被执行。
调试器调试手段类似在断点前插入调试中断
2011-1-28 13:48
0
雪    币: 93
活跃值: (55)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
4
这个你去查查“中断”和“标志寄存器”

调试时,程序把flag寄存器的 追踪标志TF(Trap Flag)置为1,CPU进入单步执行方式,即每执行一条指令,产生一个单步中断请求(1号中断)
产生该中断后,CPU自动将flag寄存器、CS、IP入栈(这个CS:IP指向被调试程序将要执行的指令),然后转到调试程序执行。
调试程序访问栈中保存的flag、CS、IP,就可以将被调试程序的CS、IP、flag显示出来。。。

除了单步调试外,程序还有一种断点调试。。。
断点就是将被调试程序的某处的指令临时储存起来,再更改为int3指令,
当程序执行到这里时,CPU将寄存器入栈,然后转到调试程序,
调试程序临时保存并显示寄存器值,然后还原被更改的指令,并且让用户输入一些命令,执行一些操作,
最后在将寄存器的值还原,再返回到断点的位置,使被调试程序继续执行下去。。。
=================================================
CPU怎么知道指令的长度~
简单的说(不考虑前缀问题)
CPU可以根据一条指令的第一个字节确定这个指令的长度~
具体怎么实现,我不清楚,请为高人,猜想:
1.可能先取第一个字节,再根据第一个字节取剩下的字节
2.可能先取很多字节(因为指令有其最长长度),在根据第一个字节舍去剩下的字节(直接不使用)~
3.其他可能也是有滴~~~

求分~最近Kx有点紧张~~~

还有,Windows是运行在保护模式下的,保护模式(x86的CPU)的中断机制与8086的不同。。。
所以我上面说的只是在8086中。。。
用Windows调试程序,实际情况有点复杂,但是大致是一样的......
2011-1-28 15:18
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
2个属于不同进程
2011-1-28 20:06
0
雪    币: 32
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
呵,首先声明我不是高手,不过对于你的疑问,我想王爽老师的《汇编语言》可以解答,书中讲到CPU中指令的读取和执行过程如下:
1、CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器;
2、(IP) = (IP) + 2,即CS:IP指向下一条指令;
3、执行指令。转到1,重复这个过程。

不知能不能帮到你
2011-1-28 21:38
0
雪    币: 544
活跃值: (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
我觉得你说的第二条有错误的。请大牛指点。
2011-1-28 22:16
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
8
第二条必定有错误……操作码并非定长,是用哈夫曼树优化的……
2011-1-28 22:28
0
雪    币: 544
活跃值: (55)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
9
同意!我之前用过反汇编引擎编写过简单的程序,就是将exe的某段代码反汇编。有函数是可以取每一条指令的字节数的。呵呵。不是定长。
最后,感谢你的回答。
2011-1-28 22:30
0
雪    币: 2368
活跃值: (81)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
10
123456
2011-1-29 08:39
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
赞  试试这个
2011-1-31 06:19
0
雪    币: 150
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
那要是在DOS下面调试呢,DOS下面的进程可不是完全隔离的,我们为什么还能用debug调试呢?在dos下用debug查看各寄存器的值,当时cs:ip指向的下一条指令到底是哪个程序的?是debug还是被调试程序的?
2011-1-31 09:04
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
13
Dos下面是否可以本机调试,这点我并不确定,不过问一句,你所谓的Dos是纯Dos模式还是Windows下的Dos程序。或者说,你所谓的在dos下用debug调试时,计算机是运行在实模式下还是保护模式下?
2011-1-31 22:43
0
雪    币: 179
活跃值: (26)
能力值: ( LV7,RANK:100 )
在线值:
发帖
回帖
粉丝
14
DOS是单任务的操作系统,具体的调试原理还真不知道

不过我们可以这样理解,就算是windows下的调试器,比如OD,它在寄存器窗口中显示的各寄存器的值也不是当前CPU中寄存器的值。而是被调试程序在发生异常的那一刻的状态的一个复制。

按照这样的思路我们可以猜想,debug在纯DOS下调试程序的时候,先把程序装入内存,然后当执行单步的时候,和windows一样应该也会发生一个单步异常,此时CPU把当前的环境,比如各个寄存器的值保存下来,然后通过中断控制程序将控制权交给debug,由debug显示这些数据。

由此可见,当用debug查看各寄存器的值的时候,显示的并不是CPU当前状态,而是被调试程序在发生异常,也就是把控制权交给系统的那一刹那的那个状态的镜像。这不就是我们要的东西吗?

所以可以得出结论,就算是在DOS下,debug显示的各个寄存器也是被调试程序的,包括ip。因为这正是我们要的数据。

CPU在设计的时候,调试是一个最基本的功能,操作系统的调试功能也是基于CPU的设计的。
2011-1-31 23:20
0
雪    币: 19
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
两个不是相同的东西
2011-2-1 05:19
0
雪    币: 233
活跃值: (285)
能力值: ( LV12,RANK:270 )
在线值:
发帖
回帖
粉丝
16
想来很久,能想到的实模式下的调试方法就是调试器负责加载被调试程序,然后Hook中断和其他相关函数……不过调试器显示的各个寄存器的值必定是被调试程序的,显示调试器的状态感觉没有任何意义~~
2011-2-1 08:46
0
雪    币: 14
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
封装概念和隐藏细节是程序重要的特点,初学者很容易认为显示的一切都是真实的,未经处理的,很多困惑来源于此
2011-2-1 09:27
0
雪    币: 9
活跃值: (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
看一看,学一学
2011-2-1 13:05
0
雪    币: 84
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
一、为什么可以调试?
re: 请参考4楼phrain、14楼SJQIANG的回复。我再重复一下4楼的,比如设置断点,大体上是这样的:
1. 在地址x的指令上设置断点:调试器(如windows的windbg,linux的gdb)把内存中x地址处的原始指令保存起来,然后把x地址的指令改为调试中断int 3
2. 调试器开始调试被调试程序:调试器把自己注册到系统,这样系统遇到调试中断时,知道该通知谁
3. cpu执行到x地址,因为该指令是int 3,所以触发调试中断:调试中断被系统处理,通知当前的调试器。 调试器处理此中断,调整显示信息,响应后续的用户请求
4. 用户选择单步跟踪或者其他方式继续执行:调试器把被调试程序的x地址处的调试中断指令,恢复为原始指令(在第1步已保存),让cpu继续运行。

其他还有单步跟踪、内存数据读写访问断点等,步骤与上述有差别,但是基本原理都是类似的,就是利用调试中断。

所以,为什么能调试?
首先,需要cpu支持:能够触发调试中断,调试中断时的现场需要保留下来,供中断处理函数读取。这方面,可以找cpu的芯片资料来了解。
其次,需要操作系统支持:能够允许应用程序(如windbg、gdb)把自己注册为调试器;能够在cpu触发调试中断时,把中断时的现场数据从cpu中得到,然后通知已注册的调试器。windows、linux等操作系统应该都提供了一些API,供第三方开发调试器使用。

二、cpu如何知道IP指向的命令有多长?
re: 请参考2楼SJQIANG、4楼phrain的回复。
另,虽然8086指令是不定长的,但是也有不少其它cpu是定长指令集。
具体的,可以参考各种不同cpu的芯片资料,会有cpu取指步骤的详细描述。
2011-2-25 23:23
0
雪    币: 313
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
20
正在学这方面的啊    感谢各位大侠啊
2011-2-28 13:35
0
雪    币: 174
活跃值: (26)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
21
ip应该是指向下一条指令.

应该就是
1.直接读取ip处的数据,
2.把ip指向刚刚读取的指令末尾,
3.再执行刚刚读取的的指令.
4.回到1。

可能2和3是相反的,我不清楚.

如果 指令={1,2,3,4,5,6,7,8,9,10}
ip=0
1.读取指令就是=指令[ip];如果指令是2直接的,当前的指令就是(指令[ip],指令[ip+1])
2.ip+指令长度:ip=ip+1=1
3.执行指令.
4.再回到1.读取指令....
2011-2-28 14:52
0
雪    币: 30
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
引用:
最初由 wulfalone发布  
恳请高手回答我的问题,请相信在此之前,我已在网上找了无数答案,苦想了许多天仍不能弄懂,怕以请高手们给详细地说说

我在学汇编语言,可每本书都到CPU执行一条命令过程说得不清不楚,差不多都是这样说的:“8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行,取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令”。我就不明白了,既然“任意时刻,CPU将CS:IP指向的内容当作指令执行,取一条指令后,IP中的值自动增加,以使CPU可以读取下一条指令”,那我们为什么还可以用debug调试程度,在用debug调试程序时,CS:IP里的值不应该是指向debug的下一条指令吗?为什么我们还可以看到原程序执行时CS:IP里面的值?还有CPU如何知道CS:IP指向的命令有多长,应该读入多少字节的数据?搞了好久都没有想明白,  
一、为什么可以调试?
re: 请参考4楼phrain、14楼SJQIANG的回复。我再重复一下4楼的,比如设置断点,大体上是这样的:
1. 在地址x的指令上设置断点:调试器(如windows的windbg,linux的gdb)把内存中x地址处的原始指令保存起来,然后把x地址的指令改为调试中断int 3
2. 调试器开始调试被调试程序:调试器把自己注册到系统,这样系统遇到调试中断时,知道该通知谁
3. cpu执行到x地址,因为该指令是int 3,所以触发调试中断:调试中断被系统处理,通知当前的调试器。 调试器处理此中断,调整显示信息,响应后续的用户请求
4. 用户选择单步跟踪或者其他方式继续执行:调试器把被调试程序的x地址处的调试中断指令,恢复为原始指令(在第1步已保存),让cpu继续运行。

其他还有单步跟踪、内存数据读写访问断点等,步骤与上述有差别,但是基本原理都是类似的,就是利用调试中断。

所以,为什么能调试?
首先,需要cpu支持:能够触发调试中断,调试中断时的现场需要保留下来,供中断处理函数读取。这方面,可以找cpu的芯片资料来了解。
其次,需要操作系统支持:能够允许应用程序(如windbg、gdb)把自己注册为调试器;能够在cpu触发调试中断时,把中断时的现场数据从cpu中得到,然后通知已注册的调试器。windows、linux等操作系统应该都提供了一些API,供第三方开发调试器使用。

二、cpu如何知道IP指向的命令有多长?
re: 请参考2楼SJQIANG、4楼phrain的回复。
另,虽然8086指令是不定长的,但是也有不少其它cpu是定长指令集。
具体的,可以参考各种不同cpu的芯片资料,会有cpu取指步骤的详细描述。
2011-2-28 16:08
0
游客
登录 | 注册 方可回帖
返回
//