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

任务1

源码:

 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

 

 

 

 

所有循环指令都是短转移,对应机器码中为位移而不是地址

loop指令,先令cx的值减1,再判断cx不等于0,则跳转到标号处

对于这条loop指令的分析:

  s1标号处的地址是 000D ,即十进制的13;loop后面一条指令的地址是001B,即十进制27,相减得到-14,换成二进制原码是1000 1110,补码是1111 0010,十六进制补码就是F2,和机器码内容一致。

 

 

同样的,再来分析下面这个loop。

  s2标号地址是0029,loop后面一条地址的指令是0039,减一减,刚好差了十进制的16,换算成十六进制补码,-16(dec)=F0(hex补码)

 

 

任务2

 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

 

 执行到程序退出前,ax=0021h, bx=0026h, cx=076eh

下面进行分析:

  

第一个call,push ip,然后跳到s1;pop ax,把ip出栈,ax=ip 注意,这里的ip是call命令后面一条指令的ip

 

 同样的,第二个call,因为是call dword 所以执行的操作是先push cs,再push ip;然后pop的时候bx=ip,cx=cs

 

任务3

 

 1 assume cs:code, ds:data
 2 data segment
 3     x db  99,72,85,63,89,97,55 ;x=0
 4     len equ $- x    ;len=7
 5 data ends
 6 
 7 code segment
 8     start:
 9         mov ax,data
10         mov ds,ax
11 
12         mov si,offset x
13         mov cx,len
14         
15         do:
16             mov ax,[si]
17             mov ah,0
18             inc si
19             push ax ;保存寄存器状态
20             push bx ;保存寄存器状态
21             push cx ;保存寄存器状态
22             push dx ;保存寄存器状态
23 
24             mov bx,10
25             mov cx,0
26 
27             yazhan:
28                 mov dx,0
29                 div bx
30                 
31                 push dx
32                 inc cx
33                 
34                 cmp ax,0
35                 jz chuzhan
36                 
37                 jmp yazhan
38                 
39             chuzhan:
40                 pop dx
41                 printNumber:
42                     add dl,30h
43                     mov ah,2            
44                     int 21h
45                     
46             loop chuzhan
47                 
48                 pop dx
49                 pop cx
50                 pop bx
51                 pop ax
52 
53             printSpace:
54                 mov ah,2
55                 mov dl,' '
56                 int 21h
57 
58         loop do
59 
60 
61         mov ah, 4ch
62         int 21h
63 code ends
64 end start

结果截图

简要的说一下这题的思路:根据提示,要么输出字符,要么输出ASCII码。数字0-9有对应的ASCII码,所以需要先对每一个数字进行拆分,然后分别输出每一位的数字对应的ASCII码。拆分数字很简单,只要模10除10循环就好。在这题,利用栈,保存每一次得到的数,出栈的过程中转换成对应的ASCII码即可。

 

 

实验4

 

 1 assume cs:code,ds:data
 2 data segment
 3     str db 'try'
 4     len equ $- str
 5 data ends
 6 
 7 code segment
 8     start:
 9         mov ax,data
10         mov ds,ax
11         mov si,offset str
12         mov cx,3
13         mov ax,0b800h
14         mov es,ax
15         mov bx,0
16         printStr:
17             mov ax,[si]
18             mov ah,02h  ;绿色
19             mov es:[bx],ax
20             inc si
21             add bx,2
22         loop printStr
23 
24         mov si,offset str
25         mov cx,3
26         mov bx,0f00h
27         printStr2:
28             mov ax,[si]
29             mov ah,00000100b  ;红色
30             mov es:[bx],ax
31             inc si
32             add bx,2
33         loop printStr2
34 
35 
36 
37         mov ah, 4ch
38         int 21h
39 code ends
40 end start

 

 

 在这个任务点中,遇到了一些问题,暂时还没有想明白,先把问题放这里:

    len equ $- str 算到了str的长度,并保存在len中。在对cx进行赋值的时候,一开始想 mov cx,len 但是出现报错了,之前一个任务点这么干也没报错,难道这题因为是字符串的问题?
 还有一个问题,我们都知道一个字符占两个字节,高字节放颜色信息,低字节放内容。所以我们调颜色一般都改高字节部分就行了。对于这题,需要两次调用printStr,但是问题来了,如何知道这是第几次调用,并且设置对应的颜色呢。这显然需要用到分支语句,暂时还没学到。
  那么可不可以把颜色的设置放在子程序外面呢,可以是可以,但是有很多需要注意的地方,比如要防止覆盖ax,要注意大小,要找准位置,还不如再复制一次printStr改名叫printStr2,中间改一句话省力呢。
 
在后面的任务5中发现了,len = $ - str就可以不报错了,equ在任务4会错。
 

 任务5

 1 assume cs:code,ds:data
 2 data segment
 3     stu_no db '201983290386'
 4     len = $ - stu_no
 5     sign db '-'
 6     space db ' '
 7 data ends
 8 
 9 code segment
10     start:
11         mov ax,data
12         mov ds,ax
13         mov ax,0b800h
14         mov es,ax
15 
16         mov cx,24*80
17         blue:
18             mov si,offset space
19             mov ax,[si]
20             mov ah,00010111b
21             mov es:[bx],ax
22             inc si
23             add bx,2
24         loop blue
25 
26         mov cx,80
27         mov bx,0f00h
28         fill:
29             mov si,offset sign
30             mov ax,[si]
31             mov ah,00010111b
32             mov es:[bx],ax
33             inc si
34             add bx,2
35         loop fill
36 
37 
38         mov si,offset stu_no
39         mov cx,len
40         mov bx,0f00h
41         add bx,68 ;80-12
42         printStr:
43             mov ax,[si]
44             mov ah,00010111b  ;蓝底白字
45             mov es:[bx],ax
46             inc si
47             add bx,2
48         loop printStr
49 
50 
51         mov ah, 4ch
52         int 21h
53 code ends
54 end start

 

 

 

可能受到前两题的锤炼,第五题感觉没那么难。思路很简单,第一步:把背景都弄蓝,最后一行不管。第二步:最后一行全部用-填充,记得背景色改成蓝色。第三步:用学号覆盖中间那一块。这里在覆盖的时候需要简单的计算一下,学号是12位的,一行最多80个字符,也就是说首字符2处于的位置是0f00h+80-12(后面两个是10进制数)

通过这题 我还学会了在data区里设置变量,要用的时候就offset导一下就好了,很方便

 

posted @ 2021-11-25 21:26  星穹铁道  阅读(39)  评论(2编辑  收藏  举报