Нужно ли оставлять код ошибки в стеке для исключений, которые помещают туда код ошибки?
Как уже упоминалось, вы должны сделать либо:
pop %eax
/* Do something with %eax */
iret
Или, если вы хотите игнорировать код ошибки:
add $4, %esp
iret
Если вы этого не сделаете, iret
будет интерпретировать код ошибки как новый CS, и вы, вероятно, получите ошибку общей защиты, как указано в: Почему iret из обработчика ошибок страницы генерирует прерывание 13 (общая ошибка защиты) и код ошибки 0x18?
Минимальный Работающий обработчик этой страницы , который я создал, чтобы проиллюстрировать это. Попробуйте закомментировать pop
и посмотрите, как он взорвется.
Сравните вышеприведенное с Исключением ошибки деления , которое не выводит стек.
Обратите внимание, что если вы просто сделаете int $14
, лишний байт не будет выдвинут: это происходит только с фактическим исключением.
Руководство Intel Том 3 Руководство по системному программированию - 325384-056RU Сентябрь 2015 г. Таблица 6-1. Столбец «Исключения и прерывания защищенного режима» «Код ошибки» содержит список прерываний, которые выдвигают код ошибки или нет.
38.9.2.2 «Коды ошибок страницы» объясняет, что означает ошибка.
Хороший способ справиться с этим - поместить в стек фиктивный код ошибки 0
для прерываний, которые этого не делают, чтобы сделать вещи единообразными. Учебник Джеймса Моллоя делает именно это .
Кажется, что ядро Linux 4.2 делает нечто подобное. В arch / x86 / entry / entry64.S он моделирует прерывания с has_error_code
:
trace_idtentry page_fault do_page_fault has_error_code=1
и затем использует его в том же файле, что и:
.ifeq \has_error_code
pushq $-1 /* ORIG_RAX: no syscall to restart */
.endif
, который делает толчок, когда has_error_code=0
.