在傳統C中,函數的參數和返回值都是以復制傳送的.
看這段代碼
struct Big
{
?char buf[1024];
}B,B2;
Big bigfun(Big b)
{
?return b;
}
int main()
{
?B2 = bigfun(B);
?return 0;
}
其中B2 = bigfun(B)要被由以下幾個過程組成
1.B要以傳值方式傳送到函數的參數表中中
2.如果返回值size很小,可以返回eax中
? 但是在這里,返回值size很大,要建立臨時變量
? 然后將臨時變量的地址入棧,此時非常象函數參數入棧
? 返回eax指向這個臨時變量
3.將這個臨時變量拷貝到B2上
B2 = bigfun(B);
展開為
;構造臨時堆棧
004017AE? sub???????? esp,400h?;堆棧大小1024(400h)
;由于函數調用是傳值方式,所以將B復制到bigfun中的參數中
;相當于將B push到堆棧中
004017B4? mov???????? ecx,100h?;傳送大小1024(100h*4)
004017B9? mov???????? esi,offset B (421138h) ;源是B首地址
004017BE? mov???????? edi,esp?;目的為bigfun中的參數地址
004017C0? rep movs??? dword ptr [edi],dword ptr [esi] ;復制
;調用函數,此時push eax中的eax并非是函數參數壓棧,而是將一個臨時對象的指針壓棧
004017C2? lea???????? eax,[ebp-4C4h]
004017C8? push??????? eax?;將堆棧中一個臨時對象地址壓堆棧
004017C9? call??????? bigfun (401750h) ;調用函數
004017CE? add???????? esp,404h?;清除堆棧(400h+4),堆棧跳過函數參數表和函數返回地址
;臨時對象為返回變量,eax指向這個地址
;將這個臨時對象復制另一個臨時對象上
004017D4? mov???????? ecx,100h?;傳送大小1024(100h*4)
004017D9? mov???????? esi,eax?;目的上面臨時對象的地址
004017DB? lea???????? edi,[ebp-8CCh] ;堆棧中第三個臨時對象
004017E1? rep movs??? dword ptr [edi],dword ptr [esi] ;復制
;將第二個臨時對象復制到B2上
004017E3? mov???????? ecx,100h?;傳送大小1024(100h*4)
004017E8? lea???????? esi,[ebp-8CCh] ;堆棧中第三個臨時對象
004017EE? mov???????? edi,offset B2 (421538h) ;目的為首地址
004017F3? rep movs??? dword ptr [edi],dword ptr [esi] ;傳送
Big bigfun(Big b) {
展開為
;初始化堆棧,以ebp為基準,ebp+4指向為return address
;ebp+8為剛才壓入堆棧的上層函數中的臨時對象的地址
;ebp-4為臨時堆棧中第一個局部變量
00401750? push??????? ebp?
00401751? mov???????? ebp,esp?;ebp此時指向以前保存bp
00401753? sub???????? esp,0C0h?;建立臨時堆棧,大小0C0h
00401759? push??????? ebx?
0040175A? push??????? esi?
0040175B? push??????? edi
;初始化堆棧全部為0xcc
0040175C? lea???????? edi,[ebp-0C0h]
00401762? mov???????? ecx,30h
00401767? mov???????? eax,0CCCCCCCCh
0040176C? rep stos??? dword ptr [edi]
?return b;
;復制b到那個臨時對象上
0040176E? mov???????? ecx,100h
00401773? lea???????? esi,[b]
00401776? mov???????? edi,dword ptr [ebp+8] ;ebp+8為參數表中的參數地址
00401779? rep movs??? dword ptr [edi],dword ptr [esi]
;返回那個臨時變量的地址
0040177B? mov???????? eax,dword ptr [ebp+8]
}