GNU/Linux >> Tutoriales Linux >  >> Linux

¿Cuáles son las convenciones de llamada para las llamadas del sistema UNIX y Linux (y funciones de espacio de usuario) en i386 y x86-64?

Lectura adicional para cualquiera de los temas aquí:La guía definitiva para las llamadas al sistema Linux

Los verifiqué usando GNU Assembler (gas) en Linux.

Interfaz del núcleo

x86-32, también conocido como i386 Convención de llamada al sistema Linux:

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 devuelto está en %eax . Todos los demás registros (incluido EFLAGS) se conservan en int $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.

Si hay más de seis argumentos, %ebx debe contener la ubicación de memoria donde se almacena la lista de argumentos, pero no se preocupe por esto porque es poco probable que use una llamada al sistema con más de seis argumentos.

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 manera más rápida de hacer llamadas al sistema de 32 bits:usando sysenter . El núcleo asigna una página de memoria a cada proceso (el vDSO), con el lado del espacio de usuario del sysenter dance, que tiene que cooperar con el núcleo para poder encontrar la dirección de retorno. Arg para registrar el mapeo es el mismo que para int $0x80 . Normalmente debería llamar al vDSO en lugar de usar sysenter directamente. (Ver La Guía Definitiva de Llamadas al Sistema Linux para obtener información sobre cómo vincular y llamar a vDSO, y para obtener más información sobre sysenter y todo lo demás relacionado con las llamadas al sistema).

x86-32 [Gratis|Abierto|Neto|DragonFly]Convención de llamada al 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 32 bits adicionales de datos ficticios (en realidad no son datos ficticios. Consulte el siguiente enlace para obtener más información) y luego proporcione una instrucción de llamada al sistema int $0x80

http://www.int80h.org/bsdasm/#default-calling-convention

Convención de llamada al sistema Linux x86-64:

(Nota:x86-64 Mac OS X es similar pero diferente de Linux. TAREAS:verifique qué hace *BSD)

Consulte la sección:"A.2 AMD64 Linux Kernel Conventions" de System V Application Binary Interface AMD64 Architecture Processor Supplement. Las últimas versiones de i386 y x86-64 System V psABI se pueden encontrar vinculadas desde esta página en el repositorio del mantenedor de ABI. (Consulte también la wiki de etiquetas x86 para obtener información actualizada). enlaces ABI actualizados y muchas otras cosas buenas sobre x86 asm.)

Aquí está el fragmento de esta sección:

  1. Las aplicaciones de nivel de usuario se utilizan como registros de enteros para pasar la secuencia %rdi, %rsi, %rdx, %rcx,%r8 y %r9. La interfaz del núcleo utiliza %rdi, %rsi, %rdx, %r10, %r8 y %r9.
  2. Se realiza una llamada al sistema a través del syscall instrucción . Esto elimina %rcx y %r11, así como el valor de retorno de %rax, pero se conservan otros registros.
  3. El número de llamada al sistema debe pasarse en el registro %rax.
  4. Las llamadas al sistema están limitadas a seis argumentos, ningún argumento se pasa directamente a la pila.
  5. Al regresar de la llamada al sistema, el registro %rax contiene el resultado de la llamada al sistema. Un valor en el rango entre -4095 y -1 indica un error, es -errno .
  6. Solo los valores de clase INTEGER o clase MEMORY se pasan al kernel.

Recuerde que esto es del apéndice específico de Linux de la ABI, e incluso para Linux es informativo, no normativo. (Pero de hecho es exacto.)

Este int $0x80 de 32 bits ABI es utilizable en código de 64 bits (pero no muy recomendable). ¿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 de función x86-32:

En x86-32, los parámetros se pasaban a la pila. El último parámetro se empujó primero a la pila hasta que todos los parámetros estén listos y luego call se ejecutó la instrucción. Esto se usa para llamar a las funciones de la biblioteca C (libc) en Linux desde el ensamblado.

Las versiones modernas de i386 System V ABI (utilizadas en Linux) requieren una alineación de 16 bytes de %esp antes de un call , como el x86-64 System V ABI siempre ha requerido. Los destinatarios de las llamadas pueden asumir eso y usar cargas/almacenamientos de 16 bytes SSE que fallan en no alineados. Pero históricamente, Linux solo requería una alineación de pila de 4 bytes, por lo que requería más trabajo reservar espacio alineado de forma natural incluso para un double de 8 bytes. o algo.

Algunos otros sistemas modernos de 32 bits aún no requieren una alineación de pila de más de 4 bytes.

Convención de llamada de función de espacio de usuario x86-64 System V:

x86-64 System V pasa argumentos en registros, lo que es más eficiente que la convención de argumentos de pila de i386 System V. Evita la latencia y las instrucciones adicionales de almacenar argumentos en la memoria (caché) y luego volver a cargarlos en el receptor de la llamada. 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 forma en que se pasa a la función llamada.

Para obtener información completa, consulte:"3.2 Secuencia de llamada de función" del Suplemento del procesador de arquitectura AMD64 de la interfaz binaria de la aplicación System V que dice, en parte:

Una vez que se clasifican los argumentos, se asignan los registros (en orden de izquierda a derecha) para pasar de la siguiente manera:

  1. Si la clase es MEMORIA, pase el argumento a la pila.
  2. Si la clase es INTEGER, se utiliza el siguiente registro disponible de la secuencia %rdi, %rsi, %rdx, %rcx, %r8 y %r9

Entonces %rdi, %rsi, %rdx, %rcx, %r8 and %r9 son los registros en orden se utiliza para pasar parámetros enteros/puntero (es decir, clase INTEGER) a cualquier función libc desde el ensamblado. %rdi se utiliza para el primer parámetro INTEGER. %rsi para el segundo, %rdx para el tercero y así sucesivamente. Entonces call se debe dar instrucción. La pila (%rsp ) debe estar alineado con 16B cuando call se ejecuta.

Si hay más de 6 parámetros INTEGER, el parámetro 7th INTEGER y posteriores 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 adelante en la pila. No hay registros vectoriales conservados en llamadas. (Una función con una combinación de argumentos FP y enteros puede tener más de 8 argumentos de registro en total).

Funciones variádicas (como printf ) siempre necesita %al =el número de argumentos de registro de FP.

Hay reglas sobre cuándo empaquetar estructuras en registros (rdx:rax a la vuelta) vs. en la 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 funciones de Windows x64 tiene varias diferencias significativas con respecto a x86-64 System V, como el espacio de sombra que debe ser reservado por la persona que llama (en lugar de una zona roja) y llamada conservada xmm6-xmm15. Y reglas muy diferentes para qué argumento va en qué registro.


¿Quizás esté buscando la ABI x86_64?

  • www.x86-64.org/documentation/abi.pdf (404 en 2018-11-24)
  • www.x86-64.org/documentation/abi.pdf (a través de Wayback Machine en 2018-11-24)
  • ¿Dónde se documenta la ABI x86-64 System V? - https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI se mantiene actualizado (por HJ Lu, uno de los mantenedores de ABI) con enlaces a archivos PDF de la versión oficial actual.

Si eso no es precisamente lo que busca, use 'x86_64 abi' en su motor de búsqueda preferido para encontrar referencias alternativas.


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 espacio de usuario y el programa kernel también utilizan la misma ABI. Linux/Freebsd siguen 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 las llamadas del sistema de 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 y el kernel de Linux: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 los parámetros):

El rendimiento es una de las razones de estas ABI (p. ej., pasar parámetros a través de registros en lugar de guardarlos en pilas de memoria)

Para ARM hay varias 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 embebido está el PPC EABI:

http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf

Este documento es una buena descripción general de todas las diferentes convenciones:

http://www.agner.org/optimize/calling_conventions.pdf


Linux
  1. ¿Cuáles son buenos libros de Linux/Unix para un usuario avanzado?

  2. ¿Cuál es la interfaz para las llamadas al sistema ARM y dónde se define en el kernel de Linux?

  3. ¿Cuáles son las llamadas al sistema operativo/sistema nativo de Windows y Linux realizadas desde malloc()?

  4. ¿Cuáles son las diferencias entre lsof y netstat en Linux?

  5. ¿Cuál es la ubicación de instalación convencional para aplicaciones en Linux?

¿Cuál es la diferencia entre Linux y Unix?

Historia de Unix y Linux

¿Qué son las llamadas al sistema Linux y las funciones de biblioteca?

Los 15 mejores programas econométricos y estadísticos para el sistema Linux

Comando superior de Linux:¿Qué somos, sy, ni, id, wa, hi, si y st (para uso de CPU)?

¿Cuál es la diferencia entre Unix, Linux, BSD y GNU?