Подтвердить что ты не робот

Найти, какая инструкция сборки вызвала ошибку нелегальной инструкции без отладки

При запуске программы, написанной на сборке, я получаю ошибку Illegal instruction. Есть ли способ узнать, какая команда вызывает ошибку, без отладки, потому что машина, на которой я запущена, не имеет отладчика или какой-либо системы разработки. Другими словами, я скомпилируюсь на одной машине и запускаю другую. Я не могу проверить свою программу на машине, которую я компилирую, потому что они не поддерживают SSE4.2. Машина, на которой я запускаю программу, все равно поддерживает инструкции SSE4.2.

Я думаю, это может быть потому, что я должен сказать ассемблеру (YASM), чтобы узнать инструкции SSE4.2, так же, как мы делаем с gcc, передав ему флаг -msse4.2. Или вы считаете, что это не причина? Любая идея, как сказать YASM распознать инструкции SSE4.2?

Может быть, я должен захватить сигнал SIGILL, а затем декодировать SA_SIGINFO, чтобы узнать, какую незаконную операцию выполняет программа.

4b9b3361

Ответ 1

На самом деле часто вы получаете ошибку незаконной инструкции не потому, что ваша программа содержит недопустимый код операции, а потому, что в вашей программе есть ошибка (например, переполнение буфера), которая заставляет вашу программу переходить в случайный адрес с простыми данными или кодом но не в начале кода операции.

Ответ 2

Недавно я испытал сбой из-за кода статуса выхода 132 (128 + 4: программа, прерванная сигналом + незаконным сигналом команды). Здесь, как я выяснил, какая инструкция вызвала сбой.

Сначала я включил основные дампы:

$ ulimit -c unlimited

Интересно, что папка, откуда я запускала двоичный файл, содержала папку с именем core. Я должен был сказать Linux, чтобы добавить PID к дампу ядра:

$ sudo sysctl -w kernel.core_uses_pid=1

Затем я запустил свою программу и получил ядро ​​с именем core.23650. Я загрузил двоичный код и ядро ​​с помощью gdb.

$ gdb program core.23650

Как только я попал в gdb, он обнаружил следующую информацию:

Program terminated with signal SIGILL, Illegal instruction.
#0  0x00007f58e9efd019 in ?? ()

Это означает, что моя программа потерпела крах из-за незаконной инструкции в адресной памяти 0x00007f58e9efd019. Затем я переключился на макет asm, чтобы проверить выполненную последнюю команду:

(gdb) layout asm
>|0x7f58e9efd019  vpmaskmovd (%r8),%ymm15,%ymm0
 |0x7f58e9efd01e  vpmaskmovd %ymm0,%ymm15,(%rdi)
 |0x7f58e9efd023  add    $0x4,%rdi
 |0x7f58e9efd027  add    $0x0,%rdi

Это была инструкция vpmaskmovd, которая вызвала ошибку. По-видимому, я пытался запустить программу, предназначенную для архитектуры AVX2, в системе, в которой отсутствует поддержка набора инструкций AVX2.

$ cat /proc/cpuinfo | grep avx2

Наконец, я подтвердил vpmaskmovd - это только инструкция AVX2.

Ответ 3

Если вы можете включить дампы ядра в этой системе, просто запустите программу, дайте ей сбой, затем вытащите основной дамп с целевой машины на вашу машину разработки и загрузите ее в GDB, созданный для отладки целевой архитектуры, - которая должна скажите, где именно произошел сбой. Просто используйте команду GDB core для загрузки основного файла в отладчик.

  • Чтобы включить дампы ядра для цели:

    ulimit -c unlimited
    
  • псевдофайлы, которые управляют тем, как будет называться основной файл (cat, чтобы увидеть текущую конфигурацию, написать им, чтобы изменить конфигурацию):

    /proc/sys/kernel/core_pattern
    /proc/sys/kernel/core_uses_pid
    

В моей системе, как только основные дампы будут включены, программа сбоев напишет файл, просто названный "ядром" в рабочем каталоге. Это, вероятно, достаточно хорошо для ваших целей, но изменение имени имени ядра дампа позволяет вам сохранить историю дампов ядра, если это необходимо (возможно, для более прерывистой проблемы).

Ответ 4

Для рукописной сборки я подозреваю, что проблема управления стеком приводит к возврату в никуда. Напишите процедуру отладки распечатки, которая сохраняет каждый регистр и вставляет вызов к ней в верхней части каждой функции.

Затем вы увидите, как далеко вы достигнете...

(BTW, хороший редактор и хорошее понимание синтаксиса макросов ассемблера являются lifesavers при написании машинного кода.)

Ответ 5

Ну... Конечно, вы можете вставить трассировочные отпечатки, чтобы вы могли быстро исключить большие области кода. Когда вы это сделаете, запустите, например,

$ objdump --disassemble my-crashing-program | less

Затем перейдите к, например, функция, которую вы знаете, вызывает ошибку, и читайте код, ища все, что выглядит странно.

Я не совсем уверен, как objdump отображает незаконные инструкции, но они должны выделяться.