Я думаю, вы испортили свой стек.Вы должны быть очень осторожны с тем, что вы делаете со своим стеком в обработчике прерываний.В этом случае кажется, что вы делаете следующее: -
Push-код ошибки (может быть выполнен CPU) Push-регистры Push-сегменты reg
добавляют 0x48 к указателю стека, чтобы свернуть стекобратный путь, чтобы он указывал на код ошибки.
вызовите вашу функцию C
В сущности, это «освобождение» части вашего стека, в которой хранятся регистры сегментов. Фактически вам даже не нужно беспокоиться офункция C вообще, потому что адрес возврата помещается в стек по команде вызова и сносит ваши записи о ds и es еще до того, как вы дойдете до C-вызова.Когда вы возвращаетесь из вызова C, вы пытаетесь привести в порядок стек вызовов, но вы не понимаете его совершенно правильно - отчасти потому, что вы уже испортили его, а отчасти потому, что вы не очищаете стек послевызов функции (при условии, что обработчик использует соглашение о вызовах _cdecl).
Это заставляет вас выдвигать поддельное значение для ds.Когда вы загружаете это в ds, процессор проверяет значение по GDT и обнаруживает, что оно недопустимо.В этот момент он поднимает GPF (исключение 13), который вы отправляете.Это в определенной степени восстанавливает стек (процессор присматривает за SS) и оставляет старое значение ds установленным, так что вы фактически никогда не меняете ds, что позволяет вам снова запускать printf.
Вы должны быть намного более осторожными при выравнивании стека, и всякий раз, когда вы добавляете к указателю стека, как вы делаете, вы должны учитывать, что данные, которые были в этом диапазоне, уходили навсегда, потому что либо следующий парень, либовозможно, неожиданное прерывание сбивает вас с толку.