实验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位表示要输出的数据,高八位表示输出的字体颜色格式。

posted @ 2021-11-28 15:07  stCQCQ  阅读(39)  评论(3)    收藏  举报