匯編語言有關(guān)在屏幕區(qū)顯示字符的四種方法(推薦)
李忠老師的《x86匯編語言:從實(shí)模式到保護(hù)模式》中第五章到第七章的部分,每一章在講述知識(shí)點(diǎn)的同時(shí),分別使用了三種不同的顯示字符的方法,加上調(diào)用BIOS的10h中 斷的方法,這里做出一次簡單梳理:
一:第五章,最基礎(chǔ)的直接用mov 的方法
代碼如下:
;代碼清單5-1 ;文件名:c05_mbr.asm ;文件說明:硬盤主引導(dǎo)扇區(qū)代碼 ;創(chuàng)建日期:2011-3-31 21:15 mov ax,0xb800 ;指向文本模式的顯示緩沖區(qū) mov es,ax ;以下顯示字符串"Label offset:" mov byte [es:0x00],'L' mov byte [es:0x01],0x07 mov byte [es:0x02],'a' mov byte [es:0x03],0x07 mov byte [es:0x04],'b' mov byte [es:0x05],0x07 mov byte [es:0x06],'e' mov byte [es:0x07],0x07 mov byte [es:0x08],'l' mov byte [es:0x09],0x07 mov byte [es:0x0a],' ' mov byte [es:0x0b],0x07 mov byte [es:0x0c],"o" mov byte [es:0x0d],0x07 mov byte [es:0x0e],'f' mov byte [es:0x0f],0x07 mov byte [es:0x10],'f' mov byte [es:0x11],0x07 mov byte [es:0x12],'s' mov byte [es:0x13],0x07 mov byte [es:0x14],'e' mov byte [es:0x15],0x07 mov byte [es:0x16],'t' mov byte [es:0x17],0x07 mov byte [es:0x18],':' mov byte [es:0x19],0x07 mov ax,number ;取得標(biāo)號(hào)number的偏移地址 mov bx,10 ;設(shè)置數(shù)據(jù)段的基地址 mov cx,cs mov ds,cx ;求個(gè)位上的數(shù)字 mov dx,0 div bx mov [0x7c00+number+0x00],dl ;保存?zhèn)€位上的數(shù)字 ;求十位上的數(shù)字 xor dx,dx div bx mov [0x7c00+number+0x01],dl ;保存十位上的數(shù)字 ;求百位上的數(shù)字 xor dx,dx div bx mov [0x7c00+number+0x02],dl ;保存百位上的數(shù)字 ;求千位上的數(shù)字 xor dx,dx div bx mov [0x7c00+number+0x03],dl ;保存千位上的數(shù)字 ;求萬位上的數(shù)字 xor dx,dx div bx mov [0x7c00+number+0x04],dl ;保存萬位上的數(shù)字 ;以下用十進(jìn)制顯示標(biāo)號(hào)的偏移地址 mov al,[0x7c00+number+0x04] add al,0x30 mov [es:0x1a],al mov byte [es:0x1b],0x04 mov al,[0x7c00+number+0x03] add al,0x30 mov [es:0x1c],al mov byte [es:0x1d],0x04 mov al,[0x7c00+number+0x02] add al,0x30 mov [es:0x1e],al mov byte [es:0x1f],0x04 mov al,[0x7c00+number+0x01] add al,0x30 mov [es:0x20],al mov byte [es:0x21],0x04 mov al,[0x7c00+number+0x00] add al,0x30 mov [es:0x22],al mov byte [es:0x23],0x04 mov byte [es:0x24],'D' mov byte [es:0x25],0x07 infi: jmp near infi ;無限循環(huán) number db 0,0,0,0,0 times 203 db 0 db 0x55,0xaa
這里采用的最基礎(chǔ)的做法,就是對(duì)字符進(jìn)行一個(gè)一個(gè)的處理。先將顯示緩存區(qū)的地址0xb800賦給es寄存器,然后通過 mov byte[es:0x00],'L' 的形式,來處理后續(xù)的字符。這種方法較為簡單,這里不再贅述。
二:第六章,采用了批量處理的方法
代碼如下:
;代碼清單6-1 ;文件名:c06_mbr.asm ;文件說明:硬盤主引導(dǎo)扇區(qū)代碼 ;創(chuàng)建日期:2011-4-12 22:12 jmp near start mytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\ 'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07 number db 0,0,0,0,0 start: mov ax,0x7c0 ;設(shè)置數(shù)據(jù)段基地址 mov ds,ax mov ax,0xb800 ;設(shè)置附加段基地址 mov es,ax cld mov si,mytext mov di,0 mov cx,(number-mytext)/2 ;實(shí)際上等于 13 rep movsw ;得到標(biāo)號(hào)所代表的偏移地址 mov ax,number ;計(jì)算各個(gè)數(shù)位 mov bx,ax mov cx,5 ;循環(huán)次數(shù) mov si,10 ;除數(shù) digit: xor dx,dx div si mov [bx],dl ;保存數(shù)位 inc bx loop digit ;顯示各個(gè)數(shù)位 mov bx,number mov si,4 show: mov al,[bx+si] add al,0x30 mov ah,0x04 mov [es:di],ax add di,2 dec si jns show mov word [es:di],0x0744 jmp near $ times 510-($-$$) db 0 db 0x55,0xaa
這里采用的辦法是批量傳送,后續(xù)用loop循環(huán)挨個(gè)處理。這樣的寫法明顯比上一種寫法要高明一些,減少了工作量。這段代碼中值得注意的地方是 mov si,mytext (其中mytext是聲明的字符的地址),這里值得留意的原因之一是在做顯示時(shí)間的編碼中,有過下列這樣的寫法,所以會(huì)格外的留心。
org 7c00h start1: mov ax, cs ; 置其他段寄存器值與CS相同 mov ds, ax ; 數(shù)據(jù)段 mov es, ax mov bl, 10h mov bp, Message1 mov ah, 02h int 1ah xor ax, ax mov al, ch div bl add al, 0x30 mov [es:bp+2], al add ah, 0x30 mov [es:bp+3], ah xor ax, ax mov al, cl div bl add al, 0x30 mov [es:bp+5], al add ah, 0x30 mov [es:bp+6], ah xor ax, ax mov al, dh div bl add al, 0x30 mov [es:bp+8], al add ah, 0x30 mov [es:bp+9], ah mov dh, 3 mov dl, 0 mov ax, 1301h ; 功能號(hào) mov bp, Message1 mov cx, MessageLength1 mov bx, 0007h int 10h ; ret Message1: db ' 00:00:00' MessageLength1 equ ($-Message1) times 510-($-$$) db 0 ; 用0填充引導(dǎo)扇區(qū)剩下的空間 db 55h, 0aah ; 引導(dǎo)扇區(qū)結(jié)束標(biāo)志
(上面的那段代碼的功能是調(diào)用BIOS中斷顯示系統(tǒng)時(shí)間)這段代碼中對(duì)于“00:00:00”的處理方法,代碼二中批量處理si處的mytext字段有異曲同工之妙,這里mark一下。
關(guān)于代碼二中顯示數(shù)字的方法,是用到了loop循環(huán)。先將數(shù)字按照“除以10”的方法得到每一位的值,然后將其加上0x30(有關(guān)ASCII的知識(shí)可解釋這一點(diǎn)是為什么),然后將最終值賦予 依次遞增的顯存地址對(duì)應(yīng)的內(nèi)容,直到將之前處理的每一位數(shù)字都顯示出來,over.
三:第七章,使用棧來操作
這一章的代碼的特殊之處在于通過將字符串按照一個(gè)一個(gè)的順序分別取到之后,將其按照順序壓棧,然后再依次出棧再處理而顯示。
;代碼清單7-1 jmp near start message db '1+2+3+...+100=' start: mov ax,0x7c0 ;設(shè)置數(shù)據(jù)段的段基地址 mov ds,ax mov ax,0xb800 ;設(shè)置附加段基址到顯示緩沖區(qū) mov es,ax ;以下顯示字符串 mov si,message mov di,0 mov cx,start-message @g: mov al,[si] mov [es:di],al inc di mov byte [es:di],0x07 inc di inc si loop @g ;以下計(jì)算1到100的和 xor ax,ax mov cx,1 @f: add ax,cx inc cx cmp cx,100 jle @f ;以下計(jì)算累加和的每個(gè)數(shù)位 xor cx,cx ;設(shè)置堆棧段的段基地址 mov ss,cx mov sp,cx mov bx,10 xor cx,cx @d: inc cx xor dx,dx div bx or dl,0x30 push dx cmp ax,0 jne @d ;以下顯示各個(gè)數(shù)位 @a: pop dx mov [es:di],dl inc di mov byte [es:di],0x07 inc di loop @a jmp near $ times 510-($-$$) db 0 db 0x55,0xaa
對(duì)于代碼段四,第一部分顯示“1+2+3+4+...+100=”的部分是沿用了上面的代碼二中的做法,使用loop循環(huán)處理。
而下面處理數(shù)字的部分,是一種新的處理方式。這里是將數(shù)字依次“除以10”得到每一位的數(shù)之后,將其加上0x00(原因:ASCII顯示字符需要)壓入棧中,然后在下一個(gè)循環(huán)中,依次出棧并且處理使得其能夠顯示出來。
四:調(diào)用BIOS的10h中斷來顯示字符
以上,無論是最簡單的mov的做法,還是movbw的做法,異或壓棧出棧的做法,都難免分別處理每一個(gè)字符的圈子。這里介紹一種調(diào)用BIOS中斷的做法,直接處理一串字符串,較為簡單,可參考性高。
org 07c00h ; 告訴編譯器程序加載到 7c00處 mov ax, cs mov ds, ax mov es, ax call DispStr ; 調(diào)用顯示字符串例程 jmp $ ; 無限循環(huán) DispStr: mov ax, BootMessage mov bp, ax ; es:bp = 串地址 mov cx, 16 ; cx = 串長度 mov ax, 01301h ; ah = 13, al = 01h mov bx, 000ch ; 頁號(hào)為 0(bh = 0) 黑底紅字(bl = 0Ch,高亮) mov dl, 0 int 10h ; 10h 號(hào)中斷 ret BootMessage: db "Hello, OS world!" times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進(jìn)制代碼恰好為 dw 0xaa55 ; 結(jié)束標(biāo)志
這里的做法是調(diào)用BIOS的10h中斷來顯示“Hello,OS world!”,其中bp為字符串地址,cx為串長度,ah為功能號(hào),al指示光標(biāo)置于串尾,bx指示頁號(hào)為0然后字符顯示屬性為黑底紅字,dh為行號(hào),dl為列號(hào)(如果不做處理的話,默認(rèn)dh,dl皆為0,即在第0行第0列顯示),參數(shù)設(shè)置完之后則調(diào)用10h中斷顯示字符串。
總結(jié):以上的四種方法,通過學(xué)習(xí)不僅了解顯示的方法,更重要的是對(duì)匯編語言有了更多的認(rèn)識(shí)。以上方法在實(shí)際操作中介于方便與否,大多采用的直接調(diào)用BIOS的10h 中斷來操作。
以上所述是小編給大家介紹的匯編語言有關(guān)在屏幕區(qū)顯示字符的四種方法,希望對(duì)大家有所幫助!
相關(guān)文章
匯編語言指令集學(xué)習(xí)條件轉(zhuǎn)移指令詳解
這篇文章主要為大家介紹了匯編語言指令集學(xué)習(xí)條件轉(zhuǎn)移的指令全面總結(jié)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11