我有一个适用于 Linux x64 的程序集应用程序,我在其中通过寄存器将参数传递给函数,因此我使用了特定的特定调用约定,在本例中为 fastcall。现在我想从程序集应用程序调用一个 C 函数,比方说,它需要 10 个参数。我是否必须为此切换到 cdecl
并通过堆栈传递参数,而不管我应用程序中的其他任何地方我都是通过寄存器传递参数的?是否允许在一个应用程序中混合调用约定?
最佳答案
我假设 fastcall 是指 SysV ABI(即 Linux 使用的)使用的 amd64 调用约定,其中前几个参数在 rdi
中传递, rsi
和 rdx
。
ABI稍微复杂一些,下面做个简化。您可能想阅读 the specification了解详情。
一般来说,前几个(最左边的)整数或指针参数被放入寄存器rdi
、rsi
、rdx
、rcx
、r8
和 r9
。浮点参数在 xmm0
中传递到 xmm7
。如果寄存器空间耗尽,则额外的参数从右到左通过堆栈传递。例如,要调用具有 10 个整数参数的函数:
foo(a, b, c, d, e, f, g, h, i, k);
你需要这样的代码:
mov $a,%edi
mov $b,%esi
mov $c,%edx
mov $d,%ecx
mov $e,%r8d
mov $f,%r9d
push $k
push $i
push $h
push $g
call foo
add $32,%rsp
对于您的具体示例,getnameinfo
:
int getnameinfo(
const struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);
你会在 rdi
中传递 sa
,在 rsi
中传递 salen
,在 host
中传递在 rdx
中,hoSTLen
在 rcx
中,serv
在 r8
中,servlen
在 r9
和 flags
在堆栈上。
关于从 Assembly 调用 C 函数——切换调用约定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41738307/