实验3 转移指令跳转原理及其简单应用编程
实验结论
1、实验任务1
task3-1.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
运行的截图:
回答问题:
1、line27, 汇编指令 loop s1 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机 器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明 是如何计算得到跳转后标号s1其后指令的偏移地址的。
当前IP
指向下一条指令开始地址,为001B
,十进制表示:27
根据公式:27 + (-14) = 13
13
的十六进制表示为:D
,跳转地址即000D
。
2、line44,汇编指令 loop s2 跳转时,是根据位移量跳转的。通过debug反汇编,查看其机 器码,分析其跳转的位移量是多少?(位移量数值以十进制数值回答)从CPU的角度,说明 是如何计算得到跳转后标号s2其后指令的偏移地址的。
当前IP
为0039
,十进制表示:57
根据公式:57 + (-16) = 41
41
的十六进制表示为:29
,跳转地址即0029。
3、附上上述分析时,在debug中进行调试观察的反汇编截图。
2、实验任务2
task3-2.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
回答问题:
1、根据call指令的跳转原理,先从理论上分析,程序执行到退出(line31)之前,寄存器(ax) = ? 寄存器 (bx) = ? 寄存器(cx) = ?
ax=0021h,bx=0026h,cx=076Ch 。
2、对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试结果与理论 分析结果是否一致。
对源程序进行汇编、链接并使用debug调试后得到的结果截图如下,与分析结果一致。
3、实验任务3
task3-3.asm源码:
1 assume ds:data, cs:code, ss:stack 2 3 data segment 4 x db 99, 72, 85, 63, 89, 97, 55 5 len equ $ - x 6 data ends 7 8 stack segment 9 dw 16 dup(?) 10 stack ends 11 12 code segment 13 start: 14 mov ax, data 15 mov ds, ax 16 17 mov ax, stack 18 mov ss, ax 19 mov sp, 32 20 21 mov cx, len ; 由于数据都是byte型,所以len就是数据个数 22 ; print循环: 依次打印所有数字 23 print: 24 mov ah, 0 ; 数据只有一个字节,先把ah置0,子函数中除法是以ax作为被除数的 25 mov al, byte ptr ds:[di] ; 把数据放入al 26 inc di ; di指针后移 27 28 push cx ; 把cx保存起来, 子程序中会修改cx值 29 30 call printNumber ; 打印数字 31 call printSpace ; 打印空格 32 33 pop cx ; 恢复cx 34 loop print 35 36 mov ah, 4ch 37 int 21h 38 39 ; 子程序: printNumber 40 ; 功能: 打印数字 41 ; 入口参数: 42 ; 寄存器ax (待输出的数据 --> ax) 43 ; 局部变量说明: 44 ; bx -> 存储数字字符个数 45 printNumber: 46 mov bx, 0 ; 获取之前位数为0 47 ; 逐位获取数字 48 ; getEach循环: 获取每一位,然后压入栈中 49 getEach: 50 mov dl, 10 51 div dl ; 数据除10 52 53 push ax ; 将数字压入栈中(ah余数在ax里了) 54 inc bx ; 位数+1 55 56 mov ah, 0 ; ah是余数,置0后ax表示除法的结果 57 mov cx, ax ; 除法结果赋给cx, 如果结果为0则说明所有位数都获取完了 58 inc cx ; 由于loop时会-1,这里先+1,防止出现负数 59 60 loop getEach 61 62 ; 打印数字 63 mov cx, bx ; 先把bx存的数字位数赋给cx 64 ; printEach循环: 依次从栈中取出数字,逐位打印 65 printEach: 66 pop ax ; 取出一位数 67 add ah, 30h ; ah是刚才除法的余数,也就是需要得到的位数,+30h是转成对应字符 68 mov dl, ah ; 放到dl, 用于打印 69 mov ah, 2 ; 调用int 21h的2号子程序打印 70 int 21h 71 loop printEach 72 73 ret 74 75 ; 子程序: printSpace 76 ; 功能: 打印空格 77 printSpace: 78 mov ah, 2 79 mov dl, 20h 80 int 21h 81 ret 82 83 code ends 84 end start
运行结果截图:
4、实验任务4
task3-4.asm源码:
1 assume cs:code, ds:data 2 data segment 3 str db 'try', 0 4 data ends 5 6 code segment 7 start: 8 mov ax, data 9 mov ds, ax 10 11 mov si, offset str 12 mov al, 2 13 call printStr 14 15 mov ah, 4ch 16 int 21h 17 18 printStr: 19 push bx 20 push cx 21 push si 22 push di 23 24 mov bx, 0b800H 25 mov es, bx 26 mov di, 0 27 s: mov cl, [si] 28 mov ch, 0 29 jcxz over 30 mov ch, al 31 mov es:[di], cx 32 inc si 33 add di, 2 34 jmp s 35 36 over: pop di 37 pop si 38 pop cx 39 pop bx 40 ret 41 42 code ends 43 end start
运行结果截图:
5、实验任务5
task3-5.asm源码:
1 assume cs:code, ds:data 2 3 data segment 4 stu_no db '201983290239' 5 len = $ - stu_no 6 data ends 7 8 code segment 9 start: 10 mov ax, data 11 mov ds, ax 12 mov di, 0 13 14 call printStuNum ; 调用打印子程序 15 16 mov ah, 4ch 17 int 21h 18 19 ; 打印子程序: 20 ; 参数说明: 21 ; 学号字符串存储在 -> ds:[di] 22 printStuNum: 23 mov ax, 0b800h 24 mov es, ax ; 控制显存区域段指针 25 mov si, 1 ; 显存区域列指针 26 27 ; 先把屏幕前24行背景打印成蓝色 28 mov al, 24 ; 前24行 29 mov dl, 80 ; 每行80个字符需要修改颜色 30 mul dl ; 24*80, 获得需要填充蓝色的字符数 31 32 mov cx, ax 33 printBlue: 34 mov al, 17h ; 蓝底+白字:0 001 0 111 -> 17h 35 mov es:[si], al ; 把颜色填充到位 36 add si, 2 ; 后移2个 37 loop printBlue 38 39 sub si, 1 ; 指针回退一个, 从最后一行起始位置开始 40 41 ; 打印最后一行 42 mov ax, 80 43 sub ax, len ; 80列 - 学号长度 44 mov dl, 2 45 div dl ; (80 - len)/2, 就是学号左右两侧需要填充'-'的长度 46 mov dx, ax ; 使用dx保存'-'的长度 47 48 ; 调用打印'-'的子程序, 打印学号左侧的'-' 49 mov cx, dx 50 call printSeparator 51 52 ; 打印学号字符串 53 mov cx, len 54 printNumber: 55 mov al, ds:[di] ; 低位是字符 56 mov ah, 17h ; 高位是颜色 57 mov word ptr es:[si], ax ; 按字放入 58 inc di 59 add si, 2 60 loop printNumber 61 62 ; 再次调用打印'-'的子程序, 打印学号右侧的'-' 63 mov cx, dx 64 call printSeparator 65 66 ret 67 68 ; 子程序: 打印分隔符'-' 69 ; 参数: 长度 -> cx 70 ; 位置 -> es:[si] 71 printSeparator: 72 mov al, '-' 73 mov ah, 17h 74 mov word ptr es:[si], ax 75 add si, 2 76 loop printSeparator 77 ret 78 79 code ends 80 end start
运行结果截图: