中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

系統(tǒng)棧的工作原理

2018-07-20    來源:編程學習網

容器云強勢上線!快速搭建集群,上萬Linux鏡像隨意使用

1.開篇

本篇文章著重寫的是系統(tǒng)中棧的工作原理,以及函數調用過程中棧幀的產生與釋放的過程,有可能名字過大,如果不合適我可以換一個名字,希望大家能夠指正,小丁虛心求教!如果有哪里寫的不清楚的或者錯誤的地方請及時更正,小丁再次謝過了。文章里面有錯別字,也可能會有好友說寄存器的32、16位的區(qū)別其實我感覺這里主要講的還是些原理性的東西,后續(xù)會將文章圖片錯別字進行調整.

2.內存的不同用途

根據不同的操作系統(tǒng),一個進程可能被分配到不同的內存區(qū)域去執(zhí)行。但是不管什么樣的操作系統(tǒng)、什么樣的計算機架構,進程使用的內存都可以按照功能大致分為以下4個部分:

(1)代碼區(qū):這個區(qū)域存儲著被裝入執(zhí)行的二進制機器代碼,處理器會到這個區(qū)域取指并執(zhí)行。

(2)數據區(qū):用于存儲全局變量等。

(3)堆區(qū):進程可以在堆區(qū)動態(tài)地請求一定大小的內存,并在用完之后歸還給堆區(qū)。動態(tài)分配和回收是堆區(qū)的特點。

(4)棧區(qū):用于動態(tài)地存儲函數之間的關系,以保證被調用函數在返回時恢復到母函數中繼續(xù)執(zhí)行。

在Windows平臺下,高級語言寫出的程序經過編譯鏈接,最終會變成PE文件。當PE文件被裝載運行后,就成了所謂的進程。

PE文件代碼段中包含的二進制級別的機器代碼會被裝入內存的代碼區(qū)(.text),處理器將到內存的這個區(qū)域一條一條地取出指令和操作數,并送入運算邏輯單元進行運算;如果代碼中請求開辟動態(tài)內存,則會在內存的堆區(qū)分配一塊大小合適的區(qū)域返回給代碼區(qū)的代碼使用;當函數調用發(fā)生時,函數的調用關系等信息會動態(tài)地保存在內存的棧區(qū),以供處理器在執(zhí)行完被調用函數的代碼時,返回母函數。

如果把計算機看成一個有條不紊的工廠,我們可以得到如下類比:

< CPU是完成工作的工人。

< 數據區(qū)、堆區(qū)、棧區(qū)等則是用來存放原料、半成品、成品等各種東西的場所。

< 存放在代碼區(qū)的指令則告訴CPU要做什么,怎么做,到哪里去領原材料,用什么工具來做,做完以后把成品放到哪個貨倉去。

< 值得一提的是,棧除了扮演存放原料、半成品的倉庫之外,它還是車間調度主任的辦公室。

3.棧與系統(tǒng)棧

從計算機科學的角度來看,棧指的是一種數據結構,是一種先進后出的數據表。棧的最常見操作有兩種:壓棧(PUSH)、彈棧(POP);

用于標識棧的屬性也有兩個:棧頂(TOP)、棧底(BASE)。

棧在內存中的存放是高地址是棧底(Base),低地址是棧頂(Top)。

下面來演示下棧的工作原理:

首先我們先以這段匯編指令來進行操作:

mov ax,0123H

push ax

mov bx 2244H

push bx

pop ax

pop bx

首先我們先將10000H-1000FH這段內存空間來當做棧來使用,首先執(zhí)行的操作是push ax,會將0123H壓入到棧中,SP=SP-2,SS:SP指向當前棧頂當前的單元,以當前的單元為新的棧頂,將ax的數據送到SS:SP指向的內存單元中,SS:SP此時指向新的棧頂。此時ax的數值是0123H;詳細請見下圖

接來下進行第二部操作:push bx,操作同上;

接下來我們要演示的是pop操作,請注意pop操作的細節(jié),比如到了棧底的時候指針是在哪里?這些都是要進行關注的。

CPU執(zhí)行pop ax時,SP=SP+2,SS:SP指向1000EH,pop操作棧頂元素,1000CH處的2266H依然存在,但是它在棧中不存在了,當再次push等入棧指令后,SS:SP移至1000CH,并在里面寫入新的數據,將其覆蓋。詳細看下圖操作:

當再次進行pop給bx時,這是SP=SP+2,這時候指針就超出了棧底,就變成了SP=10H,所以我們得出一個結論就是當棧為空時,SS=1000H,SP=10H。詳細看下面操作:

內存的棧區(qū)實際上指的就是系統(tǒng)棧。系統(tǒng)棧由系統(tǒng)自動維護,它用于實現高級語言中函數的調用。對于類似C語言這樣的高級語言,系統(tǒng)棧的PUSH、POP等堆棧平衡細節(jié)是透明的。一般說來,只有在使用匯編語言開發(fā)程序的時候,才需要和它直接打交道。

4.函數調用約定與相關指令

函數調用約定描述了函數傳遞參數方式和棧幀同工作的技術細節(jié)。不同的操作系統(tǒng)、不同的語言、不同的編譯器在實現函數調用時的原理雖然基本相同,但具體的調用約定還是有差別的。這包括參數傳遞方式,參數入棧順序是從右向左還是從左向右,函數返回時恢復堆棧平衡的操作在子函數中進行還是在母函數中進行。
調用方式之間的差異

具體的,對于Visual C++來說,可支持以下3種函數調用約定:

如果要明確使用某一種調用約定,只需要在函數前加上調用約定的聲明即可,否則默認情況下,VC會使用_stdcall的調用方式。 除了參數入棧方向和恢復棧平衡操作位置的不同之外,參數傳遞有時也會有所不同。例如,每一個C++類成員函數都有一個this指針,在Windows平臺中,這個指針一般是用ECX寄存器來傳遞的,但如果用GCC編譯器來編譯,這個指針會作為最后一個參數壓入棧中。

注意:同一段代碼用不同的編譯選項、不同的編譯器編譯鏈接后,得到的可執(zhí)行文件會有很多不同。

函數調用大概包括以下幾個步驟:

(1)參數入棧:將參數從右向左依次壓入系統(tǒng)棧中。

(2)返回地址入棧:將當前代碼區(qū)調用指令的下一條指令地址壓入棧中,供函數返回時繼續(xù)執(zhí)行。

(3)代碼區(qū)跳轉:處理器從當前代碼區(qū)跳轉到被調用函數的入口處。

(4)棧幀調整:具體包括:

<1>保存當前棧幀狀態(tài)值,已備后面恢復本棧幀時使用(EBP入棧)。

<2>將當前棧幀切換到新棧幀(將ESP值裝入EBP,更新棧幀底部)。

<3>給新棧幀分配空間(把ESP減去所需空間的大小,抬高棧頂)。

<4>對于_stdcall調用約定,函數調用時用到的指令序列大致如下:

push 參數3????? ;假設該函數有3個參數,將從右向做依次入棧

push 參數2

push 參數1

call 函數地址?? ;call指令將同時完成兩項工作:a)向棧中壓入當前指令地址的下一個指令地址,即保存返回地址。 b)跳轉到所調用函數的入口處。

push ?ebp?????? ?;保存舊棧幀的底部

mov ?ebp,esp???? ;設置新棧幀的底部 (棧幀切換)

sub ??esp,xxx???? ;設置新棧幀的頂部 (抬高棧頂,為新棧幀開辟空間)

函數返回的步驟如下:

<1>保存返回值,通常將函數的返回值保存在寄存器EAX中。

<2>彈出當前幀,恢復上一個棧幀。具體包括:

(1)在堆棧平衡的基礎上,給ESP加上棧幀的大小,降低棧頂,回收當前棧幀的空間。

(2)將當前棧幀底部保存的前棧幀EBP值彈入EBP寄存器,恢復出上一個棧幀。

(3)將函數返回地址彈給EIP寄存器。

<3>跳轉:按照函數返回地址跳回母函數中繼續(xù)執(zhí)行。

還是以C語言和Win32平臺為例,函數返回時的相關的指令序列如下:

add esp,xxx???? ;降低棧頂,回收當前的棧幀

pop ebp???????? ;將上一個棧幀底部位置恢復到ebp

retn??????????? ;a)彈出當前棧頂元素,即彈出棧幀中的返回地址,至此,棧幀恢復到上一個棧幀工作完成。b)讓處理器跳轉到彈出的返回地址,恢復調用前代碼區(qū)

5.寄存器與函數棧幀

每一個函數獨占自己的棧幀空間。當前正在運行的函數的棧幀總是在棧頂。Win32系統(tǒng)提供兩個特殊的寄存器用于標識位于系統(tǒng)棧頂端的棧幀。

(1)ESP:棧指針寄存器(extended stack pointer),其內存放著一個指針,該指針永遠指向系統(tǒng)棧最上面一個棧幀的棧頂。

(2)EBP:基址指針寄存器(extended base pointer),其內存放著一個指針,該指針永遠指向系統(tǒng)棧最上面一個棧幀的底部。

【寄存器對棧的標識作用見(圖1)】

函數棧幀:ESP和EBP之間的內存空間為當前棧幀,EBP標識了當前棧幀的底部,ESP標識了當前棧幀的頂部。

在函數棧幀中,一般包含以下幾類重要信息。

(1)局部變量:為函數局部變量開辟的內存空間。

(2)棧幀狀態(tài)值:保存前棧幀的頂部和底部(實際上只保存前棧幀的底部,前棧幀的頂部可以通過棧幀平衡計算得到),用于在本棧被彈出后恢復出上一個棧幀。

(3)函數返回地址:保存當前函數調用前的“斷點”信息,也就是函數調用前的指令位置,以便在函數返回時能夠恢復到函數被調用前的代碼區(qū)中繼續(xù)執(zhí)行指令。

注:函數棧幀的大小并不固定,一般與其對應函數的局部變量多少有關。函數運行過程中,其棧幀大小也是在不停變化的。除了與棧相關的寄存器外,我們還需要記住另一個至關重要的寄存器。

EIP:指令寄存器(extended instruction pointer),其內存放著一個指針,該指針永遠指向下一條等待執(zhí)行的指令地址。 可以說如果控制了EIP寄存器的內容,就控制了進程——我們讓EIP指向哪里,CPU就會去執(zhí)行哪里的指令。這里不多說EIP的作用,我個人認為王爽老是的匯編里面講EIP講的已經是挺好的了~這里不想多寫關于EIP的事情。

6.結束語

本文是針對上面兩篇文章的一個基礎性的補充~希望大家能夠喜歡和指正其中的不足之處,小丁虛心學習于請教~不知道名字叫啥~

內容參考:0day安全:軟件漏洞分析技術(第2版)

標簽: 安全 代碼 漏洞

版權申明:本站文章部分自網絡,如有侵權,請聯系:west999com@outlook.com
特別注意:本站所有轉載文章言論不代表本站觀點!
本站所提供的圖片等素材,版權歸原作者所有,如需使用,請與原作者聯系。

上一篇:一張圖告訴你:Android系統(tǒng)哪代強?

下一篇:2015年4月編程語言排行榜:Java回到第一