主要談談vc裡面函數調用彙編成彙編代碼的情形,首先針對之前的一個小程式,說說vc編譯器的最佳化。
例子程式:
#include <iostream>
using namespace std;
int main(int argc, char* argv[])
{
int i=10;
int a = i;
cout << "i=" << a << endl;
//下面彙編語句的作用就是改變記憶體中i的值,但是又不讓編譯器知道
__asm
{
mov dword ptr [ebp-4], 20h
}
int b = i;
cout << "i=" << b << endl;
return 0;
}
這段代碼很簡潔,但彙編代碼可不簡潔,首先看看release模式下的彙編代碼概況:
……
; 14 :
; 15 : //下面彙編語句的作用就是改變記憶體中i的值,但是又不讓編譯器知道
; 16 : __asm
; 17 : {
; 18 : mov dword ptr [ebp-4], 20h
mov DWORD PTR [ebp-4], 32 ; 00000020H
; 19 : }
; 20 : int b = i;
; 21 : cout << "i=" << b << endl;
push 10 ; 0000000aH
push OFFSET FLAT:??_C@_02HDOK@i?$DN?$AA@ ; `string’
push OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::cout
call ??6std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@0@AAV10@PBD@Z ; std::operator<<
add esp, 8
mov ecx, eax
call ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
mov esi, eax
push 10 ; 0000000aH
mov ecx, esi
call ?put@?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV12@D@Z ; std::basic_ostream<char,std::char_traits<char> >::put
mov ecx, DWORD PTR [esi]
xor edi, edi
……
調用cout前面,直接一個push 10,這是函數調用前壓參數的過程,壓了個常數在裡面,呵呵,其實i已經被修改了,但是編譯器不知道,以為i仍然是10,顧做了最佳化,考試,大提示壓參壓了常量在裡面。
再看看debug模式下的彙編代碼情況:
16: __asm
17: {
18: mov dword ptr [ebp-4], 20h
004017DE mov dword ptr [ebp-4],20h
19: }
20: int b = i;
004017E5 mov edx,dword ptr [ebp-4]
004017E8 mov dword ptr [ebp-0Ch],edx
21: cout << "i=" << b << endl;
004017EB push offset @ILT+195(std::endl) (004010c8)
004017F0 mov eax,dword ptr [ebp-0Ch]
004017F3 push eax
004017F4 push offset string "i=" (0046c01c)
004017F9 push offset std::cout (00477a10)
004017FE call @ILT+640(std::operator<<) (00401285)
00401803 add esp,8
00401806 mov ecx,eax
b = i,賦值這句成了從i的地址去取值送往b了,
mov edx,dword ptr [ebp-4]
mov dword ptr [ebp-0Ch],edx
注意release版本是沒有這兩句的,所以現在b取值就是肯定正確的了,後面壓參的時候,也把b地址指向的值壓入了堆棧,呵呵,這也是之前說的為什麼兩個版本下運行結果不同的原因。
把這個程式稍加修改,開始我們下面的函數調用彙編淺析:
#include <iostream>
using namespace std;
int ChangNum(int, int);
int main(int argc, char* argv[])
{
int i=10;
int a = i;
cout << "i=" << a << endl;
//下面彙編語句的作用就是改變記憶體中i的值,但是又不讓編譯器知道
__asm
{
mov dword ptr [ebp-4], 20h
}
int b = i;
cout << "i=" << b << endl;
ChangNum(50, 100);
return 0;
}
int ChangNum(int nParam, int nW)
{
int i = 10;
int a = i;
cout << "i=" << a << endl;
__asm
{
mov dword ptr [ebp - 4], 20h
mov dword ptr [ebp + 12], 0h
}
int b = i;
cout << "i=" << b << endl;
return 0;
}