C语言函数入参和返回值是结构体时的汇编分析

原创 2017年08月13日 13:45:12

在C语言程序中,一般不会直接传一个结构体给一个函数,也不会让函数的返回值直接返回一个结构体,这样会拷贝过多影响效率。但是这样也是合法的,有时候也会使用,并且有时候效率也并不会变得太差。

  • C函数传参:参数少或者传入的结构体小只借助寄存器即可,否则借助栈。
  • C函数返回值:如果返回一个比较小的结构体,借助寄存器即可,否则依旧借助栈。按调用约定,当返回值是较大的结构体时,会在caller栈里产生一个临时变量,并将其首地址传给callee,callee返回值会修改此变量做到将返回值返回给caller。

看一个例子, x64的Linux系统下:

#include <stdio.h>

struct Cord {
    int x;
    int y;
};

struct Cord add(struct Cord b)
{
    b.x++;
    b.y++;
    return b;
}

int main()
{
    struct Cord a = {2, 5};
    struct Cord re = add(a);
    printf("re (%d, %d)\n", re.x, re.y);
    return 0;
}

对于上面的代码,我们从汇编角度看一下如何实现结构体做函数入参和返回值的:

(gdb) disass main
Dump of assembler code for function main:
   0x000000000040054d <+0>:     push   %rbp
   0x000000000040054e <+1>:     mov    %rsp,%rbp
   0x0000000000400551 <+4>:     sub    $0x20,%rsp
   0x0000000000400555 <+8>:     movl   $0x2,-0x20(%rbp)
   0x000000000040055c <+15>:    movl   $0x5,-0x1c(%rbp)
   0x0000000000400563 <+22>:    mov    -0x20(%rbp),%rax   //结构体8字节,从首地址拷贝,直接拷贝到 %rax
   0x0000000000400567 <+26>:    mov    %rax,%rdi          //调用约定 %rdi, 可直接把这个8字节的结构体传入
   0x000000000040056a <+29>:    callq  0x40052d <add>     // 打断点 1,看后面分析
   0x000000000040056f <+34>:    mov    %rax,-0x10(%rbp)
   0x0000000000400573 <+38>:    mov    -0xc(%rbp),%edx
   0x0000000000400576 <+41>:    mov    -0x10(%rbp),%eax
   0x0000000000400579 <+44>:    mov    %eax,%esi
   0x000000000040057b <+46>:    mov    $0x400624,%edi
   0x0000000000400580 <+51>:    mov    $0x0,%eax
   0x0000000000400585 <+56>:    callq  0x400410 <printf@plt>
   0x000000000040058a <+61>:    mov    $0x0,%eax   // 断点2
   0x000000000040058f <+66>:    leaveq
   0x0000000000400590 <+67>:    retq
End of assembler dump.
(gdb) disass add
Dump of assembler code for function add:
   0x000000000040052d <+0>:     push   %rbp
   0x000000000040052e <+1>:     mov    %rsp,%rbp
   0x0000000000400531 <+4>:     mov    %rdi,-0x10(%rbp)
   0x0000000000400535 <+8>:     mov    -0x10(%rbp),%eax
   0x0000000000400538 <+11>:    add    $0x1,%eax
   0x000000000040053b <+14>:    mov    %eax,-0x10(%rbp)
   0x000000000040053e <+17>:    mov    -0xc(%rbp),%eax
   0x0000000000400541 <+20>:    add    $0x1,%eax
   0x0000000000400544 <+23>:    mov    %eax,-0xc(%rbp)
   0x0000000000400547 <+26>:    mov    -0x10(%rbp),%rax //返回值 %rax可以直接把这个8字节的结构带出
   0x000000000040054b <+30>:    pop    %rbp             //打断点2,看后面分析
   0x000000000040054c <+31>:    retq
End of assembler dump.
(gdb) r
Starting program: /tmp/a.out
Breakpoint 1, 0x000000000040056a in main ()
(gdb) p $edi //可以看出,这个 %rdi 8字节寄存器正好放的是入参结构体
$3 = 2
(gdb) p $rdi >> 32
$4 = 5
Breakpoint 2, 0x000000000040054b in add ()
(gdb) p $eax
$1 = 3
(gdb) p $rax >> 32
$2 = 6
(gdb)

从上面的例子就很容易看出,C程序是如何用结构体作为入参和返回值的,编译后的汇编指令是没有类型概念的,结构体也就是对一块连续的内存的布局的解释而已,结合x64平台的C calling convention,就很好理解这些内容了。

版权声明:本文为博主原创文章,未经博主允许不得转载。[http://blog.csdn.net/thisinnocence]

结构体、结构体体指针作为函数返回值

函数使用结构体、结构体指针作为返回值分析32位机,gcc编译器使用结构体作为返回值分析反汇编代码可知,当被调用的子函数返回值为结构体的时候,调用函数将分配一段空间用于存放返回的结构体(使用一个结构体变...

函数返回结构体的内幕

函数返回结构体的内幕 在刚接触C语言编程时,无论是前辈还是教科书,都反复告诫我们两件事: ①函数的参数是值传递(意味着在函数中对参数本身的修改无法“传回”); ②不要返回函数体内局部变量的地址,...

C语言结构体(struct)常见使用方法

结构体与函数: 关于传参,首先: void func(int); func(a.b.c); 把结构体中的int成员变量当做和普通int变量一样的东西来使用,是不用脑子就想到的一种方法。 另外两...

uboot配置和启动过程1(主Makefile分析)

转自  http://www.cnblogs.com/zou107/p/5082617.html 说明:文件位置:在uboot的目录下,文件名为:Makefile 从文件的头部开始分析 ...

uboot下ARMv8 lds

#include #include OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64"...

平台调用P-INVOKE完全掌握, 反汇编细解结构体作为返回值

这篇解决上篇那个结构体作为返回值的问题。我们结合反汇编来探索这里面的秘密。如何反汇编? 方法如下:在C++函数内下断点,调试到断点断下,右键菜单,选择"反汇编",反汇编是VS自带功能。  ...
  • lnc2003
  • lnc2003
  • 2014年09月18日 15:46
  • 462

有关结构体指针与函数传参返回值类型的六种方法

#include #include#if 0 //struct_1 在main函数中定义结构体,并实现功能 int main(void) { struct results { ...

gsoap_返回值为结构体数组

  • 2016年07月29日 10:51
  • 1.25MB
  • 下载

结构体变量作为函数的参数和返回值

结构体变量作为函数的参数和返回值 2010-07-28 13:14 准备学习一下OpenCV,可是第一个知识点的语法就没有看懂: typedef struct CvPoint...
  • jinn3
  • jinn3
  • 2012年05月22日 10:58
  • 5016

结构体变量作为函数的参数和返回值 .

http://blog.csdn.net/jinn3/article/details/7590082   结构体变量作为函数的参数和返回值 2010-07-28 13:14 ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C语言函数入参和返回值是结构体时的汇编分析
举报原因:
原因补充:

(最多只允许输入30个字)