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

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

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

留下點(diǎn)回憶

常用鏈接

統(tǒng)計(jì)

積分與排名

Denoise

English study

Web技術(shù)

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

一些連接

最新評(píng)論

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

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

首先看一個(gè)簡(jiǎn)單的代碼例子:

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;

}

?

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

1.? 沒有參數(shù)

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

3.? 3 個(gè)參數(shù)

4.? 有返回值

5.? 有兩個(gè)臨時(shí)變量

6.? 有多個(gè)臨時(shí)變量

?

VC7 中,我們將斷點(diǎn)設(shè)置到 main 函數(shù)入口的地方;然后 F5 運(yùn)行程序。再按 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 // 將當(dāng)前棧頂指針?biāo)偷?/span> ebp

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

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ù)入口部分,基本的含義是為臨時(shí)變量分配空間,并且初始化臨時(shí)變量。

這里需要說明幾點(diǎn):

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

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

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

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

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

?

?

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

由于已經(jīng)知道 i 的地址了,對(duì) i 的賦值就很簡(jiǎn)單了。這里看調(diào)用第一個(gè)沒有參數(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í)將返回地址入棧;可以看到當(dāng)前棧頂?shù)闹凳?/span> 0040114A ,實(shí)際上是 test1 的下條指令。

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

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

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

?

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

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)部沒有臨時(shí)變量,因此這里只保留了 C0 個(gè)自己的空間。

?

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

??? test(10);

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

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

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

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

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

?

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

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

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

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

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

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

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

?

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

?

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

??? i=test2();

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

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

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

?

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

?

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

??? return 0;

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

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

?

mian 函數(shù)退出的時(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 是將保留的堆棧空間釋放,同時(shí)比較 ebp 是否與 esp 相等,如果不相等就提示相應(yīng)的錯(cuò)誤,說明有內(nèi)存泄露等。最后將 ebp 彈出然后返回。

?

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

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

評(píng)論

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

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

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

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

xor eax,eax是因?yàn)樵撝噶畋萴ov eax,0無論是在指令長(zhǎng)度還是在執(zhí)行效率上都更優(yōu)秀。  回復(fù)  更多評(píng)論   

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            久久久久在线观看| 久久亚洲一区| 欧美在线视屏| 另类国产ts人妖高潮视频| 免费不卡在线视频| 欧美sm视频| 亚洲人成网站影音先锋播放| 亚洲毛片av| 亚洲欧美日韩成人| 久久人人爽人人| 欧美精品精品一区| 国产精品女同互慰在线看| 欧美日韩国产综合久久| 国产精品日本精品| 在线成人小视频| 一区二区三区欧美| 久久久91精品国产一区二区精品| 欧美成人在线免费视频| 亚洲精品1区2区| 亚洲一区二区三区精品在线| 亚洲视频一二三| 久久久久国色av免费看影院| 欧美成人中文| 国产精品亚洲综合色区韩国| 在线观看成人av| 在线亚洲欧美| 午夜精品久久久久久久久久久久久| 久久久久久国产精品mv| 亚洲国产成人久久综合一区| 国产精品99久久久久久宅男 | 午夜精品视频一区| 欧美成人午夜剧场免费观看| 在线视频你懂得一区二区三区| 久久狠狠婷婷| 欧美日韩在线直播| 国产亚洲va综合人人澡精品| 亚洲老司机av| 久久久久久电影| 一区二区三区日韩| 每日更新成人在线视频| 欧美日韩伦理在线| 影音先锋亚洲电影| 欧美一级视频免费在线观看| 欧美激情一区在线| 欧美专区在线观看一区| 欧美精品不卡| 极品裸体白嫩激情啪啪国产精品| 亚洲卡通欧美制服中文| 久久青青草原一区二区| 一区二区欧美在线观看| 欧美wwwwww| 国产精品你懂的在线欣赏| 亚洲精品国产精品国产自| 久久久www成人免费毛片麻豆| 99riav久久精品riav| 久久亚洲综合网| 国产精品国产成人国产三级| 亚洲精品美女在线观看| 久久久999精品免费| 中国成人在线视频| 欧美伦理视频网站| 91久久精品一区| 免费精品视频| 亚洲欧美在线观看| 欧美日韩另类综合| 99v久久综合狠狠综合久久| 免费不卡在线观看av| 欧美伊人久久大香线蕉综合69| 国产精品激情av在线播放| 亚洲蜜桃精久久久久久久| 免费观看成人| 久久精品国产在热久久 | 久久精品导航| 亚洲午夜精品17c| 欧美日韩精品免费看| 亚洲欧洲日韩女同| 老司机67194精品线观看| 欧美一级免费视频| 国产日韩欧美综合精品| 亚洲午夜免费福利视频| 亚洲精品综合| 欧美精品激情在线观看| 亚洲理论电影网| 亚洲青色在线| 欧美伦理视频网站| 一区二区三区国产盗摄| 亚洲毛片在线免费观看| 农夫在线精品视频免费观看| 亚洲国产高清一区| 欧美激情按摩| 欧美激情亚洲激情| 日韩视频在线观看| 亚洲高清在线观看一区| 欧美激情1区2区3区| 日韩视频在线免费观看| 99国产精品久久久久久久成人热| 欧美日韩另类视频| 在线综合亚洲| 亚洲一区二区三区在线看| 国产精品毛片va一区二区三区 | 欧美成人一区二区在线| 久热精品视频在线| 日韩视频一区| 亚洲日韩视频| 欧美大学生性色视频| 老色批av在线精品| 亚洲精品乱码久久久久久蜜桃91| 亚洲经典视频在线观看| 欧美日韩亚洲视频| 性色av一区二区三区红粉影视| 久久国产夜色精品鲁鲁99| 在线观看欧美日韩国产| 亚洲激情一区二区| 亚洲一区一卡| 在线观看视频一区二区| 99这里有精品| 国产亚洲精品成人av久久ww| 欧美国产三级| 欧美午夜在线视频| 久久久精品午夜少妇| 欧美另类一区| 欧美中文字幕在线播放| 欧美精品一区二区三区高清aⅴ| 亚洲欧美国产精品桃花| 久久婷婷久久一区二区三区| 一区二区三区视频在线| 夜夜嗨av色一区二区不卡| 黑人一区二区| 亚洲肉体裸体xxxx137| 国内精品久久久| 亚洲欧洲日韩在线| 韩国一区电影| 亚洲精品综合| 国产在线欧美日韩| 一本色道久久综合亚洲二区三区 | 久久久久国产精品麻豆ai换脸| 亚洲理论在线观看| 亚洲神马久久| 日韩视频在线一区| 久久爱www久久做| 亚洲女性喷水在线观看一区| 久久久免费精品视频| 性刺激综合网| 欧美激情综合色综合啪啪| 久久性色av| 国产精品国产a| 欧美激情一区在线| 国产一区二区三区成人欧美日韩在线观看 | 国产欧美91| 亚洲国产欧美久久| 国产亚洲午夜| 亚洲欧美另类中文字幕| 日韩视频在线你懂得| 卡通动漫国产精品| 欧美专区福利在线| 国产精品久久久久久久久免费桃花| 欧美91福利在线观看| 国产日韩精品入口| 亚洲一区二区在线视频| 日韩亚洲在线观看| 欧美.www| 久久亚洲国产精品日日av夜夜| 国产精品视频yy9099| 亚洲日韩欧美视频一区| 亚洲欧洲在线观看| 久久福利电影| 亚洲欧美久久久久一区二区三区| 欧美日韩高清免费| 亚洲第一精品福利| 91久久精品www人人做人人爽| 欧美一区二区三区在线视频| 久久aⅴ国产紧身牛仔裤| 欧美午夜a级限制福利片| 99综合在线| 夜夜嗨av一区二区三区四区| 欧美激情第一页xxx| 免费在线观看成人av| 国内精品嫩模av私拍在线观看| 欧美一区午夜精品| 久久不射中文字幕| 国产在线精品成人一区二区三区| 亚洲一卡久久| 久久精品国产精品亚洲精品| 国产精品女主播| 午夜在线精品偷拍| 午夜精品久久久| 国产欧美精品一区aⅴ影院| 亚洲一区二区在线免费观看| 一区二区三区av| 国产精品扒开腿做爽爽爽软件 | 一区二区三区在线观看欧美| 午夜精品久久一牛影视| 午夜欧美大尺度福利影院在线看| 国产精品久久久一区二区三区| 一本久道久久综合婷婷鲸鱼| 亚洲欧美激情精品一区二区| 国产精品久久网站| 欧美亚洲在线视频| 久久免费国产| 亚洲日本一区二区三区|