从汇编中调用C函数--为具有6个以上参数的函数切换调用约定?

wkyowqbh  于 11个月前  发布在  其他
关注(0)|答案(3)|浏览(102)

我有一个用于Linux x64的汇编应用程序,我通过寄存器将参数传递给函数,因此我使用了某种调用约定,在本例中是fastcall。现在我想从汇编应用程序调用一个C函数,它需要10个参数。
我是否必须切换到cdecl,并通过堆栈传递参数,而不管我的应用程序中其他任何地方都是通过寄存器传递参数的事实?

gev0vcfq

gev0vcfq1#

我假设 fastcall 是指SysV ABI使用的amd 64调用约定(即Linux使用的),其中前几个参数在rdirsirdx中传递。
ABI有点复杂,下面是一个简化。你可能想阅读the specification的细节。
一般来说,前几个(最左边)整数或指针参数被放入寄存器rdirsirdxrcxr8r9。浮点参数在xmm0xmm7中传递。如果寄存器空间耗尽,额外的参数从右向左通过堆栈传递。例如,调用一个具有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,在rdx中传递host,在rcx中传递hostlen,在r8中传递serv,在r9中传递servlen,在flags中传递flags

kmbjn2e3

kmbjn2e32#

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

int __stdcall func1()
{
   return(1);
}

int __fastcall func2()
{
  return(2);
}

int __cdecl main(void)
{
  func1();
  func2();

  return(0);
}

字符串

goqiplq2

goqiplq23#

你可以,但你不需要。
__attribute__((fastcall))只要求将前两个参数传入寄存器--其他所有参数都会自动传入堆栈,就像cdecl一样。这样做是为了不限制通过选择特定的调用约定可以给函数提供的参数数量。
在您的示例中,使用fastcall调用约定调用的函数有10个参数,前两个参数将在寄存器中传递,其余8个参数将自动在堆栈中传递,就像标准调用约定一样。
由于您已经选择将fastcall用于所有其他函数,因此我看不出您为什么要为某个特定函数更改此设置。

相关问题