組合語言課堂總結3——記憶體訪問
記憶體中字的儲存
8086CPU中,用16位暫存器儲存一個字,而在前面的學習中瞭解到記憶體是以位元組為單位劃分的,所以一個字要用兩個地址連續的記憶體單元來存放,這就提出了字資料的存取原則(小端法):高—高,低—低,即,字資料的低位位元組存放在低地址記憶體單元;字資料的高位位元組存放在高地址記憶體單元;取低地址記憶體單元地址作為字資料地址。
ex.
除此之外,還有一種儲存方法叫做大端法,顧名思義,和小端法的儲存方式正好相反。
DS和[address] and 字的傳送
DS,資料段暫存器,通常用來存放要訪問的資料的段地址,在mov, add, sub
所以需要通過一般暫存器來實現過渡,比如:
MOV BX, 1000H
MOV DS, BX ;DS<-1000H
MOV AL, [0]
前兩條mov指令完成了兩種傳送:①將資料直接送入暫存器;②將一個暫存器中的內容送入另一個暫存器。
“[...]”表示一個記憶體單元,“[...]”中的資料0表示記憶體單元的偏移地址。所以這三條指令實現的功能就是將
所以字的傳送就是使用MOV指令通過16位暫存器在CPU和記憶體之間進行資料的傳送,其中要使用資料段暫存器DS來訪問記憶體單元。
ex.
MOV、ADD、SUB指令
MOV、ADD、SUB指令都有兩個操作物件,操作物件可以是常數、暫存器、段暫存器和記憶體單元,但並不是任意兩兩組合都可以使用。
mov指令:1、兩個運算元長度要一致。
2、常數(立即數)不能作為第1個運算元(目的運算元);作第2個運算元(源運算元)時,如果最高位是十六進位制的a~f或A~F,前面要加零。
3、
4、不能使用mov指令修改CS和IP的值。
5、兩個段暫存器之間不能直接傳送;不能把常數送到段暫存器。
add指令:1、運算元不能同時是記憶體單元。
2、運算元不能是段暫存器。
3、運算元是記憶體單元時,指令中只給出「偏移地址」。預設,「段地址」在ds中。
sub指令:1、兩個記憶體單元不能直接使用sub指令相減。
2、運算元不能是段暫存器。
3、運算元是記憶體單元時,指令中只給出「偏移地址」。預設,「段地址」在ds中。
棧
棧是一個邏輯上的概念,可以將一段記憶體空間當作棧來使用。棧有“後進先出”的特性。8086CPU中棧以字為存取單位。
棧頂是最後入棧的字資料所對應的地址單元;棧底是固定的一端,棧區最高地址單元的前一個單元。8086CPU中有兩個暫存器,SS(棧段段暫存器)和SP(棧指標暫存器),棧頂的段地址存放在SS中,偏移地址存放在SP中,任意時刻,SS:SP指向棧頂元素。
棧有兩種操作:入棧push和出棧pop。
push:第1步,棧頂上移兩個單元,即:棧頂-2 → 棧頂;第2步,存入資料。
pop:第1步,取出字資料5020H → AX;第2步,棧頂下移兩個單元,即:棧頂+2 → 棧頂。(棧為空時,棧頂指向棧底+2)
push、pop指令形式:
注意:1、在push 記憶體單元和pop 記憶體單元中,指令中只需給出「偏移地址」。預設,段地址在DS中。
2、對8086CPU而言,push和pop的操作:入棧和出棧均以字為單元;操作物件不能是常數;pop 段暫存器中,段暫存器不能是CS和SS。
3、利用棧「後入先出」特性,使用push和pop指令可以完成一些特殊處理。
棧頂越界問題
當以下兩種情形出現時會發生棧頂越界問題:
·當棧滿的時候,再使用push指令入棧
·當棧空的時候,再使用pop指令出棧
因為每次入棧或出棧改變的都是SP中的值,但是SP的範圍只能在0000~FFFFH之間,也就是說一個棧空間最大隻能有64kb,並且8086CPU不會自動考慮棧頂越界,所以容易發生越界的情況。
越界情況發生後,也許不會有很大的影響,但也可能會訪問到使用者許可權之外的記憶體,如果隨意操作,可能會導致電腦出現故障;或者是在SP為FFFF時繼續執行了pop操作,這時可能會取到我們不需要的垃圾資料。
疑問
在檢測點3.1中有如下三條語句:
mov ax, 1
mov ds, ax
mov ax, [0000]
為什麼執行完這三條語句後,AX中的值是0000:0010中的值,而不是0001:0000中的值呢?(有沒有哪位大佬可以解答一下我的疑惑哇)