实验3 多个段的汇编源程序编写与调试

实验3 多个段的汇编源程序编写与调试

一、实验目的

  1. 理解和掌握将数据、代码、栈放入不同逻辑段的程序的编写和调试
  2. 理解具有多个段的汇编源程序对应的目标程序执行时,内存分配方式
  3. 掌握大小写字符的转换方法、数字字符和数值之间的转换方法
  4. 理解并掌握各种寻址方式的灵活应用
  5. 掌握汇编指令loop, and, or,div, mul的用法

二、实验准备

复习教材chapter 6-8章。

三、实验结论

任务1

该段代码实际上实现了对指定显存的控制,将“2N”“2U”等组合存入显存,经过以前的实验我们可以知道,低位控制字符,高位控制显示格式,这里2就是以绿色显示。
具体分析如下:

assume cs:code, ds:data
data segment
        db 'Nuist'
        db 5 dup(2)
data ends

code segment
start:
        mov ax, data
        mov ds, ax  ;将ds设为data段

        mov ax, 0b800H
        mov es, ax ;将es段设为0b800h,为显存段

        mov cx, 5 ;循环5次
        mov si, 0
        mov di, 0f00h
s:      mov al, [si] ;ds:0(N)存入al,即data段的字节依次存入al
        and al, 0dfh   ;统统转为大写
        mov es:[di], al  ;al存入0b800:0f00,实际上是设置显示的字符
        mov al, [5+si]
        mov es:[di+1], al  ;ds:5(2)存入0b800:0f01,实际上是设置显示字符的颜色
        inc si    ;si+1,指向下一个字符
        add di, 2  ;di+2,指向下一个显存字
        loop s

        mov ah, 4ch
        int 21h
code ends
end start

task1.exe执行结果如图,可以看到在左下角显示绿色的NUIST

使用debug工具对程序进行调试,执行到程序返回前,可以看到NUIST出现且随着屏幕滚动上移

修改line4里5个字节单元的值,NUIST分别变成了不同的颜色,印证了开头的分析,数字控制显示模式

任务2

assume cs:code, ds:data
data segment
	     db 23,50,66,71,35
data ends

code segment
	start:
	      mov  ax,data
	      mov  ds,ax
	      mov  si,0
	      mov  cx,5
	s:    mov  ah,0
	      mov  al,ds:[si]
	      mov  bl,10
	      div  bl
	      mov  bh,ah  ;ah后面会用于输出被覆盖,先暂存至bh
	      add  al,30h ;al存放商,为高位,加30h变为对应字符

	      mov  ah,2
	      mov  dl,al ;输出高位
	      int  21h
              ;此前ah已经设定好,后面输出就不用重复设置
	      add  bh,30h
	      mov  dl,bh ;输出低位
	      int  21h

	      mov  dl,32 ;32为空格ASCII码(10进制)
	      int  21h

	      inc  si
	      loop s
          
	      mov  ah, 4ch
	      int  21h
code ends
end start

运行结果如图:可以看到数字依次输出

任务3

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
  1. data段中的数据是:23 01 56 04 89 07 bc 0a ef 0d ed 0f ba 0c 87 09,观察到的结果和理论分析一致。
  2. cs=0770,ss=076f,ds=076e
  3. 程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。

任务4

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. data段中的数据是:23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00,观察到的结果和理论分析一致。
  2. cs=0770,ss=076f,ds=076e
  3. 程序加载后,code段的段地址为X,则data段的段地址为X-2,stack段的段地址为X-1。
  4. 对于任意一个段,其大小为16的倍数,即数据占N个字节,加载后实际空间为16*ceil(N/16)
    任务5
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. data段中的数据是:23 01 56 04 00 00 00 00 00 00 00 00 00 00 00 00,观察到的结果和理论分析一致。
  2. cs=076e,ss=0772,ds=0771
  3. 程序加载后,code段的段地址为X,则data段的段地址为X+3,stack段的段地址为X+4。

这里可以发现一个奇妙的现象,明明代码只是将数据、栈段与代码段交换了顺序,程序大小(CX)却变为44,增加了2,查看(初始ds+10)后的50h个字节

可以看出,40开始为栈段,但44后缺没有分配给栈段,反而代码结束,22后到数据段30前都空给了代码段,可以得到推论若程序有n个段,前n-1个段以16为单位分配,第n个段分配实际大小

任务6

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

(3)仍然可以正确执行,因为没有指明程序入口时,cs设定为ds+10,即PSP后的位置作为程序入口,而(3)的代码段放在了最前面,刚好对应上

任务7

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    		; 在集成软件环境中,请将此处的段名称由c→改为c1或其它名称
	   db 8 dup(0)
c1 ends

code segment
	start:
	      mov  ax,a
	      mov  ds,ax       	;a设为ds段
	      mov  ax,b
	      mov  es,ax       	;b设为es段
	      mov  ax,c1
	      mov  ss,ax       	;c设为栈段
	      mov  sp,8        	;栈底设为c:8
	      mov  cx,4        	;由于入栈只能为字数据,因此一次运算两个字,一并入栈,循环8/2次
	      mov  bx,6
	s:    mov  al,ds:[bx]  	;低位计算靠前的数
	      add  al, es:[bx] 	;高位计算靠后的数
	      mov  ah,ds:[bx+1]
	      add  ah,es:[bx+1]
	      push ax
	      sub  bx,2
	      loop s
	      mov  ax,4c00h
	      int  21h
code ends
end start

执行代码,观察c段,可以看到求解成功

任务8

assume cs:code
a segment
	  dw 1,2,3,4,5,6,7,8,9,0ah,0bh,0ch,0dh,0eh,0fh,0ffh
a ends

b segment
	  dw 8 dup(0)
b ends

code segment
	start:
	      mov  ax,a
	      mov  ds,ax   	;a设为ds段
	      mov  ax,b
	      mov  ss,ax   	;b设为栈段
	      mov  sp,16   	;栈底设为b:16
	      mov  cx,8    	;循环8次
	      mov  bx,0
	s:    push [bx]    	;从0开始依次入栈,即为逆序
	      add  bx,2
	      loop s
	      mov  ax,4c00h
	      int  21h
code ends
end start

执行代码,观察b段,可以看到求解成功

四、实验总结

  • 在分配段空间时,以16字节为一个单位,不足的部分以0填充,但是若程序有n个段,前n-1个段以16为单位分配,第n个段分配实际大小
  • 80806中,栈寄存器有CS, SS, DS, ES,其中DS、ES可以相对随意使用,如果操作需要3个段,如果是顺序操作考虑利用栈段,不过需要注意栈段的操作顺序是从高到低,超出3个段据就需要考虑在循环中更改ds了
posted @ 2020-11-23 22:35  GoatKing  阅读(95)  评论(2)    收藏  举报