GNU/Linux >> Tutoriales Linux >  >> Linux

x86_64 Ensamblaje Linux Confusión de llamadas del sistema

Mucho ha cambiado entre i386 y x86_64, incluidas las instrucciones que se usan para ingresar al kernel y los registros que se usan para llevar los argumentos de las llamadas al sistema. Aquí hay un código equivalente al tuyo:

.section .data

.section .text
.global _start
_start:
movq $60, %rax
movq $2, %rdi
syscall

Citando de esta respuesta a una pregunta relacionada:

Los números de llamada al sistema están en el código fuente de Linux en arch/x86/include/asm/unistd_64.h. El número de llamada al sistema se pasa en el registro rax. Los parámetros están en rdi, rsi, rdx, r10, r8, r9. La llamada se invoca con la instrucción "syscall". La llamada al sistema sobrescribe el registro rcx. La devolución es en rax.


Se encuentra con una sorprendente diferencia entre i386 y x86_64:no utilizan el mismo mecanismo de llamada al sistema. El código correcto es:

movq $60, %rax
movq $2,  %rdi   ; not %rbx!
syscall

Interrumpir 0x80 siempre invoca llamadas al sistema de 32 bits. Se utiliza para permitir que las aplicaciones de 32 bits se ejecuten en sistemas de 64 bits.

Con el fin de aprender, probablemente debería intentar seguir el tutorial exactamente, en lugar de traducir sobre la marcha a 64 bits; hay algunas otras diferencias de comportamiento significativas con las que es probable que se encuentre. Una vez que esté familiarizado con i386, luego puedes recoger x86_64 por separado.


por favor lea esto ¿Cuáles son las convenciones de llamada para las llamadas del sistema UNIX y Linux en x86-64?

y tenga en cuenta que usar int 0x80 para syscall en sistemas x64 es una capa de compatibilidad antigua. deberías usar syscall instrucción en sistemas x64.

aún puede usar este método antiguo, pero necesita compilar sus archivos binarios en un modo x86, consulte el manual del compilador/ensamblador para obtener más detalles.


La respuesta de duskwuff señala correctamente que el mecanismo para las llamadas al sistema es diferente para Linux x86 de 64 bits frente a Linux de 32 bits.

Sin embargo, esta respuesta es incompleta y engañosa por un par de razones:

  • En realidad, el cambio se introdujo antes de que los sistemas de 64 bits se hicieran populares , motivado por la observación de que int 0x80 era muy lento en Pentium 4. Linus Torvalds codificó una solución usando el SYSENTER /SYSEXIT instrucciones (que habían sido introducidas por Intel alrededor de la era Pentium Pro, pero que tenían errores y no brindaban ningún beneficio práctico). Así que los sistemas Linux modernos de 32 bits en realidad usan SYSENTER , no int 0x80 .
  • Los núcleos de Linux x86 de 64 bits en realidad no usan SYSENTER y SYSEXIT . De hecho, usan el SYSCALL muy similar /SYSRET instrucciones.

Como se señaló en los comentarios, SYSENTER en realidad no funciona en muchos sistemas Linux de 64 bits —es decir, AMD de 64 bits sistemas.

Es una situación ciertamente confusa. Los detalles sangrientos están aquí, pero todo se reduce a esto:

Para un kernel de 32 bits, SYSENTER/SYSEXIT son el único par compatible [entre CPU AMD e Intel]

Solo para un kernel de 64 bits en modo largo... SYSCALL/SYSRET son el único par compatible [entre CPU AMD e Intel]

Parece que en un Intel CPU en modo de 64 bits, puede salirse con la suya usando SYSENTER porque hace lo mismo que SYSCALL , sin embargo, este no es el caso de los sistemas AMD.

En pocas palabras:siempre use SYSCALL en Linux en sistemas x86 de 64 bits . Es lo que realmente especifica la ABI x86-64. (Consulte esta excelente respuesta wiki para obtener aún más detalles).


Linux
  1. Linux:¿por qué las utilidades de Linux no utilizan una llamada al sistema para obtener la hora actual?

  2. Linux:¿métodos de invocación de llamadas al sistema en el nuevo kernel?

  3. Mejores prácticas de codificación para la programación del sistema Linux en lenguaje C - Parte 1

  4. ¿Cómo invocar una llamada al sistema a través de syscall o sysenter en el ensamblaje en línea?

  5. No se puede llamar a la función de biblioteca estándar de C en Linux de 64 bits desde el código ensamblador (yasm)

Requisitos del sistema Linux Kali

Comando de apagado de Linux

Comando Fsck en Linux

¿Linux es un sistema operativo o un kernel?

Documentación del tiempo de actividad del sistema en Linux

¿Cómo verificar que el sistema Linux sea de 32 bits o de 64 bits?