【OS学习笔记】九 实模式:从汇编的角度理解栈结构
上一篇文章以一種更加高效的方法編寫了主引導(dǎo)扇區(qū)的代碼。主要是引入了循環(huán)和跳轉(zhuǎn)指令。點(diǎn)擊鏈接查看上一篇文章:編寫主引導(dǎo)扇區(qū)代碼-另一種更高效的寫法
本篇文章,繼續(xù)上一篇文章的學(xué)習(xí)。同樣還是編寫匯編代碼加載到主引導(dǎo)扇區(qū)讓CPU直接執(zhí)行。但是我們以一個(gè)簡單程序,實(shí)現(xiàn)1加到100,來引出8086中的棧結(jié)構(gòu)。了解處理器訪問棧需要哪些支持。
1、回顧
還記得前幾篇文章,我們學(xué)會(huì)了編寫主引導(dǎo)扇區(qū)代碼,在顯示屏顯示字符串。最開始我們的做法是一個(gè)字符一個(gè)字符的傳送給顯存。后來發(fā)現(xiàn)可以先將所有需要傳送的字符先存放到一塊內(nèi)存中,然后使用movsw連續(xù)傳送這些字符串到顯存更加方便。
今天我們的目的是,我們將我們想要顯示的數(shù)字,先暫時(shí)存放到一種稱為棧的結(jié)構(gòu)中。最后我們?cè)購臈V腥〕鲞@些數(shù)字發(fā)送給顯存。
2、代碼清單
與前幾篇文章一樣,我們先提供匯編代碼。遇到匯編代碼不要害怕,腦子里將CPU,寄存器,內(nèi)存這三個(gè)結(jié)構(gòu)與他們的關(guān)系都勾勒出來,然后分析指令的執(zhí)行,就會(huì)很清晰。
如果不懂,看后面的分析,如果你有一點(diǎn)基礎(chǔ),就一定能夠?qū)W會(huì)!!!
;代碼清單7-1;文件名:c07_mbr.asm;文件說明:硬盤主引導(dǎo)扇區(qū)代碼;jmp near startmessage db '1+2+3+...+100='start:mov ax,0x7c0 ;設(shè)置數(shù)據(jù)段的段基地址 mov ds,axmov ax,0xb800 ;設(shè)置附加段基址到顯示緩沖區(qū)mov es,ax;以下顯示字符串 mov si,message mov di,0mov cx,start-message@g:mov al,[si]mov [es:di],alinc dimov byte [es:di],0x07inc diinc siloop @g;以下計(jì)算1到100的和 xor ax,axmov cx,1@f:add ax,cxinc cxcmp cx,100jle @f;以下計(jì)算累加和的每個(gè)數(shù)位 xor cx,cx ;設(shè)置堆棧段的段基地址mov ss,cxmov sp,cxmov bx,10xor cx,cx@d:inc cxxor dx,dxdiv bxor dl,0x30 ;實(shí)際上應(yīng)該是add指令,但是這可以是or指令,因?yàn)閐l高四位為0,0x30低四位位0push dxcmp ax,0jne @d;以下顯示各個(gè)數(shù)位 @a:pop dxmov [es:di],dlinc dimov byte [es:di],0x07 ;顯示字符的顏色屬性inc diloop @ajmp near $ times 510-($-$$) db 0db 0x55,0xaa代碼不長,大部分內(nèi)容,在前幾篇文章都學(xué)過。
3、代碼分析
強(qiáng)烈建議先將上一篇文章學(xué)會(huì),再閱讀下面的代碼解釋會(huì)更加輕松:點(diǎn)擊鏈接查看上一篇文章
這里分析會(huì)比較簡潔,因?yàn)榇蟛糠执a的意思跟前幾篇文章內(nèi)容是一個(gè)意思,無非就是設(shè)置代碼段數(shù)據(jù)段基地址與偏移地址,設(shè)置顯存的基地址與偏移地址。然后將要顯示的字符串經(jīng)過計(jì)算得出結(jié)果并存起來。最后將這些字符串傳送到顯示緩沖區(qū)。
那么下面就開始分析:
-
8行:就是想要顯示‘1+2+3+…+100’,只不過這里先要將它存儲(chǔ)在這里,好方便下面的循環(huán)傳送。message是標(biāo)號(hào),代表它當(dāng)前位置的匯編地址
-
11-14行:設(shè)置數(shù)據(jù)段基地址與附加段基地址(也就是顯存的基地址),這里前幾篇文章已經(jīng)講了很多,不懂的可以回頭看前面的文章。
-
18-28行:將字符串‘1+2+3+…+100’顯示出來。這里同樣使用了循環(huán)的方法將字符串循環(huán)傳送到顯存。CX這里代表計(jì)數(shù)器,表示要傳送的字符串的字節(jié)數(shù)。inc指令代表加1的意思。
-
31-37行:計(jì)算1-100的和。這里將計(jì)算結(jié)果存到AX寄存器。CX每次加1是代表下一次要加的數(shù)。
-
40-53行:計(jì)算累加和的各個(gè)數(shù)位。畢竟我們要顯示這個(gè)累加和嘛,又不能直接將它發(fā)送到顯示緩沖區(qū)直接顯示,直接將它的各個(gè)數(shù)位拆解出出來顯示。這幾行,是我們今天要重要研究的匯編代碼。它涉及到一個(gè)新的概念----棧
得到了累加和之后,前兩篇文章,是將各個(gè)數(shù)位保存在數(shù)據(jù)段中。現(xiàn)在我們將各個(gè)數(shù)位保存在一個(gè)叫做棧的地方。
棧----是一種特殊的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)的存取只能從一端進(jìn)行。這樣先進(jìn)去的數(shù)據(jù)只能最后出來。后進(jìn)去的數(shù)據(jù)倒是最先出來。
如下圖:
和代碼段,數(shù)據(jù)段和附加段一樣,棧也是一種內(nèi)存段,叫做棧段。由棧寄存器SS指向。
針對(duì)棧有兩種操作方式:push和pop。這個(gè)應(yīng)該大家都理解。壓棧和出棧只能在一端進(jìn)行。所以需要用棧指針寄存器SP來指示下一個(gè)數(shù)據(jù)應(yīng)當(dāng)壓入到什么位置,或者數(shù)據(jù)從哪里彈出。
定義棧需要兩個(gè)步驟。即指定SS和SP寄存器。為此40-42行,設(shè)置了SS和SP。他們都是指向0地址。
到目前為止,我們已經(jīng)定義了3個(gè)段。如下圖是我們當(dāng)前程序的內(nèi)存布局:
總內(nèi)存容量是1MB,物理地址范圍是0x00000-0xFFFFF
其中數(shù)據(jù)段長度是64KB(實(shí)際上它的長度無關(guān)緊要)占據(jù)的物理地址范圍是0x07C00-0x17BFF,對(duì)應(yīng)的邏輯地址為范圍為 0x07C0:0x0000-0x7C00:0xFFFF;
代碼段和棧段是同一個(gè)段,占據(jù)著物理地址0x00000-0x0FFFF,對(duì)應(yīng)的邏輯地址的范圍是0x0000:0x0000-0x0000:0xFFFF。
雖然代碼段和棧段在本質(zhì)上指向同一塊內(nèi)存區(qū)域,但是通過后面的學(xué)習(xí)我們會(huì)知道,他們互不干擾。
分解各個(gè)數(shù)位還是要靠除法來做,44行將除數(shù)10傳送給寄存器BX。
由于每次分解得到的數(shù)位都是壓棧的,所以后面再出棧的時(shí)候,我們需要記住總共有多少個(gè)。這里用CX寄存器記錄個(gè)數(shù)。所以45行,先將CX寄存器清零。
源程序第47-53行也是一個(gè)循環(huán)體,沒執(zhí)行一次,分解出一個(gè)數(shù)位。每次分解時(shí),CX加1,表明數(shù)位又多了一個(gè),這是源程序47行所做的事。其他指令較為簡單治理不再贅述。
- 57-62行:出棧,并顯示各個(gè)數(shù)位。
這幾行都比較簡單。pop指令的意思是將邏輯地址SS:SP處的一個(gè)字彈出到寄存器DX中,然后將寄存器SP的內(nèi)容加上操作數(shù)的字長(2)。
-
64行:為了讓我們看到顯示屏的顯示效果,這里是一個(gè)死循環(huán),防止程序退出。
-
67-68行:填充空的字節(jié)區(qū)間。然后最后的0x55和0xaa是主引導(dǎo)扇區(qū)的有效標(biāo)志。
4、進(jìn)一步認(rèn)識(shí)棧
上述我們從代碼層面第一次接觸到棧這種結(jié)構(gòu)。那么下面我們就來總結(jié)一下,做幾點(diǎn)說明。
5、運(yùn)行程序
運(yùn)行結(jié)果如下;
本次程序運(yùn)行很順利!!!
筆記記得不是很全,像匯編的語法以及如何將代碼寫到虛擬硬盤的主引導(dǎo)扇區(qū)這些都沒有寫。如果又不懂的可以加我聯(lián)系方式一起交流。
學(xué)習(xí)探討加個(gè)人:
qq:1126137994
微信:liu1126137994
總結(jié)
以上是生活随笔為你收集整理的【OS学习笔记】九 实模式:从汇编的角度理解栈结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: halcon/c++接口基础 之 控制参
- 下一篇: docker 安装及打springboo