linux下gcc向主函数传递参数,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', 0, 1, 2, 3, (char*)0x4, (void**)0x5, 1.f, (void*)6, 2.f);0x000000000040067b : movsd 0x2d5(%rip),%xmm0 # 0x400958 <__dso_handle> double d = 2.f

0x0000000000400683 : movq $0x6,0x8(%rsp) # (void*) 60x000000000040068c : movq $0x5,(%rsp) # (void**) 0x5

0x0000000000400694 : movapd %xmm0,%xmm1

0x0000000000400698 : movss 0x2c0(%rip),%xmm0 # 0x400960 <__dso_handle> float f = 1.f

0x00000000004006a0 : mov$0x4,%r9d # (char*) 0x4

0x00000000004006a6 : mov $0x3,%r8d # (long long) 30x00000000004006ac : mov $0x2,%ecx # (long) 20x00000000004006b1 : mov $0x1,%edx # (int) 10x00000000004006b6 : mov $0x0,%esi # (short) 00x00000000004006bb : 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', 0, 1, 2, 3, (char*)4, (void**)5, 1.f, (void*)6, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.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 {floatx,y;};structobj

{inti;float f[8];voidfoo(point pt)

{

f[2] +=pt.x;

f[3] *=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程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值