日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Linux系統(tǒng)中堆棧的espeip解析(linux堆棧espeip)

Linux系統(tǒng)中堆棧的ESP/EIP解析

在計算機系統(tǒng)中,棧是一種常見的數(shù)據(jù)結(jié)構(gòu),常作為程序的運行空間之一,其中堆棧是最常用的一種。Linux系統(tǒng)中的棧是用C語言實現(xiàn)的,并且在內(nèi)存中以“后進先出”的方式進行存儲和管理。在程序運行時,棧被用來保存函數(shù)調(diào)用的返回地址和局部變量,還用來作為內(nèi)存緩存圈和臨時存儲區(qū)域。在本文中,將詳細分析Linux系統(tǒng)中堆棧的ESP/EIP解析。

ESP是指棧指針寄存器,EIP是指指令指針寄存器,它們都是CPU寄存器中的一種。ESP通常用來記錄棧的棧頂位置,而EIP則用來記錄程序?qū)⒁獔?zhí)行的下一條指令的地址。它們在一起被用來為CPU提供一個基于棧的函數(shù)調(diào)用機制。

當程序執(zhí)行到函數(shù)調(diào)用指令時,會將當前指令的地址壓入棧中,同時將ESP指針向下移動,指向新的棧頂。接著程序會跳轉(zhuǎn)到指定的函數(shù)地址,并繼續(xù)執(zhí)行函數(shù)中的代碼。在函數(shù)執(zhí)行過程中,棧會被用來存放函數(shù)的參數(shù)和局部變量。在函數(shù)執(zhí)行完畢后,原來的棧頂?shù)刂繁粡棾觯瑫rESP指針向上移動,指向新的棧頂。此時,程序會繼續(xù)執(zhí)行上一層函數(shù)中的代碼,通過EIP指針跳轉(zhuǎn)到之前保存的返回地址中。

在多層函數(shù)調(diào)用時,棧會不斷地被創(chuàng)建和銷毀,同時ESP和EIP指針也會有相應(yīng)的變化。當一個函數(shù)A調(diào)用另一個函數(shù)B時,程序必須將A函數(shù)的ESP和EIP指針保存下來,以便在B函數(shù)執(zhí)行完畢后,能夠正確地返回到A函數(shù)中。這種保存ESP和EIP指針的機制稱為棧幀,是用來管理棧中各個函數(shù)調(diào)用過程的重要數(shù)據(jù)結(jié)構(gòu)。

在Linux系統(tǒng)中,ESP和EIP指針的值是由操作系統(tǒng)內(nèi)核進行管理的。當一個程序通過系統(tǒng)調(diào)用向操作系統(tǒng)請求分配內(nèi)存時,內(nèi)核會自動將堆棧分配給該程序,并分配相應(yīng)的ESP和EIP寄存器。同時,內(nèi)核還會為程序分配一個初始的棧幀,用來存儲程序執(zhí)行過程中的基本信息。隨著程序的執(zhí)行,內(nèi)核會根據(jù)需要動態(tài)地創(chuàng)建和銷毀棧幀,并更新ESP和EIP指針的值。這樣,程序在運行過程中就可以訪問正確的??臻g,同時能夠正確地返回到上一層函數(shù)中。

在分析Linux系統(tǒng)中的ESP/EIP解析時,需要注意的是,ESP指針向下移動表示棧頂向下移動,而EIP指針向上移動表示程序?qū)⒁獔?zhí)行的下一條指令向上移動。它們在整個程序執(zhí)行過程中都是相對變化的,而不是絕對變化的。因此,在編寫Linux程序時,需要明確掌握棧和棧幀的相關(guān)知識,正確使用ESP和EIP指針,以確保程序能夠正確地運行和返回。

綜上所述,Linux系統(tǒng)中的ESP和EIP指針是用來管理棧和棧幀的重要寄存器。它們在程序的函數(shù)調(diào)用和返回過程中發(fā)揮重要的作用,是程序正確執(zhí)行的關(guān)鍵。在編寫Linux程序時,需要充分理解ESP和EIP指針在程序中的作用,合理管理棧和棧幀,以確保程序能夠正確運行。

相關(guān)問題拓展閱讀:

  • linux c 引用傳遞參數(shù)
  • 從用戶狀態(tài)轉(zhuǎn)換到核心狀態(tài)是通過什么實現(xiàn)的?

linux c 引用傳遞參數(shù)

C/C++函數(shù)參數(shù)的傳遞方式有三種:值傳遞(pass by value)、指針傳遞(pass bypointer)、引用傳遞(pass by reference)。

C/C++函數(shù)參數(shù)的傳遞通道是通過堆棧傳遞,默認遵循弊改__cdecl(C聲明方式),參數(shù)由改檔調(diào)用者從右往左逐個壓入堆棧,在函數(shù)調(diào)用完成之后再由調(diào)用者恢復(fù)堆棧。(Win32API遵循stdcall傳參規(guī)范的,不在本文討論范圍)

下面是測試代碼

void Swap(__int64* _pnX, __int64* _pnY)

{

__int64 nTemp = *_pnX;

*_pnX = *_pnY;

*_pnY = nTemp;

}

void Swap(__int64& _nX, __int64& _nY)

{

__int64 nTemp = _nX;

_nX = _nY;

_nY = nTemp;

}

void SetValue(__int64 _nX)

{

__int64 nTemp = _nX;

}

// Test001

void GetMemory(__int64* _pBuff)

{

_pBuff = new __int64;

}

// Test002

void GetMemory(__int64** _ppBuff)

{

*_ppBuff = new __int64;

}

int _tmain(int argc, _TCHAR* argv)

{

__int64 nA = 0x10;

__int64 nB = 0x20;

// Test to pass by pointer

Swap(&nA, &nB);

// Test to pass by reference

Swap(nA, nB);

// Test to pass by value

SetValue(nA);

// Test the pointer that points the pointer

__int64* _pArray = NULL;

GetMemory(&_pArray);

delete _pArray;

_pArray = NULL;

//租殲判 Test the pointer

GetMemory(_pArray);

return 0;

}

指針傳遞和引用傳遞

// 下面看一下對應(yīng)的反匯編的代碼(VS版)

__int64 nA = 0x10;

E movdword ptr ,10h

movdword ptr ,0

__int64 nB = 0x20;

C movdword ptr ,20h

movdword ptr ,0

// Test to pass by pointer

Swap(&nA, &nB);

A leaeax,

D pusheax

E leaecx,

pushecx

callSwap (4111E5h)

addesp,8

// Test to pass by reference

Swap(nA, nB);

A leaeax,

D pusheax

E leaecx,

pushecx

callSwap (4111E0h)

addesp,8

// GCC版

0x: lea eax,

0x: mov DWORD PTR ,eax

0xa : lea eax,

0xe : mov DWORD PTR ,eax

0x: call 0x

0x: lea eax,

0xa : mov DWORD PTR ,eax

0xe : lea eax,

0x004015a2 : mov DWORD PTR ,eax

0x004015a5 : call 0x

通過上面的反匯編代碼,我們可以看出指針傳遞和引用傳遞在機制是一樣的,都是將指針值(即地址)壓入棧中,調(diào)用函數(shù),然后恢復(fù)棧。Swap(nA, nB)和Swap(&nA, &nB);在實際上的匯編代碼也基本上一模一樣,都是從棧中取出地址來。由此可以看出引用和指針在效率上是一樣的。這也是為什么指針和引用都可以達到多態(tài)的效果。指針傳遞和引用傳遞其實都是改變的地址指向的內(nèi)存上的值來達到修改參數(shù)的效果。

值傳遞

下面是值傳遞對應(yīng)的反匯編代碼

// Test to pass by value

SetValue(nA);

A moveax,dword ptr

D pusheax

E movecx,dword ptr

pushecx

callSetValue (4111EAh)

addesp,8

因為我的機器是32位的CPU,從上面的匯編代碼可以看64Bit的變量被分成2個32Bit的參數(shù)壓入棧中。這也是我們常說的,值傳遞會形成一個拷貝。如果是一個自定義的結(jié)構(gòu)類型,并且有很多參數(shù),那么如果用值傳遞,這個結(jié)構(gòu)體將被分割為非常多個32Bit的逐個拷貝到棧中去,這樣的參數(shù)傳遞效率是非常慢的。所以結(jié)構(gòu)體等自定義類型,都使用引用傳遞,如果不希望別人修改結(jié)構(gòu)體變量,可以加上const修飾,如(const MY_STRUCT& _value);

下面來看一下Test001函數(shù)對應(yīng)的反匯編代碼的參數(shù)傳遞

__int64* _pArray = NULL;

004137E0 movdword ptr ,0

// Test the pointer

GetMemory(_pArray);

moveax,dword ptr

pusheax

callGetMemory (411203h)

B addesp,4

從上面的匯編代碼可以看出,其實是0被壓入到棧中作為參數(shù),所以GetMemory(_pArray)無論做什么事,其實都與指針變量_pArray無關(guān)。GetMemory()分配的空間是讓棧中的臨時變量指向的,當函數(shù)退出時,棧得到恢復(fù),結(jié)果申請的空間沒有人管,就產(chǎn)生內(nèi)存泄露的問題了?!禖++ Primer》將參數(shù)傳遞分為引用傳遞和非引用傳遞兩種,非引用傳遞其實可以理解為值傳遞。這樣看來,指針傳遞在某種意義上也是值傳遞,因為傳遞的是指針的值(1個4BYTE的值)。值傳遞都不會改變傳入實參的值的。而且普通的指針傳遞其實是改變的指針變量指向的內(nèi)容。

下面再看一下Test002函數(shù)對應(yīng)的反匯編代碼的參數(shù)傳遞

__int64* _pArray = NULL;

004137E0 movdword ptr ,0

GetMemory(&_pArray);

004137E7 leaeax,

004137EA pusheax

004137EB callGetMemory (4111FEh)

004137F0 addesp,4

從上面的匯編代碼lea eax, 可以看出,_pArray的地址被壓入到棧中去了。

然后看一看GetMemory(&_pArray)的實現(xiàn)匯編代碼。

0xb :push ebp

0xc :mov ebp,esp

0xe :sub esp,0x18

0x004015a1 :mov DWORD PTR ,0x20

0x004015a8 :call 0x473ef0

0x004015ad :mov edx,DWORD PTR

0x004015b0 :mov DWORD PTR ,eax

0x004015b2 :leave

0x004015b3 :ret

藍色的代碼是分配臨時變量空間,然后調(diào)用分配空間函數(shù)分配空間,得到的空間指針即eax.

然后紅色的匯編代碼即從ebp+0x8的棧上取到上面壓入棧中的參數(shù)_pArray的地址.

mov DWORD PTR ,eax即相當于把分配的空間指針eax讓edx指向,也即讓_pArray指向分配的空間eax.

從用戶狀態(tài)轉(zhuǎn)換到核心狀態(tài)是通過什么實現(xiàn)的?

用戶態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換

1)用戶態(tài)切換到內(nèi)核態(tài)的3種方式

a. 系統(tǒng)調(diào)用 這是用戶態(tài)進程主動要求切換到內(nèi)核態(tài)的一種方式,用戶態(tài)進程通過系統(tǒng)調(diào)用申請使用操作系統(tǒng)提供的服務(wù)程序完成工作,比如前例中fork()實際上就是執(zhí)行了一個創(chuàng)建新進程的系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的機制其核心還是使用了操作系統(tǒng)為用戶特別開放的一個中斷來實現(xiàn),例如Linux的int 80h中斷。系統(tǒng)調(diào)用實質(zhì)上是一個中斷,而匯編指令int 就可以實現(xiàn)用戶態(tài)向內(nèi)核態(tài)切換,iret實現(xiàn)內(nèi)核態(tài)向用戶態(tài)切換 b. 異常 當CPU在執(zhí)行運行在用戶態(tài)下的程序時,發(fā)生了某些事先不可知的異常,這時會觸發(fā)由當前運行進程切換到處理此異常的內(nèi)核相關(guān)程序中,也就轉(zhuǎn)到了內(nèi)核態(tài),比如缺頁異常。

c. 外圍設(shè)備的中斷 當外圍設(shè)備完成用戶請求的操作后,會向CPU發(fā)出相應(yīng)的中斷信號,這時CPU會暫停執(zhí)行下一條即將要執(zhí)行的指令轉(zhuǎn)而去執(zhí)行與中斷信號對應(yīng)的處理程序,如果先前執(zhí)行的指令是用戶態(tài)下的程序,那么這個轉(zhuǎn)換慎嫌的過程自然也就發(fā)生銀孝慧了由用戶態(tài)到內(nèi)核態(tài)的切換。比如硬盤讀寫操作完成,系統(tǒng)會切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等。 這3種方式是系統(tǒng)在運行時由用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài)的最主要方式,其中系統(tǒng)調(diào)用可以認為是用戶進程主動發(fā)起的,異常和外圍設(shè)備中斷則是被動的。

2)具體的切換操作 從觸發(fā)方式上看,可以認為存在前述3種不同的類型,但是從最終實際完成由用戶態(tài)到內(nèi)核態(tài)的切換操作上來說,涉及的關(guān)鍵步驟是完全一致的,沒有任何區(qū)別,都相當于執(zhí)行了一個中斷響應(yīng)的過程,因為系統(tǒng)調(diào)用實際上最終是中斷機制實現(xiàn)的,而異常和中鋒答斷的處理機制基本上也是一致的,關(guān)于它們的具體區(qū)別這里不再贅述。關(guān)于中斷處理機制的細節(jié)和步驟這里也不做過多分析,涉及到由用戶態(tài)切換到內(nèi)核態(tài)的步驟主要包括:

從當前進程的描述符中提取其內(nèi)核棧的ss0及esp0信息。

使用ss0和esp0指向的內(nèi)核棧將當前進程的cs,eip,eflags,ss,esp信息保存起來,這個 過程也完成了由用戶棧到內(nèi)核棧的切換過程,同時保存了被暫停執(zhí)行的程序的下一條指令。

將先前由中斷向量檢索得到的中斷處理程序的cs,eip信息裝入相應(yīng)的

寄存器

,開始 執(zhí)行中斷處理程序,這時就轉(zhuǎn)到了內(nèi)核態(tài)的程序執(zhí)行了。

關(guān)于linux堆棧espeip的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。

香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機、網(wǎng)站系統(tǒng)開發(fā)經(jīng)驗。專業(yè)提供云主機、虛擬主機、域名注冊、VPS主機、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。


當前題目:Linux系統(tǒng)中堆棧的espeip解析(linux堆棧espeip)
網(wǎng)頁URL:http://m.5511xx.com/article/dpphejj.html