实验3 转移指令跳转原理及其简单应用编程

实验任务 1

<task3_1.asm>

 1 assume cs:code, ds:data
 2 
 3 data segment
 4     x db 1, 9, 3
 5     len1 equ $ - x
 6 
 7     y dw 1, 9, 3
 8     len2 equ $ - y
 9 data ends
10 
11 code segment
12 start:
13     mov ax, data
14     mov ds, ax
15 
16     mov si, offset x
17     mov cx, len1
18     mov ah, 2
19  s1:mov dl, [si]
20     or dl, 30h
21     int 21h
22 
23     mov dl, ' '
24     int 21h
25 
26     inc si
27     loop s1
28 
29     mov ah, 2
30     mov dl, 0ah
31     int 21h
32 
33     mov si, offset y
34     mov cx, len2/2
35     mov ah, 2
36  s2:mov dx, [si]
37     or dl, 30h
38     int 21h
39 
40     mov dl, ' '
41     int 21h
42 
43     add si, 2
44     loop s2
45 
46     mov ah, 4ch
47     int 21h
48 code ends
49 end start

运行结果:

运算符offset:返回数据标号的偏移地址,按字节计算

伪指令equ:给字符串,寄存器,指令等取别名

预定义符号$:当前指令的偏移地址

 反汇编结果:

由反汇编得到的机器码可知,位移量为F2(补码),即-14(十进制原码)。

从CPU角度,

(1)先读取E2 F2进入指令缓冲器

(2)IP指向下一条指令的偏移地址,即001B

(3)执行指令缓冲器中的指令E2 F2,IP(001B)加上位移量 F2,27-14=13,000DH

(4)执行之后(IP)=000DH

反汇编结果:

 方法同问题1完全相同,位移量为F0(补码),即-16(十进制原码)

从CPU角度,

(1)先读取E2 F0进入指令缓冲器

(2)IP指向下一条指令的偏移地址,即0039H

(3)执行指令缓冲器中的指令E2 F0,IP(0039H)加上位移量 F0,0029H

(4)执行之后(IP)=0029H

实验任务2

<task3_2.asm>

 1 assume cs:code, ds:data
 2 
 3 data segment
 4     dw 200h, 0h, 230h, 0h
 5 data ends
 6 
 7 stack segment
 8     db 16 dup(0)
 9 stack ends
10 
11 code segment
12 start:  
13     mov ax, data
14     mov ds, ax
15 
16     mov word ptr ds:[0], offset s1
17     mov word ptr ds:[2], offset s2
18     mov ds:[4], cs
19 
20     mov ax, stack
21     mov ss, ax
22     mov sp, 16
23 
24     call word ptr ds:[0]
25 s1: pop ax
26 
27     call dword ptr ds:[2]
28 s2: pop bx
29     pop cx
30 
31     mov ah, 4ch
32     int 21h
33 code ends
34 end start

分析过程:

s1的偏移地址送到ds:[0],s2的偏移地址送到ds:[2];

call word ptr指令执行的时候,首先把下一条指令的偏移地址入栈,相当于push IP

call dword ptr,下一条指令的段地址和偏移地址都要入栈,相当于push CS,push IP

line 24 执行时,IP指向s1,把s1的偏移地址0021入栈,然后jmp到ds:[0]执行pop ax,此时ax=0021;

line 27 执行时,IP指向s2,依次把s2的段地址076C和偏移地址0026入栈,然后jmp到ds:[2]执行pop bx,此时bx=0026;再执行pop cx,此时cx=076C;

综上所述,ax=0021,bx=0026,cx=076C

调试过程:

 单步执行,ds:[0]存储0021,pop ax 后ax为0021

 执行到mov ah,4c,各寄存器内容如图,符合预期:

 实验任务3

编写8086汇编源程序task3.asm,在屏幕上以十进制形式输出data段中这一组连续的数据,数据和数据 之间以空格间隔。

<task3_3.asm>

 1 assume cs:code,ds:data
 2 
 3 data segment
 4     x db 99,72,85,63,89,97,55
 5     len equ $-x
 6 data ends
 7 
 8 code segment
 9 start:
10     mov ax,data
11     mov ds,ax
12     mov bx,0
13     mov cx,len
14 s:  call printNumber
15     call printSpace
16     add bx,1
17     loop s
18     mov ax,4c00h
19     int 21h
20 printNumber:
21     push ax
22     push bx
23     push cx
24     push dx
25 
26     mov si,0 ;记录位数
27     ;经过调试发现,若直接mov ax,ds:[bx],ax高位存放的是代表十六进制数的H,最后除法的时候会有问题
28     mov ah,0 
29     mov al,ds:[bx] ;低位放真正的被除数
30     ;mov ax,ds:[bx]
31 convert:
32     mov dx,0 ;被除数高位置0,防止干扰
33     mov cx,10 ;除数
34     div cx
35 
36     add dx,30h ;余数转为字符
37     push dx ;分离出的字符暂时保存到栈;堆栈操作是以字为单位
38 
39     inc si
40     mov cx,ax ;商为0结束
41     jcxz back
42     jmp convert
43 back:
44     mov cx,si
45 s1:
46     pop bx
47     mov ah,2
48     mov dl,bl
49     int 21h
50     loop s1
51 
52     pop dx
53     pop cx
54     pop bx
55     pop ax  
56     ret
57 printSpace:
58     mov ah,2
59     mov dl,32
60     int 21h
61     ret
62 code ends
63 end start

数值在debug中以十六进制展示(实际上以二进制存储)

在把数据放入被除数ax寄存器时,因为是字节数据,若直接mov ax,ds:[bx],会把代表十六进制的H也赋给AH,导致后续除法结果错误,如下图数值99(十六进制为63H)存放为4863:

 修改方法:让ah为0,al存放被除数,运行结果:

本题因为使用栈暂时存放数据,所以使用16位除数,若不使用栈,也可以用8位寄存器作除数。

实验任务4

<task3_4.asm>

 1 assume cs:code,ds:data
 2 data segment
 3     str db 'try'
 4     len equ $ - str
 5 data ends
 6 code segment
 7 start:
 8     mov ax,data
 9     mov ds,ax
10 
11     mov bh,0 ;指定行
12     mov bl,2 ;字符串颜色
13     mov cx,len ;字符串长度
14     mov si,0
15     call printStr
16 
17     mov bh,24 ;指定行
18     mov bl,4 ;字符串颜色
19     mov cx,len ;字符串长度
20     mov si,0
21     call printStr
22     mov ax,4c00h
23     int 21h
24 printStr:
25     push bx
26     push cx
27     push si
28 
29     mov ax,0b800h
30     mov es,ax
31     mov ax,160
32     mul bh     ;ax=显示区域的偏移地址
33 
34     mov di,ax
35     mov cx,len
36 s0:
37     mov ax,ds:[si]
38     mov es:[di],ax
39     mov es:[di+1],bl
40     inc si
41     add di,2
42     loop s0
43 
44     pop si
45     pop cx
46     pop bx
47     ret
48 code ends
49 end start

运行结果:

 实验任务5

在80×25彩色字符模式下,在屏幕最后一行正中间显示学号。要求输出窗口蓝底,学号和两侧折线,以 白色前景色显示。

 <task3_5.asm>

 1 assume cs:code,ds:data
 2 data segment
 3     stu_no db '201983300444'
 4     len = $ - stu_no
 5 data ends
 6 code segment
 7 start:
 8     mov ax,data
 9     mov ds,ax
10     mov ax,0b800h
11     mov es,ax
12 
13     mov si,0 ;偶地址存放字符
14     mov bx,1 ;奇地址存放颜色
15     mov cx,2000
16 s:
17     mov al,17h
18     mov es:[bx],al
19     add bx,2
20     loop s
21     mov bx,0f00h
22     call printLine
23     call printNum
24     mov bx,0f5ch
25     call printLine
26     mov ax,4c00h
27     int 21h
28 
29 printLine:
30     mov cx,34
31 s1:
32     mov byte ptr es:[bx],'-'
33     add bx,2
34     loop s1
35     ret
36 
37 printNum:
38     mov cx,len
39 s2:    
40     mov al,[si]
41     mov es:[bx],al
42     add bx,2
43     inc si
44     loop s2
45     ret
46 code ends
47 end start

设置背景颜色和前景文字颜色:直接设置属性即可,不用管字符。注意属性只占一个字节

测试结果:

 

 总结与分析:

1、注意操纵的是字节还是字

2、注意循环的跳出时机,跳出条件,跳出后续操作

3、灵活使用堆栈

posted @ 2021-11-28 16:20  dd摇摆  阅读(19)  评论(1)    收藏  举报