Undefined instruction.
Набор команд x86-совместимых процессоров за годы эволюции набрал немалое количество всякой экзотики. Один из примеров такой экзотики – инструкция UD2. Задача этой инструкции состоит в том, чтобы… быть несуществующей инструкцией. Выполнение UD2 всегда приводит к генерации исключения «Invalid opcode». Отличие UD2 от любой другой несуществующей инструкции в том, что эта инструкция гарантированно не станет корректной инструкцией в будущем.
Интересна мнемоника этой команды. Суффикс «2» подразумевает, что есть еще и как минимум UD1 или UD, но ни Intel ни AMD не описывают такой инструкцию. Поиск по интернету показывает, что некоторые компиляторы поддерживают (или поддерживали) три варианта этой команды:
- UD0 (0F FF)
- UD1 или UD2B (0F B9)
- UD2 или UD2A (0F 0B)
Ни одна из этих команд не является корректной командой, но все они по-разному описывается в документации Intel и AMD. Инструкции UD0 (0F FF) соответствует пустая ячейка в таблице двухбайтных команд. Т.е. эта инструкция не определена сейчас, но может быть переопределена в будущем.
Мнемоника UD1 не упоминается в “Programmer’s Manual”, но комбинация 0F B9 указана в таблице двухбайтных инструкций как «Undefined instruction opcode» и, соответственно, она не может быть переопределена впоследствии. Кроме этого указывается, что за 0F B9 должен следовать ModRM байт, определяющий расширение этой инструкции. Впрочем, все возможные комбинации ModRM байта в сочетании с кодом инструкции 0F B9 всё равно объявлены как «Undefined instruction». Закавыка правда в том, что в примерах, найденных в интернете, за 0F B9 не следует ничего. Кому верить – не понятно.
UD2, похоже, наиболее полно описанный вариант «неопределенной инструкции». Она занимает ровно два байта, её мнемоника легализована и она прочно занимает свою ячейку в таблице двухбайтных команд.
Кто бы ещё привёл пример, где эта команда применяется? Понятно, что в целях тестирования – ну а конкретнее?
Прочитал тут недавно:
http://ru.wikipedia.org/wiki/MC_Hammer
подтверждение здесь:
http://www.sandpile.org/ia32/cpuid.htm
В процессорах фирмы AMD, таких как Athlon64 и Opteron, функция Cpuid 0×8FFFFFFF возвращает в регистрах EAX, EBX, ECX и EDX строку «IT’S HAMMER TIME».
2Alexander: могу только предположить, что инструкцию можно использовать для заполнения (или предварения) памяти, в которую в нормальных условиях нельзя передавать управление. Ну и само собой, для проверки того, насколько корректно ОС обрабатывает соответствующее исключение.
Еще один вариант – получить разное поведение в зависимости от того, какой обработчик обрабатывает STATUS_INVALID_OPCODE в данный момент. В обработчике всегда можно продолжить выполнение кода после сбойной инструкции.
Для этого используется 0xCC == int3. Имеет важные преимущества – длина один байт, так что передача управления по любому адресу приведет к исполнению именно этой инструкции – в отличии от двухбайтной. Второе преимущество – выделенный вектор исключения (№3), на котором сидит либо kernel mode debugger, либо заглушка, отдающая исключение user-mode debugger или крэшающая систему в зависимости от режима фаултнувшегося кода. В общем, инструкция задуманная как помощь отладчикам.
А насчет проверки корректности обработки исключения OS – так еще важнее проверить корректность генерации исключения процессором. Недаром эта инструкция появилась в эпоху спекулятивных процессоров, исключение для которых это что-то типа длинной веревки, дергающей за то, к чему привязана не сразу, а в середине полета
MS использовала в Win95 в качестве системного вызова из virtual 8086 режима запрещенную (и бессмысленную) в нем инструкцию AVPL. Насколько я читал, такая техника использования запрещенных инструкций в качестве системных вызовов идет еще из OS/360. Делать что-то явно запрещенное в качестве системного вызова, типа DOS-овского int 21h в 32х битной OS означает наткнуться на #GP, обработчик которого и так очень перегружен – практически только ошибки страниц через него не проходят. А исключение #UD достаточно редко – либо оно окажется валидным системным вызовом, либо последним в жизни неосторожного процесса. Ну и все хорошо для авторов OS, важно только чтобы инвалидный опкод не стал внезапно разрешенным.
И чтобы положить конец этим извращениям придумали syscall/sysret.
Не забываем про sysenter/sysexit
Спасибо за информацию автору и комментаторам