《软件调试》读书笔记二

二、函数返回值
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) ;用专门的浮点指令接受返回值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值