Gcc amd64中的传递参数如何?
我想知道在amd64上调用C中的libc函数时,参数是如何传递的Gcc amd64中的传递参数如何?,gcc,x86-64,abi,Gcc,X86 64,Abi,我想知道在amd64上调用C中的libc函数时,参数是如何传递的 例如,如果我调用sqrt(double),参数是通过堆栈还是通过寄存器传递的?让我们编写一个示例用例(test.c): 然后检查导入的符号: readelf -Wa a.out |grep sqrt 4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sqrt@GLIBC_2.2.5 (3) 63: 0000000000000000 0 FUNC
例如,如果我调用
sqrt(double)
,参数是通过堆栈还是通过寄存器传递的?让我们编写一个示例用例(test.c):
然后检查导入的符号:
readelf -Wa a.out |grep sqrt
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sqrt@GLIBC_2.2.5 (3)
63: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sqrt@@GLIBC_2.2.5
分解对象:
objdump -d a.out
0000000000400582 <main>:
400582: 55 push %rbp
400583: 48 89 e5 mov %rsp,%rbp
400586: 48 83 ec 10 sub $0x10,%rsp
40058a: f2 0f 10 05 26 01 00 movsd 0x126(%rip),%xmm0
400591: 00
400592: e8 bd ff ff ff callq 400554 <foo>
400597: 66 0f 28 c8 movapd %xmm0,%xmm1
40059b: f2 0f 51 c1 sqrtsd %xmm1,%xmm0
40059f: 66 0f 2e c0 ucomisd %xmm0,%xmm0
4005a3: 7a 06 jp 4005ab <main+0x29>
4005a5: 66 0f 2e c0 ucomisd %xmm0,%xmm0
4005a9: 74 09 je 4005b4 <main+0x32>
4005ab: 66 0f 28 c1 movapd %xmm1,%xmm0
4005af: e8 ac fe ff ff callq 400460 <sqrt@plt>
4005b4: f2 0f 11 45 f8 movsd %xmm0,-0x8(%rbp)
4005b9: b8 00 00 00 00 mov $0x0,%eax
4005be: c9 leaveq
4005bf: c3 retq
objdump-d a.out
0000000000400582 :
400582:55%按需付费
400583:48 89 e5 mov%rsp,%rbp
400586:48 83欧共体10分$0x10,%rsp
40058a:F20f 10 05 26 01 00 movsd 0x126(%rip),%xmm0
400591: 00
400592:e8 bd ff ff callq 400554
400597:66 0f 28 c8 movapd%xmm0,%xmm1
40059b:F20F 51 c1 sqrtsd%xmm1,%xmm0
40059f:66 0f 2e c0 ucomisd%xmm0,%xmm0
4005a3:7a 06 jp 4005ab
4005a5:66 0f 2e c0 ucomisd%xmm0,%xmm0
4005a9:74 09 je 4005b4
4005ab:66 0f 28 c1 movapd%xmm1,%xmm0
4005af:e8 ac fe ff ff callq 400460
4005b4:f2 0f 11 45 f8 movsd%xmm0,-0x8(%rbp)
4005b9:b8 00 mov$0x0,%eax
4005be:c9-Q
4005bf:c3 retq
因此,您可以看到sqrt的参数是通过%xmm0寄存器传递的。让我们编写一个示例用例(test.c): 然后检查导入的符号:
readelf -Wa a.out |grep sqrt
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sqrt@GLIBC_2.2.5 (3)
63: 0000000000000000 0 FUNC GLOBAL DEFAULT UND sqrt@@GLIBC_2.2.5
分解对象:
objdump -d a.out
0000000000400582 <main>:
400582: 55 push %rbp
400583: 48 89 e5 mov %rsp,%rbp
400586: 48 83 ec 10 sub $0x10,%rsp
40058a: f2 0f 10 05 26 01 00 movsd 0x126(%rip),%xmm0
400591: 00
400592: e8 bd ff ff ff callq 400554 <foo>
400597: 66 0f 28 c8 movapd %xmm0,%xmm1
40059b: f2 0f 51 c1 sqrtsd %xmm1,%xmm0
40059f: 66 0f 2e c0 ucomisd %xmm0,%xmm0
4005a3: 7a 06 jp 4005ab <main+0x29>
4005a5: 66 0f 2e c0 ucomisd %xmm0,%xmm0
4005a9: 74 09 je 4005b4 <main+0x32>
4005ab: 66 0f 28 c1 movapd %xmm1,%xmm0
4005af: e8 ac fe ff ff callq 400460 <sqrt@plt>
4005b4: f2 0f 11 45 f8 movsd %xmm0,-0x8(%rbp)
4005b9: b8 00 00 00 00 mov $0x0,%eax
4005be: c9 leaveq
4005bf: c3 retq
objdump-d a.out
0000000000400582 :
400582:55%按需付费
400583:48 89 e5 mov%rsp,%rbp
400586:48 83欧共体10分$0x10,%rsp
40058a:F20f 10 05 26 01 00 movsd 0x126(%rip),%xmm0
400591: 00
400592:e8 bd ff ff callq 400554
400597:66 0f 28 c8 movapd%xmm0,%xmm1
40059b:F20F 51 c1 sqrtsd%xmm1,%xmm0
40059f:66 0f 2e c0 ucomisd%xmm0,%xmm0
4005a3:7a 06 jp 4005ab
4005a5:66 0f 2e c0 ucomisd%xmm0,%xmm0
4005a9:74 09 je 4005b4
4005ab:66 0f 28 c1 movapd%xmm1,%xmm0
4005af:e8 ac fe ff ff callq 400460
4005b4:f2 0f 11 45 f8 movsd%xmm0,-0x8(%rbp)
4005b9:b8 00 mov$0x0,%eax
4005be:c9-Q
4005bf:c3 retq
因此您可以看到,sqrt的参数是通过%xmm0寄存器传递的。我最近创建了一个函数堆栈帧、寄存器使用情况、结构化类型的内存布局和其他ABI信息。您可以查看x86_64上libssh库函数ssh_channel_read_timeout的结果
我最近创建了一个可视化的函数堆栈框架、寄存器使用情况、结构化类型的内存布局和其他ABI信息。您可以查看x86_64上libssh库函数ssh_channel_read_timeout的结果
Linux使用的X86-64 ABI(包括调用约定)非常重要,这里有文档记录:@nos:您应该将此作为答案发布。这几乎解释了一切两者都不是,您的编译器肯定会将其内联到单个SSE2指令中。问我们一点也不重要,只要让你的编译器生成一个程序集列表就行了。有指向文档的链接,包括用于非Windows和Windows的ABI文档,32位和64位。Linux使用的X86-64 ABI,包括调用约定,非常重要,并记录在这里:@nos:你应该将此作为答案发布。这几乎解释了一切两者都不是,您的编译器肯定会将其内联到单个SSE2指令中。要求我们生成一个程序集列表没有什么意义。有指向文档的链接,包括用于非Windows和Windows的32位和64位ABI文档。这是一个非常笨拙的示例,因为
sqrt
内联到sqrtsd
指令(sd=标量双精度),仅当结果为NaN时才返回到调用sqrt
库函数。它仅用于设置errno
,因此,如果您使用-fno math errno
,那么您似乎正在使用的是古老的gcc 4.6或更早版本。这是一个非常笨拙的例子,因为sqrt
内联到sqrtsd
指令(sd=Scalar Double precision),如果结果为NaN,则返回到调用sqrt
库函数。它仅用于设置errno
,因此,如果您使用-fno math errno
,那么您似乎正在使用的是古老的gcc 4.6或更早版本。(稍后为gcc)。