實驗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的原理
還學會了向顯存中寫入內容以格式化輸出字符
一個字符占兩個字節
低位字節是要輸出的字符,高位字節是字符的格式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM