王爽《組合語言》第三版 第十章 實驗十
1、顯示字串
程式碼如下:
assume cs:code
data segment
db 'Welcome to masm!', 0
data ends
code segment
start: mov dh, 8
mov dl, 3
mov cl, 2
mov ax, data
mov ds, ax
mov si, 0
call show_str
mov ax, 4 c00h
int 21h
show_str: push ax
push bx
push cx
push dx
push es
push di
push si
;根據上節中的框架,為了不讓子程式干擾主程式中暫存器的值,將所有子程式會用到的暫存器進行壓棧
mov ax, 0b800h
mov es, ax
;顏色區的段地址
mov al, 160
mul dh
;每行佔160個位元組,乘以行數
push ax
;將行計算的結果儲存到棧中
mov al, 2
mul dl
;每列佔2個位元組,乘以列數
pop bx
;將上次運算的結果(160×行數)的值轉移到bx中
add bx, ax ;此時的ax值為(2×列數)
;將兩者相加,最終結果儲存到bx中
mov dl, cl
;因為下面的跳轉指令jcxz需要用到cx暫存器,故需要將cl的值先儲存在dl中
mov di, 0
change: mov cl, ds:[di]
mov ch, 0
jcxz ok
mov ch, dl
mov es:[bx+si], cx
add si, 2
inc di
jmp short change
ok: pop si
pop di
pop es
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
執行結果
在8行3列處開始顯示綠色字串
2、解決除法溢位的問題
程式碼如下:
assume cs:code
data segment
dw 16 dup(0)
;此資料段用來臨時存放資料
data ends
code segment
start: mov ax, 4240h
mov dx, 000fh
mov cx, 0ah
mov bx, data
mov ds, bx
call divdw
mov ax, ds:[0]
mov dx, ds:[2]
mov cx, ds:[4]
mov ax, 4c00h
int 21h
divdw: push ds
push dx
push cx
push ax
mov ax, dx
mov dx, 0
div cx
;ax存放商,dx存放餘數
;根據公式,使用被除數高位除以除數得到的商×65536
;*65536等價於在低位加16個0,因此操作就會變得非常簡單
;使用被除數高位除以除數得到的餘數×65536+被除數的低位,再將得到的結果除以除數
;兩者的結果相加,即可得到32位/16位的無溢位結果
push dx
;使用棧臨時儲存餘數
mov dx, ax
mov ax, 0
mov ds:[0], ax
mov ds:[2], dx
pop dx
;彈出餘數,作為右運算元中被除數的高16位
pop ax
;得到被除數的低16位
push ax
;恢復棧頂資料,避免對主程式造成干擾
;將右運算元[]中的左運算元的低16位和被除數的低16位相加
;但是右運算元[]中的左運算元的低16位一定是全0的,因此我們可以省略這一步
;直接執行pop ax,將被除數的低16位作為右運算元的低16位
div cx
;ax存放商,dx存放餘數
;由於左運算元的低16位一定是全0,所以不必與其相加,直接將
;右運算元的低16位儲存到ds:[0]記憶體單元即可
mov ds:[0], ax
;商的低16位放到ds:[0]單元中
mov ds:[4], dx
;餘數放到ds:[4]單元中
;ds:[2]中一直儲存的都是商的高16位,且沒有被更改過,因此無須任何操作
pop ax
pop cx
pop dx
pop ds
ret
code ends
end start
執行結果
與書中結果一致
3、數值顯示
無註釋版:
assume cs:code
data segment
dw 123, 12666, 1, 8, 3, 38
data ends
ascii segment
db 100 dup(0)
ascii ends
code segment
start: mov bx, data
mov ds, bx
mov si, 0
call dtoc
mov cx, 6
mov ax, 0
mov dh, 8
show: push cx
mov dl, 3
mov cl, 2
call show_str
pop cx
inc dh
loop show
mov ax, 4c00h
int 21h
dtoc: push ax
push bx
push cx
push dx
push ds
push si
push es
mov ax, ascii
mov es, ax
mov di, 0
mov cx, 6
loop_zone: push cx
mov dx, 0
mov ax, ds:[si]
split: push dx
mov cx, 0ah
mov dx, 0
div cx
mov cx, dx
pop dx
push cx
inc dx
mov cx, ax
add cx, dx
jcxz ok1
jmp short split
ok1: pop ax
add al, 30h
mov byte ptr es:[di], al
inc di
dec dx
mov cx, dx
jcxz last
jmp short ok1
last: mov ah, 0
mov byte ptr es:[di], ah
inc di
pop cx
add si, 2
loop loop_zone
pop es
pop si
pop ds
pop dx
pop bx
pop cx
pop ax
ret
show_str: push bx
push cx
push dx
push ds
push es
push di
push ax
push si
mov di, ax
mov ax, 0b800h
mov es, ax
mov ax, ascii
mov ds, ax
mov al, 160
mul dh
push ax
mov al, 2
mul dl
pop bx
add bx, ax
mov dl, cl
change: mov cl, ds:[di]
mov ch, 0
inc di
jcxz ok2
mov ch, dl
mov es:[bx+si], cx
add si, 2
jmp short change
ok2: pop si
pop ax
mov ax, di
pop di
pop es
pop ds
pop dx
pop cx
pop bx
ret
code ends
end start
**
詳解版
assume cs:code
data segment
dw 123, 12666, 1, 8, 3, 38
data ends
ascii segment
db 100 dup(0)
;ascii碼值,一個位元組即可儲存
ascii ends
div segment
dw 16 dup(0)
;除法溢位計算需要使用該資料段來臨時儲存結果
div ends
code segment
start: mov bx, data
mov ds, bx
;ds段暫存器用來存放待處理的資料
mov si, 0
call dtoc
mov cx, 6
mov ax, 0
mov dh, 8
show: push cx
mov dl, 3
mov cl, 2
call show_str
pop cx
;我們需要更改行號來避免覆蓋
inc dh
loop show
mov ax, 4c00h
int 21h
dtoc: ;該子程式用於將數值型的數字轉換為字串
;十進位制數值轉換為ASCII碼值,轉換關係為:ascii=10進位制+30H
;要想將一個十進位制的整數拆分成一個一個的數值,那我們需要讓這個數
;除以10,然後將得到的結果依次入棧,除完之後再依次出棧,即可得到由高位到低位
;的所有數值,之後將這些值加上30H,即得到其對應的ASCII碼值,然後將這些
;ASCII碼值存放到一個數據段中,呼叫show_str函式,來在螢幕上顯示這些數值
;為了儲存轉換後的ASCII碼值,我們需要新開闢一個數據段
push ax
push bx
push cx
push dx
push ds
push si
push es
mov ax, ascii
mov es, ax
;使用es段暫存器來儲存轉換後的ascii碼值
mov di, 0
;儲存ASCII資料時用來指向ascii段中的每個記憶體單元
mov cx, 6
loop_zone: push cx
;因為內層迴圈會更改cx的值,所以我們需要使用棧結構來儲存cx的值
mov dx, 0
;記錄十進位制資料的位數
mov ax, ds:[si]
;ax存放被除數
split: push dx
;下面要用到dx暫存器,因此我們先儲存dx
mov cx, 0ah
;cx存放除數
mov dx, 0
;dx作為被除數高16位,置0
div cx
;32/16的除法運算,商儲存在ax中,餘數儲存在dx中
mov cx, dx
;call divdw
;其實用不著呼叫divdw,這個除法溢位問題不是真正的除法溢位問題
;我們只需要將被除數湊成32位的,除數當做16位的即可
;此程式返回運算後的商和餘數,分別儲存在ax和cx中
;如果被除數大於2550,al是無法存放商的,會造成溢位,因此,我們需要呼叫本實驗中第二個函式
;專門用於解決除法溢位問題的函式,雖然程式2解決的是32/16的除法運算的溢位問題,但是對於16/8位的
;除法運算也是完全適用的
;由於入棧時只能使用字型資料,所以我們壓入的是ax,此時需要將
;無關資料,也就是al置0
pop dx
;取出dx更改前的值
push cx
;餘數入棧
inc dx
;當迴圈終止的時候可以進行彈棧儲存操作了,但是我們需要一個標記,來標識我們需要
;彈出多少次,我們使用dx來進行儲存
mov cx, ax
add cx, dx
;ax中的值在下一次運算中一定會用到,dx中的值也有可能會用到(當被除數很大時)
;此時可以臨時儲存資料的只有cx了,因此我們直接將運算結果放到cx中
;一舉兩得
jcxz ok1
;處理過程是需要迴圈的,迴圈結束的條件是商==0
;我們只需要將執行jcxz指令即可,當cx的值位0的時候,它會自動跳轉到ok1迴圈的
jmp short split
ok1: pop ax
add al, 30h
mov byte ptr es:[di], al
inc di
dec dx
mov cx, dx
jcxz last
jmp short ok1
last: ;最後一步,在資料的ASCII資料形式的最後加上一個0
mov ah, 0
mov byte ptr es:[di], ah
inc di
;從split到ok1到最後一步是對data段中第一個資料的處理
;這個過程需要進行迴圈操作
;在這個迴圈中,di,bx是放在迴圈外的
pop cx
add si, 2
loop loop_zone
pop es
pop si
pop ds
pop dx
pop bx
pop cx
pop ax
ret
divdw: push ds
push dx
push cx
push ax
mov ax, div
mov ds, ax
mov dx, 0
;由於本程式中被除數是16位,但是divdw是32/16,所以我們需要將被除數的高位補16個0,也就是將dx置0
mov ax, dx
mov dx, 0
div cx
;ax存放商,dx存放餘數
;根據公式,使用被除數高位除以除數得到的商×65536
;*65536等價於在低位加16個0,因此操作就會變得非常簡單
;使用被除數高位除以除數得到的餘數×65536+被除數的低位,再將得到的結果除以除數
;兩者的結果相加,即可得到32位/16位的無溢位結果
push dx
;使用棧臨時儲存餘數
mov dx, ax
mov ax, 0
mov ds:[0], ax
mov ds:[2], dx
pop dx
;彈出餘數,作為右運算元中被除數的高16位
pop bx
;得到被除數的低16位
push bx
;恢復棧頂資料,避免對主程式造成干擾
;add ax, bx
;將右運算元[]中的左運算元的低16位和被除數的低16位相加
;但是右運算元[]中的左運算元的低16位一定是全0的,因此我們可以省略這一步
;直接執行mov ax, bx
mov ax, bx
div cx
;ax存放商,dx存放餘數
;由於左運算元的低16位一定是全0,所以不必與其相加,直接將
;右運算元的低16位儲存到ds:[0]記憶體單元即可
mov ds:[0], ax
;商的低16位放到ds:[0]單元中
mov ds:[4], dx
;餘數放到ds:[4]單元中
;ds:[2]中一直儲存的都是商的高16位,且沒有被更改過,因此無須任何操作
pop ax
pop cx
pop dx
mov ax, ds:[0]
;ax儲存商的低16位
mov dx, ds:[2]
;dx儲存商的高16位
mov cx, ds:[4]
;cx儲存餘數
pop ds
;之所以要在pop ds之前將資料轉移,是因為子程式divdw呼叫前,ds已經被使用
;指向的是其他的段,如果不在pop之前轉移資料,那麼div段的資料就無法獲取了
ret
show_str: push bx
push cx
push dx
push ds
push es
push di
push ax
push si
;根據上節中的框架,為了不讓子程式干擾主程式中暫存器的值,將所有子程式會用到的暫存器進行壓棧
mov di, ax
mov ax, 0b800h
mov es, ax
;顏色區的段地址
mov ax, ascii
mov ds, ax
;待輸出的ASCII碼值資料段
mov al, 160
mul dh
;每行佔160個位元組,乘以行數
push ax
;將行計算的結果儲存到棧中
mov al, 2
mul dl
;每列佔2個位元組,乘以列數
pop bx
;將上次運算的結果(160×行數)的值轉移到bx中
add bx, ax ;此時的ax值為(2×列數)
;將兩者相加,最終結果儲存到bx中
mov dl, cl
;因為下面的跳轉指令jcxz需要用到cx暫存器,故需要將cl的值先儲存在dl中
change: mov cl, ds:[di]
mov ch, 0
inc di
;我們需要記錄下di的值,下一輪迴圈還會用到它
;這樣一來,我們就需要調整入棧和出棧暫存器的位置了
;我們在pop di之前pop ax,然後使用ax來儲存di的值
jcxz ok2
mov ch, dl
mov es:[bx+si], cx
add si, 2
jmp short change
ok2: pop si
pop ax
mov ax, di
pop di
pop es
pop ds
pop dx
pop cx
pop bx
ret
code ends
end start
執行結果:
相關推薦
王爽《組合語言》第三版 第十章 實驗十
1、顯示字串 程式碼如下: assume cs:code data segment db 'Welcome to masm!', 0 data ends code segment start:
Java 線程第三版 第五章 極簡同步技巧 讀書筆記
prev ear ont java else 停止 第三版 不同的 結合 一、能避免同步嗎? 取得鎖會由於下面原因導致成本非常高: 取得由競爭的鎖須要在虛擬機的層面上執行很多其它的程序代碼。 要取得有競爭鎖的線程總是必須等到鎖被釋放後。 1. 寄
<深入理解計算機系統(第三版)》第一章
第一章 計算機系統漫遊 計算機系統是由硬體和系統軟體組成的,它們共同工作來執行應用程式. 1.1 資訊就是位+上下文 源程式實際上就是由一個值0和1組成的位(bit)序列,8個位被組織成一組,稱為位元組.每個位元組表示程式中某個文字字元. 大部分現代系統都是有ASCII標準表示文字字元,只由ASCII字
C語言程式設計(第三版) 第六章 實驗題 2 任務4
#include <iostream> #include<iomanip> #include<time.h> using namespace std; int main() { int flag,n1; char m; double i=0,a=0,
C語言程式設計(第三版) 第六章 實驗題 2 任務6
#include <iostream> #include<iomanip> #include<time.h> using namespace std; int main() { int flag,n1,n2; char m; double i=0,l
演算法導論第三版第六章 合併K個有序連結串列的三種解法(最小堆法和分治遞迴法)
題目要求是將k個有序連結串列合併為一個連結串列,時間複雜度限定為O(nlogk)。下面給出應用最小堆方法的兩個程式,最後再貼上利用分治遞迴法的程式碼,雖然時間複雜度不及堆方法,但思路相對簡單好理解。 (1)最小堆方法1 用一個大小為K的最小堆(用優先佇列+自定義降序實現)(
演算法導論第三版第四章思考題
4-1 a. T(n)=Θ(n4) 先用代入法證明T(n)≤cn4: T(n)≤2⋅c(n2)4+n4=(c8+1)n4 故T(n)=O(n4) 再用代入法來證明T(n)≥cn4: T(n)≥2⋅c(n2)4+n4=(c8+1)n4 故T(n
影象處理-離散傅立葉變換-數字影象處理第三版第四章內容
影象傅立葉變換方法有很多,可以通過空間光調製器輸入影象後在通過平行光照明經過傅立葉變換透鏡進行傅立葉變換,另一個方法就是利用計算機進行傅立葉變換,其中傅立葉變換有兩種演算法一種是DFT還有一種是FFT(快速傅立葉變換)。 首先我介紹一下影象的定義,影象是怎麼去得到的
深入理解計算機系統 第三版 第三章 家庭作業 答案
3.58long decode2(long x,long y,long z) { int ret; y=y-z; x=x*y; ret=y; ret<<=63; ret>>=63; return ret^x; }算術左移63再右移6
演算法導論 中文 第三版 第2-25章部分課後習題答案
由於最近在學習演算法相關的東西,發現課後的習題沒有答案,給我造成很大困擾,以下分享了從網上找到的答案連結: https://pan.baidu.com/s/1Vy2LjDxTOgYz5gdc0Cjrzg 密碼: nijb
【讀書筆記】演算法導論(第三版)第一章
練習: 1.1-1 給出現實生活中需要排序的一個例子或者現實生活中需要計算凸殼的一個例子 排序:淘寶銷量排序,凸殼:淘寶綜合排序 注:凸殼是一個點集中最小點集,就像一碗盛著飯的碗,凸殼就是那個碗 1.1-2 除速度外,在真實環境中還可能使用
Java語言程序設計(第三版)第二章課後習題答案(僅供參考)
[] main 是否 支付 都去 port span 時區 div 2.1 註意不同類型轉換 1 import java.util.Scanner; 2 3 public class Ch02 { 4 public static void main
組合語言 王爽(第三版)實驗十一
assume cs:codesg datasg segment db "Beginner's All-purpose Symbolic Instruction Code.",0 datasg ends stack segment db 16
《組合語言》(第三版)王爽第十二章實驗12個人方法記錄
assume cs:code code segment start: mov ax,cs mov ds,ax mov si,offset d0 mov ax,0 mov es,a
【組合語言】(王爽著第三版)實驗二
實驗二 實驗任務(一) 實驗前要求我們將書本P74的程式段按理論分析,將結果進行填空。之後用Debug,將該程式段寫入記憶體,逐條執行之後, 根據指令執行後的實際執行的結果填空如下。 mov ax,0021 mov ax , ffff &n
《組合語言第三版》王爽學習歷程——實驗16
編寫包含多個功能子程式的中斷例程 要求: 安裝一個新的int 7ch中斷例程,為顯示輸出提供如下功能: (1)、清屏; (2)、設定前景色; (3)、設定背景色; (4)、向上滾動一行; 入口引數說明如下。 (1)、用ah暫存器傳遞功能號:0表示
《組合語言(第三版)》王爽筆記(3)
第三章 暫存器(記憶體訪問) 使用0、1記憶體單元存放資料0420H, 則低地址單元0存放低位位元組20,高地址單元存放高位位元組04。 字單元:即存放一個字型資料(16位)的記憶體單元,由兩個地址連續的記憶體單元組成,高地址存放高位位元組,低地址存放低位位元組
《組合語言(第三版)》王爽筆記(10)CALL和RET指令
第十章 CALL和RET指令 call和ret也是轉移指令,它們都修改IP或同時修改CS和IP。他們經常被共同用來實現子程式設計。 ret指令用棧中資料修改IP,實現近轉移。使用方法:ret retf指令用棧中資料修改CS和IP,實現遠轉移。使用方法:retf
王爽《組合語言》第三版-實驗9 根據材料程式設計
assume cs:code,ds:data data segment ;在資料段定義字串 db 'Welcome to masm!' data ends code segment start: mov ax,data mov ds,ax mov ax,0b800h
組合語言王爽(第三版)第三章檢測點答案和解析
檢測點3.1 (1) 在DEBUG中,用 "D 0:0 lf" 檢視記憶體,結果如下: 0000:0000 70 80 F0 30 EF 60 30 E2-00 80 80 12 66 20 22 60 0000:0010 62 26 E6 D6 CC 2E