Ho un'applicazione di assemblaggio per Linux x64dove passo argomenti alle funzioni tramite i registri, quindi sto usando una certa convenzione di chiamata, in questo caso la chiamata veloce. Ora voglio chiamare una funzione C dall'applicazione di assemblaggio che, diciamo, prevede 10 argomenti. Devo passare a cdecl
per questo e passare gli argomenti tramite stack, indipendentemente dal fatto in qualsiasi altra parte della mia applicazione, li sto passando attraverso i registri? È consentito combinare convenzioni di chiamata in una sola applicazione?
risposte:
2 per risposta № 1Suppongo che entro fastcallintendi la convenzione di chiamata amd64 utilizzata dall'ABI SysV (ovvero ciò che utilizza Linux) in cui vengono passati i primi argomenti rdi
, rsi
, e rdx
.
L'ABI è leggermente complicato, la seguente è una semplificazione. Potresti voler leggere la specifica per dettagli.
In generale, i primi pochi argomenti interi (più a sinistra) o puntatore vengono inseriti nei registri rdi
, rsi
, rdx
, rcx
, r8
, e r9
. Vengono passati argomenti in virgola mobile xmm0
a xmm7
. Se lo spazio del registro è esaurito, gli argomenti aggiuntivi vengono passati attraverso lo stack da destra a sinistra. Ad esempio, per chiamare una funzione con 10 argomenti interi:
foo(a, b, c, d, e, f, g, h, i, k);
avresti bisogno di un codice come questo:
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
Per il tuo esempio concreto, di getnameinfo
:
int getnameinfo(
const struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);
Passeresti sa
in rdi
, salen
in rsi
, host
in rdx
, hostlen
in rcx
, serv
in r8
, servlen
in r9
e flags
in pila.
2 per risposta № 2
Sì, naturalmente. La convenzione di chiamata viene applicata in base alla funzione. Questa è un'applicazione perfettamente valida:
int __stdcall func1()
{
return(1);
}
int __fastcall func2()
{
return(2);
}
int __cdecl main(void)
{
func1();
func2();
return(0);
}
-1 per risposta № 3
Puoi, ma non è necessario.
__attribute__((fastcall))
chiede solo che i primi due parametri vengano passati nei registri: tutto il resto verrà comunque automaticamente passato nello stack, proprio come con cdecl
. Questo viene fatto al fine di non limitare il numero di parametri che possono essere dati a una funzione scegliendo una determinata convenzione di chiamata.
Nel tuo esempio con 10 parametri per una funzione chiamata con fastcall
convenzione di chiamata, i primi due parametri verranno passati nei registri, gli altri 8 automaticamente nello stack, proprio come con la convenzione di chiamata standard.
Come hai scelto di usare fastcall
per tutte le altre funzioni, non vedo un motivo per cui si desidera modificarlo per una funzione specifica.