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

一、实验目的

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

二、实验准备

复习教材chapter 6-8章。
  • chapter 6 包含多个段的程序
  • chapter 7 更灵活的定位内存地址的方法 
  • chapter 8 数据处理的两个基本问题
 

三、实验内容

1. 实验任务1

使用任意文本编辑器,录入汇编源程序task1.asm。

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

code segment
start:
        mov ax, data
        mov ds, ax

        mov ax, 0b800H
        mov es, ax

        mov cx, 5
        mov si, 0
        mov di, 0f00h
s:      mov al, [si]
        and al, 0dfh
        mov es:[di], al
        mov al, [5+si]
        mov es:[di+1], al
        inc si
        add di, 2
        loop s

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

阅读源程序,从理论上分析源代码的功能,尤其是line15-25,循环实现的功能是什么,逐行理解每条指令的功能。

  • 使用masm、link对task1.asm进行汇编、链接,得到可执行文件task1.exe,运行并观察结果。
  • 使用debug工具对程序进行调试,执行到程序返回前,即line27之前,观察结果。
  • 修改line4里5个字节单元的值,重新汇编、链接、运行,观察结果。
1 db 5 dup(2) 
2 --> 改成:
3 db 2,3,4,5,6

基于观察,分析、猜测这里的数值作用是什么。

2. 实验任务2

已知数据段data中定义字节数据如下:

1 data segments
2     db 23, 50, 66, 71, 35
3 data ends

编写程序,在屏幕上以十进制整数形式打印输出这5个两位数。

提示:

  • 1个两位数如何输出
    思路如下:

 

 

  • 具体处理步骤如下:
    第1步,利用除法指令div,计算出每个数位上的数值。
    第2步,利用数值和数字字符之间ascII码的关系,把数值→数字字符
    第3步,利用系统功能调用int 21h中的2号子功能,输出单个字符。

    int 21h中的2号子功能说明如下:
    功能:输出单个字符
    用法:
    1 mov ah, 2
    2 mov dl, ×× ; ××是待输出的字符,或其ASCII码值 
    3 int 21h
  • 5个两位数如何输出 
    利用loop指令,以及,灵活的寻址方式。

     

    3. 实验任务3

    教材「实验5 编写、调试具有多个段的程序」(1)

    程序源码见task3.asm。 

     

    4. 实验任务4

    教材「实验5 编写、调试具有多个段的程序」(2) 

    程序源码见task4.asm。

     

    5. 实验任务5

    教材「实验5 编写、调试具有多个段的程序」(3)

    程序源码见task5.asm。 

     

    6. 实验任务6

    教材「实验5 编写、调试具有多个段的程序」(4) 

     

    7. 实验任务7

    教材「实验5 编写、调试具有多个段的程序」(5) 

    程序源码见task7.asm。

    注*: 如果在集成软件环境下编写、汇编这个实验任务,请将段名为c的逻辑段,名称改为c1或别的标识 符。由于早期一些指令集中使用c指代寄存器,如不更正,有些汇编器在汇编时会报错。

    1 c segment ; 段名称改成c1或别的合法的标识符
    2  ...
    3 c ends ; c1

     

    8. 实验任务8

    教材「实验5 编写、调试具有多个段的程序」(6)

    程序源码见task8.asm。

     

    四、实验结论

    1. 实验任务1 

    源代码文件task1.asm:

    assume cs:code, ds:data
    data segment
            db 'Nuist'
            db 5 dup(2)
    data ends
    
    code segment
    start:
            mov ax, data
            mov ds, ax
    
            mov ax, 0b800H
            mov es, ax
    
            mov cx, 5
            mov si, 0
            mov di, 0f00h
    s:      mov al, [si]
            and al, 0dfh
            mov es:[di], al
            mov al, [5+si]
            mov es:[di+1], al
            inc si
            add di, 2
            loop s
    
            mov ah, 4ch
            int 21h
    code ends
    end start

    运行结果截图:

    在debug里调试到程序返回前的截图:

    执行

    1 db 5 dup(2) 
    2 --> 改成:
    3 db 2,3,4,5,6
     后的运行结果截图:

    由此可见,源代码中data段line4的字节数据包含了所显示字节的颜色。

    源代码第15~25行的作用是将代码段中的小写字母全部转换为大写,并且为每个字母赋值使其显示相应的颜色并显示在屏幕上。

     

    2. 实验任务2

    源代码文件task2.asm:

    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 cx, 5
        mov si, 0
    
    s1: mov bl, 10;除数
        mov ah, 0
        mov al, [si]
        div bl
        mov bx, ax ;al存放的是商(两位数中的十位数),ah存放的是余数(两位数中的个位数)
    
        mov ah, 2
        mov dl, 30h
        add dl, bl;将bl中的数值转化成ASCII码值并存入dl中输出
        int 21h
    
        mov dl, 30h
        add dl, bh;将bh中的数值转化成ASCII码值并存入dl中输出
        int 21h
        mov dl," ";每个两位数后输出一个空格
        int 21h
    
        inc si
        loop s1
    
        mov ah, 4ch
        int 21h
    code ends
    end start

    运行结果:

     

    3. 实验任务3

    源代码文件task3.asm:

    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

    用debug加载、追踪结果:

    ①猜测程序返回前数据段内容为23 01 56 04 89 07 bc 0a ef 0d ed 0f ba 0c 87 09

    在debug中用d命令查看数据段内容:

     结果与猜测一致。

    ②由debug调试结果可知,程序返回前CS=076C,SS=076B,DS=076A。

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

     

    4. 实验任务4

    源代码文件task4.asm:

    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

    用debug加载、追踪结果:

     ①猜测程序返回前数据段内容为23 01 56 04 00 00 ...(共12个00)

    在debug中用d命令查看数据段内容:

     

    结果与猜测一致。

    ②由g命令可知,程序返回前CS=076C,SS=076B,DS=076A。

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

    ④对于如下定义的段:

    1 name segment
    2  ...
    3 name ends

    如果段中的数据占N个字节,则程序加载后,该段实际占有的空间为 16×⌈N/16⌉ 字节。

     

    5. 实验任务5

    源代码文件task5.asm:

    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

    用debug加载、追踪结果:

     

    ①猜测程序返回前数据段内容为23 01 56 04 00 00 ...(共12个00)

    在debug中用d命令查看数据段内容:

     

    结果与猜测一致。

    ②由g命令可知,程序返回前CS=076A,SS=076E,DS=076D。

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

     

    6. 实验任务6

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

    答:task5.exe。因为如果不指明入口位置,程序就会默认以ip=0执行,而不是从start开始执行,而task5.exe的data和stack都在code之后,所以ip本来就为0。

     

    7. 实验任务7

    源代码文件task7.asm:

    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
        mov cx,8
        mov si,0
    
    s:  mov ax,[si]
        add ax,[si+10H]
        mov [si+20H],ax
        inc si
        loop s
    
        mov ax,4c00H
        int 21H
    code ends
    end start

    用debug调试结果如下:

     

    由数据段结果可知,代码正确实现了数据依次相加并存储的功能。

     

    8. 实验任务8

    源代码文件task8.asm:

    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
        mov ax,b
        mov ss,ax
        mov si,0
        mov cx,8
        mov sp,10H
    
    s:  push [si]
        add si,2
        loop s
    
        mov ax,4c00h
        int 21h
    code ends
    end start

    用debug调试结果如下:

     

    由数据段结果可知,代码正确实现了用push逆序存储数据的功能。

posted @ 2020-12-25 10:04  TimeBomb  阅读(94)  评论(0)    收藏  举报