assembly - sistema - Diferencia en ABI entre x86_64 funciones de Linux y syscalls
que es linux wikipedia (2)
El syscall
de AMD corta el registro de rcx
, por lo que se usa r10
su lugar.
La convención de llamada de función x86_64 SysV ABI define el argumento entero # 4 para pasar en el registro rcx
. El kernel syscall de Linux ABI, por otro lado, usa r10
para ese mismo propósito. Todos los demás argumentos se pasan en los mismos registros para ambas funciones y llamadas de sistema.
Esto lleva a algunas cosas extrañas. Vea, por ejemplo, la implementación de mmap
en glibc para la plataforma x32 (para la cual existe la misma discrepancia):
00432ce0 <__mmap>:
432ce0: 49 89 ca mov %rcx,%r10
432ce3: b8 09 00 00 40 mov $0x40000009,%eax
432ce8: 0f 05 syscall
Entonces, todos los registros ya están en su lugar, excepto que movemos rcx
a r10
.
Me pregunto por qué no se define el syscall ABI para que sea el mismo que el llamado a la función ABI, considerando que ya son muy similares.
La instrucción syscall
está destinada a proporcionar un método más rápido para ingresar a Ring-0 para llevar a cabo una llamada al sistema. Esto pretende ser una mejora con respecto al método anterior, que consistía en generar una interrupción de software ( int 0x80
en Linux).
Parte de la razón por la cual la instrucción es más rápida es porque no cambia la memoria, o incluso cambia rsp
para apuntar a una pila de kernel. A diferencia de una interrupción de software, donde la CPU está obligada a permitir que el sistema operativo reanude su funcionamiento sin dañar nada, para este comando la CPU puede asumir que el software es consciente de que algo está sucediendo aquí.
En particular, syscall
almacena dos partes del estado de espacio de usuario en los registros. El RIP
al que volver después de la llamada se almacena en rcx
, y los indicadores se almacenan en R11
( porque RFLAGS está enmascarado con un valor proporcionado por el kernel antes de ingresar al kernel ). Esto significa que ambos registros son destruidos por la instrucción.
Dado que son destruidos, el syscall ABI usa otro registro en lugar de rcx
, de ahí el uso de r10
para el cuarto argumento.
r10
es una elección natural, ya que en el System86 AB8686 no se usa para pasar argumentos de función, y las funciones no necesitan preservar el valor de llamador de r10
. Entonces, una función de envoltura de syscall puede mov %rcx, %r10
sin guardar / restaurar. Esto no sería posible con ningún otro registro, para syscalls de 6-arg y la convención de llamadas de función de SysV ABI.
Por cierto, la llamada al sistema ABI de 32 bits también se puede acceder con sysenter
, que requiere la cooperación entre el espacio de usuario y el kernel-space para permitir el regreso al espacio de usuario después de un sysenter
. (es decir, almacenar algún estado en el espacio de usuario antes de ejecutar sysenter
). Este es un rendimiento mayor que int 0x80
, pero incómodo. Aún así, glibc lo usa (saltando al código de espacio de usuario en las páginas de vdso que el kernel mapea en el espacio de direcciones de cada proceso).
La syscall
de AMD es otro acercamiento a la misma idea que el sysenter
de Intel: hacer que la entrada / salida del núcleo sea menos costosa al no preservar absolutamente todo.