上一篇介绍了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. CVE-2016-5159 利用脏牛漏洞Linux提权复现

    当前路径: /var/www 磁盘列表: / 系统信息: Linux zico 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 ...

  2. 6.Linux文件属性及软硬链接

    1.文件属性 使用ll -h 查看的详细信息,每一列都是干什么的 第一列第一个字符 表示文件类型---> rw-r--r-- 文件权限 1 这个文件被链接次数 root 文件的拥有者(用户) r ...

  3. 2019.10.26 CSP%您赛第三场

    \(CSP\)凉心模拟^_^ --题源\(lqx.lhc\)等各位蒟蒻 题目名称 比赛 传递消息 开关灯 源文件名 \(competition.cpp\) \(message.cpp\) \(ligh ...

  4. 卡特兰(Catalan)数入门详解

    也许更好的阅读体验 基本概念 介绍 学卡特兰数我觉得可能比组合数要难一点,因为组合数可以很明确的告诉你那个公式是在干什么,而卡特兰数却像是在用大量例子来解释什么时卡特兰数 这里,我对卡特兰数做一点自己 ...

  5. Spring Cloud - Eureka /actuator/info 如何显示信息

    在pom.xml中添加 <!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot ...

  6. Java IO_002.InputStream与OutputStream--字节流对数据的操作(读取与写入)

    Java IO之FileInputStream与FileOutputStream对象常用操作 涉及到文件(非文件夹)内容的操作,除了要用到File(见之前文章),另外就必须用到输入流或输出流. 输入流 ...

  7. 设计模式(八)Abstract Factory模式

    抽象工厂的工作是将“抽象零件”组装为“抽象产品”.在抽象工厂模式中将会出现抽象工厂,它会将抽象零件组装为抽象产品.也就是说,我们并不关心零件的具体实现,而是只关心接口.我们仅适用该接口将零件组装起来成 ...

  8. 选择器, ,>,+,~

    一.后代选择器 选取指定元素的后代元素 与子元素选择器相比,后代选择器选取的不一定是直接后代(儿子),而是作用于所有后代元素(儿子.孙子.重孙…)都可以. 二.(>)子元素选择器 选取某个元素的 ...

  9. 过滤器、拦截器和AOP的分析与对比

    目录 一.过滤器(Filter) 1.1 简介 1.2 应用场景 1.3 源码分析 二.拦截器(Interceptor) 2.1 简介 2.2 应用场景 2.2 源码分析 三.面向切面编程(AOP) ...

  10. 第二十九章 System V共享内存

    共享内存数据结构 共享内存函数 shmget int shmget(key_t key, size_t size, int shmflg); 功能: 用于创建共享内存 参数: key : 这个共享内存 ...