8086彙編
ios
本筆記是筆者觀看小甲魚老師(魚C論壇)《零基礎入門學習彙編語言》系列視頻的筆記,在此感謝他和像他同樣共享資源、幫助他人的筒子們==本文比較長,因爲筆者我的能力有限,錯漏在所不免,歡迎讀者們批評指正。程序員
總線是鏈接CPU和其餘芯片的導線,邏輯上分爲地址總線、數據總線、控制總線。編程
8086 CPU全部的寄存器是16位,能夠存放2個字節(一個字)。windows
一字節由8 bit 組成,能夠存在8位寄存器中。api
字(word)是兩字節,16位。數組
彙編指令對大小寫不敏感安全
彙編指令舉例框架
彙編指令 | 控制CPU完成的操做 | 用高級語言的語法描述 |
---|---|---|
mov ax,18 | 將8送入AX | AX=18 |
mov ah,78 | 將78送入AH | AH=78 |
add ax,8 | 將寄存器AX中的數值加上8結果存入AX中 | AX=AX+8 |
mov ax,bx | 將寄存器BX中的數據送入寄存器AX | AX=BX |
add ax,bx | 將AX,BX中的內容相加結果存入AX中 | AX=AX+BX |
移位位數 | 二進制 | 十六進制 | 十進制 |
---|---|---|---|
0 | 10B | 2H | 2 |
1 | 100B | 4H | 4 |
2 | 1000B | 8H | 8 |
3 | 10000B | 10H | 16 |
4 | 100000B | 20H | 32 |
段地址*16是移位編輯器
人爲定義的,將若干地址連續的內存單元看做一個段。用段地址*16定位段的起始地址(基址),用偏移地址定位段中的內存單元。
一個段的起始地址是16的倍數。偏移地址爲16位,尋址能力爲64K,因此段的最大長度也是64K。
一、從CS:IP指向內存單元讀取指令,讀取的指令進入指令緩衝器;
8086PC機剛開始啓動時,CPU從內存FFFF0h單元中讀取指令執行,FFFF0h單元中的指令時8086PC機開機後執行的第一條指令。
三、執行指令。轉到步驟1,周而復始。
jmp 段地址:偏移地址;同時修改CS和IP jmp 某一合法寄存器;則是僅修改IP
windows xp系統自帶debug,請使用xp以上系統的讀者執行自行下載debug.exe和dosbox,使用方法筆者再也不贅述,在dosbox中可使用debug。
8086 CPU因爲硬件的設計不支持將數據直接送入段寄存器的操做。
數據 -> 通用寄存器 -> 段寄存器
mov 寄存器名,內存單元
mov 寄存器,數據;mov ax,8 mov 寄存器,寄存器;mov ax,bx mov 寄存器,內存單元;mov ax,[0] mov 內存單元,寄存器;mov [0],ax mov 段寄存器,寄存器;mov ds,ax mov 寄存器,段寄存器;mov ax,ds ……
add 通用寄存器,數據 add 通用寄存器,通用寄存器 add 通用寄存器,內存單元 add 內存單元,寄存器
sub 通用寄存器,數據 sub 通用寄存器,通用寄存器 sub 通用寄存器,內存單元 sub 內存單元,通用寄存器
pop以後數據仍是存在內存中,push時覆蓋。
CS和IP存放當前指令的段地址和偏移地址。
;push和pop格式 push 寄存器 pop 寄存器 push 段寄存器 pop 段寄存器 push 內存單元 pop 內存單元
編寫完成的彙編語言程序,用編譯器編譯成可執行文件並在操做系統中運行。
LINKE.EXE對目標文件進行鏈接生產可在操做系統中直接運行的可執行文件。
可執行文件包含程序(機器碼)、數據(源程序中定義的數據)和相關的描述信息。
assume cs:codesg ;假設代碼段的名稱爲codesg codesg segment ;定義一個codesg段 mov ax,0123H mov bx,0456H add ax,bx add ax,ax mov ax,4c00h int 21h codesg ends ;codesg段結束 end ;是個僞指令,程序的結束標記
assume用來加上某一段寄存器和程序中的某一用segment……ends定義的段相關聯。經過assume說明這種關聯,在須要的狀況下編譯程序能夠將段寄存器和某一個具體的段相聯繫。
程序與源程序
程序的結構
小練習:
;編程運算2^3 assume cs:abc ;段與寄存器關聯 abc segment ;定義一個段,名稱爲abc mov ax,2;寫入彙編指令 add ax,ax add ax,ax abd ends end ;程序結束處
程序的返回:一個程序結束後將CPU的控制權交還給使它得以運行的程序的過程。應該在程序的末尾添加返回的程序段。
codesg:放在segment前面,做爲一個段的名稱,這個段的名稱最終將被編譯、鏈接程序,稱爲一個段的段地址 。
mov ax,4c00H int 21H ;第21號中斷 ;這兩條指令說實現的功能就是程序返回。
assume cs:ABC ABC segment mov ax,2 add ax,ax add ax,ax mov ax,4c00H int 21h ABC ends end
masn和 1.asm在同一目錄中,dos下使用masm 1.asm命令便可生產1.obj文件。
link 1.obj,生成exe文件,摁enter忽略編譯程序提示輸入的信息。
當源程序很大時,能夠將它分紅多個源程序文件編譯,每一個源程序編譯成目標文件後再用鏈接程序將他們鏈接到一塊兒,生成一個可執行文件。或者程序中調用了某個庫文件中的子程序,須要將這個庫文件和該目標文件鏈接到一塊兒,生成一個可執行文件。或者一個源程序編譯後獲得存有機器碼的目標文件,目標文件中的有些內容還不能直接生成可執行文件,鏈接程序將此內容處理爲最終的可執行文件信息。
在dos系統中.exe文件中的加載過程
mov bx,0 mov ax,[bx] mov al,[bx]
二、內訓單元的長度(類型)。
咱們用[0]表示一個內訓單元時,0表示單元的偏移地址,段地址默認在DS中,單元的長度(類型)能夠由具體指令中的其餘的操做對象(好比說寄存器)指出。
mov ax,[0];0對應的字單元,主要單位要看操做對象(寄存器) mov al,[0];字節
assume cs:code code segment mov ax,2 add ax,ax mov ax,4c00H int 21H code ends end
;計算2^3 assume cs:code code segment mov ax,2 add ax,ax add,ax,ax mov ax,4c00H int 21h code ends end
;計算2^12 assume cs:code code segment start: mov ax,2 mov cx,11 p:add,ax,ax loop p;p是標號 mov ax,4c00H;masm默認數字是十進制 int 21H code ends end start
;編程計算123*236,結果放在ax中 assume cs:code code segment start:mov ax,0 mov cx,236 an:add ax,123 loop an mov ax,4c00H int 21H code ends end start
assume cs:code code segment start:mov ax,0 mov cx,123 pa:add ax,236 loop pa mov ax,4c00H int 21H code ends end start
mov al,[0] ;將al賦值0 mov al,ds[0] ;將al賦值段地址爲ds,偏移地址爲0的內存單元中的內容 mov al,[bx] ;默認段地址爲ds,將al賦值偏移地址爲bx mov al,ds:[bx] ;將al賦值段地址爲ds,偏移地址爲bx
在8086模式中,隨意向一段內存空間寫入數據是危險的,由於這段空間中可能存放着重要的系統數據或代碼。
assume cs:code code segment mov ax,0 mov ds,ax mov ds:[26H],ax mov ax,4c00H int 21H code ends end
但筆者在練習的時候出現dosbox下debug卡死
dos下0:200H~0:2FFH的256個字節的空間是安全的,dos和其餘合法程序通常都不會使用這段空間。內存0000:0000~0000:03FF大小爲1kb的空間是系統存放中斷處理程序入口地址的中斷向量表。通常狀況下0:200H~0:2FFH的256個字節的空間所對應的中斷向量表都是空的,操做系統和其餘應用程序都不佔用。
assume cs:code code segment mov bx,0 ;(bx)=0,偏移地址從0開始 mov cx,12 ;(cx)=12,循環12次 s: mov ax,offffh mov ds,ax ;(ds)=0ffffh mov dl,[bx] ;(ds)=((ds)*16+(bx)),將ffff:bx中的數據送入dl mov ax,0020h mov ds,ax ;(ds)=0020h mov [bx],dl ;((ds)*16+(bx))=dl,將數據送入0020:bx inc bx ;(bx)=(bx)+1 loop s mov ax,4c00h int 21h code ends end
;優化後的代碼,優化了兩次設置ds assume cs:code code segment mov ax,offffh mov ds,ax ;(ds)=0ffffh mov ax,0020h mov es,ax ;(es)=0020H mov bx,0 ;(bx)=0,此時ds:bx指向ffff:0,es:bx指向0020:0 mov cx,12 ;(cx)=12,循環12次 s: mov dl,[bx] ;(ds)=((ds)*16+(bx)),將ffff:bx中的數據送入dl mov es:[bx],dl ;((es)*16+(bx))=dl,將數據送入0020:bx inc bx ;(bx)=(bx)+1 loop s mov ax,4c00h int 21h code ends end
assume cs:codesg codesg segment dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H ;dw,define word,定義字型數據,db定義字節型數據 ;因爲數據在代碼段中,因此段地址是CS ;dw定義的數據在最開始的地方,因此偏移地址是0開始 start:mov bx,0 ;第一條指令 mov ax,0 mov cx,8 s: add ax,cs:[bx] add bx,2 loop s mov ax,4c00H int 21H codesg ends end start ;入口找end
assume cs:codesg codesg segment dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H;地址0~15 dw 0,0,0,0,0,0,0,0;定義8個字型空數據,後面看成棧來使用,地址是16~31 start: mov ax,cs mov ss,ax mov sp,32;設置棧底ss:sp指向cs:32,十進制的32 mov bx,0 mov cx,8 s:push cs:[bx] add bx,2 loop s; 以上代碼段0~15個單元中的8個字型數據一次入棧 mov bx,0 mov cx,8 s0:pop cs:[bx] add bx,2 loop s0;依次出棧8個執行數據到代碼段0~15單元中 mov ax,4c00h int 21h codesg ends end start;指明程序入口在start處
assume cs:codesg,ds:data,ss:stack;在源程序中爲三個段進行有意義的名稱 data segment dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H data ends stack segment dw 0,0,0,0,0,0,0,0;定義8個字型空數據,後面看成棧來使用 stack ends code segment start: mov ax,stack mov ss,ax mov sp,16;設置棧底ss:sp指向stack:16, mov ax,data mov ds,ax;ds指向data段 mov bx,0;ds:bx指向data段中的第一個單元 s:push cs:[bx] add bx,2 loop s; 以上代碼段0~16個單元中的8個字型數據一次入棧 mov bx,0 mov cx,8 s0:pop cs:[bx] add bx,2 loop s0;依次出棧8個執行數據到代碼段0~16單元中 mov ax,4c00h int 21h codesg ends end start;指明程序入口在start處
assume cs:codesg,ds:data,ss:stack data segment dw 0123H,0564H,0789H,0abcH,0defH,0fedH,0cbaH,0987H data ends stack segment dw 0,0,0,0,0,0,0,0 stack ends codesg segment start: mov ax,stack mov ss,ax mov sp,16 mov ax,data mov ds,ax push ds:[0] push ds:[2] pop ds:[2] pop ds:[0] mov ax,4c00h int 21h codesg ends end start
and指令:邏輯與指令,按位進行與運算。
and兩個同時爲真的結果才爲真。
mov al,01100011B and al,00111011B ;執行後 al=00100011B
and al,10111111B;將al第六位設爲0 and al,01111111B;將al第七位設爲0 and al,11111110B;將al第0位設爲0
or兩個同時爲假的結果才爲假
mov al,01100011B and al,00111011B ;執行後 al=01111011B
and al,01000000B;將al第六位設爲1 and al,10000000B;將al第七位設爲1 and al,00000001B;將al第0位設爲1
assume cs:code,ds:data data segment db 'unIx' db 'foRK' data ends code segment start: mov al,'a' mov bx,'b' mov ax,4c00h int 21h code ends end start
大寫 | 二進制 | 小寫 | 二進制 |
---|---|---|---|
A | 01000001 | a | 01100001 |
B | 01000010 | b | 01100010 |
C | 01000011 | c | 01100011 |
D | 01000100 | d | 01100100 |
;大小寫轉換 assume cs:codesg,ds:datasg datasg segment db'BaSiC' db'iNfOfMaTiOn' datasg ends codesg segment start: mov ax,datasg mov ds,ax;設置ds執行datasg段 mov bx,0;設置(bx)=0,ds:bx指向'BaSiC'的第一個字母 mov cx,5;設置循環次數,由於BaSiC有5個字母 s:mov al,[bx];將ASCII碼從ds:bx所指向的單元中取出 and al,11011111B;口岸al中ASCII碼的第5個位置變爲0,變爲大寫字母 mov [bx],al;轉變後將ASCII碼寫回單元 inc bx;(bx)加1,ds:bx指向下一個字母 loop x mov bx,5;設置(bx)=5,ds:bx指向'iNfOfMaTiOn'的第一個字母 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
;[bx+idata]能夠寫成如下格式 mov ax,[200+bx] mov ax,200[bx] mov ax,[bx].200
;使用debug查看內存 mov ax,2000H mov ds:ax mov bx,1000H mov ax,[bx] mov cx,[bx+1] add cx,[bx+2]
;改進大小寫轉換程序 assume cs:codesg,ds:datasg datasg segment db'BaSiC' db'iNfOfMaTiOn' datasg ends codesg segment start: mov ax,datasg mov ds,ax;設置ds執行datasg段 mov bx,0;設置(bx)=0,ds:bx指向'BaSiC'的第一個字母 mov cx,5;設置循環次數,由於BaSiC有5個字母 s:mov al,[bx+0];將ASCII碼從ds:bx所指向的單元中取出 and al,11011111B;口岸al中ASCII碼的第5個位置變爲0,變爲大寫字母 mov [bx],al;轉變後將ASCII碼寫回單元 mov [bx+5];定位第二個字符串的字符 or al,00100000B mov [bx+5],al inc bx loop s mov ax,4c00H int 21H codesg ends end start
include<stdio.h> char a[5]="BaSiC"; char b[11]="iNfOfMaTiOn"; main() { int i; i=0; do { a[i]=a[i]&0xDF; b[i]=b[i]|0x20; i++; }while(i<5); }
mov bx,0 mov ax,[bx] mov si,0 mov ax,[si] mov di,0 mov ax,[di] ;------------- ;下面的三組指令也實現了另外一個組相同的功能 ;------------- mov bx,0 mov ax,[bx+123] mov si,0 mov ax,[si+123] mov di,0 mov ax,[di+123]
;用DI和SI實現複製到它後面的數據區中 assume cs:codesg,ds:datasg datasg segment db'welcome to asm!' db'................' datasg ends codesg segment start :mov ax,datasg mov ds,ax mov si,0 mov di,16 mov cx,8 s:mov ax,[si] mov [di],ax add si,2 add di,2 loop s mov ax,4c00h int 21H ;------ ;用數組的思惟[bx(si或di)+idata]的方式優化程序 ;------ assume cs:codesg,ds:datasg datasg segment db'welcome to asm!' db'................' datasg ends codesg segment start :mov ax,datasg mov ds,ax mov si,0 mov cx,8 s:mov ax,[si];第一個字符串的的第一個元素 mov [si+16],ax;目標字符串的第二個元素 add si,2 loop s mov ax,4c00h int 21H codesg ends end start
mov ax,2000h mov ds,ax mov bx,1000h mov si,0 mov ax,[bx+si] inc si mov cx,[bx+si] inc si mov di,si mov ax,[bx+di]
mov ax,2000h mov ds,ax mov bx,1000h mov si,0 mov ax,[bx+2+si] inc si mov cx,[bx+si+2] inc si mov di,si mov ax,[bx+di+2]
assume cs:codesg,ds:datasg datasg segment db'1. file ';長度恰好都是16個字節 db'2. edit ' db'3. search ' db'4. view ' db'5. options ' db'6. help ' datasg ends codesg segment start: mov ax,datasg mov ds,ax mov bx,0 mov cx,6 s: mov al,[bx+3] and al,11011111B mov [bx+3],al add bx,16 loop s mov ax,4c00h int 21h codesg ends end start
;有bug,問題在於cx的使用,進行二重循環,只用一個循環計數器,形成在進行內層的時候覆蓋了外層循環的循環計數值。 assume cs:codesg,ds:datasg datasg segment db 'ibm ' db 'dec ' db 'dos ' db 'vax ' datasg ends codesg segment start:mov ax,datasg mov ds,ax mov bx,0;用bx來定位行 mov cx,4 s0:mov si,0;用si來定位列 mov cx,3 s:mov al,[bx+si] and al,11011111B mov [bx+si],al inc si loop s add bx,16 loop s0 mov ax,4c00h int 21h codesg ends end start
loop s;三次循環後cx等於0了 add bx,16 loop s0;先是cx=cx-1再判斷時候等於0,此時cx=FFFF不爲0再循環,變成死循環了
assume cs:codesg,ds:datasg datasg segment db 'ibm ' db 'dec ' db 'dos ' db 'vax ' datasg ends codesg segment start: mov ax,datasg mov ds,ax mov bx,0;用bx來定會行 mov cx,4 s0: mov dx,cx;用dx寄存器來臨時存放外層cx的值 mov si,0;用si來定位列 mov cx,3 s: mov al,[bx+si] and al,11011111B mov [bx+si],al inc si loop s add bx,16 mov cx,dx;在進行外層循環的時候回覆cx的值 loop s0 mov ax,4c00h int 21h codesg ends end start
assume cs:codesg,ds:datasg datasg segment db 'ibm ' db 'dec ' db 'dos ' db 'vax ' dw 0;定義一個字用來保存cx的值 datasg ends codesg segment start:mov ax,datasg mov ds,ax mov bx,0;用bx來定位行 mov cx,4 s0:mov ds:[40h],cx;datasg:40h單元存放外層cx的值 mov si,0;用si來定位列 mov cx,3 s:mov al,[bx+si] and al,11011111B mov [bx+si],al inc si loop s add bx,16 mov cx,ds:[40h];在進行外層循環的時候回覆cx的值 loop s0 mov ax,4c00h int 21h codesg ends end start
assume cs:codesg,ds:datasg,ss:stacksg datasg segment db 'ibm ' db 'dec ' db 'dos ' db 'vax ' datasg ends stacksg segment dw 0,0,0,0,0,0,0,0;定義一個段,用做棧段,容量爲16個字節 stacksg ends codesg segment start:mov ax,stacksg mov ss,ax mov sp,16 mov ax,datasg mov ds,ax mov bx,0;用bx來定位行 mov cx,4 s0:push cx;datasg:40h單元存放外層cx的值 mov si,0;用si來定位列 mov cx,3 s:mov al,[bx+si] and al,11011111B mov [bx+si],al inc si loop s add bx,16 pop cx;在進行外層循環的時候回覆cx的值 loop s0 mov ax,4c00h int 21h codesg ends end start
assume cs:codesg,ds:datasg,ss:stacksg stacksg segment stacksg ends datasg segment db '1. display ' db '2. brows ' db '3. replace ' db '4. modify ' datasg ends codesg segment start:mov ax,stacksg mov ss,ax mov sp,16 mov ax,datasg mov ds,ax mov bx,0 mov cx,4 s0:push cx mov si,0 mov cx,4 s:mov al,[bx+si+3] and al,11011111B mov [bx+si+3],al inc si loop s add bx,16 pop cx loop s0 mov ax,4c00h int 21h codesg ends end start
;如下指令是錯誤的 mov ax,[ax] mov ax,[cx] mov ax,[dx] mov ax,[ds] mov ax,[bx+bp] mov ax,[si+di]
mov ax,[bx] mov ax,[si] mov ax,[di] mov ax,[bp] mov ax,[bx+si] mov ax,[bx+di] mov ax,[bp+si] mov ax,[bp+di] mov ax,[bx+si+idata] mov ax,[bx+di+idata] mov ax,[bp+si+idata] mov ax,[bp+di+idata]
機器碼 | 彙編指令 | 指令執行前數據的位置 |
---|---|---|
89C3 | mov bx,[0] | 內存,ds:0單元 |
89C3 | mov bx,ax | CPU內部,ax寄存器 |
BB0100 | mov bx,1 | CPU內部,指令緩衝器 |
mov word ptr ds:[0],1 inc word ptr [bx] inc word ptr ds:[0] add byte ptr [bx],2
;假設內存2000:1000 FF FF FF FF FF FF …… ;若是用如下指令 mov ax,2000H mov ds,ax mov byte ptr [1000H],1 ;那麼內存中的內容變爲 ;2000:1000 01 FF FF FF FF FF …… 若是是用如下指令 mov ax,2000H mov ds,ax mov word ptr [1000H],1 ;那麼內存中的內容變爲 ;2000:1000 01 00 FF FF FF ……
mov ax,seg mov ds,ax mov bx,60h;肯定記錄物理地址:ds:bx mov word ptr [bx+0ch],38;寄存器相對尋址 排名字段改成38 add word ptr [bx+0eh],70;收入字段增長70 mov si,0;用si來定位產品字符串中的字符 mov byte ptr [bx+10h+si],'V';相對基址變址尋址 inc si mov byte ptr [bx+10h+si],'A' inc si mov byte ptr [bx+10h+si],'X'
struct company /*定義一個公司記錄的結構體*/ { char cn[3]; /*公司名稱*/ char hn[9]; /*總裁姓名*/ int pm; /*排名*/ int sr; /*收入*/ char cp[3]; /*著名產品*/ }; struct compant dec={"DEC","Ken Olsen",137,40,"PDF"}; /*定義一個公司記錄的變量,內存中將存有一條公司的記錄*/ mian() { int i; dec.pm=38; dec.sr=dec.sr+70; i=0; dec.cp[i]='V'; i++; dec.cp[i]='A'; i++; dec.cp[i]='X'; return 0; }
mov ax,seg mov ds,ax mov bx,60h;記錄首地址送入bx mov word ptr [bx].och,38;排名字段改成38 add word ptr [bx].0eh,70;收入字段增長70 ;產品名字段改成字符串'VAX' mov si,0 mov byte ptr [bx].10h[si],'V' inc si mov byte ptr [bx].10h[si],'A' inc si mov byte ptr [bx].10h[si],'X'
div reg(寄存器) div 內存單元。
div byte ptr ds:[0] div byte ptr [bx+si+idata] ;al放商,ah放餘數 div word ptr es:[0] div word ptr [bx+si+idata] ;ax放商,dx放餘數
除數 | 被除數 |
---|---|
8位 | 16爲(AX) |
16位 | 32位(DX高16位+AX低16位) |
運算 | 8位 | 16位 |
---|---|---|
商 | AL | AX |
餘數 | AH | DX |
;被除數1001可用ax寄存器存放,除數100可用8位寄存器存放,要進行8位除法。 mov ax,1001 mov bl,100 div bl ;執行後al的值等於0AH(10),ah的值等於1(餘數爲1)。
;被除數100001大於2^16=65535(FFFF),不能用ax來存放,要用dx和ax兩個寄存器聯合存放。除數小於255,可用一個8位寄存器存放,可是被除數是32位的,除數應爲16位,因此要用一個16位寄存器來存放除數。 ;100001的十六進制爲186A1H,100001的高16位(1)存放在dx,低16位(86AH)存放在ax中。 mov dx,1 mov ax,86A1H mov bx,100 div bx ;執行後ax內容等於03E8H(即1000),dx的值等於1(餘數)。
data segment db 1;第一個數據爲01h,在data:0處,佔1個字節 dw 1;第二個數據爲0001h,在data:1處,佔1個字 dd 1;第三個數據爲00000001h,在data:3處,佔2個字 data ends
data segment dd 100001H;低16位存儲在ax中,高16位存儲在dx中 dw 100 dw 0 data ends mov ax,data mov ds,ax mov ax,ds:[0];低16位存儲在ax中 mov dx,ds:[2];高16位存儲在dx中 div word ptr ds:[4] mov ds:[6],ax
db 3 dup(0) ;定義了3個字節,它們的值都是0,等同於db 0,0,0。 db 3 dup(0,1,2) ;定義了9個直接,它們是0、一、二、0、一、二、0、一、2,至關於db 0、一、二、0、一、二、0、一、2 db 3 dup('abc','ABC') ;定義了18個直接,它們是'abcABCabcABCabcABC'
;初始化階段 mov ax,data mov ds,ax mov ax,table;data已經被佔用 mov es,ax mov bx,0 mov si,0 mov di,0 mov cx,21 ;存放年份,每個bx就是一個字節 mov al,[bx] mov es:[di],al mov al,[bx+1] mov es:[di+1],al mov al,[bx+2] mov es:[di+2],al mov al,[bx+3] mov es:[di+3],al ;存放公司的總收入 mov ax,[bx+54H];第一個年收入是dd數據類型,段地址爲54H mov dx,[bx+54H] mov es:[di+5H],ax mov es:[di+7H],dx ;存放公司的人數 mov ax,[si+0A8H];第一我的數的數據段地址爲0A8H mov es:[di+0A8H],ax ;計算人均收入並存放 mov ax,[bx+54H] mov dx,[bx+56H];這兩句詩初始化被除數 div word ptr,ds:[si+0A8H];除以人數 mov es:[di+0dH],ax;將商放入指定位置 ;爲下一次循環時存放數據作準備 add bx,4;bx肯定年份和收入 add si,2;si肯定人數 add di,16;di肯定的是每行的列數
assume cs:codesg,ds:data,es:table data segment db '1975','1976' '1977' …… dd 16,22,382 …… dw 3,7,9 …… ;數據在題目中 data ends table segment db 21 dup('year summ ne ?? ') table ends start:mov ax,data mov ds,ax mov ax,table mov es,ax mov bx,0 mov si,0 mov di,0 mov cx,21 s:mov al,[bx] mov es:[di],al mov al,[bx+1] mov es:[di+1],al mov al,[bx+2] mov es:[di+2],al mov al,[bx+3] mov es:[di+3],al mov ax,[bx+54H] mov dx,[bx+56H] mov es:[di+5H],ax mov es:[di+7H],dx mov ax,[si+0A8H] mov es:[di+0AH],ax mov ax,[bx+54H] div word ptr ds:[si+0A8H] mov es:[di+0dH],ax add bx,4 add si,2 loop s mov ax,4c00h int 21h codesg ends end start
assume cs:codesg codesg segment start:mov ax,offset start;至關於 mov ax,偏移地址0,段地址是從0開始 s:mov ax,offset s;至關於 mov ax,3,標記的是代碼段中的第二條指令,第一條指令長度爲3個字節,則s的偏移地址爲3 codesg ends end start
assume cs:codesg codesg segment start:mov ax,0 jmp short s add ax,1 s:inc ax codesg ends end start
通常彙編指令中的當即數(idata)會出如今對應的機器指令中。而jmp指令的機器指令並不包含目的地址,包含的是相對於當前IP的轉移位移,CPU並不須要目的地址就能夠實現對IP的修改。
assume cs:codesg codesg segment start:mov ax,0 mov bx,0 jmp far ptr s db 256 dup(0) s:add ax,1 inc ax codesg ends end start
mov ax,0123H mov ds:[0],ax jmp word ptr ds:[0] ;至關於 jmp ax,執行後(IP)=0123h mov ax,0123H mov [bx],ax jmp word ptr [bx] ;執行後(IP)=0123h
mov ax,0123H mov ds:[0],ax mov word ptr ds:[2],0 jmp dword ptr ds:[0] mov ax,0123H mov [dx],ax mov word ptr [bx+2],0 jmp dword ptr [bx] ;執行後 (CS)=0,(IP)=0123H CS:IP指向0000:0123
jmp short 標號 jmp near ptr 標號 jcxz 標號 loop 標號
assume cs:code code segment start: jmp short s db 128 dup(0) s:mov ax,0FFFFH code ends end start
assume cs:codesg codesg segment mov ax,4c00h int 21h start:mov ax,0 s:nop nop;nop佔用兩個字節,不執行任何操做 mov di,offset s mov si,offset s2 mov ax,cs:[si];jmp short s1的機器碼給了ax mov cs:[di],ax;覆蓋到指令 s:nop nop那 s0:jmp short s;s那已經被jmp short s1機器碼覆蓋 s1:mov ax,0 int 21h mov ax,0 s2:jmp short s1;jmp -8h,向上跳到s1,s1又向上跳-10字節 nop codesg ends end start
assume cs:code,ds:data,ss:stack data segment db'welcome to masm!';定義要顯示的字符串(共16字節) db 02H,24H,71H;定義字符的屬性 data ends stack segment dw 8 dup(0) stack ends code segment start: mov ax,data mov ds,ax mov ax,stack mov ss,ax mov sp,10H xor bx,bx;bx清零,用來索引顏色 mov ax,0b872H;算出屏幕第12行中間的顯存的段起始位置放入ax中 mov cx,3;s3循環控制行數,要顯示三個字符串外循環爲3次 s3: push cx;三個進棧操做爲外循環s3保存相關寄存器的值 push ax;以防止它們的值在內循環中被破壞 push bx mov es,ax;此時es爲屏幕第12行中間的顯存的段起始位置 mov si,0;si用來索引代碼列的字符 mov di,0;di用來定位目標列 mov cx,10H ;s1循環控制存放的字符,一個字符串中含有10H個字節內循環爲10H次 s1: mov al,ds:[si] mov es:[di],al inc si add id,2 loop s1;吃循環實現偶地址中存放字符 mov di,1;設置di的值爲1,爲在顯存奇數地址中存放字符的顏色屬性作準備 pop bx mov al.ds:[bx+10H];取消顏色屬性 inc bx mov cx,10H;第二個內循環也爲10H s2: mov es:[di],al add di 2 loop s2;此循環實現奇數地址存放字符的顏色屬性 ;如下4句爲下一趟外循環作準備 pop ax add ax,0AH;將顯存的段地址起始地址設置爲當前行的下一行 ;[在段地址中甲0aH,至關於在偏移地址中加了0a0h(=160d)] pop cx loop s3 mov ax,4C00H int 21H code ends end start
assume cs:codesg stack segment db 16 dup(0) stack ends codesg segment mov ax,4c00h int 21h start: mov ax,stack mov ss,ax mov sp,16 mov ax,0 push ax mov bx,0 ret codesg ends end start
assume cs:codesg stack segment db 16 dup(0) stack ends codesg segment mov ax,4c00h int 21h start: mov ax,stack mov ss,ax mov sp,16 mov ax,0 push cs push ax mov bx,0 retf codesg ends end start
push IP jmp near 標號
push CS push IP jmp far ptr 標號
push IP jmp 16位寄存器
call word ptr 內存單元地址;段內跳轉 call dword ptr 內存單元地址;段間跳轉
push IP jmp word ptr 內存單元地址
mov sp,10h mov ax,0123H mov ds:[0],ax call word ptr ds:[0] ;執行後IP的值等於0123H,SP的值等於0EH
push CS push IP jmp word ptr 內存單元地址
mov sp,10h mov ax,0123H mov ds:[0],ax mov word ptr ds:[0],0 call dword ptr ds:[0] ;執行後IP的值等於0123H,SP的值等於0CH,CS的值等於0
assume cs:code code segment start: mov ax,1 mov cx,3 call s mov bx,ax mov ax,4c00h int 21h s: add ax,ax loop s ret code ends end start
mull reg mull 內存單元 mull byte ptr ds:[0] mull word ptr [bx+si+idata] ;(ax)=(ax)*((ds)*16+(bx)+(si)+idata) ;(dx)=(ax)*((ds)*16+(bx)+(si)+idata)
;計算100*10,兩個數都小於255,能夠作8位乘法 mov ax,100 mov bx,10 mull bl ;結果(ax)=1000(03E8H) ;計算100*1000,1000都大於255,要作16位乘法 mov ax,100;高位自動補零 mov bx,10000 mull bx ;結果(ax)=4240H,(dx)=000FH,F4240H=1000000
cube:mov ax,bx mul bx mul bx ret
assume cs:code data segment dw 1,2,3,4,5,6,7,8 dd 8 dup (0) data ends code segment start: mov ax,data mov ds,ax mov si,0;ds:si指向第一組word單元 mov di,16;ds:di指向第二組dword單元 mov cx,8 s: mov bx,[si] call cube mov [di],ax mov [di+2],dx add si,2;ds:di指向下一個word單元 add di,4;ds:di指向下一個dword單元 loop s mov ax,4c00h int 21h cube:mov ax,bx mul bx mul bx ret code ends end start
assume cs:code data segment db'conversation' data ends start: mov ax,data mov ds,ax mov si,0;ds:si指向字符串(批量數據)所在空間的首地址 mov cx,12;cx存放字符串的長度 call capital mov ax,4c00h int 21h capital: add byte ptr [si],11011111B inc si loop capital ret code ends
capital: mov cl,[si];低8位 mov ch,0;高8位設置爲0 jcxz ok;若是(cx)=0則結束,若是不是0則處理 and byte ptr [si],11011111B inc si jmp short capital ok: ret
assume cs:code data segment db'word',0 db'unix',0 db'wind',0 db'good',0 data ends
;此程序有bug,cx有問題 assume cs:code data segment db'word',0 db'unix',0 db'wind',0 db'good',0 data ends code segment start: mov ax,data mov ds,ax mov bx,0 mov cx,4 s: mov si,bx call capital add bx,5 loop s mov ax,4c00h int 21h capital: mov cl,[si] mov ch,0 jcxz ok and byte ptr [si],11011111b inc si jmp short capital ok: ret code ends end start
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,4c00h int 21h show_str:;子程序 push cx push si mov al,0A0h;每行有80*2=160個字節=0a0h dec dh;行號在顯存中下標從0開始,因此減1 mul dh;至關於從第(n-1)*0a0h個byte單元開始 mov bx,ax;定位好的位置偏移地址存放在bx裏(行) mov al,2;每一個字符佔2個字節 mul dl;定位列,結果ax存放的是定位好的列的位置 sub ax,2;列號在顯存中下標從0開始,又由於是偶字節存放字符,因此減2 add bx,ax;此時bx中存放的是行與列的偏移地址 mov ax,0B800h;顯存開始的地方 mov es,ax;es中存放的是顯存的第0頁的起始地段地址 mov di,0;di指向顯存的偏移地址,肯定指向下一個要處理的字符的位置 mov al,cl;cl存放顏色參數,下邊cl要用來臨時存放要處理的字符 mov ch,0;下邊cx存放的是每次準備處理的字符 s: mov cl,ds:[si];指向'welcome to masm ',0 jcxz ok;cl爲0時跳轉 mov es:[bx+di],cl;偶地址存放字符 mov es:[bx+di+1],al;奇地址存放字符的顏色屬性 inc si add di,2;指向了下個字符 jmp short s ;無條件跳轉,jcxz是離開的關鍵跳 ok: pop si pop cx ret;定義結束 code ends end start
assume cs:code,ss:stack stack segment dw 8 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,10h mov ax,4240h mov dx,0fh mov xx,0ah call divdw mov ax,4c00h int 21h divdw: push ax;低16位先保存 mov ax,dx;ax這時是高16位了 mov dx,0;爲了避免影響餘數位和高位數 div cx mov bx,ax pop ax div cx mov cx,dx mov dx,dx ret code ends end start
assume cs:code,ds:data data segment db 10 dup(0) data ends code segment start: mov ax,12666 mov bx,data;指向字符串的首地址 mov ds,bx mov si,0 call dtoc;實現將word型整數轉化爲字符串並存儲 mov dh,8;打印初始化 mov dl,3 mov cl,0cah call show_str;開始打印字符串 mov ax,4c00h int 21h dtoc: push dx push cx push ax push si mov bx,0;bx在子程序中用來存放位數,用棧來臨時存放修改後的字符 s1: mov cx,10d;d表示十進制,cx準備被除,用取餘法來取出數字 mov dx,0 div cx;除以十 mov cx,ax;獲得的商複製給cx,要利用jcxz jcxz s2;當商爲0則跳到s2 add dx,30h;餘數加上30h獲得相應的ascii碼 push dx inc bx jmp short s1 s2: add ax,30h;當商爲0的時候,餘數爲個位 push dx inc bx;再進行一次棧操做(補充當商爲零而餘數不爲零時的狀況) mov cx,bx;總共有bx位進棧,因此循環次數爲bx mov si,0 s3: pop ax;s3實現將棧中的數據依次出棧放到指定的內存中 mov [si],al inc si loop s3 okay: pop bx pop si pop ax pop dx ret show_str:;子程序 push bx push cx push si mov al,0A0h;每行有80*2=160個字節=0a0h dec dh;行號在顯存中下標從0開始,因此減1 mul dh;至關於從第(n-1)*0a0h個byte單元開始 mov bx,ax;定位好的位置偏移地址存放在bx裏(行) mov al,2;每一個字符佔2個字節 mul dl;定位列,結果ax存放的是定位好的列的位置 sub ax,2;列號在顯存中下標從0開始,又由於是偶字節存放字符,因此減2 add bx,ax;此時bx中存放的是行與列的偏移地址 mov ax,0B800h;顯存開始的地方 mov es,ax;es中存放的是顯存的第0頁的起始地段地址 mov di,0;di指向顯存的偏移地址,肯定指向下一個要處理的字符的位置 mov al,cl;cl存放顏色參數,下邊cl要用來臨時存放要處理的字符 mov ch,0;下邊cx存放的是每次準備處理的字符 S: mov cl,ds:[si] jcxz ok mov es:[bx+di],cl mov es:[bx+di+i],al inc si add di,2 jmp short s ok: pop si pop cx pop bx ret code ends end start
mov ax,1 sub ax,1 mov ax,1 and ax,0 ;指令執行後,結果爲0,則ZF=1 mov ax,2 sub ax,1 mov ax,1 or ax,0 ;指令執行後,結果爲1,則ZF=0
mov al,1 add al,10 ;執行結果爲00001011B,有3個1,則PF=0 mov al,1 or al,10 ;執行後結果爲00000011B,有2個1,則PF=1
mov al,10000001B add al,1 ;執行指令後al的值是10000010B,無符號數130,有符號數-126
flag的第0位是CF,進位標誌位。通常狀況下,在進行無符號運算的時候,它記錄了運算結果的最高有效位向更高位的進位值或從更高位的借位值。對於位數爲N的無符號數,其對應的二進制信息的最高位爲N-1位的最高有效位,假想存在第N位。
mov al.98h add al,al;執行後(al)=30h,cf=1,cf記錄了從最高有效位向更高位的進位值 add al,al;執行後(al)=60h,cf=0,cf記錄了從更高有效位向更高位的進位值 mov al,97h sub al,98h;執行後(al)=ffh,cf=1,cf記錄了向更高位的借位值 sub al,al;執行後(al)=0,cf=0,cf記錄了向更高位的借位值
assume cs:code code segment start: mov al,01100010b add al,01100011b mov ax,4c00h int 21h code ends end start
assume cs:code code segment start: mov al,10001000b add al,11110000b mov ax,4c00h int 21h code ends end start
assume cs:code code segment start: mov al,98h add al,al add al,al mov ax,4c00h int 21h code ends end start
assume cs:code code segment start: mov al,97h sub al,98h add al,al mov ax,4c00h int 21h code ends end start
mov al,98d add al,99d ;對於無符號數運算,98+99沒有進位,CF=0 ;對於有符號數運算,98+99發生溢出,OF=1
mov ax,2 mov bx,1 sub bx,ax adx ax,1 ;執行後 (ax)=4,至關於計算(ax)+1+CF=2+1+1+4 mov ax,1 add ax,ax adc ax,3 ;執行後(ax)=5,至關於執行(ax)+3+CF=2+3+0=5 mov al,98H add al,al adx al,3 ;執行後 (ax)=34H,至關於執行(ax)+3+CF=30H+3+1=34H
mov ax,001EH mov bx,0F000H add bx,1000H adc ax,0020H
mov ax,001EH mov bx,0F000H mov cx,1000H add cx,1EF0H add bx,1000H adc ax,0020H
assume cs:code,ds:data data segment db 16 dup(88H) db 16 dup(11H) data ends code segment start: mov ax,data mov ds,ax mov si,0 mov di,16 mov cx,8 call add128 mov ax,4C00H int 21H add128: push ax push cx push si push di sub ax,ax;將CF設置爲0 s: mov ax,[si] adc ax,[di] mov [si],ax inc si;不能用add si,2代替 inc si;由於會影響cf位 inc di;而loop和inc不會影響 inc di loop s pop di pop si pop cx pop ax ret code ends end start
mov bx,1000H mov ax,003EH sbb bx,2000H sbb ax,0020H
cmp ax,ax ;執行後結果爲0,ZF=1,PF=1,SF=0,CF=0,OF=0 mov ax,8 mov bx,3 cmp ax,bx ;執行後ax、bx的值不變,ZF=0,PF=1,SF=0,CF=0,OF=0
cmp ax,bx
指令 | 含義 | 檢測的相關標誌位 |
---|---|---|
je | 等於則轉移 | ZF=1 |
jne | 不等於則轉移 | ZF=0 |
jb | 低於則轉移 | CF=1 |
jnb | 不低於則轉移 | CF=0 |
ja | 高於則轉移 | CF=0 and ZF=0 |
jna | 不高於則轉移 | CF=1 or ZF=1 |
j | e | ne | b | nb | a | na |
---|---|---|---|---|---|---|
jump | equal | not equal | below | not below | above | not above |
cmp ah,bh je s;ZF=1則跳轉 add ah,bh jmp short ok s: add ah,bh ok:ret
mov ax,0 mov ax,0 je s inc ax s: inc ax ;執行後ax的值等於1,add ax,0使得ZF=1,因此je指令將進行轉移。
;方案一 assume cs:code data segment db 8,11,8,1,8,5,63,38 data ends code segment start: mov ax,data mov ds,ax mov bx,0;ds:bx指向第一個字節 mov ax,0;初始化累加器 mov cx,0 s: cmp byte ptr [bx],8;和8進行比較 jne next;若是不相等轉到next,繼續循環 inc ax;若是相等就計數值加1 next: inc bx loop s;執行後:(ax)=3 mov ax,4c00h int 21h code ends end segment
;方案二 assume cs:code data segment db 8,11,8,1,8,5,63,38 data ends code segment start: mov ax,data mov ds,ax mov bx,0;ds:bx指向第一個字節 mov ax,0;初始化累加器 mov cx,0 s: cmp byte ptr [bx],8;和8進行比較 je ok;若是不相等轉到ok,繼續循環 jmp short next;若是不想等就轉到next,繼續循環 ok: inc ax;若是相等就計數值加1 next: inc bx loop s;執行後:(ax)=3 mov ax,4c00h int 21h code ends end segment
assume cs:code data segment db 8,11,8,1,8,5,63,38 data ends code segment start: mov ax,data mov ds,ax mov bx,0;ds:bx指向第一個字節 mov ax,0;初始化累加器 mov cx,0 s: cmp byte ptr [bx],8;和8進行比較 jna next;若是大於8轉到next,繼續循環 inc ax;若是大於就計數值加1 next: inc bx loop s;執行後:(ax)=3 mov ax,4c00h int 21h code ends end segment
;下面的程序執行後ax的值是多少? mov ax,0 push ax popf mov ax,0fff0h add ax,0010h pushf pop ax and al,11000101b and ah 00001000b
assume cs:code data segment db'welcome to masm!' db 16 dup(0) data ends code segment start: mov ax,data mov ds,ax mov si,0;指向data:0 mov es,ax mov di,16;指向data:16 mov cx,16;rep循環16次 cld;設置DF=0,正向傳送 rep movsb mov ax,4c00h int 21h code ends end start
assume cs:code data segment db 16 dup(0) data ends code segment start: mov ax,0f00h mov ds,ax mov si,0ffffh;指向f0000:ffff mov ax,data mov es,ax mov di,16;指向data:15 mov cx,16;rep循環16次 std;設置DF=1,逆向傳送 rep movsb mov ax,4c00h int 21h code ends end start
標誌 | 值爲1的標記 | 值爲0的標記 |
---|---|---|
OF | OV | NV |
SF | NG | PL |
ZF | ZR | NZ |
PF | PE | PO |
CF | CY | NC |
DF | DN | UP |
pop IP pop CS popf
assume cs:codesg codesg segment start: mov ax,1000h mov bh,1 div bh codesg ends end start
把程序存入內存,修改向量表(即將內存地址登記在中斷向量表的對應表項中),中斷時調用這個內存。
除法溢出對應的中斷類型碼爲0,它的中斷處理程序的入口地址應該從0* 4+2地址單元開始存放,段地址存放在0* 4+2字單元中,偏移地址存放在0*4字單元中。也就是改變後的中斷處理程序的段地址0存放在0000:0002字單元中,偏移地址200H存放在0000:0000字單元中。若是要顯示的字符串在程序的data段中,那麼程序執行完成後返回,它所佔用的內存空間被系統釋放,在其中存放的信息也可能被別的信息覆蓋。
assume cs:code code segment start: mov ax,cs mov ds,ax mov si,offset do0;設置ds:di指向源地址 mov ax,0 mov es,ax mov di,200h;設置es:si指向目的地址 mov cx,offset do0end - offset do0;設置cx爲傳輸長度,編譯器能夠識別加減乘除運算符 cld;設置傳輸方向爲正 rep movsb mov ax,0;設置中斷向量表 mov es,ax mov word ptr es:[0*4],200h mov word ptr es:[0*4+2],0 mov ax,4c00h int 21h do0: jmp short do0start db"welcome to masm!";在代碼段中存儲數據 do0start: mov ax,cs mov ds,ax mov si,202h;jmp short do0start這條指令棧兩個字節 ;顯示字符串,設置es:di指向字符串 mov ax,0b800h;顯存空間,直接顯示在顯示器上 mov es,ax mov di,12*160+36*2;這隻es:di指向顯存空間的中間位置 mov cx,16;設置cx爲字符串(welcome to masm!)長度 s: mov al,[si] mov es:[di],al inc si add di,1 mov al,02h mov es:[di],al add di,1 loop s mov ax,4c00h int 21h do0end: nop code ends end start
在有些狀況下CPU在執行完當前指令後,即使是發生了中斷也不會響應。
在執行完向ss寄存器傳送數據的指令後,即使檢測到了中斷信號CPU也不會響應。由於ss:sp指向棧頂,對他們的設置應該連續完成。若是在執行完設置ss指令後mCPU響應中斷引起中斷過程,要在棧中壓入標誌寄存器、CS和IP的值。而ss改變,sp並未改變則ss:sp指向不是正確的棧頂將引起錯誤。
咱們要將棧頂設置爲1000:0,不該該隔開
應該 | 不該該 |
---|---|
mov ax,1000h | mov ax,1000h |
mov ss,ax | mov ss,ax |
mov sp,0 | mov ax,0 |
mov ax,0 | mov sp,0 |
assume cs:code code segment start: mov ax,0b800h mov es,ax mov byte ptr es:[12*160+40*2],'!' int 0;執行int 0指令,引起中斷過程,執行0號中斷處理程序 code ends end start
;計算 ssume cs:code code segment start: mov ax,3456 int 7ch add ax,ax adc ax,dx mov ax,4c00h int 21h code ends end start ;安裝程序 assume cs:code code segment start: mov ax,cs mov ds,ax mov si offset sqr;設置ds:si指向源地址 mov ax,0 mov es,ax mov di,200h;設置es:di指向目的地址 mov cx,offset sqrend- offset sqr;設置cx爲傳輸長度 cld;設置傳輸方向爲正 rep movsb mov ax,0 mov es,ax mov word ptr es:[7ch*4],200h mov word ptr ws:[7ch*4+2],0 mov ax,4c00h int 21h sqr: mul ax iret sqrend: nop code 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 int 7ch mov ax,4c00h int 21h code ends end start assume cs:code code segment 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+2],0 mov ax,4c00h int 21h capital: push cx push si change: mov cl,[si] mov ch,0 jcxz ok and byte ptr [si],11011111b inc si jmp short change ok: pop si pop cx iret capitalend: nop code ends end start
編程:用7ch中斷例程完成loop指令的功能,在屏幕中間顯示80個"!".
loop指令須要循環次數和到標號的位移。爲了模擬loop指令7ch中斷例程應具有下面dec cx和若是cx的值不等於0則轉移到標號s處。
assume cs:code code segment start: mov ax,0b800h;顯存地址 mov es,ax mov di,160*12 mov bx,offset s- offset se;設置從標號s的轉移位移 mov cx,80 s: mov byte ptr es:[di],'!' add di,2 int 7ch;若是cx的值不等於0則轉移到標號s處 se: nop mov ax,4c00h int 21h code ends end start ;7ch中斷例程 lp: push bp mov bp,sp; dec cx jcxz lpret add [bp+2],bx lpret: pop bp iret
mov ah,2;表示調用10h號中斷例程的2號子程序,功能爲設置光標位置 mov bh,0;頁號 mov dh,5;行號 mov dl 12;列號 int 10h;
;功能爲在光標位置顯示字符功能 mov ah,9;置光標,調用9號子程序 mov al,'a';字符 mov bl,7;顏色屬性,和在顯存中的屬性字節的格式相同 mov bh,0;第0頁 mov cx,3;字符重複個數 int 10h ``` - 編程:在屏幕的第5行12列顯示3個紅底高亮閃爍綠色的'a' ```asm assume cs:code code segment mov ah,2;設置光標 mov bh,0;第0頁 mov dh,5;dh中放行號 mov dl,12;dl中放列號 int 10 mov ah,9;設置光標 mov al,'a';字符 mov bl,11001010b;顏色屬性 mov bh,0;第0頁 mov cx,3;字符重複個數 int 10h mov ax,4c00h int 21h code ends end
mov ah,4ch;程序返回 mov al,0;返回值0是正常返回 ;合起來寫就是 mov ax,4c00h int 21h
int 2h中斷例程還具備在光標位置顯示字符串的功能、
ds:dx;要顯示的字符串須要用 $ 做爲結束符 mov ah,9;功能號9,表示在光標位置顯示字符串 int 21h
;對0~255之內的端口進行讀寫 in al,20h;從20h端口讀入一個字節 out 20h,al;往20h端口寫入一個字節 ;對256~65535的端口進行讀寫時,端口放在dx中 mov dx,3f8h;將端口號3f8h送入dx in al,dx;從3f8端口讀入一個字節 out 3f8h,al;往3f8h端口寫入一個字節
bios也提供了相關的程序使用戶在開機時配置CMOS RAM中的系統信息。
mov al,01001000b shl al,1;將al中的數據左移一位 ;執行後al的值是10010000b,CF=0
mov al,01010001b mov cl,3 shl al,cl ;執行後al的值爲10001000b,cf=0
mov al,00000001b | 執行後al的值等於00000001b=1 |
---|---|
shl al,1 | 執行後al的值等於00000010b=2 |
shl al,1 | 執行後al的值等於00000100b=4 |
shl al,1 | 執行後al的值等於00001000b=8 |
mov cl,3 | |
shl al,cl | 執行後al的值等於01000000b=64 |
在CMOS RAM中以每一個信息一字節存放着當前的時間信息:年09h,月08h,日07h,時04h,分02h,秒00h。這些數據以BCD碼的方式存放,BCD碼以4位爲一位。
assume cs:code code segment start: ;向地址端口70h寫入要訪問的單元地址,讀取CMOS RAM的信息 mov al,8 out 70h,al in al,71h;從數據端口中取得指定單元中的數據 mov ah,al;al中爲從CMOS RAM的8號端口讀出數據 mov cl,4 shr ah,cl;ah中爲月份的十位數碼值 and al,00001111b;ah中爲月份的個位數值碼 add ah,30h;BCD碼值+30h(字符'0')=十進制對應的ASCII碼 add al,30h ;用BCD碼錶示的月份以十進制的形式顯示到屏幕上。 mov bx,0b800h;顯存 mov es,bx mov byte ptr es:[160*12+40*2],ah;顯示月份的十位數碼 mov byte ptr es:[160*12+40*2+2],al;顯示月份的個位數碼 mov ax,4c00h int 21h code ends end start
可屏蔽中斷所引起的中斷過程,除在第一步的實現上有所不一樣外,基本上和內中斷的中斷過程相同。由於可屏蔽中斷信息來自於CPU外部,中斷類型碼是經過數據總線送入CPU的;而內中斷的中斷類型碼是在CPU內部產生的。在中斷過程當中將IF置0的緣由是在進入中斷處理程序後禁止其餘的可屏蔽中斷。
前三步由硬件系統自動完成,第四步用戶能夠修改int 9中斷程序。
;顯示字符 code segment start: mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah inc ax cmp ah,'z' jna s mov ax,4c00h int 21h code ends end start
;延遲顯示字符 assume cs:code stack segment db 128 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,128 mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah call delay inc ah cmp ah,'z' jna s mov ax,4c00h int 21h delay: push ax push dx mov dx,10h;循環100次,延遲的時間和CPU的計算能力成反比 mov ax,0 s1: sub ax,1 sbb dx,0 cmp ax,0 jne s1 cmp dx,0 jne s1 pop dx pop ax ret code ends end start
;實現IF=0,TF=0步驟 pushf pop ax and ah,11111100b push ax popf
assume cs:code stack segment db 128 dup(0) stack ends data segment dw 0,0 data ends code segment start: mov ax,stack mov ss,ax mov sp,128 mov ax,data mov ds,ax mov ax,0 mov es,ax push es:[9*4] pop ds:[0] push es:[9*4+2] pop ds:[2];將原來的int9中斷例程的入口地址保存 mov word ptr es:[9*4+2],offset int9 mov es:[9*4+2],cs;在中斷向量表中設置新的int 9中斷例程的入口地址 mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah call delay inc ah cmp ah,'z' jna s mov ax,0 mov es,ax push ds:[0] pop es:[9*4] push ds:[2] pop es:[9*4+2];將中斷向量表中int9中斷例程的入口恢復爲原來的地址 mov ax,4c00h int 21h delay: push ax push dx mov dx,10h;循環100次,延遲的時間和CPU的計算能力成反比 mov ax,0 s1: sub ax,1 sbb dx,0 cmp ax,0 jne s1 cmp dx,0 jne s1 pop dx pop ax ret ;新的int 9中斷例程 int9: push ax push bx push es in al,60h pushf pushf pop bx and bh,11111100b push bx popf call dword ptr ds:[0];對int指令進行模擬,調用原來的int9中斷例程 cmp al,1;esc鍵盤掃描碼 jne int9ret mov ax,0b800h mov es,ax inc byte ptr es:[160*12+40*2+1];改變顏色 int9ret: pop es pop bx pop ax iret code ends end start
assume cs:code stack segment db 128 dup(0) stack ends data segment dw 0,0 data ends code segment start: mov ax,stack mov ss,ax mov sp,128 mov ax,data mov ds,ax mov ax,0 mov es,ax push es:[9*4] pop ds:[0] push es:[9*4+2] pop ds:[2];將原來的int9中斷例程的入口地址保存 mov word ptr es:[9*4+2],offset int9 mov es:[9*4+2],cs;在中斷向量表中設置新的int 9中斷例程的入口地址 mov ax,0b800h mov es,ax mov ah,'a' s: mov es:[160*12+40*2],ah call delay inc ah cmp ah,'z' jna s mov ax,0 mov es,ax push ds:[0] pop es:[9*4] push ds:[2] pop es:[9*4+2];將中斷向量表中int9中斷例程的入口恢復爲原來的地址 mov ax,4c00h int 21h delay: push ax push dx mov dx,10000h;循環100次,延遲的時間和CPU的計算能力成反比 mov ax,0 s1: sub ax,1 sbb dx,0 cmp ax,0 jne s1 cmp dx,0 jne s1 pop dx pop ax ret ;新的int 9中斷例程 int9: push ax push bx push es in al,60h pushf pushf pop bx and bh,11111100b push bx popf call dword ptr ds:[0];對int指令進行模擬,調用原來的int9中斷例程 cmp al,1;esc鍵盤掃描碼 jne int9ret mov ax,0b800h mov es,ax inc byte ptr es:[160*12+40*2+1];改變顏色 int9ret: pop es pop bx pop ax iret code ends end start
assume cs:code stack segment db 128 dup(0) stack ends code segment start: mov ax,stack mov ss,ax mov sp,128 push cs pop ds mov ax,0 mov es,ax mov si,offset int9;設置ds:si指向源地址 mov di,204h;設置es:di指向目的地址 mov cx,offset int9end - offset int9;設置cx爲傳輸長度 cld;設置傳輸方向 rep movsb push es:[9*4] pop es:[200h] push es:[9*4+2] pop es:[202h] cli mov word ptr es:[9*4],204h mov word ptr es:[9*4+2],0 sti mov ax,4c00h int 21h int9: push ax push bx push cx push es in al,60h pushf call dword ptr cs:[200h];當此中斷例程執行時(CS)=0 cmp al,3bh;f1的掃描碼 jne int9ret mov ax,0b800h mov es,ax mov bx,1 mov cx,2000 s: inc byte ptr es:[bx] add bx,2 loop s int9ret: pop es pop cx pop bx pop ax iret int9end: nop code ends end start
assume cs:code cod segment a:db 1,2,3,4,5,6,7,8 b:dw 0 start: mov si,offset a mov bx,offset b mov cx,8 s: mov al,cs:[si] mov ah,0 add cs:[bx],ax inc si loop s mov ax,4c00h int 21h code ends end start ;代碼中的 s、start等都是標號,表示了內存的地址
在code段中使用的標號a,b後面沒有:,所以他們能夠同時描述內存地址和單元長度的標號
assume cs:code cod segment a db 1,2,3,4,5,6,7,8 ;描述了地址code:0,和從這個地址開始之後的內存單元都是直接單元 b dw 0 ;則b是code[8] start: mov si,0 mov cx,8 s: mov al,a[si] ;至關於mov al,cs:0[si] mov ah,0 add b,ax inc si loop s mov ax,4c00h int 21h code ends end start
assume cs:code,ds:data cod segment a:db 1,2,3,4,5,6,7,8 b:dw 0 data ends start: mov ax,data mov ds,ax mov si,0 s: mov al,a[si] mov ah,0 add b,ax inc si loop s mov ax,4c00h int 21h code ends end start
data segment a db 1,2,3,4,5,6,7,8 b dw 0 c dw a,b ;至關於 c dw offset a,offset b data ends data segment a db 1,2,3,4,5,6,7,8 b dw 0 c dd a,b ;至關於 c dw offset a,seg a,offset b,seg b ;seg操做符,功能是取得某一標號的段地址 data ends
assume cs:code code:segment mov al,0eh call showbyte mov ax,4c00h int 21 ;子程序,用al傳送要顯示的數據 showbyte: jmp short show table db '1023456789ABCDEF';字符表 show: push bx push es mov ah,al shr ah,1 shr ah,1 shr ah,1 shr ah,1;右移4位,ah中獲得高4位的值 and al,00001111b;al中爲低4位 mov bl,ah mov bh,0 mov ah,table[bx];用高4位的值做爲相對於table的便宜,取得對應的字符 mov bx,0b800h mov es,bx mov es:[160*12+40*2],ah mov bl,al mov bh,0 mov al,table[bx];用低4位的值做爲相對於table的偏移,取得對應的字符 mov es:[160*12+40*2+2],al pop es pop bx ret code ends end start
;================================入口函數1===================================== ;入口函數說明; ;用ah傳遞功能號,0是清屏,1是設置前景色,2是設置背景色,3是向上滾動一行 setscreen: jmp short set table dw sub1,sub2,sub3,sub4 set: push bx cmp ah,3;判斷傳遞的功能號是否大於3 ja sret mov bl,ah mov bh,0 add bx,bx;根據ah中的功能號計算對應子程序的地址在table表中的偏移 call word ptr table[bx];調用對應的子程序 sret; pop bx iret ;================================入口函數2===================================== ;入口函數說明; ;用ah傳遞功能號,0是清屏,1是設置前景色,2是設置背景色,3是向上滾動一行 setscreen: cmp ah,0 je do1 cmp ah,1 je do2 cmp ah,2 je do3 cmp ah,3 je do4 jmp short sret do1: call sub1 jmp short sret do2: call sub2 jmp short sret do3: call sub3 jmp short sret do4: call sub4 jmp short sret ;子功能========================================================================== ;清屏 sub1: push bx push cx push es mov bx,0b800h mov es,bx mov bx,0 mov cx,2000 sub1s: mov byte ptr es:[bx],'' add bx,2 loop sub1s pop es pop cx pop bx ret ;設置前景色 sub2: push bx push cx push es mov bx,0b800h mov es,bx mov bx,1 mov cx,2000 sub2s: mov byte ptr es:[bx],11111000b or es:[bx],al add bx,2 loop sub2s pop es pop cx pop bx ret ;設置背景色 sub3: push bx push cx push es mov cl,4 shl al,cl mov bx,0b800h mov es,bx mov bx,1 mov cx,2000 sub3s: mov byte ptr es:[bx],10001111b or es:[bx],al add bx,2 loop sub3s pop es pop cx pop bx ret ;向上滾動一行 sub4: push cx push si push di push es push ds mov si,0b800h mov es,si mov ds,si mov si,160;ds:si指向第n+行 mov di,0;es:di指向第n行 cld mov cx,24;共複製24行 sub4s: push cx mov cx,160 rep movsb;複製 pop cx loop sub4s mov cx,80 mov si,0 sub4s1: mov byte ptr es:[160*24+si],'';最後一行清空 add si,2 loop sub4s1 pop ds pop es pop di pop si pop cx ret;結束
筆者看不下去了。。。。有興趣的讀者能夠繼續找相關的資料看。。。