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

实验任务1

使用任何一款文本编辑器,录入8086汇编程序源码task1.asm。

task1.asm

复制代码
 1 assume cs:code, ds:data
 2 data segment
 3 x db 1, 9, 3
 4 len1 equ $ - x ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是3
 5 y dw 1, 9, 3
 6 len2 equ $ - y ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是9
 7 data ends
 8 code segment
 9 start:
10 mov ax, data
11 mov ds, ax
12 mov si, offset x ; 取符号x对应的偏移地址0 -> si
13 mov cx, len1 ; 从符号x开始的连续字节数据项个数 -> cx
14 mov ah, 2
15 s1:mov dl, [si]
16 or dl, 30h
17 int 21h
18 mov dl, ' '
19 int 21h ; 输出空格
20 inc si
21 loop s1
22 mov ah, 2
23 mov dl, 0ah
24 int 21h ; 换行
25 mov si, offset y ; 取符号y对应的偏移地址3 -> si
26 mov cx, len2/2 ; 从符号y开始的连续字数据项个数 -> cx
27 mov ah, 2
28 s2:mov dx, [si]
29 or dl, 30h
30 int 21h
31 mov dl, ' '
32 int 21h ; 输出空格
33 add si, 2
34 loop s2
35 mov ah, 4ch
36 int 21h
37 code ends
38 end start
复制代码

对源程序进行汇编、链接,得到可执行程序task1.exe,运行后,结合运行结果和注释,及必要的debug 调试: 理解运算符offset、伪指令equ、预定义符号$的灵活使用。 通过line5、line8,以及数据项的数据属性(字节、字、双字,等),可以方便计算出连续数据项的个数,而无需人工计数。 注*: 符号常量len1, len2不占用数据段内存空间

给出程序task1.asm源码,及,运行截图

上方源码,运行截图:

 

回答问题①

① line27, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明 是如何计算得到跳转后标号s1其后指令的偏移地址的。

反汇编截图:

图中可知loop s1的机器码为 E2F2,已知loop跳转指令为短距离跳转,跳转范围-128~127,故对应两位机器码F2,由于往低地址跳转,故跳转的位移量为F2的补码,即十进制14字节。

回答问题②

② line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机 器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明 是如何计算得到跳转后标号s2其后指令的偏移地址的。

反汇编截图:

 

 图中可知loop s2的机器码为 E2F0,与问题①同理,跳转的位移量为16字节

问题③

③ 附上上述分析时,在debug中进行调试观察的反汇编截图

见题①②

 

实验任务2

使用任何一款文本编辑器,录入8086汇编程序源码task2.asm。

task2.asm

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

① 根据call指令的跳转原理,先从理论上分析,程序执行到退出(line23)之前,寄存器(ax) = ? 寄存器 (bx) = ? 寄存器(cx) = ?

 理论上分析,程序退出之前,ax存的数据为offset s1,bx存的数据为offset s2,cx存的数据为cs

② 对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试结果与理论分析结果是否一致。

 

上图可知:offset s1为0021,offset s2为0026

 

g跳转至0028

 

 

 ax=0021  bx=0026  cx=076C,结论正确

 

实验任务3

针对8086CPU,已知逻辑段定义如下:

1 data segment
2 x db 99, 72, 85, 63, 89, 97, 55
3 len equ $- x
4 data ends

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

要求:

编写子程序printNumber

功能:以十进制形式输出一个两位数

入口参数:寄存器ax(待输出的数据 --> ax)

出口参数:无

编写子程序printSpace

功能:打印一个空格

入口参数:无

出口参数:无

在主体代码中,综合应用寻址方式和循环,调用printNumber和printSpace, 实现题目要求。 正确编写后,预期测试结果如下:

 

 附*:int 21h中的2号子功能说明如下:

  

1 ; 功能:输出单个字符
2 mov ah, 2
3 mov dl, ×× ; ××是待输出的字符,或其ASCⅡ码值
4 int 21h

 

源码:

复制代码
 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 si, offset x   ;取符号x对应的偏移地址0 -> si
13     mov cx, len   ;从符号x开始的连续字节数据项个数 -> cx
14     s1:
15     call printNumber
16     loop s1
17     mov ah, 4ch
18     int 21h
19 printNumber:
20     mov al,[si]
21     mov ah,0
22     mov bl,10
23     div bl
24     mov bl,ah
25     mov ah,2
26     mov dl,al  ;商
27     or dl,30h  ;ASC码转数字
28     int 21h
29     mov ah,2
30     mov dl,bl  ;余数
31     or dl,30h
32     int 21h
33     inc si
34     call printSpace
35     ret
36 printSpace:
37     mov ah,2
38     mov dl,' '
39     int 21h
40     ret
41 code ends
42 end start
复制代码

使用除法div实现两位数输出,注意ASC码的转换

 

实验任务4

针对8086CPU,已知逻辑段定义如下:

1 data segment
2 str db 'try'
3 len equ $ - str
4 data ends

编写8086汇编源程序task4.asm,在屏幕上以指定颜色、指定行,在屏幕上输出字符串。

要求: 编写子程序printStr

功能:在指定行、以指定颜色,在屏幕上显示字符串

入口参数

字符串首字符地址 --> ds:si(其中,字符串所在段的段地址—> ds, 字符串起始地址的偏 移地址—> si)

字符串长度 --> cx

字符串颜色 --> bl

指定行 --> bh (取值:0 ~24)

出口参数:无 ;

在主体代码中,两次调用printStr,使得在屏幕最上方以黑底绿字显示字符串,在屏幕最下方以黑 底红色显示字符串 正确编写后,预期测试结果如下:

正确编写后,预期测试结果如下:

 源码:

复制代码
 1 assume cs:code, ds:data
 2 
 3 data segment
 4     str db 'try'
 5     len equ $ - str
 6 data ends
 7 
 8 code segment
 9 start:  
10     mov ax, data
11     mov ds, ax
12     mov ax,0b800h
13     mov es,ax
14     mov si, offset str
15     mov cx, len
16     mov bh,0  ;指定行号
17     mov bl,00000010B  ;指定颜色绿
18     mov al,160  ;一行160字节
19     mul bh
20     mov di,ax  ;设置es:di为显存首地址
21 s0:
22     call printStr
23     inc si
24     add di,2
25     loop s0
26 ;重设入口参数    
27     mov si, offset str
28     mov cx, len
29     mov bh,24  ;指定行号
30     mov bl,00000100B  ;指定颜色红
31     mov al,160  ;一行160字节
32     mul bh
33     mov di,ax  ;设置es:di为显存首地址
34 s1:
35     call printStr
36     inc si
37     add di,2
38     loop s1
39    
40     mov ah, 4ch
41     int 21h
42 
43 ;在屏幕上以指定颜色、指定行,在屏幕上输出字符串
44 ;字符串长度cx,行bh,颜色bl,ds:si指向字符串的首地址
45 printStr:
46     mov al,ds:[si]
47     mov es:[di],al
48     mov es:[di+1],bl
49     ret
50     
51 code ends
52 end start
复制代码

运行截图:

 

 实验任务5

针对8086CPU,针对8086CPU,已知逻辑段定义如下:

1 data segment
2 stu_no db '20498329042'
3 len = $ - stu_no
4 data ends

 

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

注*: 1. 80×25彩色字符模式显示缓冲区结构,参见教材「实验9 根据材料编程」里的说明。 2. 编写程序实现时,将data段的学号换成自己的学号。

程序正确编写后,预期输出效果如下:

源码:

复制代码
 1 assume cs:code
 2 
 3 data segment
 4     stu_no db '201983290044'
 5     len = $ - stu_no
 6 data ends
 7 
 8 code segment
 9 start:   
10     mov ax,data
11     mov ds,ax
12     mov ax,0b800h
13     mov es,ax
14     mov di,1    ;设置es:di显存地址
15     mov cx,2000
16 s0:   
17     mov al,es:[di]
18     and al,0fh    ;清除原屏幕的颜色
19     or al,10h    ;设置蓝色背景
20     mov es:[di],al
21     add di,2
22     loop s0
23     mov bx,0f00h               ;设置最后一行第一列为首地址   
24     mov cx,80
25 s1:
26     mov al,'-'
27     mov  ah,17h    ;设置蓝底白字
28     mov es:[bx],ax 
29     add bx,2                    ;指向下一显存单元
30     loop s1
31     mov si,offset stu_no
32     mov bx,0f40h    ;设置最后一行中间列为首地址
33     mov cx,len
34 s2:
35     mov al,[si]
36     mov ah,17h    ;设置蓝底白字
37     mov es:[bx],ax
38     add bx,2
39     inc si
40     loop s2
41     mov ax,4c00h
42     int 21h
43 
44 code ends
45 end start
复制代码

运行截图:

 

 

实验总结

1、设置背景颜色除了用循环重写偶数位数据之外,还可以使用int 10h中断来实现,本次实验用循环重写了数据,踩了没清除原屏颜色的坑。

2、所有跳转指令之所以要记录下一行的偏移地址,是为了减去或者加上该跳转指令的字节数。而跳转指令的机器码所记录的跳转字节数,本身就是剔除或者包含该跳转指令字节数,

而何时包含何时剔除,向低地址跳转包含,反之,剔除。

 

posted @   kanokksk  阅读(90)  评论(2编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示