实验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
 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

  • 回答问题

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

 

0Dh-1Bh=F2h 换算成十进制为-14,即跳转位移量是-14

CPU的角度,loop指令后,

跳转地址=loop指令后第一个字节的地址+(“标号”处的地址-loop指令后的第一个字节的地址 )

简单计算即:跳转地址=1Bh+(0Dh-1Bh)=0Dh

在计算机内,偏移量是用八位二进制补码表示,而补码的减法又要转换成加法来计算,实际计算过程如下:

1.首先算出8位偏移量——“标号”处的地址-loop指令后的第一个字节的地址

0000 1101(0D二进制补码形式)

0001 1011(1B二进制补码形式)

1110 0101(-1B的二进制补码形式)

0000 1101-0001 1011=0000 1101+1110 0101=1111 0010(F2的二进制补码形式)

计算机内,机器码用补码表示,可以看到机器码E2F2,F2则是表示计算出的偏移量,换算成十进制-14。

2.算出偏移量后和loop指令后第一个字节首地址相加:

0001 1011+1111 0010=0000 1101(0D的二进制补码形式)

  • 回答问题

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

 

如问题①所示,偏移量=29h-39h=f0h 换算成十进制-16

CPU角度不再赘述。

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
  •  给出分析、调试、验证后,寄存器(ax) = ? (bx) = ? (cx) = ? 附上调试结果界面截图。

 

(ax)=0021 (bx)=0026 (cx)=076C

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

line 13-14 将数据段首地址赋值到ds寄存器

line 16-18 取标号s1的IP存入ds[0]地址,

取标号s2的IP存入下一个字节首地址即ds[2]地址,

cs段首地址存入下一个字节首地址即ds[4]

line 20-23 将栈段首地址赋值给ss寄存器并且将栈段指针指向栈顶

line 24 将下一条语句IP进栈,并且转移到ds[0]所指向地址,由前文可知是s1标号地址进栈

line 25 将当前栈顶指针指向数据赋值给bx,由上文可知是s1标号IP地址

line 27 程序继续向下执行,将下一条语句IP进栈,然后CS进栈,程序跳转到ds[2]所指向地址即s2标号地址

line 28 将当前栈顶指针指向数据赋值给bx,即当前地址CS值

line 28 将当前栈顶指针指向数据赋值给cx,即当前地址IP值

② 对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试

结果与理论分析结果是否一致。

 

对源程序反汇编可以看到,在line16处标号s1地址是0021,与下文s1标号出位置相符。line17同理。

程序执行前,栈内预存16个字节均为0

 

单步执行到line25,栈内数据为:

 

可以看到0021进栈,同时也因为单步执行保护现场,将下一条命令的CSIP值也存入栈。

继续执行到line 27,栈内数据为:

 

可以看到下一条指令的IPCS值进栈。

程序继续执行到line29,可以看到结果如下:

 

与理论分析结果一致。

3. 实验任务3


 

此部分书写内容:

  • 给出程序源码task3.asm
     1 assume cs:code, ds:data
     2 data segment
     3     x db 99, 72, 85, 63, 89, 97, 55 
     4     len equ $- x 
     5 data ends
     6 
     7 code segment
     8 start:    
     9     mov ax, data
    10     mov ds, ax
    11     mov si, offset x
    12     mov cx, len
    13     mov bl,10
    14  
    15  s1:mov ah,0
    16     mov al, [si]
    17     div bl
    18     or al,30h
    19     mov dh,al;存商
    20     or ah,30h
    21     mov bh,ah;存余数
    22    
    23     mov ah,2
    24     ;输出商位
    25     mov dl,dh
    26     int 21h
    27     ;输出余数位
    28     mov dl,bh
    29     int 21h
    30     ;输出空格
    31     mov dl, ' '
    32     int 21h
    33     
    34     inc si
    35     loop s1
    36  
    37    mov ah,4ch
    38    int 21h
    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     
    13     mov ax,0b800h
    14     mov es,ax
    15     mov bx,0h;第一行
    16 
    17     mov si,offset str
    18     mov cx,len
    19 s1: 
    20     mov dl,[si];低位存放字符Ascii码
    21     mov es:[bx],dl
    22     mov dl,2h;设置属性
    23     mov es:[bx+1],dl;属性放入显示地址 高位地址
    24     
    25     add bx,2
    26     inc si
    27     loop s1
    28 
    29     mov bx,0f00h;第25行
    30     mov cx,len
    31     mov si,offset str
    32 s2:
    33     mov dl,[si];低位存放字符Ascii码
    34     mov es:[bx],dl
    35     mov dl,4h;设置属性
    36     mov es:[bx+1],dl;属性放入显示地址 高位地址
    37     
    38     add bx,2
    39     inc si
    40     loop s2
    41 
    42 
    43     mov ah,4ch
    44     int 21h
    45 code ends
    46 end start
  • 运行测试截图

 

5. 实验任务5


 

此部分书写内容:

  • 给出程序源码task5.asm
     1 assume cs:code,ds:data
     2 
     3 data segment
     4     stu_no db '201983290480'
     5     len = $-stu_no
     6 data ends
     7 
     8 code segment
     9 start:
    10     mov ax,data
    11     mov ds,ax
    12 
    13     mov ax,0b800h
    14     mov es,ax
    15 
    16     mov bx,0
    17     mov cx,1920
    18     call s1
    19 
    20     mov bx,0f00h
    21 Tos2: mov cx,34
    22     call s2
    23 
    24     mov si,offset stu_no
    25     mov cx,len
    26     mov bx,0f44h
    27     call s3
    28 
    29     mov ah,4ch
    30     int 21h
    31  
    32  s1: 
    33     mov dl,' '
    34     mov es:[bx],dl
    35     mov dl,1fh
    36     mov es:[bx+1],dl
    37     add bx,2
    38     loop s1
    39     ret
    40   
    41 s2: 
    42     mov dl,'-'
    43     mov es:[bx],dl
    44     mov dl,1fh
    45     mov es:[bx+1],dl
    46     add bx,2
    47     loop s2
    48     ret
    49 
    50 s3: 
    51     mov dl,[si]
    52     mov es:[bx],dl
    53     mov dl,1fh
    54     mov es:[bx+1],dl
    55     add bx,2
    56     inc si
    57     cmp cx,1;如果=1,跳转
    58     je Tos2
    59     loop s3
    60     ret 
    61 
    62 code ends
    63 end start
  • 运行测试截图

 

五、实验总结 

知识点归纳:

1.EQU 伪指令把一个符号名称与一个整数表达式或一个任意文本连接起来,它有 3 种格式:

name EQU expression
name EQU symbol
name EQU <text>

第一种格式中,expression 必须是一个有效整数表达式。第二种格式中,symbol 是一个已存在的符号名称,已经用 = 或 EQU 定义过了。第三种格式中,任何文本都可以岀现在<...>内。当汇编器在程序后面遇到 name 时,它就用整数值或文本来代替符号。

= 伪指令不同,在同一源代码文件中,用 EQU 定义的符号不能被重新定义。这个限制可以防止现有符号在无意中被赋予新值。

2.$

“$” 是汇编语言中的一个预定义符号,等价于当前正汇编到的段的当前偏移值。例如eg:指令“jmp $+3”中的“$”表示当前这条指令在代码段中的偏移量

eg即“jmp $+3”表示要向前跳转到距离这条指令3个字节的地方。若是“jmp $-3”,则表示要向后跳转到距离这条指令3个字节的地方。

在汇编中是字符串结束的标志

如:DATA SEGMENT

MES1 'HELLO',0AH,0DH,'$'

posted @ 2021-11-30 14:11  sshen270  阅读(257)  评论(4编辑  收藏  举报