還記得前幾篇文章,我們學會了編寫主引導扇區**,在顯示屏顯示字串。最開始我們的做法是乙個字元乙個字元的傳送給視訊記憶體。後來發現可以先將所有需要傳送的字元先存放到一塊記憶體中,然後使用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...