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

在計(jì)算機(jī)系統(tǒng)中,棧是一種常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),常作為程序的運(yùn)行空間之一,其中堆棧是最常用的一種。Linux系統(tǒng)中的棧是用C語(yǔ)言實(shí)現(xiàn)的,并且在內(nèi)存中以“后進(jìn)先出”的方式進(jìn)行存儲(chǔ)和管理。在程序運(yùn)行時(shí),棧被用來(lái)保存函數(shù)調(diào)用的返回地址和局部變量,還用來(lái)作為內(nèi)存緩存圈和臨時(shí)存儲(chǔ)區(qū)域。在本文中,將詳細(xì)分析Linux系統(tǒng)中堆棧的ESP/EIP解析。
ESP是指棧指針寄存器,EIP是指指令指針寄存器,它們都是CPU寄存器中的一種。ESP通常用來(lái)記錄棧的棧頂位置,而EIP則用來(lái)記錄程序?qū)⒁獔?zhí)行的下一條指令的地址。它們?cè)谝黄鸨挥脕?lái)為CPU提供一個(gè)基于棧的函數(shù)調(diào)用機(jī)制。
當(dāng)程序執(zhí)行到函數(shù)調(diào)用指令時(shí),會(huì)將當(dāng)前指令的地址壓入棧中,同時(shí)將ESP指針向下移動(dòng),指向新的棧頂。接著程序會(huì)跳轉(zhuǎn)到指定的函數(shù)地址,并繼續(xù)執(zhí)行函數(shù)中的代碼。在函數(shù)執(zhí)行過(guò)程中,棧會(huì)被用來(lái)存放函數(shù)的參數(shù)和局部變量。在函數(shù)執(zhí)行完畢后,原來(lái)的棧頂?shù)刂繁粡棾?,同時(shí)ESP指針向上移動(dòng),指向新的棧頂。此時(shí),程序會(huì)繼續(xù)執(zhí)行上一層函數(shù)中的代碼,通過(guò)EIP指針跳轉(zhuǎn)到之前保存的返回地址中。
在多層函數(shù)調(diào)用時(shí),棧會(huì)不斷地被創(chuàng)建和銷(xiāo)毀,同時(shí)ESP和EIP指針也會(huì)有相應(yīng)的變化。當(dāng)一個(gè)函數(shù)A調(diào)用另一個(gè)函數(shù)B時(shí),程序必須將A函數(shù)的ESP和EIP指針保存下來(lái),以便在B函數(shù)執(zhí)行完畢后,能夠正確地返回到A函數(shù)中。這種保存ESP和EIP指針的機(jī)制稱(chēng)為棧幀,是用來(lái)管理?xiàng)V懈鱾€(gè)函數(shù)調(diào)用過(guò)程的重要數(shù)據(jù)結(jié)構(gòu)。
在Linux系統(tǒng)中,ESP和EIP指針的值是由操作系統(tǒng)內(nèi)核進(jìn)行管理的。當(dāng)一個(gè)程序通過(guò)系統(tǒng)調(diào)用向操作系統(tǒng)請(qǐng)求分配內(nèi)存時(shí),內(nèi)核會(huì)自動(dòng)將堆棧分配給該程序,并分配相應(yīng)的ESP和EIP寄存器。同時(shí),內(nèi)核還會(huì)為程序分配一個(gè)初始的棧幀,用來(lái)存儲(chǔ)程序執(zhí)行過(guò)程中的基本信息。隨著程序的執(zhí)行,內(nèi)核會(huì)根據(jù)需要?jiǎng)討B(tài)地創(chuàng)建和銷(xiāo)毀棧幀,并更新ESP和EIP指針的值。這樣,程序在運(yùn)行過(guò)程中就可以訪問(wèn)正確的??臻g,同時(shí)能夠正確地返回到上一層函數(shù)中。
在分析Linux系統(tǒng)中的ESP/EIP解析時(shí),需要注意的是,ESP指針向下移動(dòng)表示棧頂向下移動(dòng),而EIP指針向上移動(dòng)表示程序?qū)⒁獔?zhí)行的下一條指令向上移動(dòng)。它們?cè)谡麄€(gè)程序執(zhí)行過(guò)程中都是相對(duì)變化的,而不是絕對(duì)變化的。因此,在編寫(xiě)Linux程序時(shí),需要明確掌握棧和棧幀的相關(guān)知識(shí),正確使用ESP和EIP指針,以確保程序能夠正確地運(yùn)行和返回。
綜上所述,Linux系統(tǒng)中的ESP和EIP指針是用來(lái)管理?xiàng):蜅闹匾拇嫫?。它們?cè)诔绦虻暮瘮?shù)調(diào)用和返回過(guò)程中發(fā)揮重要的作用,是程序正確執(zhí)行的關(guān)鍵。在編寫(xiě)Linux程序時(shí),需要充分理解ESP和EIP指針在程序中的作用,合理管理?xiàng):蜅源_保程序能夠正確運(yùn)行。
相關(guān)問(wèn)題拓展閱讀:
- linux c 引用傳遞參數(shù)
- 從用戶(hù)狀態(tài)轉(zhuǎn)換到核心狀態(tài)是通過(guò)什么實(shí)現(xiàn)的?
linux c 引用傳遞參數(shù)
C/C++函數(shù)參數(shù)的傳遞方式有三種:值傳遞(pass by value)、指針傳遞(pass bypointer)、引用傳遞(pass by reference)。
C/C++函數(shù)參數(shù)的傳遞通道是通過(guò)堆棧傳遞,默認(rèn)遵循弊改__cdecl(C聲明方式),參數(shù)由改檔調(diào)用者從右往左逐個(gè)壓入堆棧,在函數(shù)調(diào)用完成之后再由調(diào)用者恢復(fù)堆棧。(Win32API遵循stdcall傳參規(guī)范的,不在本文討論范圍)
下面是測(cè)試代碼
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;
}
指針傳遞和引用傳遞
// 下面看一下對(duì)應(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
通過(guò)上面的反匯編代碼,我們可以看出指針傳遞和引用傳遞在機(jī)制是一樣的,都是將指針值(即地址)壓入棧中,調(diào)用函數(shù),然后恢復(fù)棧。Swap(nA, nB)和Swap(&nA, &nB);在實(shí)際上的匯編代碼也基本上一模一樣,都是從棧中取出地址來(lái)。由此可以看出引用和指針在效率上是一樣的。這也是為什么指針和引用都可以達(dá)到多態(tài)的效果。指針傳遞和引用傳遞其實(shí)都是改變的地址指向的內(nèi)存上的值來(lái)達(dá)到修改參數(shù)的效果。
值傳遞
下面是值傳遞對(duì)應(yīng)的反匯編代碼
// Test to pass by value
SetValue(nA);
A moveax,dword ptr
D pusheax
E movecx,dword ptr
pushecx
callSetValue (4111EAh)
addesp,8
因?yàn)槲业臋C(jī)器是32位的CPU,從上面的匯編代碼可以看64Bit的變量被分成2個(gè)32Bit的參數(shù)壓入棧中。這也是我們常說(shuō)的,值傳遞會(huì)形成一個(gè)拷貝。如果是一個(gè)自定義的結(jié)構(gòu)類(lèi)型,并且有很多參數(shù),那么如果用值傳遞,這個(gè)結(jié)構(gòu)體將被分割為非常多個(gè)32Bit的逐個(gè)拷貝到棧中去,這樣的參數(shù)傳遞效率是非常慢的。所以結(jié)構(gòu)體等自定義類(lèi)型,都使用引用傳遞,如果不希望別人修改結(jié)構(gòu)體變量,可以加上const修飾,如(const MY_STRUCT& _value);
下面來(lái)看一下Test001函數(shù)對(duì)應(yīng)的反匯編代碼的參數(shù)傳遞
__int64* _pArray = NULL;
004137E0 movdword ptr ,0
// Test the pointer
GetMemory(_pArray);
moveax,dword ptr
pusheax
callGetMemory (411203h)
B addesp,4
從上面的匯編代碼可以看出,其實(shí)是0被壓入到棧中作為參數(shù),所以GetMemory(_pArray)無(wú)論做什么事,其實(shí)都與指針變量_pArray無(wú)關(guān)。GetMemory()分配的空間是讓棧中的臨時(shí)變量指向的,當(dāng)函數(shù)退出時(shí),棧得到恢復(fù),結(jié)果申請(qǐng)的空間沒(méi)有人管,就產(chǎn)生內(nèi)存泄露的問(wèn)題了?!禖++ Primer》將參數(shù)傳遞分為引用傳遞和非引用傳遞兩種,非引用傳遞其實(shí)可以理解為值傳遞。這樣看來(lái),指針傳遞在某種意義上也是值傳遞,因?yàn)閭鬟f的是指針的值(1個(gè)4BYTE的值)。值傳遞都不會(huì)改變傳入實(shí)參的值的。而且普通的指針傳遞其實(shí)是改變的指針變量指向的內(nèi)容。
下面再看一下Test002函數(shù)對(duì)應(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)的實(shí)現(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
藍(lán)色的代碼是分配臨時(shí)變量空間,然后調(diào)用分配空間函數(shù)分配空間,得到的空間指針即eax.
然后紅色的匯編代碼即從ebp+0x8的棧上取到上面壓入棧中的參數(shù)_pArray的地址.
mov DWORD PTR ,eax即相當(dāng)于把分配的空間指針eax讓edx指向,也即讓_pArray指向分配的空間eax.
從用戶(hù)狀態(tài)轉(zhuǎn)換到核心狀態(tài)是通過(guò)什么實(shí)現(xiàn)的?
用戶(hù)態(tài)和內(nèi)核態(tài)的轉(zhuǎn)換
1)用戶(hù)態(tài)切換到內(nèi)核態(tài)的3種方式
a. 系統(tǒng)調(diào)用 這是用戶(hù)態(tài)進(jìn)程主動(dòng)要求切換到內(nèi)核態(tài)的一種方式,用戶(hù)態(tài)進(jìn)程通過(guò)系統(tǒng)調(diào)用申請(qǐng)使用操作系統(tǒng)提供的服務(wù)程序完成工作,比如前例中fork()實(shí)際上就是執(zhí)行了一個(gè)創(chuàng)建新進(jìn)程的系統(tǒng)調(diào)用。而系統(tǒng)調(diào)用的機(jī)制其核心還是使用了操作系統(tǒng)為用戶(hù)特別開(kāi)放的一個(gè)中斷來(lái)實(shí)現(xiàn),例如Linux的int 80h中斷。系統(tǒng)調(diào)用實(shí)質(zhì)上是一個(gè)中斷,而匯編指令int 就可以實(shí)現(xiàn)用戶(hù)態(tài)向內(nèi)核態(tài)切換,iret實(shí)現(xiàn)內(nèi)核態(tài)向用戶(hù)態(tài)切換 b. 異常 當(dāng)CPU在執(zhí)行運(yùn)行在用戶(hù)態(tài)下的程序時(shí),發(fā)生了某些事先不可知的異常,這時(shí)會(huì)觸發(fā)由當(dāng)前運(yùn)行進(jìn)程切換到處理此異常的內(nèi)核相關(guān)程序中,也就轉(zhuǎn)到了內(nèi)核態(tài),比如缺頁(yè)異常。
c. 外圍設(shè)備的中斷 當(dāng)外圍設(shè)備完成用戶(hù)請(qǐng)求的操作后,會(huì)向CPU發(fā)出相應(yīng)的中斷信號(hào),這時(shí)CPU會(huì)暫停執(zhí)行下一條即將要執(zhí)行的指令轉(zhuǎn)而去執(zhí)行與中斷信號(hào)對(duì)應(yīng)的處理程序,如果先前執(zhí)行的指令是用戶(hù)態(tài)下的程序,那么這個(gè)轉(zhuǎn)換慎嫌的過(guò)程自然也就發(fā)生銀孝慧了由用戶(hù)態(tài)到內(nèi)核態(tài)的切換。比如硬盤(pán)讀寫(xiě)操作完成,系統(tǒng)會(huì)切換到硬盤(pán)讀寫(xiě)的中斷處理程序中執(zhí)行后續(xù)操作等。 這3種方式是系統(tǒng)在運(yùn)行時(shí)由用戶(hù)態(tài)轉(zhuǎn)到內(nèi)核態(tài)的最主要方式,其中系統(tǒng)調(diào)用可以認(rèn)為是用戶(hù)進(jìn)程主動(dòng)發(fā)起的,異常和外圍設(shè)備中斷則是被動(dòng)的。
2)具體的切換操作 從觸發(fā)方式上看,可以認(rèn)為存在前述3種不同的類(lèi)型,但是從最終實(shí)際完成由用戶(hù)態(tài)到內(nèi)核態(tài)的切換操作上來(lái)說(shuō),涉及的關(guān)鍵步驟是完全一致的,沒(méi)有任何區(qū)別,都相當(dāng)于執(zhí)行了一個(gè)中斷響應(yīng)的過(guò)程,因?yàn)橄到y(tǒng)調(diào)用實(shí)際上最終是中斷機(jī)制實(shí)現(xiàn)的,而異常和中鋒答斷的處理機(jī)制基本上也是一致的,關(guān)于它們的具體區(qū)別這里不再贅述。關(guān)于中斷處理機(jī)制的細(xì)節(jié)和步驟這里也不做過(guò)多分析,涉及到由用戶(hù)態(tài)切換到內(nèi)核態(tài)的步驟主要包括:
從當(dāng)前進(jìn)程的描述符中提取其內(nèi)核棧的ss0及esp0信息。
使用ss0和esp0指向的內(nèi)核棧將當(dāng)前進(jìn)程的cs,eip,eflags,ss,esp信息保存起來(lái),這個(gè) 過(guò)程也完成了由用戶(hù)棧到內(nèi)核棧的切換過(guò)程,同時(shí)保存了被暫停執(zhí)行的程序的下一條指令。
將先前由中斷向量檢索得到的中斷處理程序的cs,eip信息裝入相應(yīng)的
寄存器
,開(kāi)始 執(zhí)行中斷處理程序,這時(shí)就轉(zhuǎn)到了內(nèi)核態(tài)的程序執(zhí)行了。
關(guān)于linux堆棧espeip的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
香港服務(wù)器選創(chuàng)新互聯(lián),2H2G首月10元開(kāi)通。
創(chuàng)新互聯(lián)(www.cdcxhl.com)互聯(lián)網(wǎng)服務(wù)提供商,擁有超過(guò)10年的服務(wù)器租用、服務(wù)器托管、云服務(wù)器、虛擬主機(jī)、網(wǎng)站系統(tǒng)開(kāi)發(fā)經(jīng)驗(yàn)。專(zhuān)業(yè)提供云主機(jī)、虛擬主機(jī)、域名注冊(cè)、VPS主機(jī)、云服務(wù)器、香港云服務(wù)器、免備案服務(wù)器等。
文章標(biāo)題:Linux系統(tǒng)中堆棧的espeip解析(linux堆棧espeip)
網(wǎng)站URL:http://www.fisionsoft.com.cn/article/dpphejj.html


咨詢(xún)
建站咨詢(xún)
