/ / Llamar a una función de C desde Assembly - cambiar la convención de llamada - c, assembly, linux-kernel, nasm

Llamar a una función C desde el ensamblaje - cambiar la convención de llamadas - c, ensamblaje, kernel-linux, nasm

Tengo una aplicación de montaje para Linux x64donde paso argumentos a las funciones a través de registros, por lo tanto, estoy usando una cierta convención de llamada, en este caso llamada rápida. Ahora quiero llamar a una función C desde la aplicación de montaje que, digamos, espera 10 argumentos. Tengo que cambiar a cdecl para eso y pase los argumentos a través de la pila, independientemente del hecho en cualquier otra parte de mi aplicación, ¿los estoy pasando a través de registros? ¿Está permitido combinar las convenciones de llamadas en una aplicación?

Respuestas

2 para la respuesta № 1

Asumo que por llamada rápida, se refiere a la convención de llamadas amd64 utilizada por SysV ABI (es decir, qué utiliza Linux) donde se pasan los primeros argumentos rdi, rsiy rdx.

El ABI es un poco complicado, lo siguiente es una simplificación. Puede que quieras leer la especificación para detalles.

En términos generales, los primeros argumentos enteros o de puntero (más a la izquierda) se colocan en los registros rdi, rsi, rdx, rcx, r8y r9. Los argumentos de punto flotante se pasan en xmm0 a xmm7. Si se agota el espacio de registro, los argumentos adicionales se pasan a través de la pila de derecha a izquierda. Por ejemplo, para llamar a una función con 10 argumentos enteros:

foo(a, b, c, d, e, f, g, h, i, k);

necesitarías un código como este:

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

Para su ejemplo concreto, de getnameinfo:

int getnameinfo(
const struct sockaddr *sa,
socklen_t salen,
char *host,
size_t hostlen,
char *serv,
size_t servlen,
int flags);

Pasarías sa en rdi, salen en rsi, host en rdx, hostlen en rcx, serv en r8, servlen en r9 y flags en la pila.


2 para la respuesta № 2

Sí, por supuesto. La convención de llamada se aplica por función. Esta es una aplicación perfectamente válida:

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

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

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

return(0);
}

-1 para la respuesta № 3

Puedes, pero no es necesario.

__attribute__((fastcall)) solo solicita que los primeros dos parámetros se pasen en los registros; de todos modos, todo lo demás se pasará automáticamente a la pila, al igual que con cdecl. Esto se hace para no limitar el número de parámetros que se le pueden dar a una función al elegir una determinada convención de llamada.

En su ejemplo con 10 parámetros para una función que se llama con el fastcall convención de llamada, los dos primeros parámetros se pasarán a los registros, los 8 restantes automáticamente en la pila, al igual que con la convención de llamada estándar.

Como has elegido utilizar fastcall para todas sus otras funciones, no veo una razón por la que desee cambiar esto para una función específica.