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

实验任务1

task1.asm源码:

assume cs:code, ds:data

data segment
    x db 1, 9, 3
    len1 equ $ - x

    y dw 1, 9, 3
    len2 equ $ - y
data ends

code segment
start:
    mov ax, data
    mov ds, ax

    mov si, offset x
    mov cx, len1
    mov ah, 2
 s1:mov dl, [si]
    or dl, 30h
    int 21h

    mov dl, ' '
    int 21h

    inc si
    loop s1

    mov ah, 2
    mov dl, 0ah
    int 21h

    mov si, offset y
    mov cx, len2/2
    mov ah, 2
 s2:mov dx, [si]
    or dl, 30h
    int 21h

    mov dl, ' '
    int 21h

    add si, 2
    loop s2

    mov ah, 4ch
    int 21h
code ends
end start

 

 

 

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

通过debug反汇编可以看到,跳转的位移量为F2h(16进制有符号数补码),转换为十进制为-14;

loop指令是段内转移,只修改IP;loop在指令中给出位移量,通过位移量实现跳转,且位移量的范围是-128~127;

本例中跳转的目的地址由loop下条指令的起始地址+偏移量得到,即0D=1B+F2(十六进制补码)或13=27+(-14)(十进制)

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

 

debug反汇编看到跳转的位移量为F0h,转换为十进制为-16;

本例中loop跳转的偏移地址同样由下条指令起始地址与偏移量相加得到,即29=39+F0(十六进制补码)或41=57+(-16)(十进制)

 
 
实验任务2
 task2.asm源码:
assume cs:code, ds:data

data segment
    dw 200h, 0h, 230h, 0h
data ends

stack segment
    db 16 dup(0)
stack ends

code segment
start:  
    mov ax, data
    mov ds, ax

    mov word ptr ds:[0], offset s1
    mov word ptr ds:[2], offset s2
    mov ds:[4], cs

    mov ax, stack
    mov ss, ax
    mov sp, 16

    call word ptr ds:[0]
s1: pop ax

    call dword ptr ds:[2]
s2: pop bx
    pop cx

    mov ah, 4ch
    int 21h
code ends
end start

 

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

代码分析:

line16和line17 分别将s1处偏移地址存入ds:[0]和将s2处偏移地址存入ds:[2];

line24 call指令将ds:[0]处的字数据作为跳转的偏移地址,在跳转之前将当前的IP即line25的偏移地址压栈;

line25 pop指令弹出的即是line25指令的偏移地址,即(ax)=指令(pop ax)的偏移地址

line27 同理,call将ds:[2]处的双字分别作为跳转的段地址和偏移地址,跳转前将当前的即line28的CS、IP依次压栈;

line28 pop指令先弹出后入栈的IP,即(bx)=指令(pop bx)的偏移地址

line29 pop后弹出先入栈的CS,即(cx)=指令(pop bx)的段地址

 

② 对源程序进行汇编、链接,得到可执行程序task2.exe。使用debug调试,观察、验证调试结果与理论
分析结果是否一致。
反汇编:
 

 

 

 

 g命令执行到0028:

 

 

可以看到,ax=0021(pop ax的偏移地址),bx=0026(pop bx的偏移地址),cx=076C(pop bx的段地址)

,和问题①的结论一致。

 

实验任务3:

task3.asm源码:

assume cs:code, ds:data
data segment
    x db 99,72,85,63,89,97,55
    len equ $ - x       ;len = 7
data ends
code segment
start:
    mov ax, data
    mov ds, ax
    mov si, 0
    mov bl, 0ah     ;除数为10
    mov cx, len     ;7个数,循环7次

s: 
    mov al, [si]    ;将十六进制数移入ax作为被除数
    mov ah, 0
    call printNumber    ;进入转十进制子程序
    call printSpace     ;进入打印空格子长徐
    inc si          ;下一个数
    loop s
    jmp exit        ;循环结束,退出程序

printNumber:        ;子程序,十六进制转十进制并输出
    div bl          ;除法
    mov dl, ah      ;商放入dl,准备输出
    mov dh, al      
    add dl, 30h     ;转换成对应数字的ASCII码
    mov ah, 2       
    int 21h         ;输出商
    mov dl, dh
    add dl, 30h
    int 21h         ;输出余数
    ret

printSpace:     ;子程序,输出一个空格
    mov dl, ' '
    int 21h     ;输出空格
    ret

exit:           ;退出程序
    mov ah, 4ch
    int 21h
code ends
end start

分析:

目标1字节十六进制转换成十进制输出;

用16位数除以0ah,得到的商和余数分别为十进制数的十位和个位;

将数据段中的每个十六进制数(8位)移入al,0移入ah,ax即为16位被除数;除数0ah移入bl,通过div bl得到商和余数;

得到的商和余数加上30h得到对应数字的ASCII码,通过int 21h输出;

对于每个16进制数,循环以上步骤

运行结果:

 

 实验任务4:

task4.asm源码:

assume cs:code, ds:data
data segment
    str db 'try'
    len equ $ - str
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov si, 0       ;数据段指针,指向try
    mov cx, len     ;几个字符循环几次
    mov bl, 02h     ;颜色
    mov bh, 0       ;行位置
    mov ax, 0b800h  
    mov es, ax      ;显示缓冲区段地址
    mov di, 0       ;显示缓冲区指针
    mov al, 0a0h    ;每行80个字符,每个字符2字节,每行160字节,用来确定行首
    call printStr   ;调用子程序
    mov si, 0       
    mov di, 0
    mov bl, 04h
    mov bh, 18h
    mov ax, 0b800h
    mov es, ax
    mov cx, len
    mov al, 0a0h
    call printStr
    jmp exit
    
printStr:   
    mul bh          ;确定行首在显示缓冲区的位置
    add di, ax      
s:  mov al, [si]        
    mov es:[di], al     ;移入字符ASCII码
    mov al, bl
    mov es:[di+1], al   ;移入属性(颜色)
    inc si              ;try指针+1,指向下个字符
    add di, 2           ;每个显示的字符占2字节,显示缓冲区指针+2
    loop s
    ret

exit:
    mov ah, 4ch
    int 21h
code ends
end start

分析:

将try的各个字符与设置的颜色依次交替放入显示缓冲区,形式如:'t' 02 'r' 02 'y' 02

分别用si和di保存数据和显示缓冲区的当前位置;

通过 a0h×行 确定行首位置,再依次将字符ASCII码、颜色移入显示缓冲区

 

运行结果:

 

 实验任务5

task5.asm源码:

assume cs:code, ds:data
data segment
    stu_no db '201983290219'
    len = $ - stu_no
data ends

code segment
start:
    mov ax, data
    mov ds, ax
    mov ax, 0b800h
    mov es, ax
    mov bl, 017h        ;字符的属性,蓝底白字
    mov si, 0           ;指向数据段的数据
    mov di, 0           ;指向显示缓冲区位置
    mov al, 050h        ;每行80个字符
    mov bh, 18h         ;0~23行只修改属性,不修改ASCII码
    mul bh              

    mov cx, ax          ;只修改背景色的部分
s:  mov es:[di+1], bl    
    add di, 2
    loop s

    mov cx, 022h        ;最后一行前半部分的--
s1: mov byte ptr es:[di], '-'
    mov es:[di+1], bl
    add di, 2
    loop s1

    mov cx, len          ;最后一行的学号
s2: mov al, [si]
    mov es:[di], al
    mov es:[di+1], bl
    inc si
    add di, 2
    loop s2

    mov cx, 023h            ;学号后面的--
s3: mov byte ptr es:[di], '-'
    mov es:[di+1], bl
    add di, 2
    loop s3

code ends
end start

分析:

0~23行只修改字符的属性为蓝底白字,共循环24行*80个字符次;

最后一行为34个'-' + 12位学号 + 35个'-' ,通过循环写入;

运行结果:

 

 

 

posted @ 2021-11-29 22:49  思念化为君  阅读(79)  评论(1编辑  收藏  举报