1 puntos por GN⁺ 2024-07-11 | 1 comentarios | Compartir por WhatsApp

Cosas extrañas que aprendí mientras escribía un emulador de x86

  • Explica varios datos curiosos y rarezas aprendidos al escribir emuladores de x86 y amd64
  • En Time Travel Debugging (TTD), se usa un emulador de CPU para registrar la ejecución de un proceso a nivel de instrucciones
  • La primera versión de TTD se llamaba iDNA, estaba escrita en ensamblador, era rápida, pero difícil de mantener
  • La segunda versión se escribió en C++ y mejoró la mantenibilidad

Trivia inútil sobre la codificación de x86

  • El esquema de codificación de x86 permite codificar la misma instrucción de varias maneras
  • La instrucción int 3 puede codificarse como CD 03 o CC
  • El registro EAX se conoce como el "registro acumulador" y realmente tiene diferencias en la codificación
  • El prefijo REX permite acceder a un rango más amplio de registros en código de 64 bits
  • Las instrucciones pueden tener una longitud de hasta 15 bytes, y si se supera ese límite se produce una excepción
  • El prefijo de sobrescritura de dirección permite referenciar direcciones de 32 bits en modo de 64 bits

Propiedades extrañas de las banderas

  • La instrucción INC no actualiza la bandera de acarreo, a diferencia de la instrucción ADD
  • Las instrucciones CMPXCHG8B/CMPXCHG16B solo modifican la bandera de cero
  • Las instrucciones de desplazamiento y rotación dejan la bandera de overflow en estado indefinido cuando la cantidad de desplazamiento es mayor que 1

Más sorpresas sobre las instrucciones de desplazamiento

  • shr ax, 10h desplaza el registro ax 16 bits y lo convierte en 0
  • shr eax, 20h desplaza el registro eax 32 bits, pero el valor no cambia
  • La cantidad de desplazamiento se enmascara con 1FH

Sobrescritura de segmento

  • Los segmentos todavía se usan en código de 32 y 64 bits, principalmente para almacenamiento local de hilo
  • En Windows, se usan los registros FS o GS para referenciar el TEB (Thread Execution Block)
  • En procesos de 32 bits se usa FS, y en procesos de 64 bits se usa GS
  • En modo de 64 bits, el valor del registro de segmento no es importante

Sobrescritura de segmento: más trivia

  • En modo de 32 bits, el valor real del registro de segmento referencia el descriptor de segmento
  • En modo de 64 bits, la base está controlada por el MSR
  • En WinDbg no se puede leer directamente el valor de segmento de un proceso de 64 bits

Conclusión

  • Este artículo ofrece una lista aleatoria de trivia sobre x86
  • Escribir un emulador ayuda a comprender en profundidad cómo funciona la CPU
  • Se pueden consultar excelentes recursos en el sitio web de Agner Fog

Resumen de GN⁺

  • Explica varios datos curiosos y rarezas aprendidos al escribir emuladores de x86 y amd64
  • Escribir un emulador ayuda a comprender en profundidad cómo funciona la CPU
  • Cubre varias curiosidades, como los distintos métodos de codificación de la instrucción int 3, el prefijo REX y la sobrescritura de segmento
  • Se pueden consultar más recursos en el sitio web de Agner Fog

1 comentarios

 
GN⁺ 2024-07-11
Opiniones en Hacker News
  • El Intel SDM indica explícitamente que, si las instrucciones BSF/BSR reciben una entrada 0, el valor de destino queda indefinido. AMD documenta que, en ese caso, el destino no se modifica
    • glibc usa el hecho no oficial de que en Intel el destino no se modifica
    • TZCNT/LZCNT son formas de BSF/BSR con el prefijo F3, que se ignora en procesadores antiguos. El mismo código puede comportarse distinto según la CPU
  • Hay muchas quejas sobre los prefijos, pero ese no es el mayor problema. Los bits de extensión REX/VEX/EVEX.RXB se ignoran cuando no se aplican
    • APX permite que el prefijo REX2 codifique registros r16-r31, pero no xmm16-xmm31
    • El prefijo EVEX tiene distintos diseños según varios opcode
    • El uso de bits de extensión cambia según el tipo de registro
  • Opinión de alguien que disfruta programar en ensamblador. Le gusta su cualidad estética simple y vertical
    • Comparte la experiencia de haber escrito una mini VM para explicarle la pila a un amigo de JS
    • Menciona que su amigo está tan ocupado con desarrollo web que no tiene tiempo para estudiar a fondo
  • Recordaba mal que una variante de Salsa20 y código máquina estaban en cryp.to. El sitio de Dan Bernstein es cr.yp.to
    • Comparte que, mientras trabajaba con cifrado de datos en una startup, probó varias implementaciones
  • Recomienda a Justine Tunney y su emulador. La documentación explica bien cómo funciona una CPU
  • No está de acuerdo con la opinión de que escribir un emulador de CPU sea la mejor manera de entender una CPU
    • Cree que una mejor forma es construir una CPU a nivel de compuertas
  • No está de acuerdo con la opinión de que el ensamblador x86 cause más problemas que RISC
    • x86 es fácil de analizar, pero MIPS es difícil
  • Expresa respeto por los desarrolladores de emuladores de procesadores x86
    • Mientras desarrollaba un emulador de i386, aprendió mucho sobre llamadas al sistema y ELF
  • Comparte su experiencia escribiendo un emulador x86
    • Recuerda haber escrito un emulador de juguete que ejecutaba código BIOS inicial
  • Comparte que le gusta el estilo y el diseño del blog