《匯編語言(王爽)第三版》實驗【未完待續】


實驗一:查看CPU和內存,用機器指令和匯編指令編程

(3) 在內存fff00H-fffffH的某幾個單元中可以看到rom的生產日期

 

 這里是2017年5月19日

(4)向b810寫數據

  

 在這里寫入的數據都會顯示在屏幕上

檢測點3.1

(1)在Debug中,用“d 0:0 1f”查看內存,結果如下

 

 實驗二:用機器指令和匯編指令編程

(1)用debug,將下面的程序寫入內存,逐條執行,根據指令執行后的實際運行情況填空

 

 

 

 

 實驗四:[bx]和loop的使用

1.編程,向內存0:200-0:23F依次傳送數據0~63(3FH)。

;P121 第五章實驗四 (1)
assume cs:code code segment main:
         mov ax,0020h mov ds,ax     ;指定段地址0200h

         mov bx,0h mov cx,003fh mov ax,0h s:   
         mov [bx],al inc bx inc al loop s mov ax,4c00h int 21h code ends end main
View Code

  2.編程,向內存0:200-0:23F依次傳送數據0~63(3FH),只能使用9條指令。

;P121 第五章實驗四 (2)
assume cs:code code segment main:
         mov ax,0020h mov ds,ax     ;指定段地址0200h
         mov bx,0h mov cx,003fh s:mov [bx],bl inc bl loop s mov ax,4c00h int 21h code ends end main
View Code

 3.補全下面的程序,其功能是將“mov ax,4c00”之前的指令復制到內存0:200處。

assume cs:code code segment main:
        mov ax,cs mov ds,ax mov ax,0020h mov es,ax        ;es=0020
        
        mov bx,0
        mov cx,17h s:    mov al,[bx] mov es:[bx],al inc bx loop s mov ax,4c00h int 21h code ends end main
View Code

  

  PS:指令的段地址是放在CS里面,所以第一個空是“cs”,由圖可以看出這些代碼一共長15h,但是cx要賦值17h

實驗五 編寫、調試具體多個段的程序

5) 

;默認是一次記錄到代碼段中的
assume cs:code a segment db 1,2,3,4,5,6,7,8 a ends b segment db 1,2,3,4,5,6,7,8 b ends cc segment db 0,0,0,0,0,0,0,0 cc ends code segment start:  mov ax,a mov ds,ax mov ax,b mov es,ax mov bx,0
        mov cx,8
        
   s:   mov al,ds:[bx] add es:[bx],al inc bx loop s mov ax,4c00h int 21h code ends end start
View Code

6)

assume cs:code a segment dw 1,2,3,4,5,6,7,8,0ah,0bh,0ch,0dh,0eh,0fh,0ffh a ends b segment db 0,0,0,0,0,0,0,0 b ends code segment start:  mov ax,a mov ds,ax mov ax,b mov ss,ax mov sp,16
        
        mov cx,8
        mov bx,0
        
   s:   push ds:[bx] add bx,2 loop s mov ax,4c00h int 21h code ends end start
View Code

 

實驗六:實踐課程中的程序

(1)7.1

;程序7.1 P 139
assume cs:code,ds:data data segment db 'unIX' db 'foRK' data ends code segment start:  mov al,'a'
            mov bl,'b'
            
            mov ax,4c00h int 21h code ends end start
View Code

 

(2)7.4

;大小寫轉換 P143 ; and or 的使用
assume cs:codesg,ds:datasg datasg segment db 'BaSiC' db 'iNforMaTiOn' datasg ends codesg segment start:  mov ax,datasg mov ds,ax mov bx,0
            mov cx,5
            
        ;第一個循環將第一段變成大寫
          s:mov al,[bx] and al,11011111B
            mov [bx],al inc bx loop s ;第二個循環將第二段變成小寫
            mov bx,5
            mov cx,11
         s0:mov al,[bx] or al,00100000B
            mov [bx],al inc bx loop s0 mov ax, 4c00h int 21h codesg ends end start
View Code

 


問題8.1:【圖片里的代碼沒有打完整,等我截完圖才發現,懶得改了Orz】

;問題8.1 p 171 ; 100001 / 100 = 1000 …… 1 ; 186A1H / 64H = 3E8H …… 1
assume cs:code data segment dd 100001  ;186A1 64
    dw 100     ;ax=86A1 dx=0001 6400 0000
    dw 0 data ends code segment start: mov ax,data mov ds,axq mov ax,ds:[0] mov dx,ds:[2] ;ax=86A1 dx=0001
           
           div word ptr ds:[4] mov ds:[6],ax mov ax,4c00h int 21h code ends end start
View Code


實驗七:【總算是擼出來了好開心,這里要感謝一位師傅,在自閉的時候給了我冷靜】

;實驗七
assume cs:codesg data segment db '1975','1976','1977','1978','1979','1980','1981','1982','1983' db '1984','1985','1986','1987','1988','1989','1990','1991','1992' db '1993','1994','1995'
    ;年份:每一個一個4字節,4*21 【0-53H】 
 dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,19514 dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
    ;每一個一個4字節,4*21 【54H-0A7H】
 dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226 dw 11542,14430,15257,17800
    ;員工數:每一個兩個字節,2*21 【0A8H-H】
 data ends table segment db 21 dup('year summ ne ?? ') table ends codesg segment start:
        mov ax,data mov ds,ax mov ax,table mov es,ax ;定義好了數據段
        
        mov cx,21
        mov bx,0
        mov si,0
        mov di,0
        mov ax,0
        mov ss,ax mov sp,2003H s:
            
            push cx mov ax,0[si] mov es:0[bx],ax mov ax,0[si+2] mov es:2[bx],ax ;年份賦值:每一次賦一個字,執行兩次,完成四個字節的賦值,si來遍歷年份
            
            mov ax,54H[si] mov es:5[bx],ax mov ax,54H[si+2] mov es:7[bx],ax ;收入賦值:每一次賦一個字,執行兩次,完成四個字節的賦值
            
            mov ax,0A8H[di] mov es:10[bx],ax ;雇員賦值:每一次賦一個字,執行一次,完成兩個字節的賦值
                        
            mov ax,54H[si] mov dx,54H[si+2]   ;賦值被除數
            mov cx,0A8H[di] div word ptr cx pop cx mov es:13[bx],al add bx,16 ;用bx控制行
            add si,4  ;用si控制年份和收入
            add di,2  ;用di控制雇員 
 loop s mov ax,4c00H int 21H codesg ends end start
View Code


實驗八:

八沒啥好說的,直接debug一下就可以了,值得一提的是jmp放的是偏移地址,而且 “ -u ” 的時候,要加 “ 0 ”才會顯示start前的指令


實驗九:顯示綠色、紅底綠色、白底藍色的welcome to masm!

  • 我先用python腳本寫出了“welcome.....”的十六進制表示
u="welcome to masm!" strs=""

# 綠字 # for i in u: # strs=strs+str(hex(ord(i)))[2:]+"h,"+"2h"+"," # print(strs) # print(len(strs.split(",")))

# 綠地紅字 # for i in u: # strs=strs+str(hex(ord(i)))[2:]+"h,"+"24h"+"," # print(strs) # print(len(strs.split(",")))

# 3.白底藍字
for i in u: strs=strs+str(hex(ord(i)))[2:]+"h,"+"0F1h"+","
print(strs) print(len(strs.split(",")))
View Code
  •  然后再是寫asm
;實驗9
assume cs:code data1 segment ;1.綠底字體
 db 77h,2h,65h,2h,6ch,2h,63h,2h,6fh,2h,6dh,2h,65h,2h,20h,2h,74h,2h,6fh,2h,20h,2h,6dh,2h,61h,2h,73h,2h,6dh,2h,21h,2h data1 ends data2 segment ;2.綠底紅字
 db 77h,24h,65h,24h,6ch,24h,63h,24h,6fh,24h,6dh,24h,65h,24h,20h,24h,74h,24h,6fh,24h,20h,24h,6dh,24h,61h,24h,73h,24h,6dh,24h,21h,24h data2 ends data3 segment ;3.白底藍字
 db 77h,0F1h,65h,0F1h,6ch,0F1h,63h,0F1h,6fh,0F1h,6dh,0F1h,65h,0F1h,20h,0F1h,74h,0F1h,6fh,0F1h,20h,0F1h,6dh,0F1h,61h,0F1h,73h,0F1h,6dh,0F1h,21h,0F1h data3 ends code segment start:
        mov ax,0b800h mov ds,ax ;1.綠底字體
        mov ax,data1 mov es,ax mov cx,32
        mov bx,0
        
        s1:
        mov al,es:[bx] mov ds:[bx+0a12h],al inc bx loop s1 ;2.綠底紅字
        mov ax,data2 mov es,ax mov cx,32
        mov bx,0
        
        s2:
        mov al,es:[bx] mov ds:[bx+0a32h],al inc bx loop s2 ;3.白底藍字
        mov ax,data3 mov es,ax mov cx,32
        mov bx,0
        
        s3:
        mov al,es:[bx] mov ds:[bx+0a52h],al inc bx loop s3 mov ax,4c00h int 21h code ends end start
View Code

 

 

 

 


10.10 參數和結果傳遞的問題

這里我改了一下代碼   mov [di].2,dx    的時候居然報錯有點迷

;P201
assume cs:code data segment dw 1,2,3,4,5,6,7,8 dd 0,0,0,0,0,0,0,0 data ends code segment start:
            mov ax,data mov ds,ax mov si,0
            mov di,16
            
            mov cx,8
        s:   
            mov bx,[si] call cube mov [di],ax mov [di+2],dx add si,2
            add di,4 loop s mov ax,4c00h int 21h cube:   mov ax,bx mul bx mul bx ret code ends end start
View Code


 

10.11 批量數據的傳遞

assume cs:code data segment db 'conversation' data ends code segment start:
        mov ax,data mov ds,ax     ;ds賦值
        
        mov si,0
        mov cx,12    ;設置循環體
        call capital   ;調用函數
        
        mov ax,4c00h int 21h capital:
        and byte ptr [si],11011111b   ;將字符轉為大寫
        inc si loop capital ret code ends end start
View Code

 


實驗十(1) 顯示字符串

在這次實驗中,我們將要編寫3個子程序,通過它們來認識幾個常見的問題和掌握解決這些問題的方法。同前面的所有實驗一樣,這個實驗是必須要獨立完成的,在后面的課程中,將要用到這個實驗中編寫的3個子程序。
1.  顯示字符串
問題:

顯示字符串是現實工作中經常要用到的功能,應該編寫一個通用的子程序來實現這個功能。我們應該提供靈活的調用接口,使調用者可以決定顯示的位置(行、列)、內容和顏色。

提示:
(1)  子程序的入口參數是屏幕上的行號和列號,注意在子程序內部要將它們轉化為顯存中的地址,首先要分析一下屏幕上的行列位置和顯存地址的對應關系:
(2)  注意保存子程序中用到的相關寄存器:
(3)  這個子程序的內部處理和顯存的結構密切相關,但是向外提供了與顯存結構無關的接口。通過調用這個子程序,進行字符串的顯示時可以不必了解顯存的結構,為編程提供了方便。在實驗中,注意體會這種設計思想。

子程序描述
名稱:show_str
功能:在指定的位置,用指定的顏色,顯示一個用0結束的字符串。
參數:(dh)=行號(取值范圍0~24),(dl)=列號(取值范圍0~79),
    (cl)=顏色,ds:si指向字符串的首地址
返回:無
就用舉例:在屏幕的8行3列,用綠色顯示data段中的字符串。

這一份是網上的答案,我結合自己的理解添加了注釋【感覺師傅寫的很謹慎,考慮地很完善】

 1 assume cs:code  2 data segment  3         db 'welcome to masm!',0
 4 data ends  5 
 6 code segment  7 start: 
 8    ;dx存放的是行列信息
 9     mov dh,8
10     mov dl,3
11     mov cl,2
12     mov ax,data 13     mov ds,ax 14     mov si,0
15     
16     call show_str 17     mov ax,4c00h 18     int 21h 19         
20 show_str:  
21 
22     ; 23     ;入棧儲存數據tt
24     ;   
25     push dx 26     push cx 27     push si 28     
29     ; 30     ;第八行定位【460-4ff】
31     ; 【7*a0=460】
32     mov bl,dh   ;行號賦值8
33     dec bl       ;行號自減一
34     
35     mov al,160     ;A0h【每一行的自增值】
36     
37     mul bl         ;將bl與al相乘結果放到ax中
38     mov bx,ax     ;結果賦值
39     ; 40     ;第三列定位【04-05】
41     ; 42     add dl,dl ;列號自增
43     ; 44     ;行列號拼接形成偏移地址
45     ; 46     add bl,dl 47     ; 48     ;設定顯示位置
49     ; 50     mov ax,0b800h 51     mov es,ax 52     
53     mov al,cl ;顏色賦值【后面要用cx來結束循環所以這里要把cx的數據先保存起來】
54     
55     mov di,0    ;數據初始化
56     s:     
57         mov ch,0
58         mov cl,ds:[si] 59         jcxz ok 60         ;將數據賦給cx,當cx為0的時候(到字符串尾)就會自動退出
61         
62         mov es:[bx+di],cl 63         mov es:[bx+di+1],al;顏色賦值【顏色設定在高位】
64         
65         add di,2 ;es段每次跳兩個字節
66         inc si  ;ds段每次跳一個
67  loop s 68     
69     ok:    
70         ; 71         ;數據恢復
72         ; 73         pop dx 74         pop cx 75         pop si 76         ret
77 code ends 78 end start

 

然后這一份是我自己寫的暴力版,當初完全沒get到,cl=2 有什么內涵 Orz

 1 ;實驗10(1)
 2 assume cs:code  3 data segment  4     db 'Welcome to masm!',0  ;17
 5 data ends  6 
 7 code segment  8     start:
 9         mov dh,8
10         mov dl,3
11         mov cl,2
12         mov ax,data 13         mov ds,ax 14         
15         mov si,0
16         call show_str 17         
18         mov ax,4c00h 19         int 21h 20         
21         
22     show_str: 
23         mov si,0466h 24         mov cx,17
25         
26         mov ax,0b800h 27         mov es,ax 28         
29         mov di,0
30         
31     s:    mov al,ds:[di] 32         mov es:[si],al 33         
34         mov ah,2
35         mov es:[si+1],ah 36         
37         add si,2
38         add di,1
39         jcxz ok 40  loop s 41         
42         
43     ok: ret
44 code ends 45 end start

 

 


 實驗十(2) 解決除法溢出

問題
前面講過,div指令可以做除法。當進行8位除法的時候,用al存儲結果的商,ah存儲結果的余數:進行16位除法的時候,用ax存儲結果的商,dx存儲結果的余數。可是,現在有一個問題,如果結果的商大於ah或ax所能存儲的最大值,那么將如何?比如,下面的程序段:

1  mov bh,1
2  mov ax,1000
3  div   bh

進行的是8位除法,結果的商為1000,而1000在ah中放不下,又比如,下面的程序段:

1 mov ax,1000h 2 mov dx,1
3 mov bx,1
4 div   bx

進行的是16位除法,結果的商為11000H,而11000H在ax中存放不下。我們在用div指令做除法的時候,很可能發生上面的情況:結果的商過大,超出了寄存器所能存儲的范圍。當CPU執行div等除法指令的時候。如果發生這樣的情況,將引發CPU的一個內部錯誤。這個錯誤被稱為:除法溢出。我們可以通過特殊的程序來處理這個錯誤,這里我們不討論這個錯誤的處理,這是后面的課程中要涉及的內容。

好了,我們已經清楚了問題的所在:用div指令做除法的時候可能產生除法溢出。由於有這樣的問題,在進行除法運算的時候要注意除數和被除數的值,比如1000000/10就不能用div指令來計算。那么怎么辦呢?我們用下面的子程序divdw解決。

子程序描述
名稱:divdw
功能:進行不會產生溢出的除法運算,被除數為dword型,除數為word型,結果為dword型。
參數:

    (ax)=dword型數據的低16位
    (dx)=dword型數據的高16位
    (cx)=除數
返回:

    (dx)=結果的高16位,(ax)=結果的低16位
    (cx)=余數
應用舉例:

  計算1000000/10(F4240H/0AH)

1 mov ax,4240h 2 mov dx,000fh 3 mov cx,0ah 4 call divdw

結果:

   (dx)=0001h,(ax)=86a0h,(cx)=0

提示

給出一個公式:
X:被除數,范圍:[0,FFFF FFFF]
N:除數,范圍:[0,FFFF]
H:X高16位,范圍:[0,FFFF]
L:X低16位,范圍:[0,FFFF]
int():描述性運算符,取商,比如:rem(38/10)=8
rem():描述性運算符,取答數,比如:rem(38/10)=8


公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N


這個公式將可能產生溢出的除法運算:X/N,轉變為多個不會產生溢出的除法運算。公式中,等號右邊的所有除法運算都可以用div指令來做,肯定不會導致除法溢出。

 

這里我寫到pop ax就與網上的答案產生分歧了,后來才知道沒有好好理解王爽老師提供的公式的含義:

1 進行的是1000000/10
2 
3 000f 4240h / 0ah = 1h*10000h+[5*10000h+4240h]/0ah 4  = 10000h+54240h/ah 5  = 10000h+86a0h 6  = 186a0h 7 其中: 8 f / a = 1……5

 

 也就是說高位除的時候,它的商是結果的高位,它的余數是低位除的高位

 1 ;實驗十(2)
 2 
 3 assume cs:code  4 
 5 stack segment  6     dw 8 dup(0)  7 stack ends  8 
 9 code segment 10     start:
11             mov ax,stack 12             mov ss,ax 13             mov sp,16
14             
15             mov ax,4240h 16             mov dx,000fh 17             mov cx,0ah 18             ;[ dx ax ] / cx = [dx ax] …… cx
19             call divdw 20             
21             mov ax,4c00h 22             int 21h 23             
24     divdw:  ;[x/n = int()/n*65536+mod()/n] 12/3 = (1*10 + 2)/3 = [int(12/10)*10 + mod(12/10)]/3 =int(12/10)*10/3 + mod(12/10)/3= 1 + 3 
25             ;將高位與除數做運算
26             push ax    ;將L存放起來
27             
28             mov ax,dx  ;將ax轉化為H
29             mov dx,0   ;將余數位清零
30             div cx       ;int(H/N)=ax,rem(H/N)=dx
31             
32             mov bx,ax  ;將int(H/N)的值存起來[這是已經得到的高位]
33             
34             ;將低位與除數做運算
35             pop ax     ;將L賦值給ax,rem(H/N)=dx
36             div cx        ; 37             
38             mov cx,dx  ;cx放余數
39             mov dx,bx  ;dx放商的高位,ax默認低位
40     
41             ret
42 code ends 43 end start

 

實驗十(3) 解決除法溢出

問題
編程,將data段中的數據以十進制的形式顯示出來。

1 data segment 2 dw  123,12666,1,8,3,38
3 data ends

  這些數據在內存中都是二進制信息,標記了數值的大小。要把它們顯示到屏幕上,成為我們能夠讀懂的信息,需要進行信息的轉化。比如,數值12666,在機器中存儲為二進制信息:0011000101111010B(317AH),計算機可以理解它。而我們要在顯示器上讀到可以理解的數值12666,我們看到的應該是一串字符:“12666”。由於 顯卡遵循的是ASCII編碼,為了讓我們能在顯示器上看到這串字符,它在機器中應以ASCII碼的形式存儲為:31H、32H、36H、36H、36H(字符“0”~“9”對應的ASCII碼為30H~39H)。

  通過上面的分析可以看到,在概念世界中,有一個抽象的數據12666,它表示了一個數值的大小。在現實世界中它可以有多種表示形式,可以在電子機器中以高低電平(二進制)的形式存儲,也可以在紙上、黑板上、屏幕上以人類的語言“12666”來書寫。現在,我們面臨的問題就是,要將同一抽象的數據,從一種表示形式轉化為另一種表示形式。
  可見,要將數據用十進制形式顯示到屏幕上,要進行兩步工作:
(1)  將用二進制信息存儲的數據轉變為十進制形式的字符串:
(2)  顯示十進制形式的字符串。
第二步我們在本次實驗的第一個子程序中已經實現,在這里只要調用一下show_str即可。我們來討論第一步,因為將二進制信息轉變為十進制形式的字符串也是經常要用到的功能,我們應該為它編寫一個通用的子程序。

子程序描述
名稱:dtoc
功能:將word型數據轉變為表示十進制數的字符串,字符串以0為結尾符。
參數:

    (ax)=word型數據
    ds:si指向字符串的首地址
返回:無
應用舉例:編程,將數據12666以十進制的形式在屏幕的8行3列,用綠色顯示出來。在顯示時我們調用本次實驗中的第一個子程序show-str。

提示
  下面我們對這個問題進行一下簡單地分析。
(1)  要得到字符串“12666”,就是要得到一列表示該字符的ASCII碼:31H、32H、36H、36H、36H。十進制數碼字符對應的ASCII碼=十進制數碼值+30H要得到表示十進制數的字符串,先求十進制數每位的值。例:對於12666,先求得每位的值:1、2、6、6、6。再將這些數分別加上30H,便得到了表示12666的ASCII碼串:31H、32H、36H、36H、36H。
(2)  那么,怎樣得到每位的值呢?采用如圖10.2所示的方法。

 1 dtoc:
 2         push ax  3         push bx  4         push si  5             mov bx,10
 6             mov si,0
 7             
 8         s1:  
 9                         ;取出每一位並且將它轉化為字符放到棧段里面
10             mov dx,0
11             div bx 12             add dx,30h 13             push dx 14             
15             inc si    ;記錄一共push幾個數字
16             mov cx,ax 17             Inc cx 18  loop s1 19                      
20            mov cx,si 21            mov si,0
22         s2:
23            pop ds:[si] 24            add si,1 
25  loop s2 26         
27         pop si 28         pop bx 29         pop ax 30     ret    

 

 

 后記:

一開始是打算這樣寫的,但是出現了報錯,錯誤點是第17行。實際上當ax變成0的時候 loop,cx 默認自減一,然后cx就變成負的了,沒有達到當ax變成零自動退出的目的,而且也沒有三個push來保存數據,還是保有着C/C++當中的局部變量的思想Orz。這里數據恢復很重要啊

 1 dtoc:
 2             mov bx,10
 3             mov si,0
 4             
 5         s1:  
 6                         ;取出每一位並且將它轉化為字符放到棧段里面
 7             mov dx,0
 8             div bx  9             add dx,30h 10             push dx 11             
12             inc si    ;記錄一共push幾個數字
13             mov cx,ax 14  loop s1 15             push ax 16                      
17            mov cx,si 18            mov si,0
19         s2:
20            pop ds:[si] 21            add si,1 
22  loop s2 23 ret    

 


 實驗十一:

;實驗十一
assume cs:codeseg

dataseg segment
	db "Beginner's All-purpose Symboliv Instruction Code.",0
dataseg ends

codeseg segment
	begin:
		mov ax,dataseg
		mov ds,ax       ;數據段初始化
 		mov si,0		;data:[0]
		call letters
		
		mov ax,4c00h
		int 21h

letters:
s:	mov cl,ds:[si]	;ds:[si]  => 將data段的每一位賦值給cl,那么當讀到最后一位的0就會退出循環
	jcxz ok         ;當cx為0的時候跳轉到ok
	mov bl,97		;97 ascii 是一個“a”
	cmp cl,bl		;執行cl-bl判斷大小影響  cl > bl ==> cf,zf
	jnb ba		;大於等於就轉移到ba,檢測cf是否等於0(NC)
	inc si
	loop s
	
ba:					;大於等於a跳到這
	mov bl,122
	cmp cl,bl
	jna lz			;小於等於就轉移檢測cf/zf是否等於1(ZR)
	inc si          ;不然就找下一個
	jmp letters
lz:					;小於等於z跳到這( a<= x <=z )
    and cl,11011111b
	mov ds:[si],cl
	inc si
	jmp letters
ok:
	ret
	
codeseg ends
end begin

 


實驗十二:

        mov ax, cs
        mov ds, ax
        mov si, offset do0

設定ds段,用C語言來描述就是相當於有一個data段的指針,將其指向code段(asm代碼中的第29行)

        mov ax, 0
        mov es, ax
        mov di, 200h

設定es段,用C語言來描述就是相當於有一個指針,將其指向內存中的0:[200]

        mov cx, offset do0end - offset do0
        cld
        rep movsb

復習一下:

MOVSB:字符串傳送指令,這條指令按字節傳送數據。通過SI和DI這兩個寄存器控制字符串的源地址和目標地址,比如DS:SI這段地址的N個字節復制到ES:DI指向的地址,復制后DS:SI的內容保持不變。

REP:指令就是“重復”的意思,術語叫做“重復前綴指令”,因為既然是傳遞字符串,則不可能一個字(節)一個字(節)地傳送,所以需要有一個寄存器來控制串長度。這個寄存器就是CX,指令每次執行前都會判斷CX的值是否為0(為0結束重復,不為0,CX的值減1),以此來設定重復執行的次數。因此設置好CX的值之后就可以用REP MOVSB了。

CLD:則是清方向標志位,也就是使DF的值為0,在執行串操作時,使地址按遞增的方式變化,這樣便於調整相關段的的當前指針。這條指令與STD的執行結果相反,即置DF的值為1。

所以說這三條的意思是將ds的內容賦值到es中。

        mov ax, cs
        mov ds, ax
        mov si, 202h        
              
        mov ax, 0b800h
        mov es, ax
        mov di, 12*160+36*2    

這一段是設置顯示結果的初始化(指定ds,es段),其中在  “mov si,202h”中為什么設定si是202h ?因為rep movsb之后0:200段已經放的是cs中的代碼,所以可以直接用

mov cx,9
		mov bl,2
	  s:mov al,ds:[si]
	    mov es:[di],al
		mov es:[di+1],bl
		inc si
		add di,2
		loop s  

這一段是把ds段中的db內容賦值到顯存區,其中“mov es:[di+1],bl”設定顏色是綠的

        mov ax, 0
        mov es, ax
        mov word ptr es:[0], 200h
        mov word ptr es:[2], 0

設置中斷向量將入口地址0:200寫入中斷向量表0號表項中,0號表項的地址是0:0

	mov ax, 1000
        mov bl, 1
        div bl

 一段除法溢出,測試寫的對不對 

assume cs:codesg codesg segment start:
        mov ax, cs mov ds, ax mov si, offset do0 mov ax, 0
        mov es, ax mov di, 200h mov cx, offset do0end - offset do0 cld
        rep movsb
        
        mov ax, 0
        mov es, ax mov word ptr es:[0], 200h mov word ptr es:[2], 0
        
        mov ax, 1000
        mov bl, 1
        div bl mov ax, 4c00h int 21h do0:
        jmp short do0start db "overflow!"   
    do0start:
        mov ax, cs mov ds, ax mov si, 202h mov ax, 0b800h mov es, ax mov di, 12*160+36*2  
        
        mov cx,9
        mov bl,2
      s:mov al,ds:[si] mov es:[di],al mov es:[di+1],bl inc si add di,2 loop s mov ax,4c00h int 21h do0end:
        nop codesg ends end start
完整代碼

 


 

十三章案例:

問題一:編寫安裝中斷7ch的中斷案例

功能:求一word型數據的平方

參數:(ax)=要計算的數據

返回值:dx,ax中存放結果的高16位和低16位

應用舉例:求2*3456^2

assume cs:code code segment start:
            mov ax,3456
            jmp install finish:
             int 7ch add ax,ax adc dx,dx ;上面兩條進行的是加法,dx存放高位,ax存放低位
            mov ax,4c00h int 21h install:
        push ax push cx push ds push si push es push di mov ax,cs mov ds,ax mov si,offset sqr ;將代碼段的數據給data段
        mov ax,0
        mov es,ax mov di,200h mov cx,offset sqrend-offset sqr cld 
        rep movsb
        
        mov ax,0
        mov es,ax mov word ptr es:[7ch*4],200h mov word ptr es:[7ch*4+2],0
        
        pop di pop es pop si pop ds pop cx pop ax jmp finish sqr: 
        mul ax iret
    sqrend:
        nop code ends end start
View Code

 達到的目的:

 

; assume cs:codeseg
; codeseg segment
    ; start:mov ax,0b800h
    ; mov es,ax 
    ; mov byte ptr es:[12*160+42*2],'!'
    ; int 0
    
    ; mov ax,4c00h
    ; int 21
; codeseg ends
; end start

assume cs:code
data segment
    db 'conversation',0
data ends

code segment
    start:
            mov ax,data
            mov ds,ax
            mov si,0
            
            jmp install
        finish:
             int 7ch
                       
            ; mov ax, 0b800h
            ; mov es, ax
            ; mov di, 12*160+36*2 
            
            ; mov bl,2
          ; s:mov ch,0
            ; mov cl,ds:[si]
            ; mov es:[di],al
            ; mov es:[di+1],bl
            ; inc si
            ; add di,2
            
            ; loop s
            ; ;設置屏幕顯示        
            
            mov ax,4c00h
            int 21h
            
    install:
        push ax
        push cx
        push ds
        push si
        push es
        push dx 
        
        s_start: 
        mov ax,cs
        mov ds,ax
        mov si,offset capital
        
        mov ax,0
        mov es,ax
        mov di,200h
        
        mov cx,offset capitalend - offset capital
        cld 
        rep movsb
                    ;上面完成的是賦值            
        mov ax,0
        mov es,ax
        mov word ptr es:[7ch*4],200h
        mov word ptr es:[7ch*4],0
                    ;將地址寫入
        pop dx
        pop es
        pop si
        pop ds
        pop cx
        pop ax
        
        jmp finish
        
    capital:
            ;小寫轉大寫的功能函數
            push dx
            push cx
            push si
            
            mov ax,data
            mov dx,ax
            
            mov si,0
        change :
            mov cl,ds:[si]
            mov ch,0
            jcxz ok
            and byte ptr [si],11011111b
            inc si
            jmp short change
        ok:
            pop si
            pop cx
            pop dx
            iret
    capitalend:nop
            
code ends
end start
問題二的asm,還在改

 

 

 

 

  

 

 

 


免責聲明!

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



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