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

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

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

留下點(diǎn)回憶

常用鏈接

統(tǒng)計(jì)

積分與排名

Denoise

English study

Web技術(shù)

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

一些連接

最新評(píng)論

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

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

首先看一個(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.? 沒(méi)有參數(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í)變量。

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

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

2.? 函數(shù)入口的地方必須為臨時(shí)變量分配一定空間;實(shí)際上如果沒(méi)有臨時(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 ,那么后來(lái) EBP 中的值就是這個(gè)值,在保存的空間(從 0X12FE10 0X12FEDC )上將所有的內(nèi)存都初始化為 0XCC 。而 i 被分配在 0X12FED4 處,也就是第一個(gè)預(yù)留的位置)。

?

?

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

由于已經(jīng)知道 i 的地址了,對(duì) i 的賦值就很簡(jiǎn)單了。這里看調(diào)用第一個(gè)沒(méi)有參數(shù)沒(méi)有返回值的 test1 函數(shù);僅僅一條語(yǔ)句,將 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 的下條指令。

因此我們說(shuō) 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)部沒(mé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 命令來(lái)執(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ù)的返回值是通過(guò) eax 寄存器來(lái)返回的。

?

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

?

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

??? return 0;

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

特別的不在于通過(guò) 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ò)誤,說(shuō)明有內(nèi)存泄露等。最后將 ebp 彈出然后返回。

?

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

posted on 2007-01-18 15:08 笨笨 閱讀(2516) 評(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來(lái)備份esp。包含ret的分支很少的函數(shù)用release編譯之后,直接會(huì)在ret之前將esp加回到原來(lái)的值,ebp用來(lái)干其他的事。

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

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

你說(shuō)的很有道理,這里僅僅是將一段代碼再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>
            欧美精品1区2区| 亚洲最新中文字幕| 亚洲调教视频在线观看| 91久久久亚洲精品| 亚洲国产精品久久久久秋霞不卡 | 米奇777在线欧美播放| 久久精品人人| 欧美高清视频在线观看| 亚洲精品小视频| 亚洲午夜一二三区视频| 欧美在线观看视频一区二区| 免费亚洲电影| 国产精品v欧美精品∨日韩| 国产亚洲欧美一区在线观看| 亚洲精品欧美极品| 欧美在线观看一二区| 免费av成人在线| 99这里有精品| 久久精品论坛| 欧美视频在线一区| 国内成人精品视频| 亚洲性人人天天夜夜摸| 久久精品视频在线观看| 欧美激情欧美狂野欧美精品| 99国产精品久久久久久久| 午夜在线观看免费一区| 欧美激情第8页| 国产一区在线视频| 中国女人久久久| 欧美不卡福利| 午夜精品久久久久久| 久久字幕精品一区| 亚洲精品国产无天堂网2021| 一区二区三区日韩精品视频| 久久夜色精品国产欧美乱| 国产精品wwwwww| 亚洲日韩中文字幕在线播放| 久久国内精品自在自线400部| 亚洲狠狠婷婷| 久久在线观看视频| 国产一区成人| 香蕉久久国产| 日韩午夜在线| 欧美肥婆在线| 亚洲国产精品传媒在线观看 | 日韩视频在线一区二区三区| 久久精品夜色噜噜亚洲aⅴ| 亚洲精品无人区| 欧美国产极速在线| 亚洲国产精品高清久久久| 久久免费视频在线观看| 亚洲欧美日韩精品在线| 国产精品一区二区欧美| 亚洲视频精选在线| 亚洲欧洲免费视频| 欧美精品福利在线| 亚洲日本视频| 亚洲国产精品欧美一二99| 久久一区二区三区av| 在线播放不卡| 美女视频黄a大片欧美| 久久九九99| 亚洲第一在线综合网站| 欧美成人午夜77777| 久久在线精品| 亚洲精品免费一二三区| 亚洲欧洲一区二区三区| 欧美精品久久99| 一本久道久久久| aa亚洲婷婷| 国产精品视频大全| 久久精品人人爽| 久久一综合视频| 亚洲精品美女在线| 99精品欧美一区二区三区综合在线| 欧美精品一区二区视频| 亚洲免费在线视频一区 二区| 亚洲午夜精品在线| 国产在线观看一区| 亚洲国产成人精品久久| 欧美体内谢she精2性欧美| 久久精品国产久精国产思思| 久久久女女女女999久久| 亚洲人成久久| 亚洲主播在线| 亚洲国产成人在线| 在线一区亚洲| 在线观看福利一区| 一区二区三区 在线观看视| 欧美在线影院在线视频| 亚洲国产日韩欧美在线动漫| 亚洲精品美女久久7777777| 国产精品午夜av在线| 免费影视亚洲| 国产精品毛片| 欧美护士18xxxxhd| 国产精品久久久久一区二区三区| 浪潮色综合久久天堂| 欧美精品一区二区三| 欧美一区在线直播| 亚洲在线观看视频| 91久久精品国产91性色| 在线一区日本视频| 亚洲精品人人| 亚洲欧美中日韩| 亚洲人成艺术| 亚洲欧美日韩国产精品| 亚洲人体影院| 欧美一区二区三区四区在线观看地址 | 亚洲欧洲精品一区二区三区不卡 | 欧美午夜片在线免费观看| 久久亚洲电影| 国产精品久久999| 亚洲精品色图| 亚洲国产精品成人久久综合一区| 亚洲一区欧美| 亚洲香蕉网站| 欧美激情视频网站| 欧美va天堂| 国产一区清纯| 亚洲欧美视频在线观看视频| 亚洲婷婷免费| 欧美美女视频| 最新成人在线| 亚洲国产婷婷香蕉久久久久久99| 欧美在现视频| 西西裸体人体做爰大胆久久久| 欧美va日韩va| 欧美福利视频在线| 在线国产欧美| 久久久青草婷婷精品综合日韩 | 亚洲精品国久久99热| 亚洲激情欧美激情| 久久综合色88| 你懂的视频欧美| 激情国产一区| 久久精品视频免费播放| 久久精视频免费在线久久完整在线看| 国产精品www| 亚洲淫片在线视频| 午夜综合激情| 国产夜色精品一区二区av| 午夜在线成人av| 乱人伦精品视频在线观看| 国内自拍一区| 欧美成年人网站| 午夜精品视频网站| 国产精品久久久久aaaa九色| 日韩视频免费看| 亚洲欧美久久久| 国产午夜精品理论片a级大结局 | 亚洲高清视频一区| 亚洲免费高清| 欧美亚男人的天堂| 午夜精品福利一区二区蜜股av| 欧美一区二区三区久久精品| 国产婷婷色一区二区三区四区| 久久九九国产精品怡红院| 欧美黄网免费在线观看| 亚洲少妇最新在线视频| 国产精品久久久久久久久久久久| 亚洲欧美视频一区| 欧美jizz19hd性欧美| 一区二区三区免费在线观看| 国产精品日本精品| 久久只精品国产| 一二三四社区欧美黄| 久久久蜜桃一区二区人| 亚洲精品免费一二三区| 国产精品美腿一区在线看 | 日韩午夜黄色| 国产精品视频一二| 久久视频这里只有精品| 一本色道久久综合狠狠躁篇的优点 | 亚洲高清二区| 国产精品国产三级国产| 久久久av水蜜桃| 99国产精品久久久久久久成人热| 久久精品99| 亚洲天堂av图片| 怡红院精品视频| 欧美日韩一区在线观看视频| 欧美一区二区三区喷汁尤物| 亚洲精品视频免费观看| 久久亚洲春色中文字幕| 亚洲综合电影一区二区三区| 在线精品视频免费观看| 国产精品乱子久久久久| 欧美激情一区二区三区在线视频| 欧美亚洲自偷自偷| 一本色道久久综合亚洲精品婷婷| 女生裸体视频一区二区三区| 午夜激情一区| 日韩一二三区视频| 精品成人在线观看| 国产日韩欧美日韩| 欧美性感一类影片在线播放| 欧美成人在线免费观看| 久久国产精品一区二区| 亚洲欧美偷拍卡通变态|