Los siguientes enlaces explican las convenciones de llamadas al sistema x86-32 tanto para UNIX (sabor BSD) como para Linux:
Pero, ¿cuáles son las convenciones de llamadas al sistema x86-64 en UNIX y Linux?
Los siguientes enlaces explican las convenciones de llamadas al sistema x86-32 tanto para UNIX (sabor BSD) como para Linux:
Pero, ¿cuáles son las convenciones de llamadas al sistema x86-64 en UNIX y Linux?
sysret
funciona, junto con el reemplazo de rax con el valor de retorno. Todos los demás registros se conservan en amd64.Respuestas:
Lectura adicional para cualquiera de los temas aquí: La guía definitiva para las llamadas al sistema Linux
Verifiqué esto usando GNU Assembler (gas) en Linux.
Interfaz de kernel
x86-32 también conocido como i386 Linux System Call Convention:
En x86-32, los parámetros para la llamada al sistema Linux se pasan mediante registros.
%eax
para syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp se utilizan para pasar 6 parámetros a las llamadas del sistema.El valor de retorno está en
%eax
. Todos los demás registros (incluidos los EFLAGS) se conservan en todo elint $0x80
.Tomé el siguiente fragmento del Tutorial de ensamblaje de Linux, pero tengo dudas al respecto. Si alguien puede mostrar un ejemplo, sería genial.
Para ver un ejemplo y un poco más de lectura, consulte http://www.int80h.org/bsdasm/#alternate-calling-convention . Otro ejemplo de Hello World para i386 Linux usando
int 0x80
: Hola, ¿mundo en lenguaje ensamblador con llamadas al sistema Linux?Hay una forma más rápida de hacer llamadas al sistema de 32 bits: usando
sysenter
. El núcleo mapea una página de memoria en cada proceso (el vDSO), con el lado del espacio de usuario de lasysenter
danza, que tiene que cooperar con el núcleo para que pueda encontrar la dirección de retorno. Arg para registrar la asignación es lo mismo que paraint $0x80
. Normalmente debería llamar al vDSO en lugar de usarlosysenter
directamente. (Consulte la Guía definitiva para las llamadas al sistema Linux para obtener información sobre cómo vincular y llamar al vDSO, y para obtener más informaciónsysenter
y todo lo demás relacionado con las llamadas al sistema).x86-32 [Gratis | Abrir | Red | DragonFly] Convención del sistema BSD UNIX:
Los parámetros se pasan en la pila. Empuje los parámetros (último parámetro empujado primero) en la pila. Luego inserte una información ficticia adicional de 32 bits (en realidad no son datos ficticios. Consulte el siguiente enlace para obtener más información) y luego brinde una instrucción de llamada al sistema
int $0x80
http://www.int80h.org/bsdasm/#default-calling-convention
x86-64 Convención de llamada al sistema Linux:
x86-64 Mac OS X es similar pero diferente . TODO: comprueba lo que * BSD hace.
Consulte la sección: "A.2 Convenciones del kernel de Linux AMD64 " de la interfaz binaria del sistema V Suplemento del procesador de arquitectura AMD64 . Las últimas versiones de las psABI i386 y x86-64 System V se pueden encontrar enlazadas desde esta página en el repositorio del mantenedor de ABI . (Ver también elx86 etiqueta wiki para enlaces ABI actualizados y muchas otras cosas buenas sobre x86 asm.)
Aquí está el fragmento de esta sección:
Recuerde que esto es del apéndice específico de Linux al ABI, e incluso para Linux es informativo, no normativo. (Pero de hecho es exacto).
Este
int $0x80
ABI de 32 bits se puede usar en código de 64 bits (pero no se recomienda). ¿Qué sucede si usa la ABI de Linux int 0x80 de 32 bits en código de 64 bits? Todavía trunca sus entradas a 32 bits, por lo que no es adecuado para punteros, y pone a cero r8-r11.Interfaz de usuario: función de llamada
Convención de llamada a funciones x86-32:
En x86-32 los parámetros se pasaron en la pila. El último parámetro se introdujo primero en la pila hasta que se hayan completado todos los parámetros y luego
call
se haya ejecutado la instrucción. Esto se usa para llamar a las funciones de la biblioteca C (libc) en Linux desde el ensamblado.Las versiones modernas del i386 System V ABI (utilizado en Linux) requieren una alineación de 16 bytes
%esp
antes de acall
, como siempre ha requerido el x86-64 System V ABI. Los Callees pueden asumir eso y usar cargas / almacenes SSE de 16 bytes que fallan sin alinearse. Pero históricamente, Linux solo requería una alineación de pila de 4 bytes, por lo que se requería un trabajo adicional para reservar espacio alineado naturalmente incluso para un byte de 8 bytesdouble
o algo así.Algunos otros sistemas modernos de 32 bits aún no requieren una alineación de pila de más de 4 bytes.
x86-64 Convención de llamada a la función de espacio de usuario del sistema V:
x86-64 System V pasa args en registros, que es más eficiente que la convención de args de pila de i386 System V. Evita la latencia y las instrucciones adicionales de almacenar los argumentos en la memoria (caché) y luego volver a cargarlos en la persona que llama. Esto funciona bien porque hay más registros disponibles y es mejor para las CPU modernas de alto rendimiento donde la latencia y la ejecución fuera de orden son importantes. (El i386 ABI es muy antiguo).
En este nuevo mecanismo: Primero, los parámetros se dividen en clases. La clase de cada parámetro determina la manera en que se pasa a la función llamada.
Para obtener información completa, consulte: "3.2 Secuencia de llamada de función" de la interfaz binaria de la aplicación System V AMD64 Architecture Processor Supplement que lee, en parte:
También lo
%rdi, %rsi, %rdx, %rcx, %r8 and %r9
son los registros en orden utilizados para pasar parámetros de entero / puntero (es decir, clase INTEGER) a cualquier función libc desde el ensamblado. % rdi se usa para el primer parámetro INTEGER. % rsi para el segundo,% rdx para el tercero y así sucesivamente. Entonces secall
deben dar instrucciones. La pila (%rsp
) debe estar alineada con 16B cuando secall
ejecuta.Si hay más de 6 parámetros INTEGER, el séptimo parámetro INTEGER y más tarde se pasan a la pila. (La persona que llama aparece, igual que x86-32.)
Los primeros 8 argumentos de coma flotante se pasan en% xmm0-7, más tarde en la pila. No hay registros de vector de llamada preservada. (Una función con una combinación de FP y argumentos enteros puede tener más de 8 argumentos de registro total).
Las funciones variables ( como
printf
) siempre necesitan%al
= el número de argumentos de registro FP.Hay reglas sobre cuándo empacar estructuras en registros (
rdx:rax
al regreso) vs. en memoria. Consulte la ABI para obtener detalles y verifique la salida del compilador para asegurarse de que su código concuerde con los compiladores sobre cómo se debe pasar / devolver algo.Tenga en cuenta que la convención de llamada de función x64 de Windows tiene múltiples diferencias significativas con respecto al Sistema x86-64 V, como el espacio de sombra que debe ser reservado por la persona que llama (en lugar de una zona roja) y xmm6-xmm15 con llamada preservada. Y reglas muy diferentes para qué argumento va en qué registro.
fuente
int 0x80
ABI de Linux en código de 64 bits, esto es exactamente lo que sucede: stackoverflow.com/questions/46087730/… . Tiene ceros r8-r11 y funciona exactamente igual que cuando se ejecuta en un proceso de 32 bits. En esas preguntas y respuestas, tengo un ejemplo que muestra que funciona o falla al truncar un puntero. Y también busqué en la fuente del núcleo para mostrar por qué se comporta de esa manera.¿Quizás estás buscando el x86_64 ABI?
Si eso no es exactamente lo que busca, use 'x86_64 abi' en su motor de búsqueda preferido para encontrar referencias alternativas.
fuente
Las convenciones de llamada definen cómo se pasan los parámetros en los registros al llamar o ser llamado por otro programa. Y la mejor fuente de estas convenciones es en forma de estándares ABI definidos para cada uno de estos hardware. Para facilitar la compilación, el mismo espacio de usuario también es utilizado por el espacio de usuario y el programa del núcleo. Linux / Freebsd sigue el mismo ABI para x86-64 y otro conjunto para 32 bits. Pero x86-64 ABI para Windows es diferente de Linux / FreeBSD. Y, en general, ABI no diferencia la llamada del sistema frente a las "llamadas de funciones" normales. Es decir, aquí hay un ejemplo particular de convenciones de llamadas x86_64 y es lo mismo para el espacio de usuario de Linux y el núcleo: http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64 / (tenga en cuenta la secuencia a, b, c, d, e, f de parámetros):
El rendimiento es una de las razones de estos ABI (por ejemplo, pasar parámetros a través de registros en lugar de guardarlos en pilas de memoria)
Para ARM hay varios ABI:
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.swdev.abi/index.html
https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
Convención ARM64:
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
Para Linux en PowerPC:
http://refspecs.freestandards.org/elf/elfspec_ppc.pdf
http://www.0x04.net/doc/elf/psABI-ppc64.pdf
Y para incrustado está el PPC EABI:
http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf
Este documento es una buena descripción de todas las diferentes convenciones:
http://www.agner.org/optimize/calling_conventions.pdf
fuente
Comentarios de fuente del kernel 5.0 de Linux
Sabía que los detalles de x86 están por debajo
arch/x86
, y que las cosas de syscall se hundenarch/x86/entry
. Entonces, un rápidogit grep rdi
en ese directorio me lleva a arch / x86 / entry / entry_64.S :y para 32 bits en arch / x86 / entry / entry_32.S :
Implementación de llamada al sistema glibc 2.29 Linux x86_64
Ahora hagamos trampa mirando las principales implementaciones de libc y veamos qué están haciendo.
¿Qué podría ser mejor que mirar glibc que estoy usando ahora mientras escribo esta respuesta? :-)
glibc 2.29 define x86_64 syscalls en
sysdeps/unix/sysv/linux/x86_64/sysdep.h
y que contiene algún código interesante, por ejemplo:y:
que creo que se explican por sí mismas. Observe cómo esto parece haber sido diseñado para coincidir exactamente con la convención de llamada de las funciones regulares ABI AMD64 de System V: https://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions
Recordatorio rápido de los clobbers:
cc
significa registros de bandera. Pero Peter Cordes comenta que esto es innecesario aquí.memory
significa que se puede pasar un puntero en el ensamblaje y usarlo para acceder a la memoriaPara obtener un ejemplo explícito mínimo ejecutable desde cero, vea esta respuesta: ¿Cómo invocar una llamada del sistema a través del sysenter en el ensamblaje en línea?
Hacer algunas llamadas de sistema en ensamblaje manualmente
No muy científico, pero divertido:
x86_64.S
GitHub aguas arriba .
aarch64
He mostrado un ejemplo de tierra de usuario mínima ejecutable en: /reverseengineering/16917/arm64-syscalls-table/18834#18834 TODO el código de kernel grep aquí, debería ser fácil.
fuente
"cc"
clobber es innecesario: los syscalls de Linux guardan / restauran RFLAGS (las instruccionessyscall
/ losysret
hacen usando R11, y el kernel no modifica los R11 / RFLAGS guardados de otra manera que no sea a través deptrace
llamadas al sistema del depurador)."cc"
clobber es implícito para x86 / x86-64 en GNU C Extended asm, por lo que no puede obtener nada al dejarlo fuera.