实验3 转移指令跳转原理及其简单应用编程
实验结论
1.实验任务1
task1.asm源码为:
1 assume cs:code, ds:data 2 3 data segment 4 x db 1, 9, 3 5 len1 equ $ - x ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是3 6 7 y dw 1, 9, 3 8 len2 equ $ - y ; 符号常量, $指下一个数据项的偏移地址,这个示例中,是9 9 data ends 10 11 code segment 12 start: 13 mov ax, data 14 mov ds, ax 15 16 mov si, offset x ; 取符号x对应的偏移地址0 -> si 17 mov cx, len1 ; 从符号x开始的连续字节数据项个数 -> cx 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 ; 取符号y对应的偏移地址3 -> si 34 mov cx, len2/2 ; 从符号y开始的连续字数据项个数 -> cx 35 mov ah, 2 36 37 s2:mov dx, [si] 38 or dl, 30h ;数值转换为相应的ASCII码 39 int 21h 40 41 mov dl, ' ' 42 int 21h 43 44 add si, 2 45 loop s2 46 47 mov ah, 4ch 48 int 21h 49 code ends 50 end start
task1的运行截图如下:

问题①:line27, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得到跳转后标号s1其后指令的偏移地址的。
答:由问题③中的图一可知跳转目的地址为000Dh,loop指令所在地址为0019h,加上loop指令的长度为2字节,因此跳转的位移量为14。
从cpu的角度,loop指令对应的机器码是E2F2h,通过查阅资料知道F2h是补码表示的偏移量,转换为十进制为-14,loop指令所在地址加上loop指令所占字节数减去这个偏移量就能得到目的地址000Dh。
问题②:line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明是如何计算得 到跳转后标号s2其后指令的偏移地址的。
答:由问题③中的图二可知跳转目的地址为0029h,loop指令所在地址为0037h,加上loop指令的长度为2字节,因此跳转的位移量为16。
从cpu的角度,loop指令对应的机器码是E2F0h,通过查阅资料知道F0h是补码表示的偏移量,转换为十进制为-16,loop指令所在地址加上loop指令所占字节数减去这个偏移量就能得到目的地址0029h。
问题③:附上上述分析时,在debug中进行调试观察的反汇编截图。
答:问题①反汇编截图如下:

问题②反汇编截图如下:
2.实验任务2
task2.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
① 根据call指令的跳转原理,先从理论上分析,程序执行到退出(line31)之前,寄存器(ax) = ? 寄存器(bx) = ? 寄存器(cx) = ?
答:从理论上分析,line24第一条call指令执行后,会先将下一条指令的IP,也就是s1的IP入栈,而s1的IP也就是offset s1,和ds:[0]中的值相同,所以(ax)=ds:[0]。
当line27第二条call指令执行后,会先将call指令的下一条指令的CS入栈,再将call指令的下一条指令的IP入栈,即s2的CS和IP入栈,所以line28 pop bx 出栈的是s2的IP值,也就是offset s2,和ds:[2]中的值相同,因此(bx)=ds:[2]。指令line29 pop cx 出栈的是cs的值,和ds:[4]中的值相同,所以(cx)=ds:[4]。
② 对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试 结果与理论分析结果是否一致。
答:通过debug调试,先用反汇编找到line31的地址值,再通过g命令运行到line31前,使用d命令查看ds段内的数据,发现和第一问中分析的结果相同。

3.实验任务3
task3.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 si,offset x ;x的初始偏移量:0 13 mov cx,len ;从符号x开始的连续字节数据项个数,即循环次数 14 15 s: call s1 16 call s2 17 inc si 18 loop s 19 mov ah, 4ch 20 int 21h 21 22 s1: mov al,ds:[si] ;printNumber子程序 23 mov ah,0 24 mov dl,10 25 div dl ;除数为8为,al存放商,ah存放余数 26 mov dx,ax 27 or dl,30h ;数值变为对应ascii码 28 mov ah,2 29 int 21h 30 mov dl,dh 31 or dl,30h 32 int 21h 33 ret 34 35 s2: mov ah,2 ;printSpace子程序 36 mov dl,' ' 37 int 21h 38 ret 39 code ends 40 end start
运行截图为:

4.实验任务4
task4.asm源码为:
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 15 mov cx,len 16 mov bl,02h ;颜色信息 17 mov bh,0 ;所在行数 18 call s1 19 20 mov cx,len 21 mov bl,04h 22 mov bh,24 23 call s1 24 mov ah, 4ch 25 int 21h 26 27 s1: ;子程序printStr 28 mov si,offset str ;str的初始偏移量:0 29 mov ah,0 30 mov al,bh 31 mov dl,160 ;80x25彩色显示模式中一行80字符,占160字节 32 mul dl ;乘数为8为,结果存放在ax中 33 mov di,ax ;得到从b8000H开始到bh行之间的字符个数 34 s: 35 mov ah,ds:[si] 36 mov es:[di],ah ;把要输出的字符放在显存地址低八位中 37 inc di 38 mov es:[di],bl ;将输出格式信息放在显存高八位中 39 inc di 40 inc si 41 loop s 42 ret 43 code ends 44 end start
运行截图为:

5.实验任务5
task5.asm源码为:
1 assume cs:code, ds:data 2 3 data segment 4 stu_no db '201983290494' 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 15 mov cx,2000 ;80x25彩色显示模式中一行80字符,一共25行,共2000个字符,故循环2000次 16 mov di,1 17 s0: ;将输出窗口置为蓝底 18 mov byte ptr es:[di],00010111B 19 add di,2 20 loop s0 21 22 mov ax,80 23 sub ax,len 24 mov bh,2 25 div bh 26 mov bh,0 27 mov bl,al ;计算出左右两侧虚线的长度,即(一行符号数-学号所占符号数)/2,保存在bx中 28 mov di,0f00h ;从最后一行最左侧开始输出,即24×160个字节 29 mov cx,bx 30 call s1 ;打印左半侧虚线 31 mov si,offset stu_no 32 mov cx,len 33 call s2 ;打印学号 34 mov cx,bx 35 call s1 ;打印右半侧虚线 36 mov ah, 4ch 37 int 21h 38 39 s1: mov byte ptr es:[di],'-' 40 add di,2 41 loop s1 42 ret 43 44 s2: mov al,ds:[si] 45 mov es:[di],al 46 add di,2 47 inc si 48 loop s2 49 50 code ends 51 end start
运行截图为:

实验总结
通过本次实验,我对转移指令的跳转原理、使用call和ret指令编写子程序以及彩色字符模式输出显示的编写有了进一步了解和掌握。
在实验中收获了以下知识点:
(1).“$” 是汇编语言中的一个预定义符号,等价于当前正汇编到的段的当前偏移值,实验中通过$来得到数据段的长度再通过equ来付给len,非常方便。
(2).loop指令在内存中占2个字节,后一个字节表示跳转指令相对loop指令的偏移量的补码,cpu通过这个偏移量来得到目的地址。
(3).如果想将内存中的数值打印到屏幕上,需要先将数字转换为相应的ascii码值在输出,对于0-9通常加上30h或者和30h做或运算来转换。
(4).汇编程序中如果想将一个字符输出到屏幕上可以通过int 21h来实现,但要提前将ah赋值2来控制int 21h使其有输出dl的功能。或者通过将字符存储到显存内存单元中来实现,存储到内存单元时占16位,低8位表示要输出的数据,高八位表示输出的字体颜色格式。

浙公网安备 33010602011771号