Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Dos7book

.pdf
Скачиваний:
75
Добавлен:
09.02.2015
Размер:
5.1 Mб
Скачать

Глава 7: Ассемблерные команды отладчика Debug.exe

других регистров стека, включая тот, куда помещен результат, становятся на единицу меньше.

Код

Пример

DE E(8-F)

FSUBP ST(1-7),ST

7.04-61 FSUBR – вычитание в обратном порядке

Команда FSUBR (SUBtract in Reverse order) вычитает действительное число, находящееся в верхнем регистре ST(0) стека сопроцессора или в другом регистре стека ST(1-7), если он указан в качестве первого операнда, из другого действительного числа, считываемого из ячейки памяти или из какого-либо регистра стека ST(0-7), если он указан в качестве второго операнда. Получаемая разность замещает вычитаемое в регистре ST(0) или в другом регистре стека ST(1-7), если он указан в качестве первого операнда.

1-й байт

2-й байт

Байты

Примеры

данных

 

 

 

D8

(2,6,A)(8-F)

0-2

FSUBR dword ptr [bp+si+ffff]

D8

E(0-7)

 

FSUBR ST,ST(0-7)

DC

(2,6,A)(8-F)

0-2

FSUBR qword ptr [bp+si+ffff]

DC

E(0-7)

 

FSUBR ST(1-7),ST

7.04-62 FSUBRP – обратное вычитание и выталкивание

Команда FSUBRP (SUBtract in Reverse order and Pop) вычитает действительное число, находящееся в не-верхнем регистре ST(1-7) стека сопроцессора, из другого действительного числа уменьшаемого в верхнем регистре ST(0), замещает вычитаемое в регистре ST(1-7) полученной разностью, а затем увеличивает указатель вершины стека на единицу, так что доступ к прежнему числу в регистре ST(0) утрачивается, а номера всех других регистров стека, включая тот, куда помещен результат, становятся на единицу меньше.

 

 

Код

Пример

 

 

DE E(0-7)

FSUBRP ST(1-7),ST

7.04-63

FTST – сравнение с нулем

 

Команда FTST (TeST) сравнивает с нулем число, находящееся в верхнем регистре ST(0) стека сопроцессора. Состояния флагов C3 C2 C0 в служебном

– 329 –

Глава 7: Ассемблерные команды отладчика Debug.exe

регистре SWR приводятся в соответствие с результатом сравнения. Сначала следует проверить флаг C2: если C2 = 1, то операнды несопоставимы, и проверять дальше нечего. C3 = 1 отмечает равенство, то есть нулевое значение в регистре ST(0), а C0 = 1 соответствует отрицательному числу. Если число в регистре ST(0) положительное, то все три флага C0 C2 C3 должны быть сброшены в нуль. О том, как проверять состояния флагов C0 – C3, написано в 7.04-64.

Код

Пример

D9 E4

FTST

7.04-64 FXAM – определение типа операнда

Команда FXAM (eXAMine) служит для определения типа операнда, находящегося в верхнем регистре ST(0) стека сопроцессора. Результат отображается состоянием флагов C3 C2 C1 C0 в служебном регистре SWR. Флаг C1 показывает знак операнда, а состояния флагов C3 C2 C0 нужно интерпретировать согласно следующей таблице:

C3

C2

C0

Тип операнда

0

0

0

- неизвестный формат

0

0

1

- любой не-числовой формат

0

1

0

- правильное действительное число

0

1

1

- бесконечность (тег = 10)

1

0

0

- нуль (тег = 01)

1

0

1

- регистр ST(0) пуст (тег = 11).

1

1

0

- ненормализованное число

Чтобы проанализировать полученный результат, нужно скопировать слово статуса из регистра SWR командой FSTSW (7.04-58) предпочтительно в регистр AX, а далее либо проверять его командой TEST (7.03-90), либо загрузить во флаги центрального процессора командой SAHF (7.03-77). Флаги C0 C1 C2 C3 соответствуют в слове статуса (и в регистре AX) битам 08, 09, 10, 14, поэтому в однобайтовом регистре AH они окажутся в позициях 0, 1, 2, 6. При загрузке из AH во флаги центрального процессора флаг C3 будет отображен флагом нуля ZF, флаг C2 – флагом четности PF, флаг C0 – флагом переноса CF.

Код

Пример

D9 E5

FXAM

– 330 –

Глава 7: Ассемблерные команды отладчика Debug.exe

7.04-65 FXCH – обмен содержимого регистров

Команда FXCH (eXCHange) меняет местами содержимое указанного не-верхнего регистра ST(1-7) стека сопроцессора с содержимым верхнего регистра

ST(0).

Код

Пример

D9 C(8-F)

FXCH ST(1-7)

Примечание 1: отладчик DEBUG.EXE ошибочно дизассемблирует как команду

FXCH коды "DD C(8-F)" и "DF C(8-F)".

7.04-66 FXTRACT – разделение мантиссы и степени

Команда FXTRACT (eXTRACT exponent and significand) выполняет декомпозицию действительного числа в регистре ST(0) на мантиссу и показатель степени. Мантисса записывается в регистр ST(7), который в этот момент должен быть пуст. Затем команда FXTRACT уменьшает указатель вершины стека сопроцессора на единицу, так что регистры ST(0–6) оказываются переименованы в ST(1–7), а ST(7) – в ST(0). После переименования мантисса оказывается в верхнем регистре стека сопроцессора ST(0), а показатель степени в регистре ST(1).

 

 

Код

Пример

 

 

 

D9 F4

FXTRACT

 

7.04-67

FYL2X – логарифм по произвольному основанию

Команда FYL2X вычисляет логарифм по основанию 2 от положительного числа, находящегося в верхнем регистре ST(0) стека сопроцессора, и умножает этот логарифм на число в регистре ST(1). Эта операция умножения позволяет преобразовать логарифм по основанию 2 в логарифм с любым другим основанием. Затем команда FYL2X увеличивает указатель вершины стека на единицу, так что регистр ST(1), куда помещено произведение, становится верхним регистром стека ST(0), а доступ к прежнему содержимому регистра ST(0) утрачивается. Конечный результат может быть представлен формулой ST(0)=ST(1)log(ST(0)).

Код

Пример

D9 F1

FYL2X

– 331 –

Глава 7: Ассемблерные команды отладчика Debug.exe

7.04-68 FYL2XP1 – логарифм суммы ряда

Команда FYL2XP1 вычисляет логарифм по произвольному основанию так же, как это делает команда FYL2X (7.04-67), но принимает в качестве своего аргумента

врегистре ST(0) сумму ряда, вычисляемую командой F2XM1 (7.04-01). Точность

вычислений обеспечивается только в интервале значений этого аргумента от (–1+1/SQRT2) до (–1+SQRT2), что соответствует значениям логарифма по основанию 2 от –1/2 до +1/2. Умножение логарифма по основанию 2 на множитель

врегистре ST(1) и увеличение указателя стека выполняются так же, как командой FYL2X (7.04-67). Вычисленный логарифм остается в верхнем регистре стека ST(0). Конечный результат исполнения команды FYL2XP1 выражается формулой

ST(0)=ST(1)log(1+ST(0))

Код

Пример

D9 F9

FYL2XP1

– 332 –

Глава 8 Вызовы обработчиков прерываний

Случаются ситуации, когда нормальную последовательность операций процессора приходится прерывать для исполнения неотложного запроса. При

неожиданном появлении ошибок такие запросы может инициировать сам центральный процессор. Другие устройства посылают запросы через шины IRQ 00

– IRQ 15 контроллера прерываний. Исполняемые программы тоже могут вызывать прерывания с помощью команды INT (7.03-28). В любом случае запрос прерывания повлечет исполнение специальной подпрограммы обработчика запрошенного прерывания, которая выполнит требуемое действие.

При нормальной работе компьютера в его памяти постоянно находится большое количество обработчиков прерываний. Их можно рассматривать как библиотеку стандартных подпрограмм. От умения пользоваться этой библиотекой в большой степени зависит результативность Вашего "общения" с компьютером.

Адреса вызова всех обработчиков прерываний сведены в таблицу прерываний.

При защищенном и при реальном режимах работы процессора используются разные таблицы прерываний.

Таблицу прерываний защищенного режима заполняют 8-байтовыми дескрипторами адресов вызова обработчиков прерываний и служб API. Состав комплекта обработчиков, порядок размещения дескрипторов и место расположения самой таблицы прерываний в памяти компьютера не регламентированы, все это устанавливается "по усмотрению" той программы (или операционной системы), которая организует работу компьютера в защищенном режиме.

Таблица прерываний реального режима существенно более регламентирована. Прежде всего, ей выделено строго определенное место первый килобайт оперативной памяти компьютера (от 0000:0000h до 0000:03FFh). Туда записаны не дескрипторы, а просто 4-байтовые адреса обработчиков прерываний, причем унифицированное расположение адресов вызова базовых функций BIOS в таблице

прерываний реального режима служит основой совместимости программного обеспечения во всем классе AT-совместимых компьютеров. Последнее

обстоятельство определяет важную роль таблицы прерываний реального режима и наше особое внимание к ней.

После перехода в защищенный режим таблица прерываний реального режима не пропадает, а иногда продолжает работать. Операционные системы переключают процессор обратно в реальный режим на время исполнения функций BIOS для обслуживания специфических аппаратных средств материнской платы, а также функций DOS, вызываемых программами из "окна DOS". Эти манипуляции

– 333 –

Глава 8: Вызовы обработчиков прерываний

скрыты от пользователя, но именно из-за них программы в "окне DOS" исполняются заметно медленнее, чем в реальном режиме.

Смещение для считывания адреса любого обработчика из таблицы прерываний реального режима вычисляется автоматически умножением номера прерывания на 4. Каждый адрес состоит из двух двухбайтовых слов. Их надо интерпретировать в обратном порядке: четвертый и третий байты образуют сегментный адрес, а второй и первый байты образуют смещение. К примеру, содержащиеся в таблице данные 59 F8 00 F0 соответствуют адресу вызова F000:F859h.

Любой вызов прерывания по номеру исходит из предположения, что

извлекаемый из таблицы адрес указывает на исполняемый код обработчика прерывания. Однако имеются исключения: смещения 0074h, 0078h, 007Ch, 0104h, 010Ch, 0118h в таблице прерываний реального режима содержат указатели на не-исполняемые таблицы данных, перечисленные в приложении A.12-1. Соответствующие числа 1Dh, 1Eh, 1Fh, 41h, 43h, 46h нельзя использовать в качестве номеров вызываемых прерываний.

Часть таблицы прерываний реального режима, обычно до номера 1Ch, заполняет адресами система BIOS. Ядро MS-DOS7 загружает в память свои обработчики прерываний, обычно с номерами от 20h до 2Eh, и добавляет в таблицу их адреса. Потом адреса добавляет почти каждый загружаемый драйвер. На каждом этапе ранее записанные адреса могут быть замещены, некоторые даже бывают замещены более чем дважды. Тем самым вызов прерывания оказывается "перехвачен" другим обработчиком. Наиболее часто это делается для обеспечения условного исполнения дополнительных функций, а если условие не удовлетворяется, то вызов переадресуется прежнему обработчику прерывания. В результате бывает трудно предвидеть, чей именно обработчик выполнит конкретный запрос: это будет зависеть от конфигурации загрузки Вашего компьютера. По той же причине строго распределить материалы главы 8 по разделам оказывается невозможно.

Поскольку обработка прерываний зависит от многих факторов, постольку ответственность за получаемые результаты нельзя возлагать только на MS-DOS7. Достоверность результатов приходится проверять после почти каждого вызова. Тем не менее существует большое число функций, которые стали базой для сохранения совместимости программных кодов, и которые почти наверняка можно вызвать в любом компьютере, работающем под управлением MS-DOS7. Избранные программные прерывания для вызова таких функций описаны ниже в этой главе.

– 334 –

Глава 8: Вызовы обработчиков прерываний

8.01Обработчики от BIOS (INT 00 – INT 1C)

8.01-01 INT 00 – отработка ошибки деления на нуль

Если при исполнении операций деления DIV (7.03-21) или IDIV (7.03-24) возникает переполнение в том регистре, куда должно быть помещено частное, то процессор инициирует прерывание INT 00. Устанавливаемый по умолчанию обработчик этого прерывания прекращает исполнение программы, вызвавшей ошибку, выводит на экран сообщение "Your program caused a divide overflow error..." (= Ваша программа вызвала ошибку переполнения при делении...), и затем передает управление DOS.

Примечание 1: когда вызов обработчика INT 00 происходит "по инициативе" процессора, тогда процессор оставляет в стеке в составе адреса возврата не смещение следующей команды, а смещение той самой команды деления, которая вызвала переполнение.

8.01-02 INT 01 – прерывание пошагового исполнения

Если в регистре флагов процессора установлен флаг прерывания TF (trap flag), то процессор вызывает обработчика прерывания INT 01 после исполнения каждой команды. Это позволяет осуществлять пошаговое отлаживание программ. Помимо того, все современные процессоры, начиная с модели 80386, содержат отладочные регистры (A.11-5), позволяющие вызывать обработчик прерывания INT 01 при любом обращении к заранее определенным областям памяти или к портам. Вызов обработчика прерывания INT 01 происходит также при исполнении недокументированного кода F1h.

Система BIOS по умолчанию устанавливает вместо обработчика прерывания INT 01 отсылку на команду IRET (7.03-30), которая просто возвращает управление следующей команде. Отлаживающие программы должны сами записывать в таблицу прерываний адрес своего обработчика прерывания INT 01. Тогда каждый вызов INT 01 будет останавливать исполнение отлаживаемой программы перед следующей командой и передавать управление тому процессу-отладчику, который вызвал исполнение отлаживаемой программы.

Примечание 1: флаг TF сбрасывается в нуль после исполнения каждой команды, но его исходное состояние (до сброса) записывается в стек вместе с адресом возврата при вызове прерывания INT 01. Поэтому

обработчик прерывания всегда работает при сброшенном состоянии флага TF, но когда он кончает свою работу, завершающая команда IRET восстанавливает из стека исходное состояние флага TF.

– 335 –

Глава 8: Вызовы обработчиков прерываний

Примечание 2: в качестве адреса возврата из прерывания INT 01 в стек обычно помещается адрес следующей команды, но при установке отладочных точек может быть передан адрес текущей команды. Адреса следует различать по состоянию флагов в регистре DR6 (A.11-5).

8.01-03 INT 02 – немаскируемое прерывание

Вызов обработчика прерывания INT 02 производится при поступлении на процессор сигнала по отдельной шине NMI (Non-Maskable Interrupt). В отличие от других аппаратно вызываемых прерываний, вызов по шине NMI нельзя заблокировать командой CLI (7.03-12) или битом маски в контроллере прерываний. У обработчика прерывания INT 02 особая задача: реагировать на возникновение аварийных ситуаций, например, при обнаружении сбоев памяти. Неисправимые

аварийные ситуации вызывают индикацию соответствующего сообщения и кончаются остановом компьютера. Во многих компьютерах вызов по шине NMI

поступает при появлении первых признаков пропадания электропитания для выполнения самых неотложных операций по предотвращению потери данных. В таких случаях обработчик прерывания INT 02, завершив свою миссию, обычно передает управление той программе, исполнение которой было прервано: ей дается шанс продолжить исполнение, если тревога окажется ложной, и сбой электропитания все-таки не произойдет.

Примечание 1: вызов по шине NMI можно заблокировать, если командой OUT (7.03-66) послать байт с установленным битом 7 в порт 70h CMOS-памяти BIOS, причем за этим должна последовать операция обращения к порту 71h (примечание 1 к A.14-1). Блокировка вызова NMI на момент обращения к CMOS-памяти BIOS предотвращает возможность искажения данных в ней.

8.01-04 INT 03 – точка останова

Процессор отвечает вызовом обработчика прерывания INT 03 на код CCh (7.03-28), встреченный в позиции первого байта исполняемой машинной команды. Код CCh обычно вставляют программы-отладчики для того, чтобы остановить исполнение отлаживаемой программы в заданном месте. Так действует, в частности, отладчик DEBUG.EXE.

Система BIOS по умолчанию устанавливает вместо обработчика прерывания INT 03 отсылку на команду IRET (7.03-30), которая просто возвращает управление следующей команде. Отлаживающие программы должны сами заранее внести в

– 336 –

Глава 8: Вызовы обработчиков прерываний

таблицу прерываний адрес того обработчика, которому предстоит обслуживать вызовы прерывания INT 03.

8.01-05 INT 04 – отработка ошибки переполнения

В отличие от прерывания INT 00, которое заставляет программу реагировать на ошибки математических операций сразу, прерывание INT 04 обслуживает отложенную обработку ошибок по команде INTO (7.03-29). Встретив в позиции первого байта машинной команды код CEh команды INTO, процессор проверяет флаг переполнения OF (Overflow Flag), и если он не сброшен, то вызывает обработчика прерывания INT 04. Устанавливаемый по умолчанию обработчик не останавливает исполнение, а просто возвращает управление следующей команде в той программе, из которой он вызван. Каждой программе предоставлена возможность самой установить такой обработчик прерывания INT 04, который мог бы адекватно реагировать на возникновение ошибки переполнения.

8.01-06 INT 05 – распечатка экрана

Из-за несогласованности действий фирм IBM и Intel на обработчик прерывания INT 05 оказались возложены две взаимно не связанные задачи.

В IBM-совместимых компьютерах обработчик прерывания INT 05, устанавливаемый системой BIOS, выполняет распечатку воспроизводимого на экране изображения. Процедуру распечатки запускает пользователь клавишной комбинацией Shift – PrtSc. Распознав эту комбинацию, обработчик прерывания INT 09 вызывает на исполнение обработчика прерывания INT 05. Последний сначала проверяет байт статуса принтера по адресу 0000:0500h в области служебных данных (A.12-1). Состояния байта статуса означают следующее:

00h – принтер подключен к порту LPT1 и готов к работе; 01h – принтер занят выполнением предыдущего задания; FFh – предыдущий запрос к принтеру завершился неудачно.

Если в байт статуса записан код 00h, то текущая экранная страница выводится через порт LPT1 на принтер и распечатывается.

Процессоры фирмы Intel (начиная с 80286) способны сами вызывать обработчик прерывания INT 05 в случае ошибок выхода индекса за границы массива при исполнении машинной команды BOUND. Очевидно, что в таком случае миссия обработчика прерывания INT 05 должна быть совсем иной.

Команда BOUND (62h) – одна из относительно новых команд, которые "неизвестны" отладчику DEBUG.EXE и потому не описаны в главе 7. Во избежание конфликтов каждая программа реального режима, которая использует команду

– 337 –

Глава 8: Вызовы обработчиков прерываний

BOUND, должна устанавливать свои обработчики прерываний, предотвращающие неадекватную реакцию на вызовы INT 05. У программ защищенного режима подобных проблем не бывает, потому что операционные системы формируют

таблицу прерываний защищенного режима заново и не связывают прерывание INT 05 с функцией распечатки изображений.

Примечание 1: вызов обработчика прерывания INT 05 часто подменяется вызовом

процедуры из постоянного запоминающего устройства видеокарты по нажатию клавиши PrtSc (8.01-66).

Примечание 2: при вызове INT 05 командой BOUND в качестве адреса возврата в стек помещается адрес не следующей команды, а самой команды BOUND. Такой вызов нельзя перенаправлять команде IRET, так как это приведет к "зависанию" компьютера в бесконечном цикле возвратов и вызовов.

8.01-07 INT 06 – обнаружение неизвестного кода

Центральный процессор отвечает вызовом обработчика прерывания INT 06 на попытки исполнения ошибочных команд, в частности, в случаях обнаружения

-вызова команд защищенного режима при работе в реальном режиме;

-префикса LOCK перед командами, которые не обращаются к памяти;

-регистрового операнда у команд, которые работают только с памятью;

-команд, которые процессор не способен распознать.

Посредством обработчиков прерывания INT 06 можно эмулировать исполнение команд современных процессоров на компьютере с устаревшим процессором. Однако устанавливаемый по умолчанию обработчик прерывания INT 06 просто возвращает управление следующей команде в вызывающей программе.

8.01-08 INT 07 – обслуживание функций сопроцессора

Центральный процессор вызывает обработчика прерывания INT 07 в ответ на попытки исполнения команды ESC (7.03-22) или любой команды арифметического сопроцессора (7.04), если установлен бит 02h в управляющем регистре CR0 (A.11-4). Бит 02h может быть установлен намеренно с целью вызова программы эмуляции функций сопроцессора. Некоторые системы BIOS делают это автоматически, если арифметический сопроцессор в компьютере отсутствует.

В современных компьютерах арифметический сопроцессор всегда имеется, так что эмуляция его функций не нужна. Поэтому на прерывание INT 07 может быть возложена другая миссия: принятие должных мер при наличии в сопроцессоре немаскированных исключений в момент переключения задач. С этой целью предусмотрен вызов INT 07 префиксом WAIT (7.02-05), когда одновременно

– 338 –

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]