匯編語言_06


  • 棧:是一種具有特殊的訪問方式的存儲(chǔ)空間(后進(jìn)先出, Last In Out Firt,LIFO)
  • 8086會(huì)將CS作為代碼段的段地址,將CS:IP指向的指令作為下一條需要取出執(zhí)行的指令
  • 8086會(huì)將DS作為數(shù)據(jù)段的段地址,mov ax,[address]就是取出DS:address的內(nèi)存數(shù)據(jù)放到ax寄存器中
  • 8086會(huì)將SS作為棧段的段地址,任意時(shí)刻,SS:SP指向棧頂元素
  • 8086提供了PUSH(入棧)和POP(出棧)指令來操作棧段的數(shù)據(jù)
    • 比如push ax是將 ax的數(shù)據(jù)入棧,pop ax是將棧頂?shù)臄?shù)據(jù)送入ax

push ax


push ax 的執(zhí)行由以下兩個(gè)步驟完成

  • SP = SP - 2,SS:SP 指向當(dāng)前棧頂前面的單元,以當(dāng)前棧頂前面的單元為新的棧頂;
  • 將ax中的內(nèi)容送入 SS:SP 指向的內(nèi)存單元處,SS:SP此時(shí)指向新棧頂

pop ax


pop ax的執(zhí)行過程和push ax剛好相反,由以下兩步完成

  • 將SS:SP指向的內(nèi)存單元處的數(shù)據(jù)送入ax中;
  • SP=SP+2,SS:SP 指向當(dāng)前棧頂下面的單元,以當(dāng)前棧頂下面的單元為新的棧頂

思考
如果將10000H 到 1000FH 這段空間當(dāng)做棧,初始狀態(tài)棧是空的,此時(shí),SS=1000H,SP=?思考后看分析。


???SS:SP執(zhí)行??丶罡叩刂穯卧南乱粋€(gè)單元


結(jié)果

棧頂超界
push


pop


上面描述了執(zhí)行push、pop指令時(shí),發(fā)生的棧頂超界問題。可以看到,當(dāng)棧滿的時(shí)候再使用push指令入棧,或??盏臅r(shí)候再使用pop指令出棧,都將發(fā)生棧頂超界問題。

棧頂超界是危險(xiǎn)的,因?yàn)槲覀兗热粚⒁欢慰臻g安排為棧,那么在棧空間之外的空間里
很可能存放了具有其他用途的數(shù)據(jù)、代碼等,這些數(shù)據(jù)、代碼可能是我們自己程序中的,也可能是別的程序中的(畢竟一個(gè)計(jì)算機(jī)系統(tǒng)中并不是只有我們自己的程序在運(yùn)行)。但是由于我們?cè)谌霔?、出棧時(shí)的不小心,而將這些數(shù)據(jù)、代碼意外地改寫,將會(huì)引發(fā)一連串的錯(cuò)誤。

我們當(dāng)然希望CPU可以幫我們解決這個(gè)問題,比如說在CPU中有記錄棧頂上限和棧底的寄存器,我們可以通過填寫這些寄存器來指定??臻g的范圍,然后,CPU在執(zhí)行push指令的時(shí)候靠檢測棧頂上限寄存器,在執(zhí)行pop指令的時(shí)候靠檢測棧底寄存器保證不會(huì)超界。

不過,對(duì)于8086CPU,這只是我們的一個(gè)設(shè)想(我們當(dāng)然可以這樣設(shè)想,如果CPU是我們?cè)O(shè)計(jì)的話,這也就不僅僅是一個(gè)設(shè)想)。實(shí)際 的情況是,8086CPU中并沒有這樣的寄存器。

8086CPU不保證我們對(duì)棧的操作不會(huì)超界。這也就是說,8086CPU只知道棧頂在何處(由SS:SP指示),而不知道我們安排的??臻g有多大。這點(diǎn)好像CPU只知道當(dāng)前要執(zhí)行的指令在何處(由CS:IP指示),而不知道要執(zhí)行的指令是多少。從這兩點(diǎn)上我們可以看出8086CPU的工作機(jī)理,它只考慮當(dāng)前的情況:當(dāng)前的棧頂在何處,當(dāng)前要執(zhí)行的指令是哪一條。

我們?cè)诰幊痰臅r(shí)候要自己操作棧頂超界的問題,要根據(jù)可能用到的最大??臻g,來安排棧的大小,防止入棧的數(shù)據(jù)太多而導(dǎo)致的超界;執(zhí)行出棧操作的時(shí)候也要注意,以防止棧空的時(shí)候繼續(xù)出棧而導(dǎo)致的超界。

push&pop匯編
push 和 pop 指令的格式可以是如下形式

指令 說明
push 寄存器 將一個(gè)寄存器的數(shù)據(jù)入棧
pop 寄存器 出棧,用一個(gè)寄存器接收出棧的數(shù)據(jù)
push 段寄存器 將一個(gè)段寄存器中的數(shù)據(jù)入棧
pop 段寄存器 出棧,用一個(gè)段寄存器接收出棧的數(shù)據(jù)
push 內(nèi)存單元 將一個(gè)內(nèi)存字單元處的字入棧
pop 內(nèi)存單元 出棧,用一個(gè)內(nèi)存字單元接收出棧的數(shù)據(jù)
mov ax,1000H mov ds,ax 內(nèi)存單元的段地址要放在ds中
push [0] 將1000:0處的字壓入棧中
pop [2] 出棧,出棧的數(shù)據(jù)送入1000:2處

注意

  • 棧操作都是以字為單位
  • 在8086中,push、pop操作的數(shù)據(jù)都是2個(gè)字節(jié)的

編程練習(xí)

  • 將10000H到1000FH 這段空間當(dāng)做棧,初始狀態(tài)棧是空的;
  • 設(shè)置AX=001AH,BX=001BH;
  • 利用棧,交換AX和BX中的數(shù)據(jù)。
mov ax,1000H
mov ss,ax
mov sp,0010H

mov ax,001AH
mov bx,001BH

push ax
push bx
pop ax
pop bx

棧段

  • 對(duì)于8086來說,在編程時(shí),可以根據(jù)需要,將一組內(nèi)存單元定義為一個(gè)段
  • 我們可以將一組長度為N(N<=64KB)、地址連續(xù)、起始地址為16倍數(shù)的內(nèi)存單元,當(dāng)做??臻g來使用,稱為棧段。比如用10010H1001FH這段內(nèi)存空間當(dāng)做棧來使用,我們就可以認(rèn)為10010H1001FH是一個(gè)棧段,它的段地址為1001H,長度為16字節(jié)
  • 如何使用push、pop等棧操作指令訪問我們定義的棧段?
    • 用SS存放棧段的段地址,用SP存放棧頂?shù)钠频刂?/li>

段總結(jié)

  • 我們可以用一個(gè)段存放數(shù)據(jù),將它定義為"數(shù)據(jù)段"
  • 我們可以用一個(gè)段存放代碼,將它定義為"代碼段"
  • 我們可以用一個(gè)段當(dāng)作棧,將它定義為"棧段"

對(duì)于數(shù)據(jù)段,將它的段地址放在DS中,用mov、add、sub等訪問內(nèi)存單元的指令時(shí),CPU就將我們定義的數(shù)據(jù)段中的內(nèi)容當(dāng)作數(shù)據(jù)來訪問;
對(duì)于代碼段,將它的段地址放在CS中,將段中第一條指令的偏移地址放在IP中,這樣CPU就將執(zhí)行我們定義的代碼段中的指令;
對(duì)于棧段,將它的段地址放在SS中,將棧頂單元的偏移地址放在SP中,這樣CPU在需要進(jìn)行棧操作的時(shí)候,比如執(zhí)行push、pop指令等,就將我們定義的棧段當(dāng)作??臻g來用。

練習(xí)


練習(xí)1

練習(xí)1-答案

練習(xí)2

練習(xí)2-答案
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容