二、函数返回值
1.如果返回值是EAX寄存器能够容纳的整数、字符和指针(4字节或小于4字节),那么返回值存在EAX中源代码:
/**
@brief: 测试函数返回值为int型的情况下,存储返回值的方法
@environment: VS2008
*/
#include <iostream>
int fun_int(void)
{
int a;
return a;
}
int main()
{
std::cout<<fun_int();
return 0;
}
部分汇编代码:
std::cout<<fun_int();
004115DE call fun_int (41103Ch)
004115E3 mov esi,esp
004115E5 push eax ;该eax中存放的就是fun_int()的返回值
004115E6 mov ecx,dword ptr [__imp_std::cout (419290h)]
004115EC call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (419294h)]
004115F2 cmp esi,esp
004115F4 call @ILT+330(__RTC_CheckEsp) (41114Fh)
2.如果返回值超过4字节而小于8字节的整数,那么使用EDX存放超过4字节以上的部分。
源代码:
/**
@brief: 测试函数返回值为long long型的情况下,存储返回值的方法
@environment: VS2008
*/
#include <iostream>
long fun_int(void)
{
long long a;
return a;
}
int main()
{
std::cout<<fun_int();
return 0;
}
部分汇编代码:
std::cout<<fun_long();
00411C2E call fun_long (411203h)
00411C33 mov esi,esp
00411C35 push edx ;该edx存放返回值的高4byte
00411C36 push eax ;该eax存放返回值的低4byte
00411C37 mov ecx,dword ptr [__imp_std::cout (419290h)]
00411C3D call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (4192A8h)]
00411C43 cmp esi,esp
00411C45 call @ILT+330(__RTC_CheckEsp) (41114Fh)
3.当返回值是一个结构体或类是,被调用函数会把返回值的地址当作一个隐含返回参数,调用函数中会预留若干栈内存(大小由返回值的大小而定),存储这个返回值。并且该将其地址赋值给EAX。
源代码:
/**
@brief: 测试函数返回值为一个A型类的情况下,存储返回值的方法
@environment: VS2008
*/
#include <iostream>
#include <iostream>
class A
{
public:
A(){ a = 0x1234;};
~A(){};
private:
int a;
int b;
int c;
};
A fun_A()
{
A a;
return a;
}
int main()
{
A m = fun_A();
return 0;
}
部分汇编代码:
;main函数中
33: A m = fun_A();
0041162E lea eax,[a] ;把m的地址赋值给eax
00411631 push eax ;把m的地址压栈
00411632 call fun_A (411203h)
00411637 add esp,4
;fun_A函数中
16: A a;
004137F7 lea ecx,[ebp-1Ch]
004137FA call A::A (4110EBh)
17: return a;
004137FF mov eax,dword ptr [ebp+8] ;把第一个参数(隐含参数)的值(即m的地址)放到eax
00413802 mov ecx,dword ptr [ebp-1Ch] ;把a的第一个dword字节内容放到ecx
00413805 mov dword ptr [eax],ecx ;把a的第一个dword字节内容放到m的第一个dword字节空间里
00413807 mov edx,dword ptr [ebp-18h] ;把a的第二个dword字节内容放到edx
0041380A mov dword ptr [eax+4],edx ;把a的第二个dword字节内容放到m的第二个dword字节空间里
0041380D mov ecx,dword ptr [ebp-14h] ;......
00413810 mov dword ptr [eax+8],ecx ;......
00413813 mov dword ptr [ebp-4],0
0041381A mov edx,dword ptr [ebp-0E8h]
00413820 or edx,1
00413823 mov dword ptr [ebp-0E8h],edx
00413829 lea ecx,[ebp-1Ch]
0041382C call A::~A (411104h) ;函数退出了,要把fun_A函数中的a析构,因为它是局部变量
00413831 mov eax,dword ptr [ebp+8] ;把隐含参数里的值赋值给eax
如果把main函数修改如下:
int main()
{
fun_A();
return 0;
}
main函数的汇编代码将会变成:
33: fun_A();
0041162E lea eax,[ebp-0D0h]
00411634 push eax
00411635 call fun_A (411203h)
0041163A add esp,4
0041163D lea ecx,[ebp-0D0h]
00411643 call A::~A (411104h)
如上,main函数还是会在栈中分配一个空间用来存储fun_A()的返回值。
4.浮点类型的返回值和参数通常通过专门的浮点指令使用栈来传递
源代码:
float fun_float(void)
{
float d;
return d;
}
int main()
{
fun_float();
return 0;
}
部分汇编代码:
;fun_float()
34: float d;
35: return d;
00411655 cmp byte ptr [ebp-0D1h],0
0041165C jne fun_float+3Bh (41166Bh)
0041165E push offset (411682h)
00411663 call @ILT+180(__RTC_UninitUse) (4110B9h)
00411668 add esp,4
0041166B fld dword ptr [d] ;用专门的浮点指令传递返回值
;main()
39: fun_float();
004116BE call fun_float (411046h)
004116C3 fstp st(0) ;用专门的浮点指令接受返回值