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

实验任务1

代码

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,ds:[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,ds:[si]
    or dl,30h
    int 21h

    mov dl,' '
    int 21h

    add si,2
    loop s2

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

代码功能简析

输出两行1 9 3
or 30h是为了转换为\(ASCII\)码输出。 \(30h\) 是ASCII中 \('0'\) 的编号,其二进制形式为:\(0011 0000\) ,所以or上一个 \(30h\) 表示输出从'0'开始偏移量为1 9 3的数字
如果 or 61h ,则输出的是偏移量减去 \(1\) 的小写字母。( \(61h\)\(0110 0001\) ,从1开始)
$ 是预定义符号,表示当前的偏移地址,使用 jmp $ ,可以进入死循环。

问题1


反汇编查看机器码,可以看到其机器码为 \(E2F2\)
\(E2\) 表示LOOP
\(F0\) 是补码形式的位移量, \(F2\) 转换为二进制为 \(11110010\)
将其转换为原码 \(1!(1110010-1) = 1!(1110001) = 10001110 = -8+-4+-2=-14\)
所以其位移量为 \(-14\) 。当前ip为 \(0x19\) ,即 \(25\)\(25-14=11\)
但是s1处的偏移量为 \(D\) ,即 \(13\)
所以整个转移的过程如下
ip指向 \(25\) 偏移处的指令,先取指令,然后ip自动 \(+2\) ,变为 \(27\) ,然后执行指令的过程中,将ip减去 \(14\) ,得到 \(13\) ,那么下一条要执行的指令就在偏移量为 \(13\) 的地方,即s1标号处。

问题2

重复问题1的操作步骤。
\(F0\) 的二进制形式为: \(11110000\)
得到其原码: \(1!(1110000-1) = 1!(1101111) = 10010000 = -16\)
为什么指令数量相同,但是位移量不同?原因出在incadd的指令占字节数不同。8086汇编采用动态指令长度,所以每条指令的长度都不是相同的。所以这里会有位移量的不同。
CPU计算得到s2之后指令的地址方式和问题1一样,这里不重复描述。

实验任务2

代码简析

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]
    ;push ip
    ;jmp word ptr ds:[0]
s1: pop ax
    ;(ax) = stack.top() = offset line23 + size(line23) = offset s1
    call dword ptr ds:[2]
    ;push cs
    ;push ip
    ;jmp dword ptr ds:[2]
s2: pop bx
    ;(bx) = stack.top() = offset line28 + size(line28) = offset s2
    pop cx
    ;(bx) = stack.top() = cs = code
    mov ah,4ch
    int 21h
code ends
end start

问题1

(ax) = offset s1
(bx) = offset s2
(cx) = cs = code

问题2

进入debug进行验证。
验证AX寄存器

验证BX寄存器

验证CX寄存器

实验任务3

实现代码

assume cs:code, ds:data
data segment
    x db 99, 72, 85, 63, 89, 97, 55
    len equ $ - x
data ends
code segment
start:
    mov ax,data
    mov ds,ax
    mov byte ptr ds:[len],10
    mov cx,7
    mov bx,0
s:  mov al,ds:[bx]
    mov ah,0
    inc bx
    call printNumber
    call printSpace
    loop s
    mov ah,4ch
    int 21h
printNumber:
    div byte ptr ds:[len]
    mov dx,ax
    mov ah,2
    or dl,30h
    int 21h
    mov ah,2
    mov dl,dh
    or dl,30h
    int 21h
    ret
printSpace:
    mov dl,' '
    mov ah,2
    int 21h
    ret
code ends
end start

使用call和ret实现子程序编写与调用。因为mov ah,2,int21h一次只能输出一个字符,所以采用除10将十位与个位分开输出。十位是商,个位是余数。ah保存余数,al保存商。

实现结果

实验任务4

代码

assume cs:code,ds:data
data segment
    str db 'try'
    len equ $ - str
data ends
stack segment
    db 16 dup(0)
stack ends
code segment
start:
    ;F00-F9F Last
    ;000-09F Fisrt
    ;cx len
    ;bl color
    ;bh line
    ;ds:si fist value of one string's address
    mov ax,data
    mov ds,ax
    ; mov byte ptr ds:[len],160
    mov ax,stack
    mov ss,ax
    mov sp,16
    
    mov bl,00000010B
    mov bh,0
    mov cx,3
    mov si,0
    call printStr

    mov bl,00000100B
    mov bh,24
    mov cx,3
    mov si,0
    call printStr

    mov ah,4ch
    int 21h
printStr:
    mov ax,0b800h;显存地址
    mov es,ax

    mov ax,0
    mov al,bh;行号
    mov dx,160
    mul dx
    mov di,ax

s:  mov al,ds:[si]
    mov es:[di],al
    inc si
    inc di
    mov es:[di],bl
    inc di
    loop s
    ret
code ends
end start

运行结果

实验任务5

代码

assume cs:code,ds:data
data segment
    stu_no db '201983290202'
    len equ $ - stu_no;学号的长度
    len1 equ 40-len/2;-的长度
data ends
stack segment
    db 16 dup(0)
stack ends

code segment
start:
    mov ax,data
    mov ds,ax
    mov bl,00010001B
    call setBgColor
    mov bl,00010111B
    call printID
    mov ah,4ch
    int 21h
printID:
    mov ax,0b800h
    mov es,ax

    mov ax,0
    mov al,24
    mov dx,0
    mov dl,160
    mul dl
    mov di,ax
    mov cx,len1
s1: mov es:[di],2dh
    mov es:[di+1],bl
    add di,2
    loop s1

    mov si,0
    mov cx,len
s2: mov al,ds:[si]
    mov es:[di],al
    mov es:[di+1],bl
    add di,2
    inc si
    loop s2

    mov cx,len1
s3: mov es:[di],2dh
    mov es:[di+1],bl
    add di,2
    loop s3
    ret
setBgColor:
    ;bl,颜色
    mov ax,0b800h
    mov es,ax

    mov di,0

    mov ax,0
    mov al,25
    mov dx,0
    mov dl,80
    mul dl
    mov cx,ax
    mov al,20h
s:  
    mov es:[di],al
    inc di
    mov es:[di],bl
    inc di
    loop s

    ret


code ends
end start

运行结果

实验总结

本次实验学习了跳转指令的编程以及子程序的编写,了解了loop的原理以及call和ret的原理
还学会了向显存中写入内容以格式化输出字符
一个字符占两个字节
低位字节是要输出的字符,高位字节是字符的格式

posted @ 2021-11-23 12:57  Alyjay  阅读(199)  评论(1编辑  收藏  举报