匯編和可執(zhí)行文件
????????前面我們已經(jīng)知道笋轨,匯編約等于機(jī)器碼。源代碼通過(guò)編譯器(也是一個(gè)軟件)進(jìn)行編譯愈捅,得到機(jī)器碼遏考。以后我們統(tǒng)一用匯編代替機(jī)器碼。
編譯
????????編譯器在編譯程序的時(shí)候蓝谨,分為Debug版本和Release版本灌具。編譯器不會(huì)對(duì)Debug版本的程序進(jìn)行優(yōu)化,而編譯器會(huì)對(duì)Release版本的程序進(jìn)行優(yōu)化譬巫。下面是在反匯編的情況下對(duì)Debug版本和Release版本進(jìn)行一下比較咖楣。
源代碼如下所示:
int main()
{
int iCount = 10;
double dStep = 0.123;
return 0;
}
對(duì)應(yīng)的Debug版本匯編代碼如下所示:
int main()
{
000F1A50 push ebp
000F1A51 mov ebp,esp
000F1A53 sub esp,0DCh
000F1A59 push ebx
000F1A5A push esi
000F1A5B push edi
000F1A5C lea edi,[ebp-0DCh]
000F1A62 mov ecx,37h
000F1A67 mov eax,0CCCCCCCCh
000F1A6C rep stos dword ptr es:[edi]
int iCount = 10;
000F1A6E mov dword ptr [iCount],0Ah
double dStep = 0.123;
000F1A75 movsd xmm0,mmword ptr [__real@3fbf7ced916872b0 (0F6CB0h)]
000F1A7D movsd mmword ptr [dStep],xmm0
return 0;
000F1A82 xor eax,eax
}
對(duì)應(yīng)的Release版本匯編代碼如下所示:
int iCount = 10;
double dStep = 0.123;
return 0;
008B1000 xor eax,eax
}
從上面匯編代碼的結(jié)果可以看出,Debug版本的匯編代碼會(huì)將iCount和dStep這兩個(gè)變量轉(zhuǎn)換成匯編代碼芦昔,而Release版本的匯編代碼就會(huì)將iCount和dStep這兩個(gè)變量省略掉诱贿,也就是會(huì)對(duì)源代碼做一些優(yōu)化。并且Debug版本生成的可執(zhí)行文件的大小(本程序?yàn)?5.5KB)相對(duì)于Release版本的可執(zhí)行程序的大兄槭(本程序?yàn)?.00KB)也要大很多料扰。所以我們建議在以后調(diào)試程序的時(shí)候,最好使用Debug版本進(jìn)行編譯焙蹭,這樣編譯器就不會(huì)幫我們優(yōu)化源代碼晒杈。
鏈接
整個(gè)內(nèi)存可以分為四個(gè)區(qū)域,分別為:
-
棧區(qū)
棧區(qū)具有可增長(zhǎng)性孔厉。VS為每個(gè)線程默認(rèn)分配1024KB大小的椪辏空間,如果在棧上分配的空間超過(guò)1024KB撰豺,就會(huì)產(chǎn)生棧溢出的錯(cuò)誤粪般。
棧空間使用的大小由兩個(gè)寄存器來(lái)決定污桦,分別是棧底指針和棧頂指針亩歹,棧空間中的變量在增加時(shí)寡润,棧頂指針就會(huì)一點(diǎn)一點(diǎn)的向上移動(dòng)捆憎,到最后如果這些變量都已經(jīng)沒(méi)有用了,棧頂指針就會(huì)指向棧底指針梭纹,表示原來(lái)的那些變量已經(jīng)是垃圾數(shù)據(jù)了躲惰。
如果棧空間上存在函數(shù)調(diào)用過(guò)程(棧的回溯功能)变抽,那么還會(huì)有保存棧底指針的變量础拨,具體的這里就先不做詳細(xì)說(shuō)明了。 - 堆區(qū)
- 代碼區(qū)
- 常量區(qū)
這樣劃分的目的是為了我們編寫的程序更加安全绍载。這樣劃分區(qū)域后诡宗,就可以將代碼區(qū)和常量區(qū)設(shè)置為只讀屬性,從而達(dá)到程序中的代碼以及用到的一些常量就不會(huì)被意外的修改击儡,提高了程序在運(yùn)行期間的安全性塔沃。
匯編代碼
匯編指令:
push代表壓棧的操作
pop代表出棧的操作
ebp棧底指針寄存器
esp棧頂指針寄存器
eip程序計(jì)數(shù)器
efl 標(biāo)志寄存器
下面一般作為通用寄存器:
eax 累加寄存器
edi 源寄存器
esi 基址寄存器
下面是在main函數(shù)中只執(zhí)行一句printf("Hello World!")語(yǔ)句時(shí),ebp和esp的一系列值阳谍。
EBP ESP OPRATION
009DFA30 009DF964
009DF960 offset string "Hello World!" (0A06BCCh)
009DF95C 00A02093 call _printf (0A01370h)
009DF958 00A02900 push ebp
009DF958 00A02901 mov ebp,esp
009DF880 00A02903 sub esp,0D8h
009DF87C 00A02909 push ebx
009DF878 00A0290A push esi
009DF874 00A0290B push edi
009DF870 00A0291E call __vcrt_va_start_verify_argument_type<char const * const> (0A011CCh)
009DF874 00A011CC jmp __vcrt_va_start_verify_argument_type<char const * const> (0A02170h)
009DF870 00A0292C push eax
009DF86C 00A0292D push 0
009DF868 00A02932 push ecx
009DF864 00A02935 push 1
009DF860 00A02937 call dword ptr [__imp____acrt_iob_func (0A0A16Ch)]
009DF85C 53A6D362 push ebp
009DF85C 53A6D363 mov ebp,esp
009DF958 009DF860 53A6D36E pop ebp
009DF864 53A6D36F ret
009DF868 00A0293D add esp,4
009DF864 00A02942 call __RTC_CheckEsp (0A01113h)
009DF868
009DF864 00A02947 push eax
009DF860 00A02948 call __vfprintf_l (0A0136Bh)
009DF85C 00A019C0 push ebp
009DF85C 00A019C1 mov ebp,esp
009DF79C 00A019C3 sub esp,0C0h
009DF798 00A019C9 push ebx
009DF794 00A019CA push esi
009DF790 00A019CB push edi
009DF78C 00A019E3 push eax
009DF788 00A019E7 push ecx
009DF784 00A019EB push edx
009DF780 00A019EF push eax
009DF77C 00A019F0 call ___local_stdio_printf_options (0A01339h)
009DF780 00A01339 jmp __local_stdio_printf_options (0A02AB0h)
009DF77C 00A019F8 push ecx
009DF778 00A019FB push edx
009DF774 00A019FC call dword ptr [__imp____stdio_common_vfprintf (0A0A168h)]
009DF770 53A67FF2 push ebp
009DF770 53A67FF3 mov ebp,esp
009DF76C 53A67FF8 push eax
009DF768 53A67FFC push ecx
009DF764 53A68000 push edx
009DF760 53A68004 push eax
009DF75C 53A68008 push ecx
009DF758 53A6800C push edx
009DF754 53A6800D call 53A4CA90
009DF750 53A4CA92 push ebp
009DF750 53A4CA93 mov ebp,esp
009DF72C 53A4CA95 sub esp,24h
009DF728 53A4CB8A push ecx
009DF724 53A4CB8E push edx
009DF720 53A4CB92 push eax
009DF71C 53A4CB96 push ecx
009DF718 53A4CB9A push edx
009DF714 53A4CB9E call 53A20590
009DF710 53A20592 push ebp
009DF710 53A20593 mov ebp,esp
009DF70C 53A20595 push ecx
009DF710 53A205C8 mov esp,ebp
009DF750 009DF714 53A205CA pop ebp
009DF72C ret
009DF728 53A4CBA3 push eax
009DF724 53A4CBA7 push eax
009DF72C 53A4CBAD add esp,8
009DF750 53A4CBB0 mov esp,ebp
009DF770 009DF754 53A4CBB2 pop ebp
009DF758 53A4CBB3 ret
009DF770 53A68012 add esp,18h
009DF85C 009DF774 53A68015 pop ebp
009DF778 53A68016 ret
009DF790 00A01A02 add esp,18h
009DF794 00A01A0C pop edi
009DF798 00A01A0D pop esi
009DF79C 00A01A0E pop ebx
009DF85C 00A01A0F add esp,0C0h
009DF85C 00A01A17 call __RTC_CheckEsp (0A01113h)
009DF958 009DF860 00A01A1E pop ebp
009DF864 00A01A1F ret
009DF874 00A0294D add esp,10h
009DF878 00A0295D pop edi
009DF87C 00A0295E pop esi
009DF880 00A0295F pop ebx
009DF958 00A02960 add esp,0D8h
009DF958 00A02968 call __RTC_CheckEsp (0A01113h)
009DF958 009DF958 00A0296D mov esp,ebp
009DFA30 009DF95C 00A0296F pop ebp
009DF960 00A02970 ret
009DF964 00A02098 add esp,4
009DF968 00A0209D pop edi
009DF96C 00A0209E pop esi
009DF970 00A0209F pop ebx
009DFA30 00A020A0 add esp,0C0h
009DFA44 009DFA34 00A020AF pop ebp
009DFA38 00A020B0 ret
009DFA44 00A0214E add esp,0Ch
009DFA9C 009DFA48 00A02151 pop ebp
009DFA4C 00A02152 ret
009DFA48 00A01FC2 push ecx
00A01FC3 call _exit (0A012CBh)