【OS学习笔记】八 实模式:编写主引导扇区代码-另一种更高效的写法
學(xué)習(xí)交流加
- 個(gè)人qq:
1126137994 - 個(gè)人微信:
liu1126137994 - 學(xué)習(xí)交流資源分享qq群:
962535112
上一篇文章,我們用比較原始的方法編寫了主引導(dǎo)扇區(qū)的代碼。點(diǎn)擊鏈接查看上一篇文章:編寫主引導(dǎo)扇區(qū)代碼
本片文章將學(xué)習(xí)以下內(nèi)容:
- 用一種不同的分段方法,從另一個(gè)不同的的角度理解處理器的分段內(nèi)存訪問機(jī)制
- 使用循環(huán)和條件轉(zhuǎn)移指令來優(yōu)化上一篇文章的主引導(dǎo)扇區(qū)代碼
文章目錄
- 1、代碼清單
- 2、代碼分析
- 3、編譯運(yùn)行
- 4、總結(jié)
1、代碼清單
首先先貼上代碼。50行代碼,不長。看到匯編不要害怕!!!后面會(huì)一步一步分析這個(gè)匯編代碼的每一條指令的意思。
;代碼清單6-1;文件名:c06_mbr.asm;文件說明:硬盤主引導(dǎo)扇區(qū)代碼; jmp near startmytext db 'L',0x07,'a',0x07,'b',0x07,'e',0x07,'l',0x07,' ',0x07,'o',0x07,\'f',0x07,'f',0x07,'s',0x07,'e',0x07,'t',0x07,':',0x07number db 0,0,0,0,0start:mov ax,0x07c0 ;設(shè)置數(shù)據(jù)段基地址 mov ds,axmov ax,0xb800 ;設(shè)置附加段基地址,也就是將ES寄存器指向顯存的起始地址 mov es,axcld ;方向清零標(biāo)志,將DF標(biāo)志位清零,代表傳送是正向的mov si,mytext ;SI與DS組成數(shù)據(jù)段的地址 DS:SI 代表數(shù)據(jù)的真實(shí)物理地址 mov di,0 ;DI與ES組成顯存的物理地址 ES:DI 代表顯存的真實(shí)物理地址mov cx,(number-mytext)/2 ;實(shí)際上等于 13rep movsw ;循環(huán)movsw,直到cx寄存器內(nèi)容為0(rep指令代表反復(fù)傳送);得到標(biāo)號(hào)所代表的偏移地址mov ax,number;計(jì)算各個(gè)數(shù)位mov bx,axmov cx,5 ;循環(huán)次數(shù) mov si,10 ;除數(shù) digit: xor dx,dxdiv simov [bx],dl ;保存數(shù)位inc bx ;使bx寄存器里的值加1loop digit;顯示各個(gè)數(shù)位mov bx,number ;將number的匯編地址傳送給BX寄存器mov si,4 ;bx+si 得到字符串的每一個(gè)字符,SI從4遞減到0,這是由于要先顯示萬位上的數(shù)字show:mov al,[bx+si]add al,0x30 ;得到它對應(yīng)的ASCII碼mov ah,0x04 ;對應(yīng)的顏色屬性mov [es:di],ax ;AX中是一個(gè)完整的字,前8位是顯示屬性值,后8位是字符的ASCII碼add di,2 ;DI寄存器在之前用過,現(xiàn)在在“Label offset:” 字符串后面,剛好我們想讓number的匯編地址在這里顯示dec si ;SI-1,從number代表的匯編地址的萬位到個(gè)位,dec指令會(huì)影響SF標(biāo)志位,當(dāng)SI寄存器的值為0的時(shí)候,SF的標(biāo)志位置1jns show ;判斷SF標(biāo)志位是否為0,當(dāng)SF標(biāo)志位不為0,繼續(xù)執(zhí)行show處的代碼。當(dāng)SF標(biāo)志位為0,則跳過這條指令執(zhí)行下一條指令。mov word [es:di],0x0744 ;高字節(jié)0x07是黑底白字的屬性,低字節(jié)0x44是字符‘D’的ASCII碼jmp near $ ;相當(dāng)于 infi: jmp near infitimes 510-($-$$) db 0 ; 計(jì)算512字節(jié)中,需要填滿的字節(jié)有哪些。db 0x55,0xaa ;一個(gè)有效的主引導(dǎo)扇區(qū),最后兩字節(jié)必須是0x55 0xaa2、代碼分析
堅(jiān)持看完,一定能看懂!!!
- 8行-9行:這里聲明了非指令的數(shù)據(jù)。一般來說,所有處理器指令都是按順序存放,在他們中間不允許夾雜非指令的數(shù)據(jù)。但是如果有辦法讓處理器不執(zhí)行這些數(shù)據(jù),則又另當(dāng)別論。如第6行的代碼。
這兩行聲明的是要在顯示屏上顯示的數(shù)據(jù):"Label offset: ",其中0x07是每個(gè)字符的顯示屬性值。
- 6行:它是一條轉(zhuǎn)移指令。讓處理器跳轉(zhuǎn)到標(biāo)號(hào)start處開始執(zhí)行。這就避開了數(shù)據(jù)區(qū)。
- 13-14行:設(shè)置數(shù)據(jù)段的基地址。DS代表數(shù)據(jù)段的基地址。
這里為什么是0x07c0呢?
由上幾篇文章學(xué)過的知識(shí)知道,主引導(dǎo)扇區(qū)程序加載時(shí),被加載到的位置是0x0000:0x7c00.也就是物理地址:0x07c00 這其實(shí)就是將整個(gè)物理地址空間看成是基地址0x0000,偏移地址0x7c00的分段方式。
這樣的話,CPU每次訪問內(nèi)存的時(shí)候總是要加上0x7c00這個(gè)偏移地址。但是程序中一般訪問內(nèi)存的指令非常多,每一條都加上0x7c00很不現(xiàn)實(shí)。
但是Intel處理器的分段策略很靈活。邏輯地址0x0000:0x7c00對應(yīng)的物理地址是0x07c00 ,而該地址又是另一個(gè)邏輯地址0x07c0:0x0000的地址。如下圖是以兩個(gè)邏輯段的視角看待同一個(gè)內(nèi)存區(qū)域。
我們可以將512字節(jié)的區(qū)域看成是一個(gè)單獨(dú)的段。段的基地址是:0x07c0 段長512字節(jié)。注意,該段的最大長度是64KB,但是這里我們實(shí)際上只用了512字節(jié)。盡管BIOS是將主引導(dǎo)扇區(qū)加載到物理地址0x07c00處,但是我們卻可以認(rèn)為它是從0x07c0:0x0000處開始加載的。
所以13-14行將數(shù)據(jù)段寄存器DS指向0x07c0
- 16-17行:使附加段寄存器ES的內(nèi)容指向顯存的基地址0xb800
- 19-23行:循環(huán)movsw,直到cx寄存器內(nèi)容為0(rep指令代表反復(fù)傳送)。這里是循環(huán)將DS:SI所指向的數(shù)據(jù)傳送到ES:DI所指定的顯示緩沖區(qū)。
循環(huán)movsw與movsb指令執(zhí)行時(shí),將DS:SI所指向的數(shù)據(jù)傳送到ES:DI所指定地址。同時(shí)每傳送一次 ,CX寄存器的內(nèi)容減一。
rep代表循環(huán)movsw,直到寄存CX的內(nèi)容為0為止。所以22行中,計(jì)算出數(shù)據(jù)的字節(jié)數(shù),并將其傳送到CX寄存器。
20行將SI指向數(shù)據(jù)區(qū)的首地址,SI與DS組成數(shù)據(jù)段的地址 DS:SI 代表數(shù)據(jù)的真實(shí)物理地址
21行將0給DI寄存器,DI與ES組成顯存的物理地址 ES:DI 代表顯存的真實(shí)物理地址。很明顯,我們是從顯存的0偏移地址開始存數(shù)據(jù)。
19行,方向清零標(biāo)志,將DF標(biāo)志位清零,代表傳送是正向的。**正向的意思是傳送操作的方向是從內(nèi)存的低地址端到搞地質(zhì)端。**很明顯我們是正向傳送。
-
26行:我們還是想像上一篇文章一樣,顯示字符串后將number這個(gè)標(biāo)號(hào)的數(shù)值顯示出來。所以先將number標(biāo)號(hào)的匯編地址傳送給AX寄存器保存。后面會(huì)用。
-
29-37行:還記得上一篇文章是如何分解number的各個(gè)數(shù)位的么?如果不記得,請點(diǎn)擊鏈接查看:上一篇文章 上一篇文章是一個(gè)一個(gè)分解然后保存的。這里有所改變。使用了循環(huán),可以讓我們少寫很多代碼。這里就不多說了,不懂的看上一篇文章,這個(gè)循環(huán)也很好理解,loop這個(gè)指令將循環(huán)次數(shù)CX減一,指導(dǎo)CX等于0為止。
-
40-49行:顯示標(biāo)號(hào)number的匯編地址的各個(gè)數(shù)位。同理,如何顯示各個(gè)數(shù)位,可以查看上一篇文章。這里只是將重復(fù)的代碼,寫成了循環(huán)的形式。
jns這個(gè)指令判斷SF標(biāo)志位是否為0,當(dāng)SF標(biāo)志位不為0,繼續(xù)執(zhí)行show處的代碼。當(dāng)SF標(biāo)志位為0,則跳過這條指令執(zhí)行下一條指令。
dec指令會(huì)影響SF標(biāo)志位,當(dāng)SI寄存器的值為0的時(shí)候,SF的標(biāo)志位置1
這里唯一需要注意的是低端字節(jié)序傳送的時(shí)候,寄存器的低字節(jié)傳送到顯示緩沖區(qū)的低地址部分,寄存器的高字節(jié)傳送到顯示緩沖區(qū)的高地址部分。如下圖所示:
- 51行:顯示字符‘D’
- 53行:死循環(huán)
- 55行:計(jì)算512字節(jié)中,空字節(jié)有多少,然后將這些空字節(jié)填滿0
$ 代表當(dāng)前行的匯編地址
$$ 代表當(dāng)前段的起始地址。由于本程序沒有定義段,所以自成一個(gè)段,并且起始地址是0地址。
- 56行:一個(gè)有效的主引導(dǎo)扇區(qū),最后兩字節(jié)必須是0x55 0xaa
3、編譯運(yùn)行
將我們匯編代碼編譯好的二進(jìn)制bin文件寫到虛擬硬盤的主引導(dǎo)扇區(qū)中。啟動(dòng)虛擬機(jī),就會(huì)運(yùn)行我們寫的代碼,運(yùn)行結(jié)果如下:
今天的程序運(yùn)行的很順利。
4、總結(jié)
了解匯編的運(yùn)行機(jī)制,對以后深入學(xué)習(xí)高級(jí)語言,很有幫助:比如JVM。
筆記記得不是很全,像匯編的語法以及如何將代碼寫到虛擬硬盤的主引導(dǎo)扇區(qū)這些都沒有寫。如果又不懂的可以加我聯(lián)系方式一起交流。
學(xué)習(xí)探討加個(gè)人:
qq:1126137994
微信:liu1126137994
總結(jié)
以上是生活随笔為你收集整理的【OS学习笔记】八 实模式:编写主引导扇区代码-另一种更高效的写法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: nlp 停用词处理java_NLP入门:
- 下一篇: excel 个人日常记账——统计报表