7.2. Исключения
Источниками исключений являются три типа событий:
- генерируемые программой исключения,
- исключения машинного контроля (Pentium+),
- обнаруженные процессором ошибки в программе.
Инструкции INTO (проверка на переполнение), INT3 (контрольная точка) и BOUND (проверка границ массива) позволяют программе контролировать определенные условия в заданных точках программы и генерировать программные исключения. Следует отметить, что попытка вызвать обработчик исключения при помощи инструкции INT n (за исключением перечисленных выше инструкций) не является исключением и может привести к аварийному завершению программы, если соответствующее исключение должно генерировать код ошибки.
Процессоры Pentium+ предоставляют зависящий от реализации механизм контроля операций внутри чипа и транзакций на шине процессора, называемый машинным контролем. Если при выполнении машинного контроля возникает ошибка, генерируется исключение #18.
Исключения процессора в зависимости от способа генерации и возможности рестарта вызвавшей исключение команды подразделяются на нарушения, ловушки и аварии.
Нарушение (отказ) - это исключение, которое обнаруживается либо перед исполнением, либо во время исполнения команды. При этом процессор переходит в состояние, позволяющее осуществить рестарт команды. В качестве адреса возврата в стек обработчика заносится адрес вызвавшей исключение команды.
Ловушка возникает на границе команд сразу же после команды, вызвавшей это исключение. Значения регистров CS и EIP, заносимые в стек обработчика, указывают на очередную команду. Например, если ловушка сработала на команде JMP, то в стеке запоминаются значения регистров CS и EIP, указывающие на адресат команды JMP.
В некоторых случаях для ловушек и нарушений невозможен рестарт команды, например, если один из операндов расположен ниже текущего указателя стека, т.е. по адресу памяти меньше, чем вершина стека.
Авария не позволяет осуществить рестарт программы, и зачастую нельзя точно локализовать команду, вызвавшую это исключение. Исключения типа "авария" генерируются при обнаружении серьезных ошибок, таких как неразрешенные или несовместимые значения в системных таблицах или аппаратные сбои.
Типичным случаем аварии является исключение #8 "двойная ошибка". Двойная ошибка происходит, когда процессор пытается обработать исключение, а его обработчик генерирует еще одно исключение. Для некоторых исключений процессор не генерирует двойную ошибку, такие исключения называют "легкими": 1, 2, 3, 4, 5, 6, 7, 9, 14 и 16. Только ошибки деления (исключение #0) и сегментные исключения (10, 11, 12, 13), называемые "тяжелыми", могут вызвать двойную ошибку. Таким образом, получение исключения "неприсутствие сегмента" во время обработки исключения отладки не приведет к двойной ошибке, в то время как ошибка сегмента, происходящая во время обработки ошибки деления на нуль, приведет к исключению #8.
Если при попытке вызвать обработчик исключения #8 возникает ошибка, процессор переходит в режим отключения (shutdown mode). Вывести из этого режима процессор могут только аппаратные сигналы: NMI#, SMI#, RESET# или INIT#. Обычно чипсет, обнаружив на шине процессора цикл отключения, инициирует аппаратный сброс.
Если на границе инструкции обнаруживается, что требуется обработка более одного прерывания или исключения, процессор обрабатывает прерывание или исключение с наивысшим приоритетом. Исключения с низким приоритетом снимаются, а прерывания с низким приоритетом откладываются. Снятые исключения могут быть потом снова сгенерированы при возврате из обработчика.
Приоритеты событий:
Приоритет | Описание |
---|---|
1 | Аппаратный сброс (RESET#) и машинный контроль (#18) |
2 | Ловушка при переключении задач (#1) |
3 | Внешний сигнал (INIT#, SMI# и др.) |
4 | Контрольная точка (#3) и ловушка отладки (#1) |
5 | Аппаратные прерывания (NMI#, INTR#) |
6 | Нарушения, обнаруженные при предвыборке очередной инструкции:
|
7 | Нарушения, обнаруженные при декодировании очередной инструкции:
|
8 | Нарушения, обнаруженные при исполнении инструкции (все остальные) |
Назначение прерываний и исключений:
номер | описание | тип | возможен рестарт | код ошибки | источник исключения |
---|---|---|---|---|---|
0 | Ошибка деления | нарушение | да | нет | DIV, IDIV |
1 | Отладка | нарушение / ловушка | да | нет | любая команда |
2 | NMI | прерывание | со след. команды | нет | сигнал NMI |
3 | Контрольная точка | ловушка | со след. команды | нет | INT3 |
4 | Переполнение | ловушка | со след. команды | нет | INTO |
5 | Нарушение границы массива | нарушение | да | нет | BOUND |
6 | Недействительный код операции | нарушение | да | нет | Инструкция UD2 (P6+), неверный код операции, неверный операнд, выполнение спец. команд в RM, неверное использование префикса LOCK |
7 | Сопроцессор отсутствует | нарушение | да | нет | ESC, WAIT |
8 | Двойное нарушение | авария | нет | 0 | Если при обработке тяжелого исключения1 или страничного нарушения возникает еще одно тяжелое исключение. |
9 | Нарушение сегмента для сопроцессора2 | нарушение | да | нет | ESC, WAIT |
10 | Недействительный TSS | нарушение | да | есть | JMP, CALL, IRET, INT |
11 | Неприсутствие сегмента | нарушение | да | есть | при попытке загрузить сегментный регистр или LDTR |
12 | Нарушение стека | нарушение | да | есть | операции со стеком, загрузка SS |
13 | Нарушение общей защиты | нарушение / ловушка | да | есть | любое обращение к памяти или проверка защиты |
14 | Страничное нарушение | нарушение | да | есть | любое обращение к памяти |
15 | резерв | ||||
16 | Ошибка сопроцессора | нарушение | да | нет | ESC, WAIT |
17 | Контроль выравнивания3 | нарушение | да | 0 | любое обращение к данным в памяти |
18 | Машинный контроль4 | авария | стоп | зависит от МП | зависит от МП |
19 | Ошибка SIMD5 | нарушение | да | нет | инструкция SSE или SSE2 |
20-31 | резерв | ||||
32-255 | Определяемые пользователем прерывания | прерывание | да | - | INT n или внешний сигнал |
1К тяжелым относят исключения 0, 10, 11, 12, 13. 2Это исключение генерируется только МП 80386. В поздних процессорах - зарезервировано. 3Используется в i486 и выше. 4Используется в Pentium и выше. 5Используется в Pentium-III и выше. |