OS學習筆記 九 實模式 從彙編的角度理解棧結構

2021-09-02 07:42:45 字數 3439 閱讀 2094

還記得前幾篇文章,我們學會了編寫主引導扇區**,在顯示屏顯示字串。最開始我們的做法是乙個字元乙個字元的傳送給視訊記憶體。後來發現可以先將所有需要傳送的字元先存放到一塊記憶體中,然後使用movsw連續傳送這些字串到視訊記憶體更加方便。

今天我們的目的是,我們將我們想要顯示的數字,先暫時存放到一種稱為的結構中。最後我們再從棧中取出這些數字傳送給視訊記憶體。

與前幾篇文章一樣,我們先提供彙編**。遇到彙編**不要害怕,腦子裡將cpu,暫存器,記憶體這三個結構與他們的關係都勾勒出來,然後分析指令的執行,就會很清晰。

;**清單7-1

;檔名:c07_mbr.

asm;檔案說明:硬碟主引導扇區**

;jmp near start

message db '1+2+3+...+100='

start:

mov ax,

0x7c0

;設定資料段的段基位址

mov ds,ax

mov ax,

0xb800

;設定附加段基址到顯示緩衝區

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

;以下計算1到100的和

xor ax,ax

mov cx,

1 @f:

add ax,cx

inc cx

cmp cx,

100 jle @f

;以下計算累加和的每個數字

xor cx,cx ;設定堆疊段的段基位址

mov ss,cx

mov sp,cx

mov bx,

10 xor cx,cx

@d:inc cx

xor dx,dx

div bx

or dl,

0x30

;實際上應該是add指令,但是這可以是or指令,因為dl高四位為0

,0x30低四位位0

push dx

cmp ax,

0 jne @d

;以下顯示各個數字

@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

**不長,大部分內容,在前幾篇文章都學過。

這裡分析會比較簡潔,因為大部分**的意思跟前幾篇文章內容是乙個意思,無非就是設定**段資料段基位址與偏移位址,設定視訊記憶體的基位址與偏移位址。然後將要顯示的字串經過計算得出結果並存起來。最後將這些字串傳送到顯示緩衝區。

那麼下面就開始分析:

18-28行:將字串『1+2+3+…+100』顯示出來。這裡同樣使用了迴圈的方法將字串迴圈傳送到視訊記憶體。cx這裡代表計數器,表示要傳送的字串的位元組數。inc指令代表加1的意思。

40-53行:計算累加和的各個數字。畢竟我們要顯示這個累加和嘛,又不能直接將它傳送到顯示緩衝區直接顯示,直接將它的各個數字拆解出出來顯示。這幾行,是我們今天要重要研究的彙編**。它涉及到乙個新的概念----棧

得到了累加和之後,前兩篇文章,是將各個數字儲存在資料段中。現在我們將各個數字儲存在乙個叫做棧的地方。

棧----是一種特殊的資料儲存結構,資料的訪問只能從一端進行。這樣先進去的資料只能最後出來。後進去的資料倒是最先出來。

如下圖:

定義棧需要兩個步驟。即指定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行所做的事。其他指令較為簡單治理不再贅述。

這幾行都比較簡單。pop指令的意思是將邏輯位址ss:sp處的乙個字彈出到暫存器dx中,然後將暫存器sp的內容加上運算元的字長(2)。

上述我們從**層面第一次接觸到棧這種結構。那麼下面我們就來總結一下,做幾點說明。

push指令的運算元可以是16位暫存器或者16位記憶體單元。push指令執行後,壓入棧中的僅僅是該暫存器或者記憶體單元中的數值

棧在本質上也只是普通的記憶體區域,之所以用push和pop指令來訪問,是因為你把它看成棧而已。引入棧和push、pop只是方便程式開發而已。

要注意保持棧平衡。push多少,pop多少。

在編寫程式時,必須充分估計所需的棧空間,以防止破壞有用的資料。

儘管不能完全阻止程式中的錯誤,但是,通過將棧定義到乙個單獨的64kb記憶體段,可以使錯誤僅侷限於棧段,而不破壞其他段的有用資料。

執行結果如下;

本次程式執行很順利!!!

筆記記得不是很全,像彙編的語法以及如何將**寫到虛擬硬碟的主引導扇區這些都沒有寫。如果又不懂的可以加我****一起交流。

彙編學習筆記九

原理 可以修改cs或ip jmp指令 loop指令 和cx有關 操作符 offset 這個指令使用之前需要在乙個指令前面定義乙個標號,使用offset獲取指令的偏移位址 jmp指令跳轉指令,jmp的後面可以跟乙個標號,表示跳轉到的位置 assume cs code code segment mov ...

python學習筆記(九)之os模組

os operating system os模組是python標準庫中乙個用於訪問作業系統功能的模組。使用os模組中提供的介面,可以實現跨平台訪問。當os模組被匯入後,它會自適應於不同的作業系統平台,根據不同的平台進行相應的操作。通用操作 獲取平台資訊 對目錄的操作 判斷操作 方法功能 os.sep...

Python學習筆記九4 os模組

模組os讓你能夠訪問多個作業系統服務。它包含的內容很多,表10 3只描述了其中幾個最有用的函式和變數。除此之外,os及其子模組os.path還包含多個檢視 建立和刪除目錄及檔案的函式,以及一些操作路徑的函式 例如,os.path.split和os.path.join讓你在大多數情況下都可忽略os.p...