我有一个用于Linux x64的汇编应用程序,我通过寄存器将参数传递给函数,因此我使用了某种调用约定,在本例中是fastcall。现在我想从汇编应用程序调用一个C函数,它需要10个参数。我是否必须切换到cdecl,并通过堆栈传递参数,而不管我的应用程序中其他任何地方都是通过寄存器传递参数的事实?
fastcall
cdecl
gev0vcfq1#
我假设 fastcall 是指SysV ABI使用的amd 64调用约定(即Linux使用的),其中前几个参数在rdi、rsi和rdx中传递。ABI有点复杂,下面是一个简化。你可能想阅读the specification的细节。一般来说,前几个(最左边)整数或指针参数被放入寄存器rdi、rsi、rdx、rcx、r8和r9。浮点参数在xmm0到xmm7中传递。如果寄存器空间耗尽,额外的参数从右向左通过堆栈传递。例如,调用一个具有10个整数参数的函数:
rdi
rsi
rdx
rcx
r8
r9
xmm0
xmm7
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为例:
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。
sa
salen
host
hostlen
serv
servlen
flags
kmbjn2e32#
当然可以。调用约定是基于每个函数的。这是一个完全有效的应用程序:
int __stdcall func1() { return(1); } int __fastcall func2() { return(2); } int __cdecl main(void) { func1(); func2(); return(0); }
字符串
goqiplq23#
你可以,但你不需要。__attribute__((fastcall))只要求将前两个参数传入寄存器--其他所有参数都会自动传入堆栈,就像cdecl一样。这样做是为了不限制通过选择特定的调用约定可以给函数提供的参数数量。在您的示例中,使用fastcall调用约定调用的函数有10个参数,前两个参数将在寄存器中传递,其余8个参数将自动在堆栈中传递,就像标准调用约定一样。由于您已经选择将fastcall用于所有其他函数,因此我看不出您为什么要为某个特定函数更改此设置。
__attribute__((fastcall))
3条答案
按热度按时间gev0vcfq1#
我假设 fastcall 是指SysV ABI使用的amd 64调用约定(即Linux使用的),其中前几个参数在
rdi
、rsi
和rdx
中传递。ABI有点复杂,下面是一个简化。你可能想阅读the specification的细节。
一般来说,前几个(最左边)整数或指针参数被放入寄存器
rdi
、rsi
、rdx
、rcx
、r8
和r9
。浮点参数在xmm0
到xmm7
中传递。如果寄存器空间耗尽,额外的参数从右向左通过堆栈传递。例如,调用一个具有10个整数参数的函数:字符串
你需要这样的代码:
型
以
getnameinfo
为例:型
在
rdi
中传递sa
,在rsi
中传递salen
,在rdx
中传递host
,在rcx
中传递hostlen
,在r8
中传递serv
,在r9
中传递servlen
,在flags
中传递flags
。kmbjn2e32#
当然可以。调用约定是基于每个函数的。这是一个完全有效的应用程序:
字符串
goqiplq23#
你可以,但你不需要。
__attribute__((fastcall))
只要求将前两个参数传入寄存器--其他所有参数都会自动传入堆栈,就像cdecl
一样。这样做是为了不限制通过选择特定的调用约定可以给函数提供的参数数量。在您的示例中,使用
fastcall
调用约定调用的函数有10个参数,前两个参数将在寄存器中传递,其余8个参数将自动在堆栈中传递,就像标准调用约定一样。由于您已经选择将
fastcall
用于所有其他函数,因此我看不出您为什么要为某个特定函数更改此设置。