汇编语言(王爽第三版)实验6 实践课程中的程序

实验6 实践课程中的程序

(1)将课程中所有讲解过的程序上机测试,用debug跟踪其执行过程,并在过程中理解所讲内容。

       问题7.6 将data段中每个单词的头一个字母改为大写字母。

assume cs:code

data segment

    db '1. file         '

    db '2. edit         '

    db '3. search       '

    db '4. view         '

    db '5. options      '

    db '6. help         '

data ends

code segment

程序分析:

       1)数据段定义了6个字符串结构,长度一致都是16字节,并且字符都是连续的,并且头一个字母在字符串中的位置都是第4个字符,在上面的寻址方式中,我们发现[bx+idata]方式比较适合这种情况,idata代表每个字符串起始地址,bx代表基本偏移地址,bx的偏移量也是有规律的16。

       2)在debug中,这6个字符串显示的正好是6行16列的字符,是一个我们在C语言中讲到的二维数组[6][16],其实它在内存中是线性单列排列的。

       3)遇到此种情况我们使用[bx+idata]的方式进行内存的寻址比较科学。

       完整的代码如下:

assume cs:code

data segment

    db '1. file         '

    db '2. edit         '

    db '3. search       '

    db '4. view         '

    db '5. options      '

    db '6. help         '

data ends

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;将ds:bx指向data第一个单元

        mov cx, 6           ;需要修改6次

       

    s:  mov al, [bx+3]      ;使用[bx+idata]寻址方式,并送入al(单字节)

        and al, 11011111b   ;转换为大写字母

        mov [bx+3], al      ;回写内存

        add bx, 16          ;6个字符串长度一致,都是16字节,增量为16

        loop s

       

        mov ax, 4c00H

        int 21H

code ends

end start

       结果分析:

       (1)在循环中,如遇到loop指令,首先我们要认识到,(cx)=(cx)-1;直到cx=0退出循环。

       问题7.7将data段中每个单词的字母改为大写字母。

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

       程序分析:

       (1)数据段定义了4个字符串,长度依然是16字节,并且是连续存储的,这次是要求将每个字符串的小写字母都给修改了,这样[bx+idata]就不合适了,我们采用[bx+si]方式寻址。bx依然代表基本偏移地址,si代表了每个字符串每个字母的偏移地址。

       (2)一个循环肯定满足不了要求了,这里需要二重循环,外层循环递增bx的值;内存循环对每个字符串的字符进行变换操作。

       (3)对于loop循环来说,它判断的是cx计数器,对于二重循环,一个cx值显然满足不了要求。书中代码中的cx设置就有问题了。

       问题7.8 解决cx计数器重复设置的问题:

       程序分析:我们可以想法将外层循环计数器保存起来,待某一个内层循环执行完毕后,在恢复。这样可以解决了cx计数器冲突的问题。

       改进的代码:

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作为基本偏址变量

        mov cx, 4           ;需要外循环4次,修改4个字符串

   

    s0: mov dx, cx          ;将外层循环计数器cx保存到dx中

        mov si, 0           ;si作为每个字符串的偏址

       

        mov cx, 3           ;内存循环s1,需要循环3次

    s1: mov al, [bx+si]     ;使用[bx+si]寻址方式,并送入al(单字节)

        and al, 11011111b   ;转换为大写字母

        mov [bx+si], al     ;回写内存

        inc si                 

        loop s1

       

        add bx, 16          ;6个字符串长度一致,都是16字节,增量为16

        mov cx, dx          ;将外层循环计数器cx从dx中恢复

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       结果分析:

       (1)我们通过将cx寄存器变量保存的方式,来解决多重循环cx变量冲突的问题。

       (2)此例中我们解决方式是将cx保存到dx中,在8086CPU中,寄存器本来就比较紧张,段寄存器肯定不能用,ip是程序的指针、dx一般用于结果的输出,占用后又出现新的问题,sp是默认的ss栈段的指针;显然,将临时的数据保存在一个寄存器中的方式是不合适的。

       (3)既然不能讲暂存的数据(它可能是寄存器变量的值,也可能是内存中单元的值)保存到一个寄存器中,那么使用内存作为暂存空间是可行的。我们将代码继续改进。

        改进后的代码:

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

    dw 0                    ;定义一个字,用于暂存cx值

data ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作为基本偏址变量

        mov cx, 4           ;需要外循环4次,修改4个字符串

   

    s0: mov ds:[40H], cx    ;将外层循环计数器cx保存到data内存中

        mov si, 0           ;si作为每个字符串的偏址

       

        mov cx, 3           ;内存循环s1,需要循环3次

    s1: mov al, [bx+si]     ;使用[bx+si]寻址方式,并送入al(单字节)

        and al, 11011111b   ;转换为大写字母

        mov [bx+si], al     ;回写内存

        inc si                 

        loop s1

       

        add bx, 16          ;6个字符串长度一致,都是16字节,增量为16

        mov cx, ds:[40H]    ;将外层循环计数器cx从data内存中恢复

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       结果分析:

       (1)在data段中定义了一个字单元空间,用于暂存cx的值。用直接寻址方式就行了。它在data段中偏移地址是40H,那么ds:[40H]==data:[40H]就代表了内存的那个字。

       (2)这种情况,如果需要暂存的数据多的情况下,比较混乱,你还得记住内存单元的地址。

       (3)一般来说,在需要暂存数据的时候,我们都应该使用栈。

       继续改进代码,使用人工创建的栈空间来暂存cx值。

assume cs:code

data segment

    db 'ibm             '

    db 'dec             '

    db 'dos             '

    db 'vax             '

data ends

stack segment

    db 16 dup (0)           ;人工定义一个栈段,空间16个字节,初始化为0

stack ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作为基本偏址变量

        mov cx, 4           ;需要外循环4次,修改4个字符串

       

        mov ax, stack          

        mov ss, ax          ;人工创建一个栈结构

        mov sp, 16          ;将ss:sp指向栈顶

       

    s0: push cx             ;将外层循环计数器cx保存到stack栈中

        mov si, 0           ;si作为每个字符串的偏址

       

        mov cx, 3           ;内存循环s1,需要循环3次

    s1: mov al, [bx+si]     ;使用[bx+si]寻址方式,并送入al(单字节)

        and al, 11011111b   ;转换为大写字母

        mov [bx+si], al     ;回写内存

        inc si                 

        loop s1

       

        add bx, 16          ;6个字符串长度一致,都是16字节,增量为16

        pop cx              ;将外层循环计数器cx从stack栈中恢复

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       结果分析:

       (1)以后我们遇到越来越多的将暂存的数据存储在栈空间中去。下面讲到的子程序就大量使用栈。

       (2)此例中我们使用的是人工创建的栈结构,还是就是系统自动创建的栈结构,那个我们不需要在内存中定义栈空间所需的单元。

 

(2)编程完成7.9问题中的程序

问题 7.9编程将data段中每个单词的前4个字母改为大写字母。

assume cs:code

data segment

    db '1. display      '

    db '2. brows        '

    db '3. replace      '

    db '4. modify       '

data ends

stack segment

    db 16 dup (0)           ;人工定义一个栈段,空间16个字节,初始化为0

stack ends

       程序分析:

       (1)4个字符串,每个字符串长度都相同,都是16个字节,并且是连续的,此时我们可以把这种结构看成是一个二维数组。每个单词字符长度都大于4.

       (2)需要改变的是每个字符串的第4个字符开始的4个字符,那么在每一行,我们表示内存单元可以使用[si+idata]的方式寻址,idata代表每个行(每个字符串)开始地址3.si作为每行的偏移地址,偏移量从0~3;由于是个二维数组结构,bx代表每行的偏移量,偏移量从0~3,最终我们采用[bx+si+idata]寻址的方式来定位每行的字符串。

       代码如下:

assume cs:code

data segment

    db '1. display      '

    db '2. brows        '

    db '3. replace      '

    db '4. modify       '

data ends

stack segment

    db 16 dup (0)           ;人工定义一个栈段,空间16个字节,初始化为0

stack ends

 

code segment

start:

        mov ax, data

        mov ds, ax

        mov bx, 0           ;bx作为基本偏址变量

               

        mov ax, stack          

        mov ss, ax          ;人工创建一个栈结构

        mov sp, 16          ;将ss:sp指向栈顶

       

        mov cx, 4           ;需要外循环4次,修改4个字符串

    s0: push cx             ;将外层循环计数器cx保存到stack栈中

        mov si, 0           ;si作为每个字符串的偏址

       

        mov cx, 4           ;内存循环s1,需要循环4次

    s1: mov al, [bx+si+3]   ;使用[bx+si+3]寻址方式,并送入al(单字节)

        and al, 11011111b   ;转换为大写字母

        mov [bx+si+3], al   ;回写内存

        inc si                 

        loop s1

       

        add bx, 16          ;4个字符串长度一致,都是16字节,增量为16

        pop cx              ;将外层循环计数器cx从stack栈中恢复

        loop s0

       

        mov ax, 4c00H

        int 21H

code ends

end start

       程序运行结果:

-d ds:0

0B65:0000  31 2E 20 44 49 53 50 6C-61 79 20 20 20 20 20 20   1. DISPlay

0B65:0010  32 2E 20 42 52 4F 57 73-20 20 20 20 20 20 20 20   2. BROWs

0B65:0020  33 2E 20 52 45 50 4C 61-63 65 20 20 20 20 20 20   3. REPLace

0B65:0030  34 2E 20 4D 4F 44 49 66-79 20 20 20 20 20 20 20   4. MODIfy

 

posted @ 2017-05-21 08:54  筑基2017  阅读(2796)  评论(0编辑  收藏  举报