【问题标题】:Calling a C function from Assembly -- switching calling convention从汇编调用 C 函数——切换调用约定
【发布时间】:2017-06-03 22:42:54
【问题描述】:

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

【问题讨论】:

  • 你读过ABI specification吗?它在那里说明了如何处理参数多于可用寄存器的函数。

标签: c assembly linux-kernel nasm


【解决方案1】:

我假设 fastcall 是指 SysV ABI 使用的 amd64 调用约定(即 Linux 使用的),其中前几个参数在 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);

你会通过sa in rdi, salen in rsi, host in rdx, hostlen in rcx, serv in r83, r9 和 flags 在堆栈上。

【讨论】:

  • @Kooiomo 你理解气体语法有困难吗?如果是这样,我可以为您翻译示例。
【解决方案2】:

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

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

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

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

  return(0);
}

【讨论】:

  • 如果我从 C 中获取 getnameinfo,我是否必须在从 Assembly 调用时通过堆栈将 所有 参数传递给它?还是允许我通过寄存器传递其中的一部分并通过堆栈传递一部分?还是所有参数都通过寄存器?
  • @Kooiomo 查看我的回答。
  • @fuz,这并不能完全回答我的 3 个问题。
  • @Kooiomo 我明白了。哪个问题仍然悬而未决?
  • @fuz,剩下 3 个。 “我必须这样做吗”,“我允许吗”
【解决方案3】:

你可以,但你不需要。

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

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

由于您已选择将fastcall 用于所有其他功能,因此我看不出您为什么要为某个特定功能更改此设置。

【讨论】:

  • 1) 不是 eax,而是 rax。 2)为什么? x64 Linux 有 r1-r10 寄存器。
  • OP 指定 x64,fastcall 未标准化,您的示例是 MS 实现而不是 Sys V,它将至少使用 RDI 和 RSI 作为第一个和第二个参数。
猜你喜欢
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 2018-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多