Pasaje de Parámetros en 64 bits para C Presentación
Arquitectura x86-64
Convención Registros a preservar: %rbp %rsp %rbx %r12 %r13 %r15 Estos registros pertenecen a la función llamadora y deben mantener su valor al terminar la función
Clases de Datos Los tipos de argumentos se agrupan en 3 clases. INTEGER SSE MEMORY Existen más clasificaciones, pero estas clases son las que nos interesan.
Tipos de Datos Los tipos built-in de C se clasifican cómo: INTEGER: char, short, int, long, long long y punteros. SSE: float y double MEMORY: Tamaño mayor a 4 quadwords (8 bytes) o datos desalineados
Pasaje de Parámetros Si el tipo es INTEGER, el argumento se pasa en el siguiente registro libre de izquierda a derecha en la secuencia %rdi, %rsi, %rdx, %rcx, %r8 y %r9 Si son necesarios más argumentos se pushean al stack de derecha a izquierda.
Pasaje de Parámetros Si el tipo es SSE, el argumento se pasa en el siguiente registro libre de izquierda a derecha en la secuencia %xmm0, %xmm1, %xmm2, %xmm3, %xmm4, %xmm5, %xmm6 y %xmm7 Si son necesarios más argumentos se pushean al stack de derecha a izquierda. Si la función es f(…) %al es una cóta sup. de cuantos argumentos se pasaron por registro.
Pasaje de Parámetros Si el tipo es MEMORY, se pushea al stack de derecha a izquierda
Pasaje de Parámetros Cuando se pasan datos por stack, estos siempre son redondeados (hacia arriba) a un multiplo de quadword (8 bytes). Los miembros de las estructuras tambíen son redondeados. Esto mantiene la alineación a palabra.
Valores de Retorno Si es tipo INTEGER, el retorno se hace por el primer registro libre de la secuencia %rax, %rdx Si es tipo SSE, el retorno se hace por el primer registro libre de la secuencia %xmm0, %xmm1 Si es tipo MEMORY, la función llamadora proveé espacio para el retorno, el registro %rdi apunta a esta zona como si fuera un argumento más. Al salir de la función el valor de %rax es el mismo que el de %rdi.
Uso de los registros
Ejemplos Las siguientes funciones reciben los argumentos de la misma forma: double foo(long arg1, double arg2); double bar(double arg2, long arg1);
Ejemplos La siguiente función recibe todos sus argumentos por registro. long foo(int integer1, float sse1, long integer2, float sse2, void *integer3, double sse4, short integer4, float sse5, char integer5, double sse6, long long integer6, double sse7, double sse8);
Ejemplos La siguiente función recibe sus últimos 3 argumentos por stack. long foo(long arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7, long arg8, long arg9);
Ejemplo de Integración Escribir una implementación de la llamada al system call int write(int fd, const void *buff, int count); Datos: Las llamadas a los system calls en x86-64 es el mismo que en i386. El número de system call de write es 4.
Preguntas Alguna duda? Porqué se usan los registros en lugar del stack en esta arquitectura?