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

Dict.CN 在線詞典, 英語學習, 在線翻譯

學海苦作舟,書山勤為徑

留下點回憶

常用鏈接

統計

積分與排名

Denoise

English study

Web技術

數據壓縮

一些連接

最新評論

函數是如何被調用的?-探索代碼背后的故事

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

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

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 函數調用幾個被測試的函數,分別是:

1.? 沒有參數

2.? 有一個參數

3.? 3 個參數

4.? 有返回值

5.? 有兩個臨時變量

6.? 有多個臨時變量

?

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

Main 函數變成這樣了:

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 // 直接將數據 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?????????????

?

函數入口部分:

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

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

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

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]// 復制

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

這里需要說明幾點:

1.? 函數調用是通過堆棧來完成的。

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

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

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

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

?

?

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

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

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

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

EBP = 0012FEDC EFL = 00000202

上面是 Call 指令調用前各寄存器的值;下面是調用后的值:

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

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

EBP = 0012FEDC EFL = 00000202

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

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

1.? EIP 從當前值改為被調用函數的值。

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

?

現在進入 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????? ??????

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

?

繼續回到主程序:

??? test(10);

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

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

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

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

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

?

對于 test3 的調用:

??? 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

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

?

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

?

mian 函數的返回值,有點特別:

??? return 0;

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

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

?

mian 函數退出的時候有這段代碼:

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?????????????

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

?

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

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

評論

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

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

# re: 函數是如何被調用的?-探索代碼背后的故事 2007-01-27 01:04 SonicLing

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

xor eax,eax是因為該指令比mov eax,0無論是在指令長度還是在執行效率上都更優秀。  回復  更多評論   

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

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

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲欧美日韩精品| 免费视频一区二区三区在线观看| 一区二区三区国产| 亚洲欧洲精品成人久久奇米网| 国产日韩亚洲欧美精品| 亚洲九九精品| 欧美成人视屏| 亚洲新中文字幕| 欧美精选在线| 久久国产精品毛片| 午夜在线一区| 一区一区视频| 91久久精品国产91性色tv| 久久国内精品视频| 国产亚洲欧美日韩日本| 亚洲综合色网站| 欧美激情精品久久久六区热门| 一区二区三区四区国产| 一区二区三区免费网站| 国产欧美日韩专区发布| 性做久久久久久久久| 亚洲少妇自拍| 精品不卡在线| 久久久久一区二区| 亚洲砖区区免费| 久久在线视频| 99国产精品久久久久老师| 亚洲电影在线免费观看| 老司机久久99久久精品播放免费 | 亚洲一区激情| 欧美激情第五页| 欧美在线精品一区| 老司机免费视频久久| 亚洲欧美日韩视频一区| 久久久精品国产免费观看同学| 国产一区二区精品在线观看| 一区二区三区 在线观看视| 欧美一区二区啪啪| 日韩亚洲欧美成人| 久久视频国产精品免费视频在线| 亚洲国产成人av| 欧美精品国产一区| 日韩视频免费观看高清在线视频 | 亚洲一区二区三区四区在线观看 | 午夜精品999| 亚洲一级在线| 欧美日韩国产色站一区二区三区| 美脚丝袜一区二区三区在线观看| 欧美电影打屁股sp| 快射av在线播放一区| 极品尤物一区二区三区| 久久国产精品久久久久久久久久| 中国日韩欧美久久久久久久久| 欧美成在线视频| 91久久亚洲| 亚洲欧美国产77777| 国产精品日韩精品欧美在线| 亚洲欧美在线高清| 久久综合狠狠| 亚洲国产另类久久精品| 国产精品美女久久久| 久久免费国产精品1| 夜夜爽av福利精品导航 | 亚洲高清自拍| 一区二区三区 在线观看视频| 欧美日韩午夜精品| 亚洲一区综合| 嫩草影视亚洲| 亚洲国产精品va在看黑人| 国产精品成人久久久久| 亚洲欧美日韩另类精品一区二区三区| 亚洲制服欧美中文字幕中文字幕| 国产日韩一区二区| 一区在线影院| 国产综合精品| 国产精品一级久久久| 久久影院亚洲| 午夜精品久久久久久99热软件| 欧美资源在线| 亚洲一区三区视频在线观看| 一色屋精品视频在线观看网站| 欧美激情一区二区三级高清视频| 制服丝袜激情欧洲亚洲| 中文网丁香综合网| 亚洲毛片在线| 欧美高清在线播放| 欧美一级淫片aaaaaaa视频| 亚洲电影av在线| 91久久国产综合久久| 国产女人18毛片水18精品| 欧美视频日韩视频| 欧美激情五月| 黄色小说综合网站| 在线免费观看视频一区| 欧美在线观看天堂一区二区三区| 日韩视频中文| 亚洲午夜高清视频| 小黄鸭精品密入口导航| 亚洲区第一页| 日韩午夜精品视频| 99在线热播精品免费| 久久精品视频网| 亚洲第一色在线| 亚洲第一福利在线观看| 欧美在线视频免费播放| 久久精品一区二区三区不卡牛牛| 亚洲第一免费播放区| 久久看片网站| 亚洲大胆女人| 亚洲欧美日韩在线播放| 亚洲国产精品视频一区| 在线观看国产欧美| 一本大道久久a久久综合婷婷| 亚洲综合二区| 欧美韩日一区二区三区| 亚洲九九九在线观看| 久久国产福利| 国产亚洲一区在线| 亚洲第一精品久久忘忧草社区| 国产免费观看久久| 99re66热这里只有精品4| 欧美一区二区三区在线观看| 亚洲美女黄网| 欧美日韩一区二区三| 亚洲精品国久久99热| 蜜臀久久99精品久久久久久9| 欧美一区二区日韩| 激情欧美亚洲| 欧美国产精品中文字幕| 欧美国产日韩xxxxx| 一区二区在线不卡| 欧美www视频| 欧美日韩无遮挡| av不卡免费看| 午夜精品视频在线| 亚洲欧洲精品一区二区三区不卡 | 欧美国产另类| 免费成人高清视频| 亚洲激情在线播放| 性色av一区二区怡红| 在线视频日本亚洲性| 亚洲精品中文字幕在线| 午夜精品免费视频| 欧美激情一区二区三区四区| 久久在线免费观看| 一区二区激情视频| 亚洲欧美一区二区在线观看| 欧美色道久久88综合亚洲精品| 亚洲一区免费观看| 在线亚洲伦理| 先锋亚洲精品| 最新国产成人在线观看| 欧美激情精品久久久久久变态 | 欧美中文日韩| 国产精品乱码妇女bbbb| 美日韩在线观看| 国产日韩一区二区| 91久久国产综合久久| 欧美日韩精品伦理作品在线免费观看| 亚洲午夜在线观看视频在线| 亚洲精品在线一区二区| 精品成人一区| 欧美亚洲一区在线| 久久久久88色偷偷免费| 欧美一区二区三区在| 欧美视频精品在线| 欧美黄色aaaa| 欧美xart系列高清| 狠狠干成人综合网| 欧美在线观看视频一区二区| 亚洲一区三区视频在线观看| 欧美午夜在线视频| 日韩午夜精品视频| 亚洲精选视频免费看| 亚洲欧美日韩区| 久久九九精品99国产精品| 国产麻豆精品久久一二三| 午夜精彩视频在线观看不卡 | 亚洲欧美国产精品专区久久| 欧美91福利在线观看| 亚洲高清视频一区二区| 午夜亚洲精品| 国产精品久久久一区麻豆最新章节 | 免费91麻豆精品国产自产在线观看| 国产精品日韩欧美一区二区三区| 亚洲女女女同性video| 欧美日韩小视频| 久久久伊人欧美| 欧美一级网站| 99成人在线| 快射av在线播放一区| 中文av一区特黄| 国产精品入口夜色视频大尺度 | 亚洲视频欧美在线| 亚洲欧洲偷拍精品| 欧美高清在线精品一区| 香蕉亚洲视频| 亚洲一区bb| 免费国产一区二区| 午夜久久资源|