X86彙編3.內存訪問

最近學習了X86彙編,其實無論是古老的8086還是現在i3/5/7/9,Xeon3/5,在最基本原理上,都是相通的,只是CPU位數,尋址空間,寄存器個數,指令集的擴充等方面有所不同,對於學習,8086永不過時。

1.內存中字的存儲
8086CPU中,用16位寄存器來存儲一個字,高8位存放高字節,低8位存放低字節。在內存中存儲時,由於內存單元是字節單元,一個單元存放一個字節,那麼一個字(2字節,16位)應該用兩個連續的存儲單元(內存地址)來存儲,低字節存放在低地址,高字節存放在高地址,這就是我們所說的小端序,大端序與之相反。
字單元:存放一個字型數據(16位)的內存單元,它由兩個連續內存單元組成。
8086CPU不支持將數據直接存入段寄存器(DS),需要先將數據存放到通用寄存器,然後再MOV到段寄存器。
“[address]”做爲一個整體表示一個內存單元,中括號中的數字表示內存單元的偏移地址。如:
假設DS中爲1000H,那麼:
MOV Al, [0] ;將10000H內存地址中的數據存入AX
MOV [0], Al ;將AX中的數據存入內存地址10000H
eg.1讀取10000H中內存單元的內容
mov bx, 1000H
mov ds, bx
mov al, [0]
eg.2將al中的數據存入10000H內存地址中
mov bx, 1000H
mov ds, bx
mov [0], al

字的傳送:
mov bx, 1000H
mov ds, bx
mov ax, [0] ;1000:0處的數據存入AX寄存器
mov [0], ax ;AX寄存器中的值存入1000:0

2.指令學習:mov、add、sub
(1)mov 指令格式:
mov 寄存器, 數據
mov 寄存器,寄存器
mov 寄存器,內存單元
mov 內存單元,寄存器
mov 段寄存器,寄存器
mov 寄存器,段寄存器
mov 段寄存器,內存單元
(2)add指令格式:
add 寄存器, 數據
add 寄存器,寄存器
add 寄存器,內存單元
add 內存單元,寄存器
(3)sub指令格式:
sub 寄存器, 數據
sub 寄存器,寄存器
sub 寄存器,內存單元
sub 內存單元,寄存器

3.數據段
前面講過段的概念,也講過代碼段,那麼我們知道指令和數據都是二進制形式,既然有代碼段,那麼也應該有數據段。
我們可以將一組長度爲N、地址連續、起始地址爲16倍數的內存單元當做專門存儲數據的內存段,即:數據段。如:123B0H~123B9H這段內存空間做數據段,那麼它的段地址爲123BH,長度爲10個字節。
相比於代碼段有代碼段寄存器:CS,那麼數據段也有數據段寄存器:DS
數據段的數據訪問:可以用ds作爲數據段的地址,再根據需要訪問數據段中的具體單元
如:123B0H~123B9H作爲一個數據段
mov ax, 123BH
mov ds, ax ;設置段地址
mov al, 0 ;清零al寄存器,保存累加結果
add al, [0] ;累加數據段第0偏移地址
add al, [1] ;累加數據段第1偏移地址
add al, [2] ;累加數據段第2偏移地址

4.棧
8086CPU提供操作把一段內存以棧的方式進行操作,入棧指令:push,出棧指令:pop。
(1)push 指令格式:
push 寄存器
push 段寄存器
push 內存地址
(2)pop指令格式:
pop 寄存器
pop 段寄存器
pop 內存地址
eg1.
push ax ;把ax寄存器中的數據存入棧
eg2.
pop ax ;從棧頂取出數據存入ax

8086CPU的入棧和出棧操作都可以以字爲單位進行。
8086CPU提供段寄存器SS和寄存器SP,棧頂的段地址存放在SS,偏移地址粗放在SP,任意時刻:SS:SP指向棧頂元素。posh和pop指令被執行時,CPU從SS和SP中取到棧頂地址
push ax的執行可分2部分完成:
(1)SP=SP-2,SS:SP指向當前棧頂前面的單元,以當前棧頂前面的單元爲新的棧頂。因爲棧地址是從高地址向低地址移動使用的。如:棧地址10000H~1000FH,棧底是1000FH,棧頂是10000H,初始時SS是1000H,SP是0010H,棧爲空,由於此時要壓入數據,SP=SP-2,則SP變成了000EH。
(2)將ax中的內容存入SS:SP指向的內存單元,即:執行push ax後,第一個數據被壓入1000EH地址單元,SSH和SP的值不變,等待下一次入棧。
總結:入棧是從高地址向低地址方向增長,此外:任意時刻SS:SP指向棧頂元素
pop ax的執行過程與入棧相反,也可分2部分完成:
(1)將SS:SP指向的內存單元處的數據送入ax中
(2)SP=SP+2,SS:SP指向當前棧頂下面的單元,以當前棧頂下面的單元爲新的棧頂。
總結:出棧是從低地址高地址方向減少的,此外:細心讀者可以看一下,出棧後,棧內數據並不清零,也就是垃圾數據,所以有時候我們依然能在某些時候讀到正確數據,但是千萬別僥倖,因爲棧隨時會增長,覆蓋這些數據,更危險的是,此時入果向該地址寫入數據,那麼程序將立即崩潰。

棧頂越界和棧底越界的問題:棧底越界,我們會讀到棧外的數據;棧頂越界,我們會向超出棧空間外的內存空間寫入數據,這是非常危險的。但是8086CPU並不提供棧保護機制,這需要程序員自己來完成。

棧段:我們可以將長度爲N的一組地址連續、起始地址爲16倍數的內存單元,當做棧空間來使用,從而定義一個棧段,但是這僅僅是一種安排,CPU並不會由於這種安排,就在執行pop和push指令時,自動爲將我們定義的棧空間當做棧空間訪問,需要我們通過SS:SP來控制。此外,pop和push本質上是一種特殊的內存訪問指令,pop和push修改的是SP。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章