Gcc amd64中的传递参数如何?

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

我想知道在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    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)。