欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

【源碼剖析】?jī)?nèi)存分區(qū)和函數(shù)調(diào)用原理-創(chuàng)新互聯(lián)

函數(shù)調(diào)用序,一文即可知

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名雅安服務(wù)器托管、營(yíng)銷軟件、網(wǎng)站建設(shè)、祥符網(wǎng)站維護(hù)、網(wǎng)站推廣。文章目錄
    • 概述
      • 基礎(chǔ)知識(shí)
      • 函數(shù)調(diào)用過(guò)程
      • 反匯編演示
      • 棧溢出實(shí)驗(yàn)
    • 參考博客


😊點(diǎn)此到文末驚喜??

概述基礎(chǔ)知識(shí)
  1. 程序靜態(tài)內(nèi)存模型
    • 代碼區(qū):存放函數(shù)體編譯后的二進(jìn)制指令,并且是只讀的。
    • 常量區(qū):存放常量,并且是只讀的,如字符串、數(shù)字、const修飾的全局變量···
    • 靜態(tài)區(qū)&全局區(qū):存放編譯時(shí)即可確定存儲(chǔ)大小的靜態(tài)變量和全局變量,可讀可寫
      • .bss段:存放程序中未初始化的或者初始化為0的全局變量和靜態(tài)變量,但是在可執(zhí)行文件中只簡(jiǎn)單維護(hù)每個(gè)變量起始地址和大小,在運(yùn)行時(shí)由操作系統(tǒng)初始化
      • .data段:存儲(chǔ)已初始化(非零)的全局變量和靜態(tài)變量,占用可執(zhí)行文件空間,其內(nèi)容有程序初始化
    • 自由存儲(chǔ)區(qū):自由存儲(chǔ)是C++中通過(guò)new和delete動(dòng)態(tài)分配和釋放對(duì)象的抽象概念,new可以被重載從而出現(xiàn)不同的分配方式,如在棧上new
    • 堆區(qū):存儲(chǔ)malloc動(dòng)態(tài)分配的內(nèi)存(new底層也是調(diào)用malloc),內(nèi)存由低地址向高地址生長(zhǎng),由程序員進(jìn)行內(nèi)存的分配和釋放,系統(tǒng)維護(hù)開銷大,速度比棧慢
    • 棧區(qū):存儲(chǔ)函數(shù)調(diào)用過(guò)程,由操作系統(tǒng)進(jìn)行自動(dòng)的分配和釋放在這里插入圖片描述
  2. 進(jìn)程地址空間(程序動(dòng)態(tài)內(nèi)存模型)
    • 只讀代碼段
      • .init段:初始化時(shí)調(diào)用的小函數(shù)
      • .text段:存放已編譯程序的機(jī)器碼
      • .rodata段:存放常量,并且是只讀的,如字符串、數(shù)字、const修飾的全局變量···
    • 共享庫(kù): 該區(qū)域用于映射可執(zhí)行文件用到的動(dòng)態(tài)鏈接庫(kù)
    • 其他如上靜態(tài)模型所示(下面是低地址,上面是高地址)在這里插入圖片描述
  3. 其他注意事項(xiàng)
    • 使用局部變量時(shí),盡量進(jìn)行初始化。編譯器不會(huì)初始化局部變量,所以如果使用未初始化的局部變量,內(nèi)部的值是垃圾值。但是debug調(diào)試模式下,運(yùn)行時(shí)機(jī)制會(huì)將??臻g全部初始化為0
    • 進(jìn)程是程序的一次動(dòng)態(tài)運(yùn)行,靜態(tài)的程序內(nèi)存模型,載入內(nèi)存執(zhí)行時(shí)會(huì)發(fā)生上述變化
  4. 棧和堆的區(qū)別
    • 管理方式不同:棧由操作系統(tǒng)自動(dòng)分配釋放。堆的申請(qǐng)和釋放工作由程序員控制,容易產(chǎn)生內(nèi)存泄漏;
    • 空間大小不同:通常每個(gè)進(jìn)程的??臻g遠(yuǎn)遠(yuǎn)小于堆空間
    • 生長(zhǎng)方式不同:堆在內(nèi)存中由低地址向高地址生長(zhǎng),棧在內(nèi)存中由高地址向地址生長(zhǎng)
    • 分配方式不同:堆都是動(dòng)態(tài)分配的。棧有 2 種分配方式:靜態(tài)分配和動(dòng)態(tài)分配。靜態(tài)分配是由操作系統(tǒng)完成的。動(dòng)態(tài)分配由alloca()函數(shù)分配,由操作系統(tǒng)自動(dòng)釋放。
    • 分配效率不同。
      • 棧由操作系統(tǒng)自動(dòng)分配,會(huì)在硬件層級(jí)對(duì)棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。
      • 堆則是由C/C++提供的庫(kù)函數(shù)或運(yùn)算符來(lái)完成申請(qǐng)與管理,實(shí)現(xiàn)機(jī)制較為復(fù)雜,頻繁的內(nèi)存申請(qǐng)容易產(chǎn)生內(nèi)存碎片。顯然,堆的效率比棧要低得多。
    • 存放內(nèi)容不同。
      • 棧,存放函數(shù)的調(diào)用過(guò)程。存放的內(nèi)容,函數(shù)返回地址、相關(guān)參數(shù)、局部變量和寄存器內(nèi)容等
      • 堆,一般堆頂使用一個(gè)字節(jié)的空間來(lái)存放堆的大小,而堆中具體存放內(nèi)容是由程序員來(lái)填充的。
函數(shù)調(diào)用過(guò)程
  1. 時(shí)間緊迫就不要看,【 call 計(jì)算機(jī)從開機(jī)加電到執(zhí)行main函數(shù)之前的過(guò)程】如果看完了這篇文章,別忘了ret返回這里,哈哈哈
  2. 任何的C或C++在main函數(shù)執(zhí)行前有一個(gè)啟動(dòng)碼函數(shù)mainCRTStartup(),而main函數(shù)由啟動(dòng)碼函數(shù)中的invoke_main()調(diào)用
  3. 構(gòu)造主函數(shù)棧幀(這也是一個(gè)調(diào)用過(guò)程,現(xiàn)在將main調(diào)用子函數(shù)的過(guò)程進(jìn)行細(xì)化)
  4. call 子函數(shù)名,即主函數(shù)調(diào)用子函數(shù)
    • 將主函數(shù)中調(diào)用點(diǎn)的下一條指令地址壓入棧中
    • 轉(zhuǎn)移到調(diào)用的子函數(shù)
  5. push ebp,將主函數(shù)的棧底指針壓入棧中
  6. mov ebp esp,使棧底指針指向棧頂,即構(gòu)造子函數(shù)的棧底
  7. 棧頂下移留出局部變量存儲(chǔ)內(nèi)存空間
  8. 壓入caller-save register(ebx,esi,edi),用于保存函數(shù)的處理信息
  9. 初始化棧底ebp指向地址和存儲(chǔ)ebx的地址之間的內(nèi)存空間
  10. 執(zhí)行子函數(shù)
  11. 將 caller-save register value逆序彈出到對(duì)應(yīng)寄存器中
  12. mov esp ebp,用子函數(shù)的ebp給esp賦值,將棧頂指針指向棧底
  13. pop ebp將棧頂?shù)纳弦粋€(gè)函數(shù)的ebp值彈出到ebp寄存器中
  14. ret將棧頂?shù)闹担ㄖ骱瘮?shù)的調(diào)用斷點(diǎn)的下一條指令的地址)彈出到EIP中,EIP會(huì)執(zhí)行下一條指令,即返回主函數(shù)。
    在這里插入圖片描述
反匯編演示
  1. 編譯環(huán)境:vs2022&win10

  2. 編譯器問(wèn)題:編譯器越高級(jí),其中處理的越會(huì)繁瑣。在不同的編譯器下,函數(shù)的調(diào)用過(guò)程中的棧幀的創(chuàng)建是略有差異的,具體細(xì)節(jié)取決于編譯器的實(shí)現(xiàn)

  3. 前置知識(shí)

    • 程序寄存器組是所有函數(shù)調(diào)用過(guò)程的共享資源。所以函數(shù)調(diào)用需要將當(dāng)前函數(shù)執(zhí)行相關(guān)的寄存器值保存到函數(shù)自己的棧幀中,當(dāng)函數(shù)返回時(shí),再將函數(shù)棧幀中的值恢復(fù)到相應(yīng)的寄存器中。IA32采用于一組統(tǒng)一的寄存器使用慣例:寄存器eax,edx,ecx被分為調(diào)用者的可用寄存器,即當(dāng)過(guò)程P調(diào)用Q時(shí),Q可以覆蓋這些寄存器,而不會(huì)破壞任何P所需要的數(shù)據(jù)。另外,ebx,esi,edi分為被調(diào)用者保存寄存器,意味著覆蓋他們之前,將這些寄存器的值保存在棧中,并在返回前恢復(fù)他們。
    • 調(diào)用函數(shù)所做的工作:將當(dāng)前的指令的下一條指令的地址保存,保存的目的是為了調(diào)用結(jié)束后修改PC值返回,然后跳轉(zhuǎn)至目標(biāo)地址處。實(shí)現(xiàn)跳轉(zhuǎn)是由修改EIP(PC)的值完成的。
    • 任何一個(gè)臨時(shí)變量都保存在當(dāng)前的函數(shù)的棧幀內(nèi)。調(diào)用結(jié)束后,修改esp和ebp完成空間釋放,但棧幀實(shí)際還存在,只是告訴編譯器這部分??臻g可以被覆蓋掉。文件刪除也是這個(gè)原理。
    • return所做的工作是將當(dāng)前的函數(shù)的返回值地址出棧,利用pop的數(shù)據(jù)修改EIP。
    • 調(diào)用函數(shù)的空間時(shí)間開銷主要來(lái)自于棧幀的開辟與釋放。每個(gè)函數(shù)棧幀都有自己的 ebp 和 esp 來(lái)維護(hù)棧幀空間
    • 函數(shù)的返回值時(shí)通過(guò)寄存器進(jìn)行保存和返回的
  4. 32位下反匯編(下面從0開始)

// 被調(diào)用的子函數(shù)
int sum(int a, int b) {// 5. 構(gòu)造子函數(shù)棧幀
00451740  push        ebp  //把ebp寄存器的值入棧,此時(shí)的ebp中存放的是主調(diào)函數(shù)的棧基址
00451741  mov         ebp,esp// 將當(dāng)前棧頂指針esp賦值給?;芳拇嫫鱡bp,即現(xiàn)在為子函數(shù)棧幀
00451743  sub         esp,0CCh// 棧頂指針esp下移(棧由高向低生長(zhǎng)),即由esp和ebp共同維護(hù)這一段子函數(shù)棧幀
00451749  push        ebx  //將寄存器ebx的值壓棧,esp-4
0045174A  push        esi  //將寄存器esi的值壓棧,esp-4
0045174B  push        edi  //將寄存器edi的值壓棧,esp-4
0045174C  lea         edi,[ebp-0Ch]  //先把ebp-0E4h的地址,放在edi中
// 下三行將ebp指向的內(nèi)存到值為ebx之間初始化成0CCCCCCCCh  
0045174F  mov         ecx,3  
00451754  mov         eax,0CCCCCCCCh  
00451759  rep stos    dword ptr es:[edi]  
// 下兩行為編譯器debug模式下調(diào)試用的cookie
0045175B  mov         ecx,offset _01833B24_TestCpp@cpp (045C008h)  
00451760  call        @__CheckForDebuggerJustMyCode@4 (045130Ch)  
	// 6. 執(zhí)行子函數(shù)功能
	int c = a + b;
00451765  mov         eax,dword ptr [a]  
00451768  add         eax,dword ptr [b]  
0045176B  mov         dword ptr [c],eax  
	return c;
// 返回值放入eax中,函數(shù)調(diào)用返回時(shí)不會(huì)被覆蓋
0045176E  mov         eax,dword ptr [c]  
}
00451771  pop         edi  //在棧頂彈出一個(gè)值,存放到edi中,esp+4
00451772  pop         esi  //在棧頂彈出一個(gè)值,存放到esi中,esp+4
00451773  pop         ebx  //在棧頂彈出一個(gè)值,存放到ebx中,esp+4
// 下三行為debug模式下的cookie
00451774  add         esp,0CCh  
0045177A  cmp         ebp,esp  
0045177C  call        __RTC_CheckEsp (0451235h)  
	// 7. 將棧幀恢復(fù)為主函數(shù)的棧幀(ebp和esp)
00451781  mov         esp,ebp // 將子函數(shù)的棧底指針賦值給棧頂指針esp,相當(dāng)于回收棧,但是子函數(shù)棧幀仍然存在棧中 
00451783  pop         ebp  //彈出棧頂?shù)闹荡娣诺絜bp,棧頂此時(shí)的值恰好就是main函數(shù)的ebp,esp+4,此時(shí)恢復(fù)了main函數(shù)的棧幀維護(hù),esp指向main函數(shù)棧幀的棧頂,ebp指向了main函數(shù)棧幀的棧底。
	// 8. 返回到主函數(shù)的調(diào)用點(diǎn)的下一條指令的地址
00451784  ret  //ret指令的執(zhí)行,首先是從棧頂彈出一個(gè)值,此時(shí)棧頂?shù)闹稻褪莄all指令下一條指令的地址,此時(shí)esp+4,然后直接跳轉(zhuǎn)到call指令下一條指令的地址處,繼續(xù)往下執(zhí)行
···
// 主函數(shù)
int main() {// 0. 構(gòu)造主函數(shù)棧幀(配合堆棧結(jié)構(gòu)圖片看更容易理解)
004517B0  push        ebp  //把ebp寄存器的值入棧,此時(shí)的ebp中存放的是invoke_main棧基址
004517B1  mov         ebp,esp // 將當(dāng)前棧頂指針esp賦值給?;芳拇嫫鱡bp,即現(xiàn)在為mian函數(shù)棧幀
004517B3  sub         esp,0D8h// 棧頂指針esp下移(棧由高向低生長(zhǎng)),即由esp和ebp共同維護(hù)這一段mian棧幀  
004517B9  push        ebx //將寄存器ebx的值壓棧,esp-4,這三個(gè)應(yīng)該是main的三個(gè)形參變量 
004517BA  push        esi //將寄存器esi的值壓棧,esp-4 
004517BB  push        edi //將寄存器edi的值壓棧,esp-4 
004517BC  lea         edi,[ebp-18h]  //先把ebp-18h的地址,放在edi中
// 下三行將ebp指向的內(nèi)存到值為ebx之間初始化成0CCCCCCCCh  
004517BF  mov         ecx,6  
004517C4  mov         eax,0CCCCCCCCh  
004517C9  rep stos    dword ptr es:[edi]
// 下兩行為編譯器debug模式下調(diào)試用的cookie  
004517CB  mov         ecx,offset _01833B24_TestCpp@cpp (045C008h)  
004517D0  call        @__CheckForDebuggerJustMyCode@4 (045130Ch)  
// 函數(shù)功能實(shí)現(xiàn)
	// 1. 為main函數(shù)棧幀中的局部變量賦值(系統(tǒng)啥時(shí)候把a(bǔ)和b初始化成main堆棧的?)
	int a = 1;
004517D5  mov         dword ptr [a],1  // a相當(dāng)于一個(gè)指針,將1賦值到a指向的內(nèi)存中,實(shí)際在mian函數(shù)的棧幀中
	int b = 2;
004517DC  mov         dword ptr [b],2  // 同上
	sum(a, b);
	// 2. 將被調(diào)用函數(shù)的參數(shù)從右向左依次用通用寄存器保存
004517E3  mov         eax,dword ptr [b]  
004517E6  push        eax  
004517E7  mov         ecx,dword ptr [a]  
004517EA  push        ecx  
	// 3. call子函數(shù),分成兩步,1.將程序下一條指令地址壓入棧中2.轉(zhuǎn)移到調(diào)用的子函數(shù)(最后一行)
004517EB  call        sum (045116Dh)  
004517F0  add         esp,8  
	return 0;
004517F3  xor         eax,eax  
}
004517F5  pop         edi  
004517F6  pop         esi  
004517F7  pop         ebx  
004517F8  add         esp,0D8h  
004517FE  cmp         ebp,esp  
00451800  call        __RTC_CheckEsp (0451235h)  
00451805  mov         esp,ebp  
00451807  pop         ebp  
00451808  ret  
// 以下是函數(shù)表,只是一個(gè)中轉(zhuǎn)作用
···
	// 4. 執(zhí)行跳轉(zhuǎn)指令到子函數(shù)的執(zhí)行(第一行)
0045116D  jmp         sum (0451740h)
··· 

在這里插入圖片描述
5. 64位下反匯編,代碼沒(méi)問(wèn)題,但是我的注釋可能有問(wèn)題,有的地方?jīng)]理解,等我神功大成

#include// 主函數(shù)調(diào)用的子函數(shù)
int sum(int a, int b) {// 4. 將子函數(shù)的參數(shù)自右向左依次壓入棧中
00007FF7F5631740  mov         dword ptr [rsp+10h],edx // 棧由高地址向低地址生長(zhǎng)
00007FF7F5631744  mov         dword ptr [rsp+8],ecx  // 這是低地址
	// 5. 壓入主調(diào)函數(shù)的?;罚瓷弦粋€(gè)棧幀的開始地址
00007FF7F5631748  push        rbp  
	// 6.將主調(diào)函數(shù)的函數(shù)調(diào)用點(diǎn)的下一條指針地址壓入棧中
00007FF7F5631749  push        rdi  
00007FF7F563174A  sub         rsp,108h  
00007FF7F5631751  lea         rbp,[rsp+20h]  
00007FF7F5631756  lea         rcx,[__01833B24_TestCpp@cpp (07FF7F5641008h)]  
00007FF7F563175D  call        __CheckForDebuggerJustMyCode (07FF7F5631343h)  
	// 7. 執(zhí)行函數(shù)體內(nèi)的功能語(yǔ)句
	int c = a + b;
00007FF7F5631762  mov         eax,dword ptr [b]  
00007FF7F5631768  mov         ecx,dword ptr [a]  
00007FF7F563176E  add         ecx,eax  
00007FF7F5631770  mov         eax,ecx  
00007FF7F5631772  mov         dword ptr [c],eax  
	return c;
00007FF7F5631775  mov         eax,dword ptr [c]  // 將返回值賦值到eax中
}
00007FF7F5631778  lea         rsp,[rbp+0E8h]
	// 8. 注意此時(shí)棧頂依次為rdi rbp。所以逆序pop到相應(yīng)的寄存器中
00007FF7F563177F  pop         rdi  
00007FF7F5631780  pop         rbp  
	// 9. ret是子函數(shù)返回指令,與call搭配使用,修改pc(存儲(chǔ)下一條將要執(zhí)行的指令地址),并恢復(fù)主函數(shù)堆棧
00007FF7F5631781  ret  
// main函數(shù)
int main() {// 0. debug模式下的插入的cookie?
00007FF7F56317A0  push        rbp  
00007FF7F56317A2  push        rdi  
00007FF7F56317A3  sub         rsp,128h  
00007FF7F56317AA  lea         rbp,[rsp+20h]  
00007FF7F56317AF  lea         rcx,[__01833B24_TestCpp@cpp (07FF7F5641008h)]  
00007FF7F56317B6  call        __CheckForDebuggerJustMyCode (07FF7F5631343h)  
	// 1. 分別開辟4個(gè)字節(jié)大小的雙字內(nèi)存并將值移入
	int a = 1;
00007FF7F56317BB  mov         dword ptr [a],1  
	int b = 2;
00007FF7F56317C2  mov         dword ptr [b],2  
	// 2. 將參數(shù)壓入寄存器中,調(diào)用子函數(shù)
	sum(a, b);
00007FF7F56317C9  mov         edx,dword ptr [b]  // 將內(nèi)存地址為a的雙字類型的數(shù)據(jù)賦值給edx
00007FF7F56317CC  mov         ecx,dword ptr [a]  
00007FF7F56317CF  call        sum (07FF7F56313A2h)  // 調(diào)用子函數(shù)(最后一行)
	return 0;
00007FF7F56317D4  xor         eax,eax  
}
00007FF7F56317D6  lea         rsp,[rbp+108h]  
00007FF7F56317DD  pop         rdi  
00007FF7F56317DE  pop         rbp  
00007FF7F56317DF  ret  

// 從函數(shù)表中截取的子函數(shù)跳轉(zhuǎn)指令
	// 3. 跳轉(zhuǎn)到子函數(shù)
00007FF7F56313A2  jmp         sum (07FF7F5631740h)  // 第一行
···
棧溢出實(shí)驗(yàn)
  1. 【深度補(bǔ)充】這樣還學(xué)不會(huì)棧溢出的小伙伴麻煩私信我https://www.bilibili.com/video/BV1QV411r7UU/?spm_id_from=333.337.search-card.all.click&vd_source=ce626ff62ed6a7b65ff163189a520fb1
  2. 兩個(gè)棧溢出的CVE漏洞實(shí)驗(yàn)https://blog.csdn.net/qq_43840665/article/details/124265725


少年,我觀你骨骼清奇,穎悟絕倫,必成人中龍鳳。
秘籍(點(diǎn)擊圖中書籍)·有緣·贈(zèng)予你


🚩點(diǎn)此跳轉(zhuǎn)到首行??

參考博客
  1. 侯捷——c++的生前死后
  2. 一文讀懂 .bss段 的作用
  3. 簡(jiǎn)述代碼中關(guān)于.data、.bss、.rodata、.text段的意義
  4. 一文讀懂堆與棧的區(qū)別
  5. 《C語(yǔ)言》函數(shù)棧幀的創(chuàng)建與銷毀–(內(nèi)功)
  6. 函數(shù)調(diào)用的執(zhí)行過(guò)程
  7. 函數(shù)調(diào)用過(guò)程中函數(shù)棧詳解

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧

網(wǎng)站名稱:【源碼剖析】?jī)?nèi)存分區(qū)和函數(shù)調(diào)用原理-創(chuàng)新互聯(lián)
標(biāo)題來(lái)源:http://chinadenli.net/article6/ddioog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、電子商務(wù)網(wǎng)站制作、企業(yè)網(wǎng)站制作手機(jī)網(wǎng)站建設(shè)、網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)