一、预备知识

ps:这一章我同样不分开做知识点总结了,一个是因为觉得能力不够,没有那么多的发现,而且掌握也不算好,还有一点是现在时间不够,每一次作业都要花好久的时间

(1)dw:字型数据;db:字节型数据

(2)如果代码和数据放在一个段中,反汇编时,如果从0开始,会把数据当成指令机器码反汇编,所以反汇编时注意sp的值

(3)8086CPU不允许将一个数值直接送入段寄存器中

(4)调试时,可以通过r命令修改ip的值或在t/g命令中指定执行的起始地址

(5)end 标号:表示程序到标号处开始,到此结束,后面的标号有时候可以省略

(6)使用assume仅仅表示将某个逻辑段和某个段寄存器关联起来;真正当做特定的段使用,需要在代码段中设置相应的段寄存器值

 

二、实验任务

1、将下面的程序编译、连接、,用debug加载、跟踪,然后回答问题

assume cs:code,ds:data,ss:stack

data segment

      dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

data ends

stack segment

      dw 0,0,0,0,0,0,0,0

stack ends

code segment

start:     mov ax,stack

            mov ss,ax

            mov sp,16

            mov ax,data

            mov ds,ax

            push ds:[0]

            push ds:[2]

            pop ds:[2]

            pop ds:[0]

            mov ax,4c00h

            int 21h

code ends

end start

先用r查看各寄存器的值,CX的值为42h,前面的数据一共用了20h,剩下的一共是22h,从0~21h

接着用g命令多步执行,到程序返回前停下,所以用g 001d,接着查看data段中的数据

 

(1)CPU执行程序,程序返回前,data段中的数据为多少?

0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h

(2)CPU执行程序,程序返回前,cs=0772h,ss=0771h,ds=0770h

(3)设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1

 

2、将下面的程序编译、连接,用debug加载、跟踪,然后回答问题

assume cs:code,ds:data,ss:stack

data segment

      dw 0123h,0456h

data ends

stack segment

      dw 0,0

stack ends

code segment

start:     mov ax,stack

            mov ss,ax

            mov sp,16

            mov ax,data

            mov ds,ax

            push ds:[0]

            push ds:[2]

            pop ds:[2]

            pop ds:[0]

            mov ax,4c00h

            int 21h

code ends

end start

这个程序和上面的程序一样的方法调试

 

(1)CPU执行程序,程序返回前,data段中的数据为多少?

0123h,0456h

(2)CPU执行程序,程序返回前,cs=0772h,ss=0771h,ds=0770h

(3)设程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1

(4)对于如下定义的段:

name segment

……

name ends

如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为((N+15)/16)*  16

ps:这道题我确实无从下手,不知道是该怎么处理,最后没办法,去查了一下

N分为被16整除和不被16整除。

当N被16整除时: 占有的空间为(N/16)*16

当N不被16整除时: 占有的空间为(N/16+1)*16,N/16得出的是可以整除的部分,还有一个余数,余数肯定小于16,加上一个16。

程序加载后分配空间是以16个字节为单位的,也就是说如果不足16个字节的也分配16个字节。

两种情况总结成一个通用的公式:((N+15)/16)*16 

 

3、将下面的程序编译、连接,用debug加载、跟踪,然后回答问题

assume cs:code,ds:data,ss:stack

code segment

start:     mov ax,stack

            mov ss,ax

            mov sp,16

            mov ax,data

            mov ds,ax

            push ds:[0]

            push ds:[2]

            pop ds:[2]

            pop ds:[0]

            mov ax,4c00h

            int 21h 

code ends

data segment

      dw 0123h,0456h

data ends

stack segment

      dw 0,0

stack ends

end start

这个程序和上面的程序一样的方法调试

 

(1)CPU执行程序,程序返回前,data段中的数据为多少?

0123h,0456h

(2)CPU执行程序,程序返回前,cs=0772h,ss=0774h,ds=0773h

(3)设程序加载后,code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4

 

4、如果将(1)、(2)、(3)题中的最后一条伪指令“end start”改为“end”(也就是说,不知名程序的入口),则哪个程序仍然可以正确执行?请说明原因

(3)可以,(1)、(2)的开始都是数据段,而(3)的开始是指令

(1)、(2)如果直接执行,机器会把数据当成指令才执行,而(3)指令的一开始偏移地址就是0,直接执行不会有问题

 

5、程序如下,编写code段中的代码,将a段和b段中的数据依次相加,将结果存到c段中

assume cs:code

a segment

      db 1,2,3,4,5,6,7,8

a ends

b segment

      db 1,2,3,4,5,6,7,8

b ends

c1 segment

      db 0,0,0,0,0,0,0,0

c1 ends

code segment

start:

???

code ends

end start

 

源代码:

 

接着,调试一下,看看能不能达到预期的效果

在实现数据相加前,逻辑段c中放的是原本的数据

很明显,最后数据的确相加了,而且存在了c段中

但素,做这个可没那么容易

中间出了各种各样的问题,做了很久才做出来

 

这是我一开始的代码,粗来的数据很奇怪,找了很久才找到错误

assume cs:code

a segment

      db 1,2,3,4,5,6,7,8

a ends

b segment

      db 1,2,3,4,5,6,7,8

b ends

c1 segment

      db 0,0,0,0,0,0,0,0

c1 ends

code segment

start:     mov ax,c1

            mov es,ax

            mov ax,b

            mov ds,ax

            mov ax,a

            mov ss,bx //问题出在这里,不应该是ss,bx,而应该是ss,ax

            mov bx,0

            mov cx,8

           

s:          mov al,ds:[bx]

            add al,ss:[bx]

            mov es:[bx],al

            inc bx

            loop s

           

            mov ax,4c00h

            int 21h

code ends

end start

我在调试的时候才发现这个程序的问题

前面都没有什么问题,直到我用d命令查看寄存器的值的时候,很奇怪,为什么这个数据是这个样子的

我看了一下到程序返回前各寄存器的值,一看,ss的值还是0,也就是说,数据段中的数据并没有到栈段中去

而那些数据都是操作系统自己的数据

因此,我去看了一下程序,问题出在我上面标出来的那一行

改过来之后程序就没有问题了

 

6、程序如下,编写code段中的代码,用push指令将a段中的前8个字型数据,逆序存储到b段中

assume cs:code

a segment

      dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0dh,0fh,0ffh

a ends

b segment

      dw 0,0,0,0,0,0,0,0

b ends

code segment

start:    

???

code ends

end start

 

源代码:

这个代码是借鉴了书上P133页的代码

下面是调试过程:

这里是在push操作执行前,查看逻辑段b的8个子单元

在程序返回前,再次查看逻辑段b的8个子单元

最后实现了逆序存储

 

总结:

(1)当提到逆序存储的时候,可以利用栈的先进后出的特点来实现这个问题

(2)可以利用寄存器cx的值来进行精确反汇编,同时可以用反汇编得到的偏移地址的值进行多步执行

(3)当程序达不到自己想要的结果时,可以通过单步执行来寻找问题,也可以利用寄存器的值来寻找问题

(4)要看清楚给的数据是字型数据还是字节型数据,用相应的寄存器去实现题目的问题

(5)前面的几个程序,由每个段写的位置可见,代码段,数据段和栈段的段地址之间存在一定的关系

posted on 2018-11-26 23:41  樱花飘落の季節  阅读(1566)  评论(2编辑  收藏  举报