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