Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Asm: Общие вопросы > Целочисленное деление на 0 |
Автор: FCM 31.10.2009, 16:45 |
В каком регистре CPU фиксируется деление целого на ноль того же типа? |
Автор: AndNot 1.11.2009, 00:56 |
Ни в каком. При делении на ноль процессор генерирует исключение. Перехватывай INT 0. На 8086 в него передается адрес следующей за делением команды, а в 286-м и выше - адрес команды деления на ноль. |
Автор: Mikl_ 2.11.2009, 06:02 |
FCM, В операциях деления предполагается, что частное значительно меньше, чем делимое. Деление на 1, например, может также вызвать переполнение, так как частное равно делителю, поэтому рекомендуется следующее правило: если делитель – байт, то его значение должно быть меньше чем старший байт делителя (содержимое регистра ah); если делитель – двойное слово, то его значение должно быть меньше чем старшее двойное слово делителя (содержимое регистра edx). Деление на 0 сработает при div/idiv ah, div/idiv dx, div/idiv edx при любом содержимом ah/dx/edx ![]() |
Автор: FCM 11.11.2009, 09:30 |
Т.е. получается, что исключение целочисленого деления на ноль генерируется CPU в рез-те операций, которые в ассемблированном виде имеют вид " div/idiv ah, div/idiv dx, div/idiv edx при любом содержимом ah/dx/edx" и ни в каком флаге CPU это событие не отражается? (С другой стороны целочисленный overflow фиксируется CPU, но самостоятельно CPU такое исключение не генерит.) |
Автор: Mikl_ 11.11.2009, 12:58 |
FCM, Вы ответили моим ответом на свой вопрос -- какой ответ вы еще ждете? ![]() |
Автор: AndNot 16.11.2009, 15:13 | ||||
В корне неверно. При чем тут "div ah" и прочие? Тебе это привели только для примера возникновения переполнения. Пойми одну простую вещь. Делимое всегда в два раза больше делителя, а результат всегда должен быть равен, по размеру, делителю. Поэтому возможны случаи возникновения переполнения результата. Для примера раздели 600 на 2. Если использовать команду деления на БАЙТ, то возникнет переполнение (300 не уместится в регистр AL). Если же делить на СЛОВО, то переполнения не будет, поскольку 300 легко умещается в регистр AX. Выставляется флаг OVERFLOW, в регистре флагов. Но тебе он вряд ли поможет, поскольку будет доступен только в обработчике исключения, а тот по умолчанию выведет сообщение о делении на ноль и подвесит программу.
|
Автор: FCM 16.11.2009, 19:30 | ||
Так как же на самом деле?
Меня как раз все это интересует со стороны С++ и со стороны исключений (SEH, C++) |
Автор: 111u3 17.11.2009, 05:22 |
FCM, если обратится к интеловским манам то можно найти следующее; Overflow is indicated with the #DE (divide error) exception rather than with the CF flag. т.е. тебе остается ловить это исключение. |
Автор: AndNot 17.11.2009, 12:26 |
На самом деле сам факт всплытия обработчика исключения 0 свидетельствует о некорректной операции деления и проверять флаги уже нет нужды. Что и делают стандартные обработчики - просто прикрывают программу (или вешают комп). Можно конечно в обработчике проанализировать опкод и если возможно, то выполнить деление повторно, расширив разрядность операндов. Но это рискованно - еще одна ошибка и получим другое исключение - двойной отказ, а это уже серьезно, поскольку малейшая ошибка уже приведет к отключению процессора. Ну так с этого и надо начинать. Флаги тебе здесь не помогут, поскольку SEH универсален и всплывает при любом исключении, а не только при делении на ноль. Тут тебе скорее нужно маны по винде изучать, а не хард. Могу только предположить, что самым простым вариантом будет анализ опкода, что вызвал исключение. |
Автор: 111u3 17.11.2009, 15:07 |
AndNot, ну допустим если быть точным двойной отказ получить в этом случае крайне трудно - так он появляется только если во время одного исключения словили другое(вернее из другого класса) это я точно говорю (это так прописано в манах и работает на практике) ну а SEH и настроить можно равно как и другие инструменты для подобных ситуаций. |
Автор: AndNot 18.11.2009, 05:53 |
А я разве не об этом говорил? ![]() Это легче чем кажется. Чем сложнее код, тем больше вероятности наличия в нем скрытых ошибок ;) За примерами далеко ходить не надо - в соседней теме дал простейший код, но даже не заметил опечатки с условным переходом. И это обычное дело, когда явную ошибку в упор не видишь и проявится она необязательно сразу. Поэтому грамотно разрулить ситуацию в самом обработчике исключения довольно сложно (а значит рискованно) и применяют альтернативные методы, в частности обработчик только фиксирует ситуацию, а обрабатывается она уже вне обработчика (что автоматом исключает вероятность двойного отказа). Это не только безопаснее, но и более выгодно с точки зрения альтернативных путей решения ситуации. Например таким макаром в простом паскале легко обходятся деления на ноль (ну не совсем легко, приходится использовать асм, либо инлайн вставки). Но все эти альтернативные обработчики (и в паскале и SEH) сами по себе не являются обработчиками исключительных ситуаций, это скорее постобработчики, всего лишь фичи языка и ОС. |
Автор: Mikl_ 18.11.2009, 06:44 | ||
FCM, а вот так нельзя? Допустим делитель в ebx
![]() |
Автор: 111u3 18.11.2009, 08:38 |
AndNot, не совсем верно - получить 2 исключение ни во время обработки 1, а сразу после него перед заходом в обработчик и то для каждого конкретного случая есть свои оссобенности. Я вон поток #GP ловил один за другим и не разу двойного не было. а вот когда во время исключения #GP я #PG хватанул тогда проц и перезагрузился причем без захода в обработчики #GP и #PG(на двойном исключении у меня тогда ничего не стояло). + никто не заставляет автора поста лезть в обработчики idt - его ос туда не пустит(по крайней мере за так). А SEH пишут когда данное событие не должно происходить но происходит по причине "отсутствия настроения у ос рано утром". И еще не все обработчики допускают обработку во вне. респект Mikl_ - зачем гемороится с исключениями когда можно ловить 0 до деления. |