上一篇介绍了vc(windows)平台在x64体系当中,c函数的传参方式。本篇将要介绍gcc(类linux,mac)平台在x64中,c函数是如何传参的。
为节约时间和篇幅,首先来定义一个有十个参数的函数,参数类型包罗了内嵌类型:

int foo(char c, short s, int i, long l, long long ll, char* p, // 前6个参数,注意我的划分和参数类型
void** pp, float f, void* x, double d);

反汇编调用

foo('c', , , , , (char*)0x4, (void**)0x5, .f, (void*), .f);
0x000000000040067b <+>: movsd 0x2d5(%rip),%xmm0 # 0x400958 <__dso_handle+> double d = .f
0x0000000000400683 <+>: movq $0x6,0x8(%rsp) # (void*)
0x000000000040068c <+>: movq $0x5,(%rsp) # (void**) 0x5
0x0000000000400694 <+>: movapd %xmm0,%xmm1
0x0000000000400698 <+>: movss 0x2c0(%rip),%xmm0 # 0x400960 <__dso_handle+> float f = .f
0x00000000004006a0 <+>: mov $0x4,%r9d # (char*) 0x4
0x00000000004006a6 <+>: mov $0x3,%r8d # (long long)
0x00000000004006ac <+>: mov $0x2,%ecx # (long)
0x00000000004006b1 <+>: mov $0x1,%edx # (int)
0x00000000004006b6 <+>: mov $0x0,%esi # (short)
0x00000000004006bb <+>: mov $0x63,%edi # (char) 'c'
0x00000000004006c0 <+>: callq 0x4005c4 <_Z3foocsilxPcPPvfS0_d>

可以看到数据类型分两类,浮点和非浮点型。我传的实参数也是按这两类划分递增的。
非浮点参数分别是 'c', 0, 1, 2, 3, (char*)0x4, (void**)0x5, (void*)6。先将前6个优先按顺序按排到rdi,rsi,rdx,rcx,r8和r9。剩下(void**)5,(void*)6。
浮点参数分别是 1.f, 2.f。 按顺序安排到xmm0,xmm1。
最后将两种类型不能放入寄存器的剩余参数,由右向左依次入栈。

下面再定义一个超级无敌多参数的函数,用尽全部传参寄存器,印证我上面的分析。

int foo2(char c, short s, int i, long l, long long ll, char* p,
void** pp, float f, void* x, double d, // 至此和上面foo定义一样
float xmm2, float xmm3, float xmm4, float xmm5, float xmm6, float xmm7, // 追加6个浮点型用尽余下的寄存器
float xmmUnknow);

反汇编调用

foo2('c', , , , , (char*), (void**), .f, (void*), .f, .f, .f, .f, .f, .f, .f, (float)i);
0x00000000004006c5 <+>: cvtsi2ssl -0xc(%rbp),%xmm0
0x00000000004006ca <+>: movsd 0x286(%rip),%xmm1 # 0x400958 <__dso_handle+>
0x00000000004006d2 <+>: movss %xmm0,0x10(%rsp) # *** 最尾的浮点型只被放入堆栈中
0x00000000004006d8 <+>: movq $0x6,0x8(%rsp) # *** 和foo一样
0x00000000004006e1 <+>: movq $0x5,(%rsp) # *** 和foo一样
0x00000000004006e9 <+>: movss 0x273(%rip),%xmm7 # 0x400964 <__dso_handle+>
0x00000000004006f1 <+>: movss 0x26f(%rip),%xmm6 # 0x400968 <__dso_handle+>
0x00000000004006f9 <+>: movss 0x26b(%rip),%xmm5 # 0x40096c <__dso_handle+>
0x0000000000400701 <+>: movss 0x267(%rip),%xmm4 # 0x400970 <__dso_handle+>
0x0000000000400709 <+>: movss 0x263(%rip),%xmm3 # 0x400974 <__dso_handle+>
0x0000000000400711 <+>: movss 0x25f(%rip),%xmm2 # 0x400978 <__dso_handle+>
0x0000000000400719 <+>: movss 0x23f(%rip),%xmm0 # 0x400960 <__dso_handle+>
0x0000000000400721 <+>: mov $0x4,%r9d
0x0000000000400727 <+>: mov $0x3,%r8d
0x000000000040072d <+>: mov $0x2,%ecx
0x0000000000400732 <+>: mov $0x1,%edx
0x0000000000400737 <+>: mov $0x0,%esi
0x000000000040073c <+>: mov $0x63,%edi
0x0000000000400741 <+>: callq 0x4005f5 <_Z4foo2csilxPcPPvfS0_dfffffff>

非浮点参数分别是 'c', 0, 1, 2, 3, (char*)0x4, (void**)0x5, (void*)6。先将前6个优先按顺序按排到rdi,rsi,rdx,rcx,r8和r9。剩下(void**)5,(void*)6。
浮点参数分别是 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, (float)i。 按顺序安排到xmm0-xmm7,剩下(float)i。
最后将两种类型不能放入寄存器的剩余参数,分别是(void**)5,(void*)6,(float)i,由右向左依次入栈。

最后我选取一个特例来作为本篇结束,gcc如何传递临时对象。

struct point {float x,y;};
struct obj
{
int i;
float f[];
void foo(point pt)
{
f[] += pt.x;
f[] *= pt.y;
}
};

反汇编调用

obj j;
point pt;
j.foo(pt);
0x000000000040078d <+>: movq -0x20(%rbp),%xmm0
0x0000000000400792 <+>: lea -0x50(%rbp),%rax
0x0000000000400796 <+>: mov %rax,%rdi
0x0000000000400799 <+>: callq 0x400814 <_ZN3obj3fooE5point>

rdi是什么大家都清楚,剩下另一个参数载体就是xmm0了。再看一看函数定义,参数是个临时对象,再看对象定义,point结构体是两个单精浮点,共占64位。而xmm寄存器可以存放4个单精浮点数据。
下面再看成员函数foo的反汇编刚好印证了。

Dump of assembler code for function _ZN3obj3fooE5point:
0x0000000000400814 <+>: push %rbp
0x0000000000400815 <+>: mov %rsp,%rbp
0x0000000000400818 <+>: mov %rdi,-0x8(%rbp)
0x000000000040081c <+>: movq %xmm0,-0x10(%rbp) # 低64位存放了临时对象
0x0000000000400821 <+>: mov -0x8(%rbp),%rax
0x0000000000400825 <+>: movss 0xc(%rax),%xmm1
0x000000000040082a <+>: movss -0x10(%rbp),%xmm0 # pt.x
0x000000000040082f <+>: addss %xmm1,%xmm0
0x0000000000400833 <+>: mov -0x8(%rbp),%rax
0x0000000000400837 <+>: movss %xmm0,0xc(%rax)
0x000000000040083c <+>: mov -0x8(%rbp),%rax
0x0000000000400840 <+>: movss 0x10(%rax),%xmm1
0x0000000000400845 <+>: movss -0xc(%rbp),%xmm0 # pt.y
0x000000000040084a <+>: mulss %xmm1,%xmm0
0x000000000040084e <+>: mov -0x8(%rbp),%rax
0x0000000000400852 <+>: movss %xmm0,0x10(%rax)
0x0000000000400857 <+>: leaveq
0x0000000000400858 <+>: retq
End of assembler dump.

到此为止,我已经用了三篇来介绍x64体系三种常用平台在c/c++/objc编程的传参方式。
上篇,通过lldb调试介绍mac平台下x64传参;
中篇,通过windbg调试介绍windows平台下x64传参;
下篇,通过gdb调试介绍gcc(类linux)平台下x64传参,本篇对于mac,ios同样适用。

预告:后面将要进入反汇编分析objc程序。

gcc在x64体系中如何传递参数,linux,mac,iOS适用的更多相关文章

  1. vc在x64体系的一般传参数方式

    前篇分析过在objc中函数调用传参的一般方式,本篇分析vc在x64体系中的一般传参方式.手头上因为没有64位的vc编译器,只好用windbg看ms自身的函数是怎么样调用的. 首先看两个再熟悉不过的ap ...

  2. 深入理解python中函数传递参数是值传递还是引用传递

    深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...

  3. Python中函数传递参数有四种形式

    Python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...

  4. 关于Delphi中多线程传递参数的简单问题

    http://bbs.csdn.net/topics/390513469/ unit uThread; interface uses Classes; type Th = class(TThread) ...

  5. JavaScript中url 传递参数(特殊字符)解决方法

    有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码 十六进制值1. + URL 中+号表示空格 %2B2. 空格 UR ...

  6. vue项目webpack中Npm传递参数配置不同域名接口

    项目开发中,前端在配置后端api域名时很困扰,常常出现:本地开发环境: api-dev.demo.com测试环境: api-test.demo.com线上生产环境: api.demo.com, 这次是 ...

  7. 转载】JQuery中如何传递参数如click(),change()等具体实现

    转载地址:http://www.jb51.net/article/36249.htm 有个需求让两个select中option相互转换,这个作业就是给几个按钮添加click()事件接下来为大家介绍下如 ...

  8. vue.js中路由传递参数

    知识点:vue路由传递参数,第二个页面(A.B页面)拿到参数,使用参数 方法一:使用 <router-link :to="{name:'edithospital',params:{hi ...

  9. JavaScript中url 传递参数(特殊字符)解决方法及转码解码的介绍

    有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码   十六进制值 1. + URL 中+号表示空格 %2B 2. 空 ...

随机推荐

  1. Kafka源码研究--Comsumer获取partition下标

    背景 由于项目上Flink在设置parallel多于1的情况下,job没法正确地获取watermark,所以周末来研究一下一部分,大概已经锁定了原因: 虽然我们的topic只设置了1的partitio ...

  2. Web登录中的信心安全问题

    1. 一个简单的HTML例子看看用户信息安全 标准的HTML语法中,支持在form表单中使用<input></input>标签来创建一个HTTP提交的属性,现代的WEB登录中, ...

  3. fenby C语言P24

    #include <stdio.h> int main(){ char cArr[]={'I','L','O','V','E','C'}; char sArr[]="ilovec ...

  4. Maven optional关键字透彻图解

    写在前面 本来想写一篇「如何自定义Spring Boot Starter」,但是为了更好理解 Starter 的一些设计理念和其中的关键点,所以提前将一些细节内容单独提取出来讲解说明 在 Maven ...

  5. fiddler的过滤

    1.User Fiters启用 2.Action Action:Run Filterset now是否运行,Load Filterset加载,Save Filterset保存: 3.Hosts过滤 Z ...

  6. Go语言入门:Hello world

    本文是「vangoleo的Go语言学习笔记」系列文章之一. 官网: http://www.vangoleo.com/go/go-hello-world/ 在上一篇文章你好,Go语言中,我们对Go语言的 ...

  7. 在VMware下进行的Windows2008操作系统虚拟机的安装

    一.VMware虚拟机的安装 首先你需要拥有一款软件VMware,这是一款虚拟机安装软件.Vmware比起Vbox收费较贵,占用资源大,但是拥有大量的资源以及拥有克隆技术,适合新手学习使用,较为专业. ...

  8. 转:NFS原理详解

    原文:http://atong.blog.51cto.com/2393905/1343950 一.NFS介绍 1)什么是NFS 它的主要功能是通过网络让不同的机器系统之间可以彼此共享文件和目录.NFS ...

  9. Unity2-投影方式

  10. [考试反思]1109csp-s模拟测试106:撞词

    (撞哈希了用了模拟测试28的词,所以这次就叫撞词吧) 蓝色的0... 蓝色的0... 都该联赛了还能CE呢... 考试结束前15分钟左右,期望得分300 然后对拍发现T2伪了写了一个能拿90分的垃圾随 ...