青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Dict.CN 在線詞典, 英語學(xué)習(xí), 在線翻譯

學(xué)海苦作舟,書山勤為徑

留下點回憶

常用鏈接

統(tǒng)計

積分與排名

Denoise

English study

Web技術(shù)

數(shù)據(jù)壓縮

一些連接

最新評論

函數(shù)是如何被調(diào)用的?-探索代碼背后的故事

C/C++ 語言中,函數(shù)是如何被調(diào)用的呢?本文就實際的例子,走進匯編代碼來看下函數(shù)調(diào)用的過程。

首先看一個簡單的代碼例子:

void test(int i)

{

??? int j = i;

}

?

void test1()

{

?

}

?

int test2()

{

??? return 1;

}

?

void test3(int a,int b,int c)

{

}

?

void test4()

{

??? int i,j;

}

?

void test5()

{

??? int i,j,k,l;

}

?

int main()

{??

??? int i =0;

??? test1();

???

??? test(10);

???

??? test3(1,2,3);

?

??? i=test2();

???

??? test4();

???

??? test5();

?

??? return 0;

}

?

這段代碼很簡單, mian 函數(shù)調(diào)用幾個被測試的函數(shù),分別是:

1.? 沒有參數(shù)

2.? 有一個參數(shù)

3.? 3 個參數(shù)

4.? 有返回值

5.? 有兩個臨時變量

6.? 有多個臨時變量

?

VC7 中,我們將斷點設(shè)置到 main 函數(shù)入口的地方;然后 F5 運行程序。再按 ALT+8 反匯編,我們看到下面的代碼:

Main 函數(shù)變成這樣了:

int main()

{??

00401120? push??????? ebp?

00401121? mov???????? ebp,esp

00401123? sub???????? esp,0CCh

00401129? push??????? ebx?

0040112A ? push??????? esi?

0040112B? push??????? edi?

0040112C ? lea???????? edi,[ebp-0CCh]

00401132? mov???????? ecx,33h

00401137? mov?? ??????eax,0CCCCCCCCh

0040113C ? rep stos??? dword ptr [edi]

??? int i =0;

0040113E? mov???????? dword ptr [i],0 // 直接將數(shù)據(jù) 0 放到指定地址中

??? test1();

00401145? call??????? test1 (401030h)

???

??? test(10);

0040114A ? push??????? 0Ah?

0040114C ? call??????? test (401000h)

00401151? add???????? esp,4

???

??? test3(1,2,3);

00401154? push??????? 3???

00401156? push??????? 2???

00401158? push??????? 1???

0040115A ? call??????? test3 (401090h)

0040115F ? add???????? esp,0Ch

?

??? i=test2();

00401162? call??????? test2 (401060h)

00401167? mov???????? dword ptr [i],eax

?

??? test4();

0040116A ? call??????? test4 (4010C0h)

???

??? test5();

0040116F ? call ???????test5 (4010F0h)

?

??? return 0;

00401174? xor???????? eax,eax

}

00401176? pop???????? edi?

00401177? pop???????? esi?

00401178? pop???????? ebx?

00401179? add???????? esp,0CCh

0040117F ? cmp???????? ebp,esp

00401181? call??????? _RTC_CheckEsp (4011E0h)

00401186? mov???????? esp,ebp

00401188? pop???????? ebp?

00401189? ret?????????????

?

函數(shù)入口部分:

00401120? push??????? ebp? // 保存 ebp 的值

00401121? mov???????? ebp,esp // 將當前棧頂指針送到 ebp

00401123? sub???????? esp,0CCh // 將棧頂指針下移 0XCC 個字節(jié),為臨時變量留出空間

00401129? push??????? ebx? // 保存 ebx

0040112A ? push??????? esi? // 保存 esi

0040112B? push??????? edi? // 保存 edi

0040112C ? lea???????? edi,[ebp-0CCh] // edp-0CC 地址送 EAX

00401132? mov???????? ecx,33h //CC/4 得到的

00401137? mov???????? eax,0CCCCCCCCh // 初始化為 0XCCCCCCCCH

0040113C ? rep stos??? dword ptr [edi]// 復(fù)制

這寫匯編是編譯器為我們生成的函數(shù)入口部分,基本的含義是為臨時變量分配空間,并且初始化臨時變量。

這里需要說明幾點:

1.? 函數(shù)調(diào)用是通過堆棧來完成的。

2.? 函數(shù)入口的地方必須為臨時變量分配一定空間;實際上如果沒有臨時變量,也要留出 C0 個字節(jié)。

3.? 堆棧棧頂指針隨數(shù)據(jù)的進入逐漸減小。因此 sub esp 0CCh 實際上是留出了 CC 個自己的堆棧空間。

我們看到實現(xiàn)將棧頂指針保存在 ebp 中,然后對該段空間設(shè)置初始值。而 0XCCCCCCH 是由堆棧的性質(zhì)決定,可以看 MSDN

如果開始的時候假設(shè) ESP 等于 0X12FEE0 ,那么在保存 EBP 之后, ESP 變成 0X12FEDC ,那么后來 EBP 中的值就是這個值,在保存的空間(從 0X12FE10 0X12FEDC )上將所有的內(nèi)存都初始化為 0XCC 。而 i 被分配在 0X12FED4 處,也就是第一個預(yù)留的位置)。

?

?

call??????? test1 (401030h)

由于已經(jīng)知道 i 的地址了,對 i 的賦值就很簡單了。這里看調(diào)用第一個沒有參數(shù)沒有返回值的 test1 函數(shù);僅僅一條語句,將 test1 的函數(shù)地址給 call 指令。

EAX = CCCCCCCC EBX = 7FFDE000 ECX = 00000000 EDX = 00000001

ESI = 00000040 EDI = 0012FEDC EIP = 00401145 ESP = 0012FE04

EBP = 0012FEDC EFL = 00000202

上面是 Call 指令調(diào)用前各寄存器的值;下面是調(diào)用后的值:

EAX = CCCCCCCC EBX = 7FFD7000 ECX = 00000000 EDX = 00000001

ESI = 00000040 EDI = 0012FEDC EIP = 00401030 ESP = 0012FE00

EBP = 0012FEDC EFL = 00000202

主要變化在于 EIP ESP ;前者是指令指針寄存器,而后者是堆棧指針寄存器。調(diào)用前指令的位置在 00401145 位置,而 call 指定將 EIP 改為 test1 的地址;同時將返回地址入棧;可以看到當前棧頂?shù)闹凳?/span> 0040114A ,實際上是 test1 的下條指令。

因此我們說 Call 指定做了兩件事情:

1.? EIP 從當前值改為被調(diào)用函數(shù)的值。

2.? 將返回地址,也就是當前地址的下條指令放入堆棧。

?

現(xiàn)在進入 test1 中看個究竟。

void test1()

{

00401030? push??????? ebp?

00401031? mov???????? ebp,esp

00401033? sub???????? esp,0C0h

00401039? push??????? ebx?

0040103A ? push??????? esi?

0040103B? push??????? edi?

0040103C ? lea???????? edi,[ebp-0C0h]

00401042? mov??? ?????ecx,30h

00401047? mov???????? eax,0CCCCCCCCh

0040104C ? rep stos??? dword ptr [edi]

?

}

0040104E? pop???????? edi?

0040104F ? pop???????? esi?

00401050? pop???????? ebx?

00401051? mov???????? esp,ebp

00401053? pop???????? ebp?

00401054? ret????? ??????

上面的命令基本相同,主要區(qū)別在于 test1 內(nèi)部沒有臨時變量,因此這里只保留了 C0 個自己的空間。

?

繼續(xù)回到主程序:

??? test(10);

0040114A ? push??????? 0Ah?

0040114C ? call??????? test (401000h)

00401151? add???????? esp,4

由于 test 函數(shù)有一個參數(shù),因此需要首先將參數(shù)壓入堆棧中,然后執(zhí)行與前面相似的操作。

這里有一點需要注意:函數(shù)返回之后需要將壓入的參數(shù)彈出;可以使用 pop 命令,也可以使用 add 命令來執(zhí)行。

?

對于 test3 的調(diào)用:

??? test3(1,2,3);

00401154? push??????? 3???

00401156? push??????? 2???

00401158? push??????? 1???

0040115A ? call??????? test3 (401090h)

0040115F ? add???????? esp,0Ch

?

由于它需要三個參數(shù),因此都必須壓入棧,返回的時候一次性彈出。

?

下面看如何調(diào)用帶有返回值的參數(shù):

??? i=test2();

00401162? call??????? test2 (401060h)

00401167? mov???????? dword ptr [i],eax

其他的相同,但重要的一點是函數(shù)的返回值是通過 eax 寄存器來返回的。

?

其他幾個函數(shù)的調(diào)用不同的是臨時變量數(shù)目的不同,僅僅在初始化預(yù)留空間的時候不同,基本上是每增加一個變量多出 12 個字節(jié)的堆棧空間。

?

mian 函數(shù)的返回值,有點特別:

??? return 0;

00401174? xor???????? eax,eax

特別的不在于通過 eax 返回,而是自己和自己異或,大部分返回 0 的函數(shù)都這么做。

?

mian 函數(shù)退出的時候有這段代碼:

00401176? pop???????? edi?

00401177? pop???????? esi?

00401178? pop???????? ebx?

00401179? add???????? esp,0CCh

0040117F ? cmp???????? ebp,esp

00401181? call??????? _RTC_CheckEsp (4011E0h)

00401186? mov???????? esp,ebp

00401188? pop???????? ebp?

00401189? ret?????????????

前面幾行是將寄存器的值恢復(fù),而 add esp 0CCh 是將保留的堆棧空間釋放,同時比較 ebp 是否與 esp 相等,如果不相等就提示相應(yīng)的錯誤,說明有內(nèi)存泄露等。最后將 ebp 彈出然后返回。

?

從上面的分析我們可以看到編譯器為我們做了很多事情,包括:堆棧空間分配和釋放、寄存器狀態(tài)保存、參數(shù)傳遞等。當然這些事情也可以完全由我們自己來完成,那么需要做的是使用關(guān)鍵字 naked 來聲明函數(shù)。

posted on 2007-01-18 15:08 笨笨 閱讀(2516) 評論(3)  編輯 收藏 引用 所屬分類: 編碼

評論

# re: 函數(shù)是如何被調(diào)用的?-探索代碼背后的故事 2007-01-18 15:09 笨笨

終于又找回密碼了,痛恨木馬編寫的人,痛恨病毒!同時感謝論壇斑竹的熱心幫助!  回復(fù)  更多評論   

# re: 函數(shù)是如何被調(diào)用的?-探索代碼背后的故事 2007-01-27 01:04 SonicLing

很多時候并不一定會用ebp來備份esp。包含ret的分支很少的函數(shù)用release編譯之后,直接會在ret之前將esp加回到原來的值,ebp用來干其他的事。

xor eax,eax是因為該指令比mov eax,0無論是在指令長度還是在執(zhí)行效率上都更優(yōu)秀。  回復(fù)  更多評論   

# re: 函數(shù)是如何被調(diào)用的?-探索代碼背后的故事 2007-01-29 08:45 笨笨

你說的很有道理,這里僅僅是將一段代碼再VC中反匯編的到的。當然,這里的代碼并非唯一的寫法。
所以,謝謝你的補充
  回復(fù)  更多評論   

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲综合导航| 亚洲激情视频在线播放| 欧美伊人精品成人久久综合97 | 国产精品视频网| 欧美精品久久99| 欧美国产第二页| 免费日韩av片| 欧美精选午夜久久久乱码6080| 欧美成人午夜激情视频| 免费一级欧美片在线播放| 久久精品水蜜桃av综合天堂| 嫩草国产精品入口| 欧美日韩在线直播| 国产一区二区精品在线观看| 狠狠色狠狠色综合日日tαg| 亚洲国产婷婷| 亚洲自拍偷拍色片视频| 久久久久久亚洲精品杨幂换脸| 蜜臀91精品一区二区三区| 亚洲欧洲日韩在线| 亚洲日本中文字幕区| 亚洲小说欧美另类社区| 久久亚洲欧美| 国产精品久久久久久av下载红粉| 国自产拍偷拍福利精品免费一| 亚洲国产第一| 欧美中文在线字幕| 亚洲经典三级| 欧美在线日韩精品| 欧美三级特黄| 亚洲国产欧美久久| 欧美中文字幕在线播放| 亚洲精品小视频| 久久婷婷国产麻豆91天堂| 国产精品美女午夜av| 91久久久一线二线三线品牌| 亚洲永久在线| 亚洲国产精品小视频| 午夜精品久久久久久久久久久| 欧美sm重口味系列视频在线观看| 国产精品一二一区| 一区二区欧美精品| 免费在线看一区| 羞羞色国产精品| 国产精品欧美一区喷水| 夜夜嗨av一区二区三区免费区| 久久久夜精品| 一本一道久久综合狠狠老精东影业| 久久久久久久精| 国产婷婷色一区二区三区| 亚洲一区二区成人在线观看| 亚洲国产小视频| 欧美高清你懂得| 亚洲区免费影片| 男女av一区三区二区色多| 亚洲男女自偷自拍图片另类| 欧美日韩午夜激情| av成人免费在线| 久热精品视频在线观看| 一区二区自拍| 亚洲欧美日韩第一区| 亚洲欧洲另类国产综合| 玖玖视频精品| 亚洲国产欧美一区二区三区同亚洲| 久久久亚洲欧洲日产国码αv| 午夜精品区一区二区三| 国产欧美日韩| 久久久久99| 久久久久免费| 亚洲靠逼com| 中文国产成人精品久久一| 欧美午夜精品伦理| 亚洲一区二区三区在线| 日韩系列欧美系列| 欧美性猛交99久久久久99按摩| 99国产精品久久久久老师| 91久久亚洲| 国产精品乱码妇女bbbb| 久久国产一区二区三区| 久久久国产一区二区| 亚洲欧洲在线视频| 亚洲精品小视频在线观看| 欧美性大战久久久久久久| 欧美一进一出视频| 久久一二三区| 一本综合精品| 亚洲欧美日韩一区二区三区在线| 国产亚洲精品高潮| 欧美成人精品一区二区| 欧美国产在线电影| 西瓜成人精品人成网站| 久久人人超碰| 亚洲欧美国产va在线影院| 久久九九久久九九| 日韩一区二区电影网| 亚欧成人在线| 99国产精品久久久久老师| 亚洲欧美亚洲| 最新日韩在线视频| 亚洲特黄一级片| 亚洲国产精品视频一区| 在线综合+亚洲+欧美中文字幕| 国产精品一区二区你懂的| 亚洲国产99| 国内精品久久久久久影视8| 亚洲精品日本| 在线看日韩av| 亚洲欧美激情视频| 99综合在线| 久久一二三区| 久久精品女人| 国产精品美女主播| 日韩视频一区| 亚洲毛片在线| 久久综合一区二区| 久久精品国产精品亚洲综合| 欧美三级网址| 欧美高清成人| 伊人成综合网伊人222| 亚洲欧美日韩综合| 亚洲直播在线一区| 欧美日韩mp4| 国产精品亚洲网站| 亚洲破处大片| 国模精品一区二区三区| 亚洲最新视频在线| 亚洲精品在线观看视频| 久久伊伊香蕉| 快播亚洲色图| 尤物九九久久国产精品的特点 | 欧美国产激情二区三区| 国产亚洲一区精品| 亚洲午夜精品在线| 亚洲综合成人在线| 国产精品成人v| 中文一区字幕| 翔田千里一区二区| 国产精品―色哟哟| 亚洲视频精选在线| 亚洲一区二区三区中文字幕在线| 欧美日本二区| 亚洲精品一二| 亚洲欧美视频在线观看| 国产精品国产三级国产a| 一区二区三区欧美激情| 亚洲欧美日韩综合国产aⅴ| 国产精品亚洲综合久久| 午夜伦欧美伦电影理论片| 欧美一区久久| 韩国成人精品a∨在线观看| 久久久久久999| 亚洲国产高清在线| 一本久久a久久免费精品不卡| 欧美日韩国产a| 亚洲午夜极品| 巨胸喷奶水www久久久免费动漫| 国语自产精品视频在线看8查询8| 久久青青草综合| 亚洲精品男同| 久久国产视频网| 最新成人av在线| 国产精品美腿一区在线看 | 久久成人羞羞网站| 国产午夜精品久久久久久免费视 | 性伦欧美刺激片在线观看| 欧美一区二区三区免费看| 国模私拍一区二区三区| 久久综合电影一区| 亚洲黑丝在线| 性欧美大战久久久久久久免费观看| 国产亚洲精品自拍| 欧美~级网站不卡| 一区二区三区鲁丝不卡| 久久久久久久久综合| 日韩亚洲视频| 国产有码在线一区二区视频| 欧美顶级大胆免费视频| 亚洲欧美日本伦理| 亚洲国产成人av好男人在线观看| 亚洲视频电影在线| 一区二区在线观看av| 欧美国产综合| 久久成人一区二区| 亚洲视频免费在线| 欧美激情一区二区| 久久gogo国模啪啪人体图| 日韩视频不卡中文| 国产综合第一页| 欧美三级电影大全| 亚洲第一成人在线| 亚洲福利视频网站| 欧美日韩一区在线| 久久久久国产一区二区| 中文精品视频一区二区在线观看| 麻豆精品在线观看| 欧美在线看片| 亚洲欧美日韩国产精品| 亚洲人成高清| 在线视频观看日韩| 国产一区 二区 三区一级|