来看三段程序,你学会了什么?

学习任何一门语言都不能少的了 debug汇编也是。,下面我们就依据这几个功能来跟踪一下程序的执行过程。,debug 对我们来说非常重要,有很多代码细节和问题通过肉眼是观察出来的,我们肉眼可能能够判断一些简单的程序问题,但是对于很多隐藏较深的问题,还是要依据 debug 才能发现。,下面是一段汇编代码,这段汇编代码我之前的文章中也给大家写过。,新建文本文件,把代码 cv 过去,然后右键保存,使用 dosbox 将其编译为 1.obj 文件,链接为 1.exe 文件后,我们使用 ​​debug 1.exe​​ 命令来分析一下这段程序,并用 -r 命令来看一下初始的寄存器情况。,图片,程序初始状态下,可以看到 CX 中的数据为 000F,这也表示着程序的长度是 000F,1.exe 中共有 15 个字节,CX 中的内容为 000FH。,好,现在我们已经知道程序被成功的载入内存并运行起来了,但是我们现在先不妨想一下,被链接成为 EXE 的程序会被装入内存的哪个地方的呢?我们怎么知道程序被装入在哪里呢?,程序装载的过程分下面几步:,图片,图片,图片,程序被装入内存后,由 DS 段寄存器存放着内存区的段地址,此时内存区域的偏移量为 0 ,所以此时的物理地址为 SA * 16:0,我们并不用知道真实的 DS 是多少,反正都是由操作系统和 DOS 分配的。,然后这个内存区域的前 256 个字节被用于存放 PSP ,所以程序的物理地址为 SA * 16 + 256 : 0 。,SA * 16 + 256 = SA * 16 + 16 * 16 = (SA  + 16) * 16 ,转换为 16 进制就是 SA + 10H,所以物理地址就是 SA + 10H : 0。,我们上面 debug 1.exe 之后可以看到,DS 段寄存器的值为 076AH ,而 CS 段寄存器的值为 076BH ,正好符合 076A * 16 + 10 = 076BH (注意这里的 * 16 就是左移 4 位的意思,之前文章中也解释过原因。),我们使用 -u 指令可以看到完整的汇编源代码。,图片,上图中用红框圈出来的就是我们这段汇编程序的源代码,可以看到这是一个程序段,程序段的段地址始终为 076A,偏移地址在不断变化。,我们使用 -t 命令来单步执行以下这段程序,如下图所示。,图片,(为了连续的观察一下程序的执行结果,我索性直接把主要的程序步骤执行完了。),这段程序就是 mov 和 add 的基本使用,将 0123 送入 AX 寄存器,将 0456 送入 BX 寄存器,对 AX 寄存器执行 AX = AX + BX ,再对 AX 执行 AX = AX + AX。,程序继续向下执行,当执行到 int 21H 处,程序执行完毕,此时要使用 -p 命令结束程序的执行,如下图所示。,图片,当显示 Program terminated normally 时,表示程序正常结束,这里大家先不用考虑为什么执行到 int 21 处才执行 -p 命令,也不用关心 mov ax,4c00 和 int 21 是什么意思,大家先记住就行。,由于程序装载的过程是 command 将程序装载进入内存,然后 debug 程序对 exe 程序其进行跟踪,所以程序退出后也是先从 exe 程序退出到 debug 程序中,由 debug 程序再退回到 command 程序中。,下面再分析一段程序,汇编原代码,仍然是将其保存为 test.txt,然后执行编译和链接操作,将其生成可执行文件 test.exe,观察其执行过程。,我们先使用 -r 查看一下初始寄存器的内容。,图片,主要观察一下 CX 、DS 、CS 和 IP 的值,是否和我们上面描述的一致,CX 存放程序长度,DS 存放程序段地址,CS 存放程序初始地址,IP 存放程序偏移地址。,再使用 -u 看一下 exe 程序的源代码,这个 exe 程序是经过编译和链接之后的程序。,图片,我们来分析一下这段,这是一段栈段的入栈和出栈的程序,首先,是设置栈段的栈顶指令,执行完成后会设置栈顶的物理地址为 20000 H ,即 SS:SP = 2000:0000。,图片,我们执行这个程序的过程中,发现 mov sp,0 这个指令为什么没有出现呢?难道是我们漏写了?查看了一下,源代码确实是有这条指令的,难道是没有执行?,为了验证这个假设,我们重新 debug 一下这段程序,然后先把 SP 的值进行修改,如下图所示。,图片,刚开始,我们使用 -r 把 sp 的值改成 0002,然后单步执行,在执行到 mov ss,ax 之后,发现 SP 的值变为 0000,这也就是说 mov sp,0 这条指令其实是执行了的,只是 debug 模式下没有显示而已。,程序继续向下执行,下面是两个 pop 出栈操作。,图片,pop ax 和 pop bx 做了两件事:把寄存器清空;栈顶位置 + 2 ,所以 ax 和 bx 寄存器的内容为 0 ,并且 SP = SP + 2 ,执行后 SP = 000E。,之后是两个 push 操作,把出栈的两个寄存器再进行入栈,如下图所示。,图片,push 操作也做了两件事情,将寄存器入栈,SP = SP – 2,由于 ax 和 bx 已经 pop 出栈了,所以寄存器内容为 0 ,最后再进行 pop 操作,然后再结束程序的执行过程。,图片,我们再来看一下 PSP 的情况,由于程序被装入的时候前 256 个字节是 PSP 所占用的,此时 DS(SA)处就是 PSP 的起始地址,而 CS = SA + 10H ,也就是 CS = 076AH。,下面我们来 debug 一下循环程序,看看有哪些有意思的细节。,现在有这样一道问题,计算 ffff:0006 单元中的数乘 3 ,让结果存储在 dx 中。,针对这个问题,有几个点需要思考:,所以这段汇编程序的代码如下,编写完毕,编译链接成 exe 程序后,对其进行 debug xxx.exe 操作。,我们来看下程序的执行过程。,图片,前两段没毛病,设置 DS 段寄存器的值为 FFFF 。然后继续向下执行,图片,执行到 mov al,[6] 的时候我发现,怎么 AX 寄存器中的内容变成 0006 了?我不是想要把 06 放入 ax 中啊,我是想把 ffff:06 内存单元中的值放入 ax 中啊,我突然意识到编译器是个傻子。,经过我认真仔细细心耐心用心的排查了一番问题之后,我方才大悟,原来我是个傻子!不知道各位小伙伴们看出来我代码的问题了吗?,我怎么敢在源程序中把立即数当做内存偏移地址来用呢?必须要用 bx 中转啊!,这也就是说,编译器编译完源代码之后,会把 06 当做立即数使用,如果想要使 06 表示内存地址,必须要用 bx 进行中转,修改之后的源代码如下:,然后再重新链接成为 exe 程序之后,我们一步一步 debug 看一下。,图片,执行到 mov al,[bx] 的时候,我们发现,此时右侧有个 ds:0006 = 31,这段代码表示的是 ds:0006 处内存单元的值是 31,这才表明我们的程序是正确的。,继续向下执行程序。,图片,前两条指令执行完成后,(dx) = 0 ,(cx) = 3,完成对累加寄存器的清空和循环计数器的赋值操作。最后一条指令是第一次循环操作指令,此时 CS:IP 指向 076A:0012 ,继续向下执行。,图片,可以看到,第一次 add dx,ax 执行完成后 IP = 0014H ,此时指向的指令是 LOOP 0012,这条指令的意思是让程序再执行一次 (IP) = 0012H 处的指令,也就是再执行一次 add dx,ax,可以看到 cx 的值变成了 0002,因为循环指令执行后 (cx) = (cx) – 2 ,然后再向下执行,发现后面的循环指令还是 LOOP 0012 ,再执行一次 add dx,ax,一直到 (cx) = 0 后结束程序执行,如下图所示,图片,可以发现,整个程序一共循环三次,最终 dx 中的值是 93 ,程序执行到 int 21H 处,使用 -p 命令结束程序的执行。

文章版权声明

 1 原创文章作者:cmcc,如若转载,请注明出处: https://www.52hwl.com/19166.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年3月5日 上午12:00
下一篇 2023年3月7日 下午10:34