从汇编中调用 C 函数——切换调用约定

问题描述 投票:0回答:3

我有一个适用于 Linux x64 的汇编应用程序,我通过寄存器将参数传递给函数,因此我使用了某种调用约定,在本例中为

fastcall
。现在我想从汇编应用程序调用一个 C 函数,比如说,需要 10 个参数。我是否必须切换到 cdecl
 并通过堆栈传递参数,而不管我的应用程序中的其他地方是否通过寄存器传递它们?是否允许在一个应用程序中混合调用约定?

c assembly linux-kernel nasm
3个回答
2
投票
我假设

fastcall 是指 SysV ABI 使用的 amd64 调用约定(即 Linux 使用的),其中前几个参数在 rdi

rsi
rdx
 中传递。

ABI稍微复杂,以下是简化的。您可能需要阅读

规范了解详细信息。

一般来说,前几个(最左边的)整数或指针参数被放入寄存器

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);

您将在

sa

 中传递 
rdi
,在 
salen
 中传递 
rsi
,在 
host
 中传递 
rdx
,在 
hostlen
 中传递 
rcx
,在 
serv
 中传递 
r8
servlen
r9
flags
 在堆栈上。


2
投票
当然可以。调用约定基于每个函数应用。这是一个完全有效的应用程序:

int __stdcall func1() { return(1); } int __fastcall func2() { return(2); } int __cdecl main(void) { func1(); func2(); return(0); }
    

-1
投票
可以,但没必要。

__attribute__((fastcall))

 仅要求将前两个参数传递到寄存器中 - 其他所有参数都会自动在堆栈上传递,就像 
cdecl
 一样。这样做是为了不通过选择特定的调用约定来限制可以赋予函数的参数数量。

在您的示例中,使用

fastcall

 调用约定调用的函数有 10 个参数,前两个参数将在寄存器中传递,其余 8 个参数自动在堆栈中传递,就像标准调用约定一样。

由于您已选择将

fastcall

 用于所有其他功能,我看不出您为何要针对某个特定功能更改此设置。

© www.soinside.com 2019 - 2024. All rights reserved.