gcc在x64体系中如何传递参数,linux,mac,iOS适用
上一篇介绍了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适用的更多相关文章
- vc在x64体系的一般传参数方式
前篇分析过在objc中函数调用传参的一般方式,本篇分析vc在x64体系中的一般传参方式.手头上因为没有64位的vc编译器,只好用windbg看ms自身的函数是怎么样调用的. 首先看两个再熟悉不过的ap ...
- 深入理解python中函数传递参数是值传递还是引用传递
深入理解python中函数传递参数是值传递还是引用传递 目前网络上大部分博客的结论都是这样的: Python不允许程序员选择采用传值还是传 引用.Python参数传递采用的肯定是"传对象引用 ...
- Python中函数传递参数有四种形式
Python中函数传递参数有四种形式 fun1(a,b,c) fun2(a=1,b=2,c=3) fun3(*args) fun4(**kargs) 四种中最常见是前两种,基本上一般点的教程都会涉及, ...
- 关于Delphi中多线程传递参数的简单问题
http://bbs.csdn.net/topics/390513469/ unit uThread; interface uses Classes; type Th = class(TThread) ...
- JavaScript中url 传递参数(特殊字符)解决方法
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码 十六进制值1. + URL 中+号表示空格 %2B2. 空格 UR ...
- vue项目webpack中Npm传递参数配置不同域名接口
项目开发中,前端在配置后端api域名时很困扰,常常出现:本地开发环境: api-dev.demo.com测试环境: api-test.demo.com线上生产环境: api.demo.com, 这次是 ...
- 转载】JQuery中如何传递参数如click(),change()等具体实现
转载地址:http://www.jb51.net/article/36249.htm 有个需求让两个select中option相互转换,这个作业就是给几个按钮添加click()事件接下来为大家介绍下如 ...
- vue.js中路由传递参数
知识点:vue路由传递参数,第二个页面(A.B页面)拿到参数,使用参数 方法一:使用 <router-link :to="{name:'edithospital',params:{hi ...
- JavaScript中url 传递参数(特殊字符)解决方法及转码解码的介绍
有些符号在URL中是不能直接传递的,如果要在URL中传递这些特殊符号,那么就要使用他们的编码了.下表中列出了一些URL特殊符号及编码 十六进制值 1. + URL 中+号表示空格 %2B 2. 空 ...
随机推荐
- 《Java并发编程实战》读书笔记-第3章 对象的共享
可见性 在没有同步的情况下,编译器.处理器以及运行时都可能做指令重排.执行结果可能会出现错误 volatile变量 编译器与运行时不会进行指令重排,不会进行缓存,使用volatile变量要满足以下条件 ...
- Linux本地内核提权漏洞复现(CVE-2019-13272)
Linux本地内核提权漏洞复现(CVE-2019-13272) 一.漏洞描述 当调用PTRACE_TRACEME时,ptrace_link函数将获得对父进程凭据的RCU引用,然后将该指针指向get_c ...
- [NOIP2013提高组]华容道
这道题第一眼看是暴力,然后发现直接暴力会TLE. 把问题转换一下:移动空格到处跑,如果空格跑到指定位置的棋子,交换位置. 这个可以设计一个状态:$[x1][y1][x2][y2]$,表示空格在$(x1 ...
- 如何使用代理IP进行数据抓取,PHP爬虫抓取亚马逊商品数据
什么是代理?什么情况下会用到代理IP? 代理服务器(Proxy Server),其功能就是代用户去取得网络信息,然后返回给用户.形象的说:它是网络信息的中转站.通过代理IP访问目标站,可以隐藏用户的真 ...
- java中的无穷大和无穷小
double型和float型都可以如下表示无穷大和无穷小 import static java.lang.Double.NEGATIVE_INFINITY;import static java.lan ...
- 数据结构(四十二)散列表查找(Hash Table)
一.散列表查找的基础知识 1.散列表查找的定义 散列技术是在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key).查找时,根据这个确定的对应关系找到 ...
- django-HttpResponse,render,redirect
1.导入相应的包 from django.shortcuts import HttpResponse, render, redirect 2.HttpResponse(返回字符串给浏览器) def i ...
- Python中的is和==的区别
Python中的is和==的区别 1. is 是比较内存地址id() a = "YongJie" b = "YongJie" print(id(a)) #233 ...
- 【POJ3208】Apocalypse Someday
Description 666号被认为是神秘的"野兽之数",在所有以启示录为主题的大片中都是一个被广泛使用的数字.但是,这个数字666不能总是在脚本中使用,所以应该使用1666这样 ...
- [2018-03-06] 基于Django的轻量级CMS Mezzanine搭建笔记
一丶什么是Mezzanine? 它是基于django的内容管理平台(),组成简单,可扩展性和定制性强,特别是个小型的个人博客系统.它也提供了类似wordpress的管理页面.博客发布.图片展示等功能, ...