language - Encuentre qué instrucción de ensamblado causó un error de Instrucción ilegal sin depurar
nasm (5)
Bueno ... Por supuesto, puede insertar impresiones de rastreo, para que pueda descartar rápidamente grandes áreas del código. Una vez que haya hecho eso, ejecute, por ejemplo
$ objdump --disassemble my-crashing-program | less
Luego, vaya a, por ejemplo, la función que sabe que está causando el error, y lea el código, buscando cualquier cosa que parezca extraña.
No estoy del todo seguro de cómo objdump
muestra instrucciones ilegales, pero deberían destacarse.
Mientras ejecuto un programa que he escrito en ensamblado, recibo un error de Illegal instruction
. ¿Hay alguna manera de saber qué instrucción está causando el error, sin depuración, porque la máquina en la que estoy ejecutando no tiene un depurador ni ningún sistema de desarrollo? En otras palabras, compilo en una máquina y corro en otra. No puedo probar mi programa en la máquina que estoy compilando porque no son compatibles con SSE4.2. La máquina en la que ejecuto el programa sí admite las instrucciones de SSE4.2.
Creo que tal vez porque necesito decirle al ensamblador (YASM) que reconozca las instrucciones de SSE4.2, al igual que hacemos con gcc pasándole el indicador -msse4.2
. ¿O crees que no es la razón? ¿Alguna idea de cómo decirle a YASM que reconozca las instrucciones de SSE4.2?
Tal vez debería atrapar la señal SIGILL y luego decodificar el SA_SIGINFO para ver qué tipo de operación ilegal hace el programa.
En realidad, a menudo obtienes un error de instrucción ilegal no porque tu programa contenga un código de operación ilegal sino porque hay un error en tu programa (por ejemplo, un desbordamiento del búfer) que hace que tu programa salte en una dirección aleatoria con datos simples o en código pero no en el comienzo del código de operación
Para el ensamblaje escrito a mano, sospecho que hay un problema de administración de la pila que da como resultado un retorno a la nada. Escriba una rutina de impresión de depuración que guarda cada registro e inserte una llamada en la parte superior de cada función.
Entonces verás qué tan lejos llegarás ...
(Por cierto, un buen editor y una buena comprensión de la macro sintaxis del ensamblador son salvavidas cuando se escribe código máquina).
Si puede habilitar los volcados del núcleo en ese sistema, simplemente ejecute el programa, déjelo colapsar, luego extraiga el volcado del núcleo de la máquina de destino en su máquina de desarrollo y cárguelo en un GDB construido para depurar la arquitectura de destino; eso debería decirle exactamente donde ocurrió el choque. Simplemente use el comando core
de GDB para cargar el archivo central en el depurador.
Para habilitar los volcados centrales en el destino:
ulimit -c unlimited
pseudo-archivos que controlan cómo se nombrará el archivo central (para ver la configuración actual, escríbales para cambiar la configuración):
/proc/sys/kernel/core_pattern /proc/sys/kernel/core_uses_pid
En mi sistema, una vez que los volcados centrales están habilitados, un programa bloqueado escribirá un archivo simplemente llamado "núcleo" en el directorio de trabajo. Probablemente sea lo suficientemente bueno para sus propósitos, pero cambiar la forma en que se nombra el archivo de volcado del núcleo le permite mantener un historial de volcados del núcleo si es necesario (tal vez para un problema más intermitente).
Recientemente experimenté un bloqueo debido a un código de estado de salida 132 (128 + 4: programa interrumpido por una señal + señal de instrucción ilegal). Así es como descubrí qué instrucción estaba causando el bloqueo.
Primero, habilité los volcados centrales:
$ ulimit -c unlimited
Curiosamente, la carpeta desde donde estaba ejecutando el binario contenía una carpeta llamada core
. Tuve que decirle a Linux que agregue el PID al volcado del núcleo:
$ sudo sysctl -w kernel.core_uses_pid=1
Luego ejecuto mi programa y tengo un núcleo llamado core.23650
. Cargué el binario y el núcleo con gdb.
$ gdb program core.23650
Una vez que ingresé a gdb, apareció la siguiente información:
Program terminated with signal SIGILL, Illegal instruction.
#0 0x00007f58e9efd019 in ?? ()
Eso significa que mi programa se bloqueó debido a una instrucción ilegal en la memoria de dirección 0x00007f58e9efd019
. Luego cambié a la disposición del asm para verificar la última instrucción ejecutada:
(gdb) layout asm
>|0x7f58e9efd019 vpmaskmovd (%r8),%ymm15,%ymm0
|0x7f58e9efd01e vpmaskmovd %ymm0,%ymm15,(%rdi)
|0x7f58e9efd023 add $0x4,%rdi
|0x7f58e9efd027 add $0x0,%rdi
Fue la instrucción vpmaskmovd
que causó el error. Aparentemente, estaba tratando de ejecutar un programa dirigido a la arquitectura AVX2 en un sistema que carece de soporte para el conjunto de instrucciones AVX2.
$ cat /proc/cpuinfo | grep avx2
Por último, confirmé que vpmaskmovd es solo una instrucción de AVX2 .