Почему инструкция x86 называется ud2, а не просто ud

· Технологии
Реймонд Чен из Microsoft разбирает, откуда в архитектуре x86 взялась «двойка» в названии инструкции, гарантированно вызывающей исключение недопустимого кода.

Разбирая аварийный дамп или изучая вывод компилятора, можно наткнуться на инструкцию ud2. Реймонд Чен в блоге The Old New Thing объясняет, что это архитектурно неопределённая инструкция, которая гарантированно возбуждает исключение «недопустимый код операции». Компиляторы вставляют её, чтобы пометить недостижимый код: например, если функция, помеченная [[noreturn]], всё же вернёт управление, программа аварийно завершится, а не свалится в исполнение случайных байтов.

Остаётся вопрос, вынесенный в заголовок: почему ud2, а не просто ud? Существовали ли ud0 и ud1, и чем они провинились?

Как всё началось

Поначалу никакой штатной «недопустимой» инструкции в x86 не было. Тем, кому требовалось надёжно спровоцировать исключение, приходилось искать подходящую последовательность байтов. Кто-то обнаружил, что этим свойством обладает 0F FF, кто-то другой — что и 0F B9 ведёт себя так же. Обе последовательности внутренне декодировались так, будто принимают два операнда, но операнды не использовались: исключение возбуждалось раньше. Так сложились два лагеря приверженцев, причём без всякого противостояния — работали оба приёма.

Затем Intel выпустила новый процессор, и часть программ перестала запускаться. После долгих разбирательств выяснилось: код полагался на то, что 0F FF — недопустимая инструкция, а на новом чипе поведение изменилось. Аналогичная история приключилась и с 0F B9. Чен видит здесь классическую иллюстрацию закона Хайрума: при достаточном числе пользователей на любую наблюдаемую особенность поведения кто-нибудь непременно начнёт полагаться.

Появление ud2

Осознав, что разработчикам нужен надёжный способ вызвать исключение, Intel узаконила его, добавив постоянно недопустимую инструкцию ud2. Задним числом вариант 0F FF назвали ud0, вариант 0F B9ud1, а рекомендованным осталось ud2.

Преимущество ud2 в том, что это двухбайтовая инструкция без операндов — не нужно возиться со «случайными» декодированными, но неиспользуемыми источником и приёмником. И это важнее, чем кажется: даже если процессор не использует лишние байты операнда, он их всё равно декодирует. Если декодирование заедет на отсутствующую страницу памяти, вы получите не исключение недопустимого кода, а ошибку доступа. А некоторые старые процессоры возбуждали исключение сразу после 0F FF, не проверяя остаток, — так что в зависимости от расположения инструкции результат мог оказаться разным.

Вывод прост: ud2 ведёт себя предсказуемо и гарантирован архитектурой — на него и стоит опираться.


Источник: Hacker News

Комментарии

Войдите, чтобы комментировать.

  • Пока нет комментариев.