對棧操作的理解

2021-07-07 07:03:33 字數 1989 閱讀 5185

對棧操作的理解

乙個cpu具有八個通用暫存器:eax,edx,ecx,esi,edi,ebp,esp,ebx。這八個通用暫存器中的每乙個都被安排了特定用途,cpu在執行某些特定指令時需要特定的暫存器協作以高效的完成其指令執行過程。

其中有兩個重要的暫存器負責棧的處理:  ebp(擴充套件基址指標)和  esp(擴充套件棧頂指標)。

除上面的八個通用暫存器,下面還會提到  eip(擴充套件指令指標)。

當呼叫乙個函式時:

①:呼叫程式首先將函式引數壓入棧中,從而對函式呼叫進行設定。

而被呼叫函式的職責是:

①:將呼叫程式的ebp暫存器儲存到棧上。

②:將當前esp暫存器儲存到ebp暫存器。(設定當前棧幀)

③:將esp暫存器減小,從而為該函式的本地變數騰出空間。

④:上面的語句執行完畢後,函式才可以執行自己的語句。

被呼叫函式返回到呼叫程式之前:

①:將esp增加到ebp,從而將棧清空。

②:從棧中彈出所儲存的eip。

說了這麼多,其實不用知道這些,我們只需要知道函式呼叫的工作原理就行了。

函式呼叫的工作原理就是:壓棧 - 操作 - 彈棧 ,但是有上面的解釋,我們可以更好的理解函式呼叫的原理。

而壓棧的本質就是記錄壓棧前的狀態,彈棧是恢復到壓棧前的狀態。而這個記錄狀態的東西(想不出來叫什麼,暫且叫它東西吧),這個東西當然要能在彈棧時恢復的跟壓棧前一模一樣,這樣,我們就需要知道在函式執行過程中哪些量變了,哪些量沒變,所因為我們沒必要將沒變的量壓入棧中。現在,重點已經不是壓棧和彈棧了,重點是如何恢復到函式呼叫前的那個狀態。下面貼上兩段**:

#include

#include

int main()

int print(int n)

#include

#include

int main()

printf("%d\n",n);

}我們先不看注釋掉的部分。第一段**呼叫了函式來輸出,而第二段**中沒有呼叫函式,只是用{}括起來了一部分**,兩段**的結果一模一樣,而第二段**沒有用棧就實現了第一段**中用棧的效果,可想而知,效率肯定是比用棧高的。這樣做的原理其實很簡單,函式呼叫時的棧操作就是儲存呼叫的引數的資訊,並在函式操作結束時還原引數資訊。而第二段**的思想就是在壓棧前(printf函式執行前)對「引數」進行更改,並在彈棧後(printf函式執行完後)將「引數」恢復為原來的值。所以可以實現和第一段**相同的功能。

現在我們可以看看注釋的部分,如果加上注釋的部分,兩段**的結果就不同了。第一段**的執行結果並沒有改變,但是第二段**的結果變了。原因是第二段**在{}內的**段裡,沒能將n改回原先的值。

看到這裡應該有些小收穫吧,把第二段**改一下就不會出現n不能變回原值的問題了。

#include

#include

int main()

printf("%d\n",n);

}這樣子,用temp記錄下了n的初始值,接下來在{}內部,n想怎麼改就怎麼改,不用在擔心n不能變回原始值的問題了。

哈啊啊,這樣子就體現出了棧的三大特性(這三大特性是我自己總結的,可能並不是很準確。)之一:記錄。而其他兩大特性:追蹤 和 保密 並沒有體現出來。

追蹤無法體現的原因是:假設還有temp1,temp2,……tempn,由於各個temp並不是連續定義的,所以他們在記憶體中的位址不連續,如果知道temp1的位址,無法根據temp1找到temp2的位址,以此類推,這樣子的話就無法實現連續壓棧,連續彈棧的操作。

保密無法體現的原因是:temp定義在這個**段之外,也就是說temp的訪問許可權在main函式手裡,而不是在這個**段手裡。這樣子,main函式中的其他操作也可以更改temp,這樣會造成潛在的錯誤。這裡的感覺有點像物件導向的封裝,的確是有封裝的意思,但是最致命的並不是沒有封裝,致命的是如果乙個棧不能保密的話,訪問棧的人就可以獲取棧頂的位址,而找到棧頂位址就意味著整個棧的資訊都可以通過訪問位址訪問到,而通過訪問位址訪問棧的元素就已經脫離了棧的規則,也就是說訪問者可以隨意修改你的棧,當然也可以讓你的棧崩潰。

希望大家看了之後能有收穫。

資料結構 棧的簡單理解以及對棧的基本操作

先來簡單的了解一下棧 1.棧 一種特殊的線性表,其實只允許在固定的一端進行插入或刪除操作。進行資料插入和刪除的一端稱為棧頂,另一端稱為棧底。不含任何元素的棧稱為空棧,棧又稱為 後進先出的線性表。2.順序棧和順序表資料成員相同,不同之處 順序棧的入棧和出棧操作只允許對當前棧頂進行操作!棧的初始化 vo...

iOS 對堆和棧的理解

堆 和 棧的 區別 經典 此 文章雖然是 面向 c c 程式設計師寫得,但是對咱們 ios程式設計師還是很有幫助的。堆和棧的區別 一 預備知識 程式的記憶體分配 乙個由 c c 編譯的程式佔 用的記憶體分為以下 幾個部分 1 棧區 stack 由編譯器 自動分配釋放 存放函式的引數值,區域性變數的值...

對棧的一些理解

之前總結過一篇有關函式棧幀的部落格 函式棧幀以及呼叫約定相關的一些總結 但是感覺自己還是有一點知識點沒有弄懂,今天中午跟郭哥吃過飯一起 有關殼的問題的時候,順便把這個問題請教了一下郭哥,終於弄明白了,在此要特地感謝他,這裡把一些心得體會寫出來 先看一幅圖 選自ida權威指南 注意圖中是基於esp的棧...