四、实验结论
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进栈,同时也因为单步执行保护现场,将下一条命令的CS、IP值也存入栈。
继续执行到line 27,栈内数据为:
可以看到下一条指令的IP、CS值进栈。
程序继续执行到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,'$'