打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
函数返回值如何传递

一般情况下,函数返回值是通过eax进行传递的,但是eax只能存储4个字节的信息,对于那些返回值大于4个字节的函数,返回值是如何传递的呢?

假设返回值大小为M字节

1. M <= 4字节,放入eax返回

2. 4 < M <=8,把eax,edx联合起来,其中,edx存储高位,eax存储低位

3. M > 8,如何传递呢?

 

测试代码:

//test.cpp

  1. struct big_thing  
  2. {  
  3.     char str[64];  
  4. };  
  5.   
  6. big_thing test()  
  7. {  
  8.     big_thing big;  
  9.     big.str[1] = 'c';  
  10.   
  11.     return big;  
  12. }  
  13.   
  14. int main()  
  15. {  
  16.     big_thing n = test();  
  17.   
  18.     return 0;  
  19. }  

 

如上,test()函数的返回值大小为64字节,那它是如何将这个大小的返回值传递给函数调用者的呢?

 

g++ -S test.cpp

 

查看汇编代码,如下:

  1.     .file   "test1.cpp"  
  2.     .text  
  3.     .align 2  
  4. .globl _Z4testv  
  5.     .type   _Z4testv, @function  
  6. _Z4testv:  
  7. .LFB2:  
  8.     pushl   %ebp  
  9. .LCFI0:  
  10.     movl    %esp, %ebp  
  11. .LCFI1:  
  12.     subl    $64, %esp  
  13. .LCFI2:  
  14.     movl    8(%ebp), %eax  
  15.     movb    $99, 1(%eax)  
  16.     leave  
  17.     ret $4  
  18. .LFE2:  
  19.     .size   _Z4testv, .-_Z4testv  
  20. .globl __gxx_personality_v0  
  21.     .align 2  
  22. .globl main  
  23.     .type   main, @function  
  24. main:  
  25. .LFB3:  
  26.     leal    4(%esp), %ecx  
  27. .LCFI3:  
  28.     andl    $-16, %esp  
  29.     pushl   -4(%ecx)  
  30. .LCFI4:  
  31.     pushl   %ebp  
  32. .LCFI5:  
  33.     movl    %esp, %ebp  
  34. .LCFI6:  
  35.     pushl   %ecx  
  36. .LCFI7:  
  37.     subl    $68, %esp  
  38. .LCFI8:  
  39.     leal    -68(%ebp), %eax  
  40.     movl    %eax, (%esp)  
  41.     call    _Z4testv  
  42.     subl    $4, %esp  
  43.     movl    $0, %eax  
  44.     movl    -4(%ebp), %ecx  
  45.     leave  
  46.     leal    -4(%ecx), %esp  
  47.     ret   
  48. .LFE3:  
  49.     .size   main, .-main  
  50.     .ident  "GCC: (GNU) 4.2.1"  
  51.     .section    .note.GNU-stack,"",@progbits  

 

其中:符号_Z4testv,用c++filt查看可知为test()。

先看看main函数的汇编代码:

pushl   %ecx         //将ecx的值压栈

subl    $68, %esp  //栈中分配68字节的空间,可以将这个空间看成两部分,一部分64字节是为变量n分配的空间,另一部分暂不考虑

 

此时main函数栈的情况如下:

leal    -68(%ebp), %eax        //将%ebp - 68字节处的值传到eax中,也就是4(%esp)处,也就是变量n的起始地址

movl    %eax, (%esp)            //将eax值,也就是变量n的起始地址,放入栈的%esp处,也就是上面分配的68字节空间的第二部分

call    _Z4testv                   //调用函数 test()

 

看看函数test的汇编代码:

subl    $64, %esp           //为变量big分配64字节的空间

movl    8(%ebp), %eax        //将%ebp + 8 字节处的值,也就是main函数中分配的68字节的第二部分的值,

                                                 也就是main中变量n的起始地址的值,存入eax中

movb    $99, 1(%eax)          //将99也就是'c'的ascii值放入%eax + 1字节处,而刚才说了eax中的值是变量n的其实地址,

                                                  所以这一步就相当于直接改变了变量n的值,从而实现了函数test的返回值到调用函数的传递。

 

 

如果将代码test.cpp中的:

big_thing n = test();

改成:

test();

汇编代码有什么变化,在main函数的栈中还会为test函数的返回值准备空间吗,但是现在main函数现在并不想接受test的返回值呀~

 

比较一下汇编代码你就知道啦,呵呵

(汇编代码没有任何变化,编译器还是在main的栈中为其分配了空间)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
对gcc编译汇编码解析
C语言过程(函数)的机器级表示
通过内核源码看函数调用之前世今生
C语言中的数组越界
ASM调试
xcode反汇编调试iOS模拟器程序
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服