Зубков С. В.
О УДК 004.438Assembler ББК 32.973.26-018.1 3-91
Зубков С. В.
3-91 Assembler для DOS, Windows и UNIX / Зубков Сергей Владимирович. - 3-е изд., стер. - М. : ДМК Пресс ;
СПб. : Питер, 2004. - с. : ил. (Серия Для ISBN 5-94074-259-9 В книге освещаются все аспекты современного программирования на ассембле ре для DOS, Windows и UNIX (Solaris, Linux и включая созда ние резидентных программ и драйверов, прямое программирование периферий ных устройств, управление защищенным режимом и многое другое. Детально рассматривается архитектура процессоров Intel вплоть до Pentium III. Все главы иллюстрируются подробными примерами работоспособных программ.
Издание ориентировано как на профессионалов, так и на начинающих без опыта программирования.
Все права защищены. Любая часть этой книги не может быть воспроизведена в какой бы то ни было форме и какими бы то ни было средствами без письменного разреше ния владельцев авторских прав.
Материал, изложенный в данной книге, многократно проверен. Но, поскольку вероятность на личия технических и просто человеческих ошибок все равно существует, издательство не может гарантировать абсолютную точность и правильность приводимых сведений. В связи с этим изда тельство не несет ответственности за возможные ошибки, связанные с использованием книги.
й
Зубков С. В.
, ISBN 5-94074-259-9 й ДМК Пресс, Зубков Сергей Владимирович Assembler для DOS, Windows и UNIX Главный редактор Захаров И. М.
editor-in-chief@dmkpress.ru Научный редактор Шалаев В.
Литературный редактор Космачева Н. А.
Верстка В. X.
Дизайн обложки Антонов А. И.
Подписано в печать 12.11.2003. Формат Гарнитура Петербург. Печать офсетная.
Усл. печ. л. 49,4. Тираж 3000 экз. Зак. № Издательство ДМК Пресс, 105023, Москва, пл. Журавлева, 2/ Web-сайт издательства: www.dmk.ru Internet-магазин: www.abook.ru, Ордена Трудового Красного Знамени Чеховский полиграфический комбинат Министерства Российской Федерации по делам печати, телерадиовещания и средств массовых коммуникаций 142300, г. Чехов Московской области Тел. (272) факс (272) 62- Введение Глава Предварительные сведения Что нужно для работы с ассемблером 1.2. Представление данных в компьютерах Двоичная система счисления 1.2.2. Биты, байты и слова счисления 1.2.4. Числа со знаком 1.2.5. Логические операции 1.2.6. Коды символов 1.2.7. Организация памяти Глава 2. Процессоры в реальном режиме Регистры процессора 2.1.1. Регистры общего назначения 2.1.2. Сегментные регистры 2.1.3. Стек 2.1.4. Регистр флагов 2.2. Способы адресации 2.2.1. Регистровая адресация 2.2.2. Непосредственная адресация 2.2.3. Прямая адресация 2.2.4. адресация 2.2.5. Адресация по базе со сдвигом 2.2.6. адресация с масштабированием 2.2.7. Адресация по базе с индексированием 2.2.8. Адресация по базе с индексированием и масштабированием 2.3. Основные непривилегированные команды Пересылка данных 2.3.2. Двоичная арифметика 2.3.3. Десятичная арифметика для Windows и 2.3.4. Логические операции 2.3.5. Сдвиговые операции 2.3.6. Операции над битами и байтами 2.3.7. Команды передачи управления 2.3.8. Строковые операции 2.3.9. Управление флагами 2.3.10. Загрузка сегментных регистров Другие команды 2.4. Числа с плавающей запятой Типы 2.4.2. Регистры FPU 2.4.3. Исключения 2.4.4. Команды пересылки данных FPU 2.4.5. Базовая арифметика 2.4.6. Команды сравнения FPU 2.4.7. Трансцендентные операции FPU 2.4.8. Константы FPU 2.4.9. Команды управления FPU 2.5. Расширение IAMMX 2.5.1. Регистры ММХ Типы ММХ 2.5.3. Команды пересылки данных ММХ 2.5.4. Команды преобразования типов ММХ 2.5.5. Арифметические операции ММХ 2.5.6. Команды сравнения ММХ 2.5.7. Логические операции ММХ 2.5.8. Сдвиговые операции ММХ 2.5.9. Команды управления состоянием ММХ.'. 2.5.10. Расширение 3D 2.6. Расширение SSE SSE Типы SSE 2.6.3. Команды SSE 2.6.4. Определение поддержки SSE 2.6.5. Исключения Глава 3. Директивы и операторы 3.1. Структура программы 3.2. Директивы распределения памяти Псевдокоманды определения переменных 3.2.2. Структуры Содержание 3.3. Организация программы Сегменты 3.3.2. Модели памяти и упрощенные директивы определения сегментов 3.3.3. Порядок загрузки сегментов 3.3.4. Процедуры 3.3.5. Конец программы 3.3.6. Директивы задания набора допустимых команд 3.3.7. Директивы управления программным счетчиком 3.3.8. Глобальные объявления 3.3.9. Условное ассемблирование 3.4. Выражения 3.5. Макроопределения 3.5.1. Блоки повторений 3.5.2. Макрооператоры 3.5.3. Другие директивы, используемые в макроопределениях 3.6. Другие директивы Управление файлами 3.6.2. Управление листингом :
3.6.3. Комментарии 4. Основы программирования для MS DOS 4.1. Программа типа COM 4.2. Программа типа EXE 4.3. Вывод на экран в текстовом режиме Средства DOS 4.3.2. Средства BIOS 4.3.3. Прямая работас видеопамятью 4.4. Ввод с клавиатуры 4.4.1. Средства DOS 4.4.2. Средства BIOS 4.5. Графические видеорежимы 4.5.1. Работа с VGA-режимами 4.5.2. Работа с SVGA-режимами 4.6. Работас мышью 4.7. Другие устройства 4.7.1. Системный таймер 4.7.2. Последовательный порт 4.7.3. Параллельный порт для Windows и 4.8. Работа с файлами Создание и открытие файлов 4.8.2. Чтение и запись в файл 4.8.3. Закрытие и удаление файла 4.8.4. Поиск файлов 4.8.5. Управление файловой системой 4.9. Управление памятью 4.9.1. Обычная память : 4.9.2. Область памяти UMB 4.9.3. Область памяти 4.9.4. Интерфейс EMS 4.9.5. XMS 4.10. Загрузка и выполнение программ Командные параметры и переменные среды Глава 5. Более сложные приемы.. 5.1. Управляющие структуры Структуры 5.1.2. Структуры CASE 5.1.3. Конечные автоматы 5.1.4. Циклы 5.2. Процедуры и функции 5.2.1. Передача параметров 5.2.2. Локальные переменные 5.3. Вложенные процедуры 5.3.1. Вложенные процедуры со статическими ссылками 5.3.2. Вложенные процедуры с дисплеями 5.4. Целочисленная арифметика повышенной точности Сложение и вычитание 5.4.2. Сравнение 5.4.3. Умножение 5.4.4. Деление 5.5. Вычисления с фиксированной запятой 5.5.1. Сложение и вычитание 5.5.2. Умножение 5.5.3. Деление 5.5.4. Трансцендентные функции 5.6. Вычисления с плавающей запятой Содержание 5.7. Популярные алгоритмы 5.7.1. Генераторы случайных чисел 5.7.2. Сортировки 5.8. Перехват прерываний 5.8.1. Обработчики прерываний 5.8.2. Прерывания от внешних устройств 5.8.3. Повторная 5.9. Резидентные программы 5.9.1. Пассивная резидентная программа 5.9.2. Мультиплексорное прерывание 5.9.3. Выгрузка резидентной программы из памяти 5.9.4. Полурезидентные программы 5.9.5. Взаимодействие между процессами 5.10. Программирование на уровне портов ввода-вывода Клавиатура 5.10.2. Последовательный порт 5.10.3. Параллельный порт 5.10.4. Видеоадаптеры VGA 5.10.5. Таймер 5.10.6. Динамик Часы реального времени и CMOS-память 5.10.8. Звуковые платы 5.10.9. Контроллер 5.10.10. Контроллер прерываний Джойстик Драйверы устройств в DOS Символьные устройства 5.11.2. Блочные устройства Глава 6. Программирование в защищенном режиме... Адресация в защищенном режиме 6.2. VCPI 6.3. Интерфейс DPMI 6.3.1. Переключение в защищенный режим 6.3.2. Функции DPMI управления дескрипторами 6.3.3. Передача управления между режимами в DPMI 6.3.4. Обработчики прерываний 6.3.5. Пример программы. Assembler для DOS, Windows и 6.4. Расширители DOS Способы объединения программы с расширителем 6.4.2. Управление памятью в DPMI 6.4.3. Вывод на экран через линейный кадровый Глава 7. Программирование для Windows 95/NT 7.1. Первая программа 7.2. Консольные приложения 7.3. Графические приложения 7.3.1. типа MessageBox Окна 7.3.3. Меню 7.3.4. Диалоги 7.3.5. Полноценное приложение 7.4. Динамические библиотеки 7.5. Драйверы Глава 8. Ассемблер и языки высокого уровня 8.1. Передача параметров 8.1.1. Конвенция Pascal 8.1.2. Конвенция С Смешанные конвенции 8.2. Искажение имен 8.3. Встроенный ассемблер 8.3.1. Ассемблер, встроенный в 8.3.2. Ассемблер, встроенный в С Глава 9. Оптимизация Высокоуровневая оптимизация 9.2. Оптимизация на среднем уровне 9.2.1. Вычисление констант вне цикла 9.2.2. Перенос проверки условия в конец цикла 9.2.3. Выполнение задом наперед 9.2.4. Разворачивание циклов 9.3. Низкоуровневая оптимизация Общие принципы низкоуровневой оптимизации 9.3.2. Особенности архитектуры Pentium и Pentium MMX 9.3.3. Особенности архитектуры процессоров Pentium Pro и Pentium II Содержание Глава 10. Процессоры Intel в защищенном режиме... Регистры Системные флаги 10.1.2. Регистры управления памятью 10.1.3. Регистры управления процессором 10.1.4. Отладочные регистры 10.1.5. Машинно-специфичные регистры 10.2. Системные и привилегированные команды 10.3. Вход и выход из защищенного режима 10.4. Сегментная адресация Модель памяти в защищенном режиме 10.4.2. Селектор 10.4.3. Дескрипторы 10.4.4. Пример программы 10.4.5. Нереальный режим....: 10.5. Обработка прерываний и исключений 10.6. Страничная адресация 10.7. Механизм защиты 10.7.1. Проверка лимитов 10.7.2. Проверка типа сегмента 10.7.3. Проверка привилегий 10.7.4. Выполнение привилегированных команд 10.7.5. Защита на уровне 10.8. Управление задачами Сегмент состояния задачи 10.8.2. Переключение задач 10.9. Режим виртуального 8086 10.9.1. Прерывания в V86 10.9.2. Ввод-вывод в V86 Глава Программирование на ассемблере в среде Синтаксис AT&T Основные правила Запись команд Адресация Операторы ассемблера Префиксные, или унарные, операторы Инфиксные, или бинарные, операторы Assembler для DOS, Windows и UNIX Директивы ассемблера Директивы определения данных Директивы управления символами 11.3.3. Директивы определения секций Директивы управления разрядностью Директивы управления программным указателем Директивы управления листингом г. Директивы управления ассемблированием 11.3.8. Блоки повторения 11.3.9. Макроопределения Программирование с использованием Программирование без использования libc Переносимая программа для UNIX Заключение Приложение Таблицы символов Символы ASCII 2. Управляющие символы ASCII 3. Кодировки второй половины ASCII 4. Коды символов расширенного ASCII 5. клавиатуры Приложение 2. Команды Intel 80x86 Общая информация о кодах команд Общий формат команды процессора Intel 1.2. Значения полей кода команды 1.3. Значения поля ModRM 1.4. Значения поля SIB : 2. Общая информация о скоростях выполнения 3. Префиксы 4. Команды процессоров Intel 8088 - Pentium III Используемые сокращения ГОССарИЙ Алфавитный указатель Введение Первый вопрос, который задает себе человек, впервые услышавший об ассембле ре, - а зачем он, собственно, нужен? Особенно теперь, когда все пишут на Delphi или других языках высокого уровня? Действительно очень многое можно создать на С, но ни один язык, даже такой популярный, не может претендовать на то, чтобы на нем можно было написать абсолютно все.
Итак, на ассемблере пишут:
все, что требует скорости выполнения: основные компоненты компьютерных игр, ядра операционных систем реального времени и просто критические участки программ;
все, что взаимодействует с внешними устройствами: драйверы, программы, работающие напрямую с портами, звуковыми и видеоплатами;
все, что использует полностью возможности процессора: ядра многозадачных операционных систем, DPMI-серверы и вообще любые программы, перево дящие процессор в защищенный режим;
все, что возможности операционной системы: виру сы и антивирусы, защиты от несанкционированного доступа, программы, об ходящие эти защиты, и программы, защищающиеся от данных программ;
и многое другое. Стоит познакомиться с ассемблером поближе, как оказыва ется, что большую часть из того, что обычно пишут на языках высокого уров ня, лучше, проще и быстрее написать на ассемблере.
Как же так? - спросите вы, прочитав последний пункт. - Ведь всем известно, что ассемблер - неудобный язык, и писать на нем долго и сложно! Попробуем перечислить мотивы, которые обычно выдвигаются в доказательство того, что ассемблер не нужен.
Говорят, что ассемблер трудно выучить. Любой язык программирования трудно выучить. Легко выучить С или Delphi после Pascal, потому что они похожи. А по пробуйте освоить Lisp, Forth или Prolog, и окажется, что ассемблер в действитель ности даже проще, чем любой абсолютно незнакомый язык программирования.
Говорят, что программы на ассемблере трудно понять. Разумеется, на ассембле ре легко написать неудобочитаемую программу... точно так же, как и на любом дру гом языке! Если вы знаете язык и если автор программы не старался ее запутать, то понять программу будет не сложнее, чем если бы она была написана на Basic.
Говорят, что программы на ассемблере трудно Программы на ассемблере легко отлаживать - опять же при условии, что вы знаете язык. Более того, знание ассемблера часто помогает отлаживать программы на других языках, потому что оно дает представление о том, как на самом деле функционирует ком пьютер и что происходит при выполнении команд языка высокого уровня.
для DOS, Windows и Говорят, что современные такие быстрые, что ассемблер больше не нужен. Каким бы быстрым ни был компьютер, пользователю всегда хочется большей скорости, иначе не наблюдалось бы постоянного спроса на еще более мощные компьютеры. И самой быстрой программой на данном оборудовании все гда будет программа, написанная на ассемблере.
Говорят, что на ассемблере сложно. В этом есть доля правды. Очень часто авторы программ на ассемблере лизобретают велосипеды, программируя заново элементарные процедуры типа форматированного вывода на экран генератора случайных чисел, в то время как программисты на С просто вызывают функции. Библиотеки таких функций существуют и для ассемблера, но они не стандартизированы и не распространяются вместе с компиляторами.
Говорят, что программы на ассемблере не переносятся. Действительно, в этом заключается самая сильная и самая слабая сторона ассемблера. Во-первых, благо даря этой особенности программы на ассемблере используют возможности ком пьютера с наибольшей полнотой;
во-вторых, эти же программы не будут работать на другом компьютере. Стоит заметить, что и другие языки часто не гарантируют переносимости - та же программа на С, например, под Windows 95, не скомпилируется ни на Macintosh, ни на SGI.
Далеко не всё, что говорят об ассемблере, является правдой, и далеко не все, кто говорят об ассемблере, на самом деле знают его. Но даже ярые согласятся с тем, что программы на ассемблере Ч самые быстрые, самые малень кие и могут то, что не под силу программам, созданным на любом другом языке программирования.
Эта книга рассчитана на читателей с разным уровнем подготовки - как на на чинающих, которые хотят познакомиться с ассемблером серьезно или желают лишь написать пару программ, выполняющих необычные трюки с компьютером, так и на профессиональных программистов, которые тоже найдут здесь интерес ные разделы.
Почти все, что надо знать об ассемблере, где-нибудь да объяснено, а также объяснено многое из того, что не заботит большинство программистов. С одной стороны, чтобы написать простую программу, не нужно знать язык и устройство процессора в совершенстве, но, с другой стороны, по-настоящему серьезная рабо та потребует и основательной подготовки. Уровень сложности в этой книге воз растает от начала к концу, но в первой ее половине отдельные абзацы помечены специальной которая означает, что данный абзац лучше про пустить при чтении, если вы знакомитесь с ассемблером впервые. Впрочем, если у вас есть время и желание выучить ассемблер с нуля, - читайте все по порядку.
Если же вам хочется немедленно приступить к написанию программ, начните сразу с главы 4, но будьте готовы к тому, что иногда придется возвращаться к пре дыдущим главам за более подробным описанием тех или иных команд. И нако нец, если вам уже доводилось программировать на ассемблере, - выбирайте то, что интересно.
Глава Предварительные сведения 1.1. Что нужно для работы с ассемблером Прежде всего вам потребуется ассемблер. Здесь самое время сказать, что язык программирования, которым мы собираемся заниматься, называется лязык ассем блера (assembly language). Ассемблер - это программа, которая переводит текст с языка, понятного человеку, в язык, понятный процессору, то есть говорят, что она переводит язык ассемблера в машинный Однако сначала в повседневной речи, а затем и в литературе слово лассемблер стало также и названием самого языка программирования. Понятно, что, когда говорят программа на ассемблере, имеют в виду язык, а когда говорят макроассемблер версии 6.13, имеют в виду программу. Вместе с ассемблером обязательно должна быть еще одна программа компоновщик (linker), которая и создает исполнимые файлы из одного или несколь ких объектных модулей, полученных после запуска ассемблера. Помимо этого для разных целей могут потребоваться дополнительные вспомогательные программы компиляторы ресурсов, расширители DOS и тому подобное (см. табл. 1).
Трудно говорить о том, продукция какой из трех компаний (Borland, Microsoft или Watcom) однозначно лучше. С точки зрения удобства компиляции TASM луч ше подходит для создания 16-битных программ для DOS, WASM - для 32-бит ных программ для DOS, MASM - для Windows. С точки зрения удобства про граммирования развитость языковых средств растет в ряду WASM - MASM TASM. Все примеры программ в этой книге построены так, что можно использо вать любой из этих компиляторов.
Таблица Ассемблеры и программы Microsoft Borland Watcom DOS, или ml, tasm бит link (16 бит) tasm masm или ml, DOS, tlink wlink link (32 бита) и dosx 32 бита wdosx dos4gw, pmodew, zrdx или link (16 бит) и dos или dos32 wdosx masm386 или ml tasm wasm Windows link (32 бита) tlink32 wlink EXE brcc32 wrc tasm wasm Windows masm386 или ml tlink32 wlink DLL link (32 бита) implib Предварительные сведения Разумеется, существуют и другие компиляторы, например бесплатно распрос траняемый в сети Internet NASM или условно бесплатный А86, но пользоваться ими проще, если вы уже знаете или макроассемблер. Бесплатно распрост раняемый GNU ассемблер, gas, вообще использует совершенно непохожий син таксис, который будет рассмотрен в главе рассказывающей о программирова нии для UNIX.
Во всех программах встречаются ошибки. Если вы собираетесь не только упражняться на примерах из книги, но и написать что-то свое, то вам рано или поздно обязательно потребуется отладчик. Кроме поиска ошибок отладчики иног да применяют и для того, чтобы исследовать работу существующих программ. Бе зусловно, самый мощный отладчик на сегодняшний день - от Software. Это фактически единственный отладчик для Windows позволя ющий исследовать все - от ядра Windows до программ на поддерживающий одновременно 16- и 32-битный код и т. п. Другие популярные отладчики, распро страняемые вместе с соответствующими ассемблерами, - Codeview (MS), Turbo Debugger (Borland) и Watcom Debugger (Watcom).
Еще одна особенность ассемблера, отличающая его от всех остальных языков программирования, - возможность дизассемблирования. То есть, имея исполняе мый файл, с помощью специальной программы (дизассемблера) почти всегда мож но получить исходный текст на ассемблере. Например, можно дизассемблировать BIOS вашего компьютера и узнать, как выполняется переключение видеорежимов, или драйвер для DOS, чтобы написать такой же для Windows. Дизассемблер не является необходимой программой, но иногда очень удобно иметь его под рукой.
Лучшие дизассемблеры на сегодняшний день - Sourcer от V Communications и И наконец, последняя необязательная, но весьма полезная утилита - шестнад редактор. Многие подобные редакторы (hiew, hexit) имеют встроенный дизассемблер, так что можно, например, открыв в таком ре дакторе свою программу, посмотреть, как тот или иной участок программы, поправить какую-нибудь команду ассемблера или изменить значения констант и тут же, без перекомпиляции, запустить программу, чтобы посмотреть на результат изменений.
1.2. данных в компьютерах Для того чтобы освоить программирование на ассемблере, следует познако миться с двоичными и числами. Иногда в тексте програм мы можно обойтись и обычными десятичными числами, но без понимания того, как на самом деле хранятся данные в памяти компьютера, очень трудно использо вать логические и битовые операции, упакованные форматы данных и многое другое.
1.2.1. Двоичная система счисления Практически все существующие сейчас компьютерные системы, включая Intel, используют для вычислений двоичную систему счисления. В их электрических Представление данных в компьютерах цепях напряжение может принимать два значения, и эти значения назвали нулем и единицей. Двоичная система счисления раз и использует только эти две цифры, а вместо степеней десяти, как в обычной десятичной системе, здесь при меняют степени двойки. Чтобы перевести двоичное число в десятичное, надо сло жить двойки в степенях, соответствующих позициям, где в двоичном стоят еди ницы. Например:
Для перевода десятичного числа в двоичное мож системы но, например, разделить его на 2, записывая остаток в двоичную справа налево (см. табл. 2).
Чтобы отличать двоичные числа от десятичных, Остаток в ассемблерных программах в конце каждого двоич 151/2 ного ставят букву 75/2 37/2 = 7.2.2. Биты, байты и слова 18/2 Минимальная единица информации называется 9/2 битом. Бит принимает только два значения - обычно 4/2 О и 1. На самом деле они совершенно необязательны 2/2 один бит может принимать значения да и нет, по 1/2 казывать присутствие и отсутствие жесткого диска, Результат:
а также является ли персонаж игры магом или вои ном - важно лишь то, что бит имеет только два значения. Но многие величины принимают большее число значений, следовательно, для их описания нельзя обойтись одним битом.
Единица информации размером 8 бит называется байтом. Байт - это мини мальный объем данных, который реально может использовать компьютерная программа. Даже для изменения значения одного бита в памяти надо сначала считать байт, содержащий его. Биты в байте нумеруют справа налево, от нуля до семи, нулевой бит часто называют младшим битом, а седьмой - старшим (см. рис. 1).
Так как всего в байте восемь бит, он может принимать до 256 разных зна чений. Байт используют для представления целых чисел от 0 до 255 (тип unsigned char в С), целых чисел со знаком от -128 до +127 (тип signed char в С), набора символов ASCII (тип char в С) или переменных, принимающих менее 256 значе ний, например для представления десятичных чисел от 0 до 99.
Следующий по размеру базовый тип данных - слово. Размер одного слова в про цессорах Intel - два байта (см. рис. 2). Биты с 0 по 7 составляют младший байт слова, а биты с 8 по 15 - В слове содержится бит, а значит, оно может РИС. Байт Предварительные сведения принимать до 65 536 разных значений. Слова используют для представле ния целых чисел без знака со значениями 0-65 535 (тип unsigned short в С), це лых чисел со знаком от -32 768 до +32 767 (тип short int в С), адресов сегментов и смещений при 16-битной адресации. Два слова подряд образуют двойное слово, состоящее из 32 бит, а два двойных слова - одно учетверенное слово (64 бита).
Байты, слова и двойные слова - основные типы данных, с которыми мы будем работать.
Еще одно важное замечание: в с процессорами Intel все дан ные хранятся так, что младший байт находится по младшему адресу, по этому слова записываются задом наперед, то сначала (по младшему адресу) - последний (младший) байт, а потом (по старшему адресу) первый (старший) байт. Если из программы всегда к слову как к слову, а к двойному слову как к двойному слову, это не оказывает ни какого влияния. Но если вы хотите первый (старший) байт из слова в памяти, то придется адрес на 1. Двойные и учетверен ные слова записываются так же - от младшего байта к старшему.
\ I 15 О Рис. 2. Слово 1.2.3. система счисления Главное двоичной системы счисления - это размеры чисел, с ко торыми приходится обращаться. На практике с двоичными числами работают, только если необходимо следить за значениями отдельных битов, а когда разме ры переменных превышают хотя бы четыре бита, используется шестнадцатерич ная система. Она хороша тем, что компактнее десятичной, и тем, что перевод в двоичную систему и обратно происходит очень легко. В системе используется 16 лцифр (О, 1, 2, 3, 4, 5, 6, 7, 8, 9, А, В, С, D, E, F), и но мер позиции цифры в числе соответствует степени, в которую надо возвести число 16, следовательно:
96h = 9 X 16 + 6 = Перевод в двоичную систему и обратно осуществляется крайне просто - вме сто каждой шестнадцатеричной цифры подставляют соответствующее четырех значное двоичное число:
9h = 1001b, 6h 96h В ассемблерных программах при записи чисел, начинающихся с А, В, С, Е, F, в начале приписывается цифра 0, чтобы не перепутать такое число с названием переменной или другим идентификатором. После чисел ста вится буква h (см. табл. 3).
Представление данных в компьютерах | Таблица 3. Двоичные и числа Десятичное Двоичное 0 ооооь OOh 2 Ob 02h 4 04h 5 0101b 6 08h 7 0111b 8 08h 1001b 09h 10 1010b OAh 11 1011b 12 OCh 13 1101b ODh 14 1110b OEh 15 1111b OFh 7.2.4. Числа со знаком Легко использовать байты, слова или двойные слова для представления целых положительных чисел - от 0 до 535 или 4 294 967 295 соответственно. Чтобы применять те же самые байты или слова для представления отрицательных чисел, существует специальная операция, известная как дополнение до двух. Для измене ния знака числа выполняют инверсию, то есть заменяют в представлении числа все единицы нулями и нули единицами, а затем прибавляют Например, пусть используются переменные типа 150 = = 0000 0000 инверсия дает: 1111 1111 + 1 1111 1111 0110 = OFF6Ah Проверим, что число на самом деле -150: сумма + 150 должна быть равна нулю:
+150 + (-150) = 0096h + = 10000h Единица в 16-м разряде не помещается в слово, мы действи тельно получили 0. В данном формате старший (7-й, 31-й для байта, слова, двойного слова) бит всегда знаку числа: 0 - для положительных и 1 - для отрицательных. Таким образом, схема с использованием дополнения до двух выделяет для положительных и отрицательных чисел равные диапазоны:
Предварительные сведения -128...+127 - для байта, -32 768...+32 767 - для слов, -2 147 483 147 483 647 для двойных слов.
7.2.5. операции Самые распространенные варианты значений, которые может принимать один бит, - это значения правда и используемые в логике, откуда происхо дят так называемые логические операции над битами. Так, если объединить правду и правду Ч получится правда, а если объединить правду и ложь - правды не получится. В ассемблере нам встретятся четыре основные опера ции - (AND), ИЛИ (OR), лисключающее ИЛИ (XOR) и отрицание (NOT), действие которых приводится в табл. 4.
Таблица 4. Логические операции И ИЛИ Исключающее ИЛИ Отрицание 0 AND 0 = 0 0 OR 0 = 0 XOR 0 = 0 NOT 0 = 0 OR 1 = 1 0 XOR 1 = 1 NOT 1 = 1 AND 0 = 0 1 OR 0 = 1 1 XOR 0 = 1 AND 1 = 1 1 OR 1 = 1 XOR 1 = Все перечисленные операции являются побитовыми, поэтому для выполнения логического действия над числом надо перевести его в двоичный формат и про извести операцию над каждым битом, например:
96h AND 10010110b AND 00001111b = = 1.2.6. Коды символов Для представления всех букв, цифр и знаков, появляющихся на экране ком пьютера, обычно используется всего один байт. Символы, соответствующие зна чениям от 0 до 127, то есть первой половине всех возможных значений байта, были стандартизированы названы символами ASCII (хотя часто кодами ASCII именуют всю таблицу из 256 символов). Сюда входят некоторые управляющие коды (символ с кодом - конец строки), знаки препинания, цифры (симво лы с кодами - 39h), большие (41h - 5Ah) и маленькие (61h - латинс кие буквы. Вторая половина символьных кодов используется для алфавитов дру гих языков и псевдографики, набор и порядок символов в ней отличаются в разных странах и даже в пределах одной страны. Например, для букв одного только русского языка существует пять вариантов размещения во второй поло вине таблицы символов ASCII (см. приложение 1). Существует также стандарт, использующий слова для хранения кодов символов, известный как UNICODE или и даже двойные слова (UCS-4), но мы пока не будем на нем оста навливаться.
данных в компьютерах 12.7. Организация памяти Память с точки зрения процессора представляет собой последовательность байтов, каждому из которых присвоен уникальный адрес со значениями от 0 до (4 Гб). Программы же могут работать с памятью как с одним непрерывным массивом (модель памяти flat) или как с несколькими массивами (сегментирован ные памяти). Во втором случае для адреса любого байта требует ся два числа - адрес начала массива и адрес искомого байта внутри массива. По мимо основной памяти программы могут использовать регистры - специальные ячейки памяти, расположенные физически внутри процессора, доступ к которым осуществляется не по адресам, а по именам. Но здесь мы вплотную подходим к рассмотрению собственно работы процессора, о чем подробно рассказано в сле дующей главе.
Глава 2. Процессоры Intel реальном режиме Процессор Intel x86 после включения питания оказывается в так называемом ре жиме реальной адресации памяти, или просто реальном режиме. Большинство операционных систем сразу же переводит его в защищенный режим, позволяю щий им обеспечивать многозадачность, распределение памяти и другие функции.
Пользовательские программы в таких операционных системах часто работают еще и в режиме V86, из которого им доступно все то же, что и из реального, кроме команд, относящихся к управлению защищенным режимом. Следовательно, дан ная глава описывает реальный режим и V86, то есть все, что доступно программи сту в подавляющем большинстве случаев, если он не проектирует операционную систему или DPMI-сервер.
2.1. Регистры процессора Начиная с 80386 процессоры Intel предоставляют 16 основных регистров для пользовательских программ плюс еще регистров для работы с мультимедий ными приложениями (ММХ) и числами с плавающей запятой Все команды так или иначе изменяют значения регистров, и всегда быстрее и удобнее обращаться к регистру, чем к памяти.
Из реального (но не из виртуального) режима помимо основных регистров доступны также регистры управления памятью (GDTR, TR, реги стры управления (CRO, CR1 - CR4), отладочные регистры (DRO - DR7) и ма шинно-специфичные регистры, но они не применяются для решения повседнев ных задач и рассматриваются далее в соответствующих разделах.
Регистры общего назначения 32-битные регистры ЕАХ (аккумулятор), ЕВХ (база), ЕСХ (счетчик), EDX (регистр данных) могут использоваться без ограничений для любых целей - вре менного хранения данных, аргументов или результатов различных операций. На звания регистров происходят от того, что команды применяют их спе циальным образом: так, аккумулятор часто необходим для хранения результата действий, выполняемых над двумя операндами, регистр данных в этих случаях получает старшую часть результата, если он не умещается в аккумулятор, регистр счетчик работает как счетчик в циклах и строковых операциях, а регистр-база при так называемой адресации по базе. Младшие бит каждого из этих регист ров применяются как самостоятельные регистры с именами АХ, ВХ, СХ, DX. На Регистры процессора самом деле в процессорах 8086-80286 все регистры были 16-битными и называ лись именно так, а 32-битные ЕАХ - EDX появились с введением 32-битной ар хитектуры в 80386. Кроме этого, отдельные байты в 16-битных регистрах АХ DX тоже могут использоваться как 8-битные регистры и иметь свои имена. Стар шие байты этих регистров называются АН, ВН, СН, а младшие - AL, BL, CL, DL (см. рис. 3).
Остальные четыре регистра - ESI (индекс источника), EDI (индекс приемни ка), ЕВР (указатель базы), ESP (указатель стека) - имеют более конкретное на значение и применяются для хранения всевозможных временных переменных.
Регистры ESI tfEDI необходимы в строковых операциях, ЕВР и ESP - при рабо те со стеком (см. раздел 2.1.3). Так же как и в случае с регистрами ЕАХ - EDX, младшие половины этих четырех регистров называются SI, DI, BP и SP соот ветственно, и в процессорах до 80386 только они и присутствовали.
АХ ЕАХ АН 31 16 15 8 ВХ ЕВХ сх ЕСХ СН DX EDX ESI SI EDI DI ЕВР ЗР ESP SP Рис. 3. Регистры общего назначения Процессоры Intel реальном режиме 2.1.2. Сегментные регистры При использовании сегментированных моделей памяти для формирования лю бого адреса нужны два числа - адрес начала сегмента и смещение искомого байта относительно этого начала (в бессегментной модели памяти flat адреса начал всех сегментов равны). Операционные системы (кроме DOS) могут размещать сегмен ты, с которыми работает программа пользователя, в разных местах памяти и даже временно записывать их на диск, если памяти не хватает. Так как сегменты способ ны оказаться где угодно, программа обращается к ним, применяя вместо щего адреса начала сегмента число, называемое селектором. В процес сорах Intel предусмотрено шесть 16-битных регистров - CS, DS, ES, FS, GS, SS, где хранятся селекторы. (Регистры FS и GS отсутствовали в 8086, но появились уже в 80286.) Это означает, что в любой момент можно изменить параметры, запи санные в этих регистрах.
В режиме селектор каждого сегмента равен адресу его начала, де ленному на 16. Чтобы адрес в памяти, 16-битное смещение скла дывают с этим селектором, предварительно сдвинутым влево на 4. Таким образом, оказывается, что максимальный доступный адрес в ре жиме - 1 = 1 048 575. Для сравнения: в защищенном режиме адрес нача ла для каждого сегмента хранится так что возможно (64 Тб) различных логических адреса в формате сегментхмещение (программа оп ределяет до 16 383 сегментов, каждый из которых до 4 Тб), хотя процессор адресуется к 4 или 64 (для Pentium Pro) Тб памяти.
В отличие от DS, ES, GS, FS, которые называются регистрами сегментов дан ных, CS и SS отвечают за сегменты двух особенных типов - сегмент кода и сегмент стека. Первый содержит программу, исполняющуюся в данный момент, следова тельно, запись нового селектора в этот регистр приводит к тому, что далее будет исполнена не следующая по тексту программы команда, а команда из кода, нахо дящегося в другом сегменте, с тем же смещением. Смещение очередной выпол няемой команды всегда хранится в специальном регистре EIP (указатель инст рукции, 16-битная форма IP), запись в который также приведет к тому, что далее будет исполнена какая-нибудь другая команда. На самом деле все команды пере дачи управления - перехода, условного перехода, цикла, вызова подпрограммы и т. п. - и осуществляют эту самую запись в CS и EIP.
2.1.3. Стек Стек - организованный специальным образом участок памяти, который ис пользуется для временного хранения переменных, передачи параметров вызыва емым подпрограммам и сохранения адреса возврата при вызове процедур и пре рываний. Легче всего представить стек в виде стопки листов бумаги (это одно из значений слова stack в английском языке) Ч вы класть и забирать листы только с вершины стопки. Поэтому, если записать в стек числа 1, 2, 3, то при чте нии они окажутся в обратном порядке - 3, 2, 1. Стек располагается в сегменте па мяти, описываемом регистром SS, и текущее смещение вершины стека отражено Регистры процессора в регистре ESP, причем во время записи значение этого смещения то есть он растет вниз от максимально возможного адреса (см. рис. 4). Такое расположение стека вверх ногами может быть необходимо, к в бес сегментной модели памяти, когда все сегменты, включая сегменты стека и кода, занимают одну и ту же область - память целиком. Тогда программа исполняет ся в нижней области памяти, в области малых адресов, и EIP растет, а стек распо лагается в верхней области памяти, и ESP уменьшается.
При вызове подпрограммы параметры в большинстве случаев помещают в стек, а в ЕВР записывают текущее значение ESP. Если подпрограмма использует стек для хранения локальных переменных, ESP изменится, но ЕВР можно будет ис пользовать для того, чтобы считывать Значения параметров напрямую из стека (их смещения запишутся как ЕВР + номер параметра). Более подробно вызовы подпрограмм и все возможные способы передачи параметров рассмотрены в раз деле 5.2. Дно стека FCh Параметры J Рис. 4. Стек 2.1.4. Регистр флагов Еще один важный регистр, использующийся при выполнении большинства ко манд, - регистр флагов. Как и раньше, его младшие 16 бит, представлявшие собой весь этот регистр до процессора 80386, называются FLAGS. В EFLAGS каждый бит является флагом, то есть устанавливается в 1 при определенных условиях или установка его в 1 изменяет поведение процессора. Все флаги, расположенные в старшем слове регистра, имеют отношение к управлению защищенным режи мом, поэтому здесь рассмотрен только регистр FLAGS (см. рис. 5):
CF - флаг переноса. Устанавливается в 1, если результат предыдущей опера ции не уместился в приемнике и произошел перенос из старшего бита или 0 NT OF DF IF TF SF ZF 0 AF 0 PF CF Рис. 5. Регистр флагов FLAGS Процессоры Intel в реальном режиме если требуется заем (при вычитании), в противном случае - в 0. Например, после сложения слова OFFFFh и 1, если регистр, в который надо поместить результат, - слово, в него будет записано и флаг CF = 1.
a PF - флаг четности. Устанавливается в если младший байт результата предыдущей команды содержит четное число битов, равных 1, и в 0, если нечетное. Это не то же самое, что делимость на два. Число делится на два без остатка, если его самый младший бит равен нулю, и не делится, когда равен 1.
AF - флаг полупереноса или вспомогательного переноса. Устанавливается в 1, если в результате предыдущей операции произошел перенос (или заем) из третьего бита в четвертый. Этот флаг используется автоматически коман дами двоично-десятичной коррекции.
Q ZF - флаг нуля. Устанавливается в если результат предыдущей команды ноль.
SF - флаг знака. Он всегда равен старшему биту результата.
Q TF - флаг ловушки. Он был предусмотрен для работы отладчиков, не ис пользующих защищенный режим. Установка его в 1 приводит к тому, что после выполнения каждой программной команды управление временно пере дается отладчику (вызывается прерывание 1 - см. описание команды INT).
IF - флаг прерываний. Сброс этого флага в 0 приводит к тому, что процессор перестает обрабатывать прерывания от внешних устройств (см. описание ко манды INT). Обычно его сбрасывают на короткое время для выполнения критических участков кода.
Ч флаг направления. Он контролирует поведение команд обработки строк: когда он установлен в 1, строки обрабатываются в сторону уменьше ния адресов, когда DF = 0 - наоборот.
OF - флаг переполнения. Он устанавливается в 1, если результат предыду щей арифметической операции над числами со знаком выходит за допусти мые для них пределы. Например, если при сложении двух положительных чисел получается число со старшим битом, равным единице, то есть отрица тельное, и наоборот.
Флаги IOPL (уровень привилегий ввода-вывода) и NT (вложенная задача) применяются в защищенном режиме.
2.2. Способы адресации Большинство команд процессора вызываются с аргументами, которые в ассем блере принято называть операндами. Например: команда сложения содержимого регистра с числом требует задания двух операндов Ч содержимого регистра и чис ла. Далее рассмотрены все существующие способы задания адреса хранения опе рандов - способы адресации.
2.2.7. Регистровая адресация Операнды могут располагаться в любых регистрах назначения и сегмент ных регистрах. Для этого в тексте программы указывается название соответствующего Способы регистра, например: команда, копирующая в регистр АХ содержимое регистра ВХ, записывается как 2.2.2. Непосредственная адресация Некоторые команды (все арифметические, кроме деления) позволяют ука зывать один из операндов непосредственно в тексте программы. Например:
команда mov помещает в регистр АХ число 2.
2.2.3. Прямая адресация Если у операнда, располагающегося в памяти, известен адрес, то его можно использовать. Если операнд - слово, находящееся в сегменте, на который указы вает ES, со смещением от начала сегмента 0001, то команда mov поместит это слово в регистр АХ. В реальных программах для задания статичес ких переменных обычно используют директивы определения данных (раздел 3.3), которые позволяют ссылаться на статические переменные не по адресу, а по име ни. Тогда, если в сегменте, указанном в ES, была описана переменная размером в слово, можно записать ту же команду как mov В таком случае ассемблер сам заменит слово на соответствующий адрес. Если селектор сегмента данных находится в DS, то имя сегментного реги стра при прямой адресации не указывать, DS используется по умолча нию. Прямая адресация иногда называется адресацией по смещению.
Адресация отличается для реального и защищенного режимов. В реальном (так же как и в режиме V86) смещение всегда 16-битное. Это значит, что ни не указанное смещение, ни результат сложения содержимого разных регистров в более сложных методах адресации не могут превышать границ слова.
При работе в Windows, DOS4G, PMODE и в других ситуациях, когда программа будет запускаться в защищенном смещение не должно превышать гра ниц двойного слова.
2.2.4. Косвенная адресация По аналогии с регистровыми и непосредственными операндами адрес операн да в памяти также можно не указывать, а хранить в любом регистре. До процессо ра 80386 для этого можно было использовать только ВХ, SI, DI и ВР, но потом ограничения были сняты и адрес операнда разрешили считывать также из ЕАХ, ЕВХ, EDX, ESI, EDI, ЕВР и ESP (но не из АХ, DX или SP напрямую надо использовать ЕАХ, ЕСХ, EDX, ESP соответственно или предварительно ско пировать смещение в ВХ, SI, DI или ВР). Например, следующая команда помещает Процессоры в реальном режиме в регистр АХ слово из ячейки памяти, селектор сегмента которой находится в DS, а смещение - в ВХ:
' Как и в случае с прямой адресацией, DS используется по умолчанию, но не всегда: если смещение берут из регистров ESP, EBP или ВР, то в качестве сегмен тного регистра применяется SS. В реальном режиме можно свободно работать со всеми 32-битными регистрами, надо только следить, чтобы их содержимое не пре вышало границ 16-битного слова.
2.2.5. Адресация по базе со сдвигом Теперь скомбинируем два предыдущих метода адресации. Следующая команда mov помещает в регистр АХ слово, которое есть в сегменте, указанном в DS, со смеще нием на два больше, чем число из ВХ. Так как слово занимает ровно 2 байта, эта команда поместила в АХ слово, непосредственно следующее за тем, которое было в предыдущем примере. Такая форма адресации используется в тех случаях, ког да в регистре находится адрес начала структуры данных, а доступ надо осуще ствить к какому-нибудь ее элементу. Еще один вариант применения адресации по базе со сдвигом Ч доступ из подпрограммы к параметрам, переданным в стеке, ис пользуя регистр ВР (ЕВР) в качестве базы и номер параметра в качестве смеще ния, что детально рассмотрено в разделе 4.3.2. Другие допустимые формы записи этого способа адресации:
mov mov До процессора 80386 в качестве базового регистра разрешалось использовать только ВХ, ВР, SI или DI и сдвиг мог быть только байтом или словом (со знаком).
Начиная с 80386 и старше, процессоры Intel позволяют дополнительно использо вать ЕАХ, ЕВХ, ЕСХ, EDX, EBP, ESP, ESI и EDI, так же и для обычной косвен ной адресации. С помощью этого метода разрешается организовывать доступ к од номерным массивам байтов: смещение соответствует адресу начала массива, а число в регистре - индексу элемента массива, который надо считать. Очевидно, что, если массив состоит не из байтов, а из слов, придется умножать базовый ре гистр на два, а если из двойных слов - на четыре. Для этого предусмотрен специ альный метод - косвенная адресация.
2.2.6. Косвенная адресация с масштабированием Этот метод адресации полностью идентичен предыдущему, однако с его помо щью можно прочитать элемент массива слов, двойных слов или учетверенных слов, просто поместив номер элемента в регистр:
ax, [esi*2]+ Множитель, который равен 1, или 8, соответствует размеру элемента мас сива Ч байту, слову, двойному или учетверенному слову. Из регистров в этом Способы адресации варианте адресации можно использовать только ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, EBP, ESP, но не SI, DI, ВР или SP.
2.2.7. Адресация по базе с индексированием В этом методе адресации смещение операнда в памяти вычисляется как сумма чисел, содержащихся в двух регистрах, и смещения, если оно указано. Все перечис ленные ниже команды представляют собой разные формы записи одного и того же действия:
mov mov mov В регистр АХ помещается слово из ячейки памяти со смещением, равным сум ме чисел, содержащихся в ВХ, SI, и числа 2. Из 16-битных регистров так можно складывать только ВХ + SI, ВХ + DI, ВР + SI и ВР + DI, а из 32-битных Ч все восемь регистров общего назначения. Как и для прямой адресации, вместо непос редственного указания числа разрешено использовать имя переменной, заданной одной из директив определения данных. Таким можно считать, напри число из двумерного массива: если задана таблица байт, 2 - смещение ее начала от начала сегмента данных (на практике будет использоваться имя этой таблицы), ВХ = 20, a SI = 7, приведенные команды прочитают слово, состоящее из седьмого и восьмого байтов третьей строки. Если таблица состоит не из оди ночных байтов, а из слов или двойных слов, удобнее использовать наиболее пол ную форму - адресацию по базе с индексированием и масштабированием.
2.2.8. Адресация по базе с индексированием и масштабированием Это самая полная схема адресации, в которую входят все случаи, рассмотрен ные ранее как частные. Полный адрес операнда можно записать как выражение, представленное на рис. 6.
Смещение может быть байтом или двойным словом. Если ESP или ЕВР ис пользуются в роли базового регистра, Селектор сегмента операнда берется по умолчанию из регистра SS, во всех остальных случаях - из DS.
EAX EAX CS:
EBX EBX SS: ECX ECX EDX DS:
смещение EDX * EBP ES:
EBP FS: ESP ESI EDI OS:
EDI ESI Рис. 6. Полная форма адресации Процессоры Intel в реальном режиме 2.3. Основные непривилегированные команды В этом разделе описаны все непривилегированные команды процессоров Intel серии х86, включая команды расширений IA NPX (чаще называемое FPU - рас ширение для работы с числами с плавающей запятой) и IA MMX (мультимедий ное расширение). Для каждой команды указана форма записи, название и модель процессоров Intel, начиная с которой она поддерживается: 8086, 80186, 80286, 80386, 80486, Р5 (Pentium), MMX, P6 (Pentium Pro и Pentium II).
2.3.1. Пересылка Команда Назначение Процессор приемник, источник Пересылка данных Базовая команда пересылки данных. Копирует содержимое источника в при емник, источник не изменяется. Команда MOV действует аналогично операторам присваивания из языков высокого уровня, то команда эквивалентна выражению ах:=Ьх;
языка Pascal или ах=Ьх;
языка С, за исключением того, что команда ассемблера позволяет работать не только с переменными в памяти, но и со всеми регистрами процессора.
В качестве источника для MOV могут использоваться: число (непосредствен ный операнд), регистр общего назначения, сегментный регистр или переменная (то есть операнд, находящийся в памяти);
в качестве приемника: регистр общего назначения, сегментный регистр (кроме CS) или переменная. Оба операнда дол жны быть одного и того же размера - байт, слово или двойное слово.
Нельзя выполнять пересылку данных с помощью MOV из одной переменной в другую, из одного сегментного регистра в другой и нельзя помещать в сегмент ный регистр непосредственный операнд - эти операции выполняют двумя коман дами MOV (из сегментного регистра в обычный и уже из него в другой сегмент ный) или парой команд PUSH/POP.
Загрузка регистра командой автоматически запрещает прерывания до окончания следующей за ней команды MOV, поэтому можно не что в этот момент произойдет прерывание, обработчик которого получит неправильный стек. В любом случае для загрузки значения в регистр SS пред команда Команда Назначение Процессор Условная пересылка данных Р Непривилегированные команды Это набор команд, которые копируют содержимое источника в приемник, если удовлетворяется то или иное условие (см. табл. 5). Источником может быть ре гистр общего назначения или переменная, а приемником - только регистр. Тре бование, которое должно выполниться, - просто равенство нулю или единице тех или иных флагов из регистра FLAGS, но, если использовать команды CMOVcc сразу после СМР (сравнение) с теми же операндами, условия приобретают осо бый смысл, например:
ах, Сравнить ах и ах, Если ах < скопировать в ах.
Слова выше и ниже в табл. 5 относятся к сравнению чисел без знака, сло ва больше и меньше учитывают знак.
Таблица 5. Разновидности команды CMOVcc Код команды Реальное условие Условие для СМР Если выше CF = 0 и ZF = Если не ниже и не равно Если выше или равно CMOVNB CF = 0 Если не ниже Если нет переноса Если ниже Если не выше и не равно Если перенос CMOVBE Если ниже или равно 1 CMOVNA Если не выше Если равно Если ноль CMOVG Если больше ZF = 0 и SF = OF CMOVNLE Если не меньше и не равно CMOVGE Если больше или равно SF = OF CMOVNL Если не меньше Если меньше OF Если не больше и не равно Если меньше или равно ZF = 1 или SF 0 OF Если не больше Если равно ZF = Если не ноль OF = 0 Если нет переполнения Если есть переполнение Если нет четности PF Если нечетное Если есть четность Если четное SF = 0 Если нет знака Если есть знак Процессоры в реальном режиме Команда Назначение Процессор Обмен операндов между собой Содержимое операнда 2 копируется в операнд а старое содержимое операн да 1 - в операнд 2. XCHG можно выполнять над двумя регистрами или над реги стром и переменной.
xchg еах, ebx To же, что три команды на языке С:
= temp = еах еах = ebx;
ebx temp xchg al А эта команда ничего не делает.
Команда Назначение Процессор BSWAP Обмен байтов внутри регистра Обращает порядок байтов в 32-битном регистре. Биты 0-7 (младший байт младшего слова) меняются местами с битами 24-31 (старший байт старшего слова), а биты 8-15 (старший байт младшего слова) - с битами 16-23 (младший байт старшего слова).
;
Теперь в еах находится Чтобы обратить порядок байтов в 16-битном регистре, следует использовать команду XCHG:
xchg ;
Обратить порядок байтов в АХ.
В процессорах Intel команду BSWAP можно использовать и для обращения порядка байтов в регистрах, но в некоторых совместимых процессорах других фирм этот вариант не реализован.
Команда Назначение Процессор PUSH источник Поместить данные в стек Помещает содержимое источника в стек. Источником может быть регистр, сег регистр, непосредственный операнд или переменная. Фактически эта ко манда уменьшает ESP на размер источника в байтах (2 или 4) и копирует содер жимое источника в память по адресу SS:[ESP]. Команда PUSH почти всегда используется в паре с POP (считать данные из стека). Поэтому, чтобы скопиро вать содержимое одного сегментного регистра в другой (что нельзя выполнить од ной командой можно использовать такую последовательность команд:
push cs pop Теперь DS указывает на тот же сегмент, что и CS.
Другой вариант применения команд PUSH/POP - временное хранение пере менных, например:
push еах ;
Сохраняет текущее значение ЕАХ.
;
Здесь располагаются какие-нибудь команды, ;
которые используют ЕАХ, например pop еах ;
Восстанавливает старое значение ЕАХ.
Непривилегированные команды.
Начиная с процессора 80286 команда PUSH ESP (или SP) помещает в стек значение ESP до того, как она же его уменьшит, а на 8086 регистр SP располагал ся в стеке уже уменьшенным на два.
Команда Назначение Процессор POP приемник Считать данные из стека - Помещает в приемник слово или двойное слово, находящееся в вершине сте ка, увеличивая ESP на 2 или 4 соответственно. POP выполняет действие, полно стью обратное PUSH. Приемником может быть регистр общего назначения, сег ментный регистр, кроме CS (чтобы загрузить CS из стека, надо воспользоваться командой RET), или переменная. Если в роли приемника выступает операнд, ис пользующий ESP для косвенной адресации, команда POP вычисляет адрес опе ранда уже после того, как она увеличивает ESP.
Команда Назначение Процессор PUSHA Поместить в стек PUSHAD все регистры общего назначения PUSHA располагает в стеке регистры в следующем порядке: АХ, СХ, DX, ВХ, SP, ВР, SI и DI. PUSHAD помещает в стек EAX, ECX, EDX, EBX, ESP, EBP, ESI и EDI. (В случае с SP и ESP используется значение, которое находилось в регист ре до начала работы команды.) В паре с командами POPA/POPAD, считывающи ми эти же регистры из стека в обратном порядке, это позволяет писать подпро граммы (обычно обработчики прерываний), которые не должны изменять значения регистров по окончании своей работы. В начале такой подпрограммы вызывают команду PUSHA, а в конце - РОРА.
На самом деле PUSHA и PUSHAD - одна и та же команда с кодом Ее поведение определяется тем, выполняется ли она в 16- или в 32-битном режиме. Если программист команду PUSHAD в 16-битном сегмен те или PUSHA в ассемблер просто записывает перед ней префикс изменения размерности операнда Это же будет на некоторые другие пары команд: POPA/POPAD, POPF/POPFD, PUSHF/ и Команда Назначение Процессор РОРА Загрузить из стека POPAD все регистры общего назначения Команды выполняют действия, полностью обратные действиям PUSHA и PUSHAD, но помещенное в стек значение SP или ESP игнорируется. РОРА загру жает из стека SI, ВР, увеличивает SP на два, загружает ВХ, СХ, АХ, a POPAD загружает EDI, ESI, ЕВР, увеличивает ESP на 4 и загружает EBX, EDX, ECX, EAX.
Процессоры в реальном режиме Команда Назначение Процессор IN Считать данные из порта Копирует число из порта ввода-вывода, номер которого указан в источнике, в приемник. Приемником может быть только AL, АХ или ЕАХ. Источник - или непосредственный операнд, или DX, причем во время использования непосред ственного операнда можно указывать лишь номера портов не больше 255.
Команда Назначение Процессор OUT Записать данные в порт Копирует число из источника (AL, АХ или ЕАХ) в порт ввода-вывода, номер которого указан в приемнике. Приемник может либо непосредственным номером порта (не больше 255), либо регистром DX. На командах IN и OUT стро ится все общение процессора с устройствами ввода-вывода - клавиатурой, жест кими дисками, различными контроллерами, и используются они, в первую оче редь, в драйверах устройств. Например, чтобы включить динамик PC, достаточно выполнить команды:
in al,61h or al, out 61h,al Программирование портов ввода-вывода рассмотрено подробно в разделе 5.10.
Команда Назначение Процессор CWD Конвертирование слова в двойное слово CDQ Конвертирование двойного слова в учетверенное Команда CWD превращает слово в АХ в двойное слово, младшая половина которого (биты остается в АХ, а старшая (биты располагается в DX.
Команда выполняет аналогичное действие по отношению к двойному слову в ЕАХ, расширяя его до учетверенного слова в EDX:EAX.
Эти команды лишь устанавливают все биты регистра DX или EDX в значение, равное величине старшего бита регистра АХ или ЕАХ, сохраняя таким образом его знак.
Команда Назначение Процессор CBW Конвертирование байта в слово CWDE Конвертирование слова в двойное слово CBW расширяет байт, находящийся в регистре AL, до слова в АХ;
CWDE рас ширяет слово в АХ до двойного слова в ЕАХ. Команды CWDE и CWD отличают ся тем, что CWDE размещает свой результат в ЕАХ, в то время как CWD, выпол няющая точно такое же действие, располагает результат в паре регистров DX:AX.
Так же как и в командах расширение выполняется путем установки команды каждого бита старшей половины результата равным старшему биту исходного байта или слова, то есть:
AL = OF5h = 245 = Cbw ;
Теперь АХ = = 65 525 = -11.
Как и в случае с командами PUSHA/PUSHAD, пара - это одна команда с кодом и пара CBW/CWDE - одна команда с кодом Интер претация этих команд зависит от того, в каком (16-битном или в 32-бит ном) сегменте они исполняются. Если или CWDE в 16-битном сегменте, ассемблер поставит префикс изменения разрядности операнда.
Команда Назначение Процессор Пересылка с расширением знака Копирует содержимое источника (регистр или переменная размером в байт или слово) в приемник (16- или 32-битный регистр) и расширяет знак аналогич но командам CBW/CWDE.
Команда Назначение Процессор Пересылка с расширением нулями Копирует содержимое источника (регистр или переменная размером в байт или слово) в приемник (16- или 32-битный регистр) и расширяет нулями, то есть команда ax, эквивалентна паре команд mov mov Команда Назначение адрес Трансляция в соответствии с таблицей Помещает в AL байт из таблицы в памяти по адресу ES:BX (или ES:EBX) со смещением относительно начала таблицы равным AL. В качестве аргумента для XLAT в ассемблере можно указать имя таблицы, но эта информация никак не используется процессором и служит только в качестве комментария. Если он не нужен, можно применить форму XLATB. Например, можно написать сле дующий вариант преобразования шестнадцатеричного числа в ASCII-код соответ ствующего ему символа:
mov mov bx, offset htable если в сегменте данных, на который указывает регистр ES, было записано htable 2 Assembler для DOS Процессоры Intel в режиме то теперь AL содержит не число а ASCII-код буквы С. Разумеется, это пре образование разрешается выполнить посредством более компактного кода всего из трех арифметических команд, который будет рассмотрен в описании команды DAS, но с XLAT можно любые преобразования такого рода.
Команда Назначение Процессор LEA Вычисление эффективного адреса Вычисляет эффективный адрес источника (переменная) и помещает его в при емник (регистр). С помощью LEA можно вычислить адрес переменной, которая описана сложным методом адресации, например по базе с индексированием. Если адрес - 32-битный, а регистр-приемник - 16-битный, старшая половина вычис ленного адреса теряется, если наоборот, приемник - 32-битный, а адресация 16-битная, то вычисленное смещение дополняется нулями.
Команду LEA часто используют для быстрых арифметических вычисле ний, например умножения:
lea ;
ВХ = ЕВХ х или сложения:
;
ЕВХ (эти команды чем соответствующие MOVu ADD, и не изменяют флаги) 23.2. Двоичная арифметика Все команды этого раздела, кроме команд деления и умножения, изменяют флаги OF, SF, ZF, AF, CF, PF в соответствии с назначением каждого из них (см.
раздел 2.1.4).
Команда Назначение Процессор ADD Сложение Команда выполняет арифметическое сложение приемника и источника, поме щает сумму в приемник, не изменяя содержимое источника. Приемник может быть регистром или переменной, источник - числом, регистром или переменной, но нельзя использовать переменную одновременно и для источника, и для при емника. Команда ADD никак не различает числа со знаком и без знака, но, упот ребляя значения флагов CF (перенос при сложении чисел без знака), OF (пере нос при сложении чисел со знаком) и SF (знак результата), разрешается применять ее и для тех, и для других.
Команда Назначение Процессор ADC Сложение с переносом Эта команда аналогична ADD, но при этом выполняет арифметическое сложе ние приемника, источника и флага CF. Пара команд ADD/ADC используется для команды сложения чисел повышенной точности. Сложим, два 64-битных целых числа. Пусть одно из них находится в паре регистров ЕрХ:ЕАХ (младшее двой ное слово (биты 0-31) - в ЕАХ и старшее (биты 32-63) - в EDX), а другое - в паре регистров add adc Если при сложении младших двойных слов перенос из старшего разряда (флаг CF = то он будет учтен следующей ADC.
Команда Назначение Процессор XADD Обменять между собой и Выполняет сложение, помещает содержимое в источник, а сумму операндов - в приемник. Источник - всегда регистр, может быть регист ром и переменной.
Команда Назначение Процессор SUB Вычитание Вычитает источник из приемника и помещает в приемник.
ник может быть регистром или переменной, источник - числом, регистром или переменной, но использовать переменную одновременно и для источника, и для приемника. Точно так же, как и команда ADD, не делает различий между со и без знака, но флаги использовать ее и для тех, и для других.
Команда Назначение Процессор SBB Вычитание с займом Эта команда SUB, но она вычитает из приемника значение источ и дополнительно вычитает значение флага СЕ Ее можно использовать для вычитания 64-битных чисел в EDX:EAX и ЕВХ:ЕСХ ADD/ADC:
sub sbb Если при вычитании двойных слов заем, то он будет уч тен при вычитании старших слов.
Команда Назначение Процессор IMUL источник Умножение чисел со знаком IMUL,источник2 Процессоры Intel з реальном Эта команда имеет три формы, различающиеся числом операндов:
IMUL источник: источник (регистр или переменная) умножается на AL, АХ или ЕАХ (в зависимости от размера операнда), и результат располагается в АХ, DX:AX или EDX:EAX соответственно.
2. IMUL источник (число, регистр или переменная) ум ножается на приемник (регистр), и результат заносится в приемник.
3. IMUL источник 1 (регистр или переменная) умножается на источник 2 (число), и результат заносится в приемник (регистр).
Во всех трех вариантах считается, что результат может занимать в два раза больше места, чем размер источника. В первом случае приемник автоматически оказывается очень большим, но во втором и третьем случаях существует вероят ность переполнения и потери старших битов результата. Флаги OF и CF будут равны единице, если это произошло, и нулю, если результат умножения помес тился целиком в приемник (во втором и третьем случаях) или в младшую поло вину приемника (в первом случае).
Значения флагов SF, ZF, AF и PF после команды IMUL не определены.
Команда Назначение Процессор MUL источник Умножение чисел без знака ' Выполняет умножение содержимого источника (регистр или переменная) и ре гистра AL, АХ, ЕАХ (в зависимости от размера источника) и помещает результат в АХ, DX:AX, соответственно. Если старшая половина результата (АН, DX, EDX) содержит только нули (результат целиком поместился в младшую половину), флаги CF и OF устанавливаются в 0, иначе - в 1. Значение остальных флагов (SF, ZF, AF и PF) не определено.
Команда Назначение Процессор IDIV источник Целочисленное деление со знаком Выполняет целочисленное деление со знаком AL, АХ или ЕАХ (в зависимос ти от размера источника) на источник (регистр или переменная) и помещает ре зультат в AL, АХ или остаток - в АН, DX или EDX соответственно. Ре зультат всегда округляется в сторону нуля, знак остатка совпадает со знаком делимого, абсолютное значение остатка меньше абсолютного значения делителя.
Флаги CF, OF, SF, ZF, AF и PF после этой команды не определены, а переполне ние или деление на ноль вызывает исключение #DE (ошибка при делении) в за щищенном режиме и прерывание реальном.
Команда Назначение Процессор DIV источник Целочисленное деление без знака Выполняет целочисленное деление без знака AL, АХ или ЕАХ (в зависимости от размера источника) на источник (регистр или переменная) и помещает результат в AL, АХ или ЕАХ, а остаток - в АН, DX или EDX соответственно. Результат всегда Непривилегированные команды округляется в сторону нуля, абсолютное значение остатка меньше абсолютного значения делителя. Флаги CF, SF, ZF, AF и PF после этой команды не опреде лены, а переполнение или деление на ноль вызывает исключение #DE (ошибка при делении) в защищенном режиме и прерывание реальном.
Команда Назначение Процессор INC приемник Инкремент Увеличивает приемник (регистр или переменная) на Единственное отличие этой команды от ADD состоит в том, что флаг CF не затрагивается.
Остальные арифметические флаги (OF, SF, ZF, AF, PF) устанавливаются в соот ветствии с результатом сложения.
Команда Назначение Процессор DEC приемник Декремент Уменьшает приемник (регистр или переменная) на 1. Единственное отличие этой команды от SUB заключается в том, что флаг CF не затрагивает ся. Остальные арифметические флаги SF, ZF, AF, PF) устанавливаются в со ответствии с результатом вычитания.
Команда Назначение Процессор NEG приемник Изменение Выполняет над числом, содержащимся в приемнике (регистр или переменная), операцию дополнения до двух. Эта операция эквивалентна обращению знака опе ранда, если рассматривать его как число со знаком. Если приемник равен нулю, флаг CF устанавливается в 0, иначе - в 1. Остальные флаги (OF, SF, ZF, AF, PF) назначаются в соответствии с результатом операции.
Красивый пример использования команды NEG - получение значения числа, применяя всего две команды - изменение знака и переход на первую команду еще раз, если знак neg eax js labelO Назначение Процессор СМР Сравнение Сравнивает приемник и источник и устанавливает флаги. Действие осуществ ляется путем вычитания источника (число, регистр или переменная) из прием ника (регистр или переменная;
приемник и источник не могут быть переменны ми одновременно), причем результат вычитания никуда не записывается.
Единственным следствием работы этой команды оказывается изменение флагов CF, OF, SF, ZF, AF и PF. Обычно команду СМР используют вместе с командами условного перехода условной пересылки данных (CMOVcc) или условной Процессоры Intel в реальном установки байтов (SETcc), которые позволяют применить результат сравнения, не обращая внимания на детальное значение каждого флага. Так, команды CMOVE, JE и SETE выполнят соответствующие действия, если значения операндов пред шествующей команды СМР были равны.
Несмотря на то что условные команды почти всегда вызываются сразу после СМР, не надо что их можно после любой ко манды, модифицирующей флаги, например: равенство АХ нулю более короткой командой test а равенство единице - командой dec ax Команда Назначение Процессор CMPXCHG приемник, источник Сравнить и обменять между собой Сравнивает значения, содержащиеся в AL, АХ, ЕАХ (в зависимости от разме ра операндов), с приемником (регистром). Если они равны, информация из ис точника копируется в приемник и флаг ZF устанавливается в 1, в противном слу чае содержимое приемника копируется в АХ, ЕАХ и флаг ZF устанавливается в 0. Остальные определяются по результату операции сравнения, как после СМР. Источник - всегда регистр, приемник может быть регистром и переменной.
Команда Назначение Процессор приемник Сравнить и обменять 8 байт Р Выполняет сравнение содержимого регистров EDX:EAX как 64-битного чис ла (младшее двойное слово - в ЕАХ, старшее - в EDX) с приемником (8-байтная переменная в памяти). Если они равны, содержимое регистров ЕСХ:ЕВХ как 64-битное число (младшее двойное слово в ЕВХ, старшее - в ЕСХ) помещается в приемник. В противном случае содержимое приемника копируется в EDX:EAX.
Десятичная арифметика Процессоры Intel поддерживают операции с двумя форматами десятичных чисел:
неупакованное двоично-десятичное число - байт, принимающий значения от до 09h, и упакованное двоично-десятичное число - байт, принимающий значения от 00 до Все обычные арифметические операции над такими числами приво дят к неправильным результатам. Например, если увеличить 19h на 1, то полу чится число а не 20h. Для коррекции результатов арифметических действий над двоично-десятичными числами используются приведенные ниже команды.
Команда Назначение Процессор DAA BCD-коррекция после сложения Если эта команда выполняется сразу после ADD (ADC, INC или XADD) и в ре гистре AL находится сумма двух упакованных двоично-десятичных чисел, то в AL Непривилегированные команды записывается упакованное двоично-десятичное число, которое должно было стать результатом сложения. Например, если AL содержит число 19h, последова тельность команд inc daa приведет к тому, что в AL окажется 20h (а не 1 Ah, как было бы после INC).
DAA выполняет следующие действия:
Если младшие четыре бита AL больше 9 или флаг = 1, то AL увеличивается на 6, если при этом сложении произошел перенос, и AF устанавливается в 2. Иначе AF = 0.
3. Если теперь старшие четыре бита AL 9 или флаг CF = 1, то AL увеличивается на и CF устанавливается в 1.
4. Иначе CF = 0.
Флаги AF и CF если в ходе коррекции происходил перенос из первой или второй цифры. SF, ZF и PF устанавливаются в соответствии с ре флаг OF не определен.
Команда Назначение Процессор DAS BCD-коррекция после вычитания Если эта команда выполняется сразу после SUB (SBB или DEC) и в регистре AL находится разность двух упакованных двоично-десятичных чисел, то в AL записыва ется упакованное двоично-десятичное число, которое должно было быть результатом вычитания. Например, если AL содержит число последовательность команд dec al das приведет к тому, что в регистре окажется 19h (а не как было бы после DEC).
DAS выполняет следующие действия:
Если младшие четыре бита AL 9 или AF = то AL на если при этом вычита нии произошел заем, и устанавливается в 0.
3. Если старшие четыре бита AL больше 9 или флаг CF Ч 1, то AL на 60h и CF устанавливается в 1.
4. Иначе CF 0.
Известный пример необычного использования этой команды ~ самый ком пактный вариант преобразования цифры в ASCII-код соответствующего символа (более длинный и очевидный вариант этого преобразования рассматривался в описании команды XLAT):
al, sbb al,69h das Процессоры Intel в реальном режиме После числа 0-9 превращаются в 96h - 9Fh, а числа - в - Затем DAS вычитает 66h из первой группы чисел, переводя их в 30h - и 60h из второй группы чисел, переводя их в h Ч 46h.
Флаги AF и CF устанавливаются, если в ходе коррекции происходил заем из первой или второй цифры. SF, ZF и PF устанавливаются в соответствии с резуль татом, флаг OF не определен.
Команда Назначение Процессор ASCII-коррекция после сложения Корректирует сумму двух неупакованных двоично-десятичных чисел в AL.
Если коррекция приводит к десятичному переносу, АН увеличивается на 1. Эту команду лучше использовать сразу после команды сложения двух таких чисел.
Например, если при сложении 05 и 06 в АХ окажется число то команда скорректирует его в (неупакованное десятичное Флаги CF и OF устанавливаются в 1, если произошел перенос из AL в АН, в противном случае они равны нулю. Значения флагов OF, SF, ZF и PF не определены.
Команда Назначение Процессор AAS ASCII-коррекция после вычитания Корректирует разность двух неупакованных двоично-десятичных чисел в AL сразу после команды SUB или SBB. Если операция приводит к займу, АН уменьша ется на 1. Флаги CF и OF устанавливаются в если произошел заем из AL в АН, и в ноль - в противном случае. Значения флагов OF, SF, ZF и PF не определены.
Команда Назначение Процессор ASCII-коррекция после умножения Корректирует результат умножения неупакованных двоично-десятичных чисел, который находится в АХ после выполнения команды MUL, преобразовывая полу ченное в пару неупакованных чисел (в АН и AL). Например:
;
Умножить 5 на 5.
;
Результат в АХ ;
Теперь АХ содержит 0205h.
ААМ устанавливает флаги SF, ZF и PF в соответствии с результатом и остав ляет OF, AF и CF неопределенными.
Код команды ААМ - D4h OAh, где OAh - основание системы счисления, по отношению к которой выполняется коррекция. Этот байт можно заме на любое другое число (кроме нуля), и ААМ преобразует к двум не упакованным цифрам любой системы счисления. обобщенная форма ААМ работает на всех процессорах (начиная с 8086), но появляется в доку ментации Intel с процессоров Pentium. Фактически действие, кото рое выполняет ААМ, - целочисленное деление AL на OAh (или любое другое Непривилегированные команды число в общем случае), частное помещается в АН, и остаток - в AL, поэто му команду часто используют для быстрого деления в высокооптимизиро ванных алгоритмах.
Команда Назначение Процессор AAD ASCII-коррекция перед Выполняет коррекцию неупакованного двоично-десятичного числа, находяще гося в регистре АХ, так, чтобы последующее деление привело к десятичному ре зультату. Например, разделим десятичное 25 на 5:
mov ;
25 в неупакованном mov aad ;
Теперь в АХ находится ;
АХ = 0005.
Флаги SF, ZF и PF устанавливаются в соответствии с результатом, OF, AF и CF не определены.
Команда AAD, как и ААМ, с любой системой счисления: ее код и второй байт можно на любое другое число. Действие AAD заключается в том, что содержимое регистра АН умножается на второй байт команды no умолчанию) и складывается с AL, после чего АН обнуляется, так что AAD можно для быстрого умноже ния на любое число.
Логические операции Команда Назначение Процессор AND Логическое И Команда выполняет побитовое логическое И над приемником (регистр или переменная) и источником (число, регистр или переменная;
источник и прием ник не могут быть переменными одновременно) и помещает результат в прием ник. Любой бит результата равен 1, только если соответствующие биты обоих операндов были равны 1, и равен 0 в остальных случаях. Наиболее часто AND применяют для выборочного обнуления отдельных битов. Например, команда and обнулит старшие четыре бита регистра AL, сохранив неизменными четыре младших.
Флаги OF и CF SF, ZF и PF устанавливаются в соответствии с ре зультатом, AF не определен.
Команда Назначение Процессор OR Логическое ИЛИ Выполняет побитовое логическое ИЛИ над приемником (регистр или пере менная) и источником (число, регистр или переменная;
источник и приемник не Процессоры Intel в реальном режиме могут быть переменными одновременно) и помещает результат в приемник. Любой бит результата равен 0, только если соответствующие биты обоих операндов были равны 0, и равен 1 в остальных случаях. Команду OR чаще всего используют для выборочной установки отдельных битов. Например, команда or al,00001111b приведет к тому, что младшие четыре бита регистра AL будут установлены в При выполнении команды OR флаги OF и CF обнуляются, SF, ZF и PF уста навливаются в соответствии с результатом, AF не определен.
Команда Назначение Процессор XOR Логическое исключающее ИЛИ Выполняет побитовое логическое исключающее ИЛИ над приемником (ре гистр или переменная) и источником (число, регистр или переменная;
источник и приемник не могут быть переменными одновременно) и помещает результат в приемник. Любой бит результата равен 1, если соответствующие биты операн дов различны, и нулю - в противном случае. XOR используется для самых раз ных операций, например:
;
Обнуление регистра АХ.
или ;
Меняет местами содержимое АХ и ВХ.
Оба примера могут выполняться быстрее, чем соответствующие очевидные команды или Команда Назначение Процессор NOT приемник Инверсия Каждый бит приемника (регистр или равный нулю, устанавли вается в 1, и каждый бит, равный сбрасывается в 0. Флаги не затрагиваются.
Команда Назначение Процессор TEST приемник, источник Логическое сравнение Вычисляет результат действия побитового логического И над приемником (регистр или переменная) и источником (число, регистр или переменная;
источник и приемник не могут быть переменными одновременно) и устанавливает флаги SF, ZF и PF в соответствии с полученным показателем, не сохраняя результата (фла ги OF и CF обнуляются, значение AF не определено). TEST, так же как и используется в основном в сочетании с командами условного перехода условной пересылки данных (CMOVcc) и условной установки байтов (SETcc).
Непривилегированные команды 2.3.5. Сдвиговые операции Команда Назначение Процессор SAR Арифметический сдвиг вправо SAL Арифметический сдвиг влево SHR Логический сдвиг Логический сдвиг влево Эти четыре команды выполняют двоичный сдвиг приемника (регистр или пере менная) вправо (в сторону младшего бита) или влево (в сторону старшего бита) на значение счетчика (число или регистр CL, из которого учитываются только младшие 5 бит, принимающие значения от 0 до 31). Операция сдвига на 1 экви валентна умножению (сдвиг или делению (сдвиг вправо) на 2. Так, число (2) после сдвига на 1 влево превращается в (4). Команды SAL и SHL выполняют одну и ту же операцию (на самом деле это одна и та же коман да) - на каждый шаг сдвига старший бит заносится в CF, все биты сдвигаются влево на одну и младший бит обнуляется. Команда SHR осуществляет прямо противоположную операцию: младший бит заносится в CF, все биты сдви гаются на 1 вправо, старший бит обнуляется. Эта команда эквивалентна беззнако вому целочисленному делению на 2. Команда SAR действует по аналогии с SHR, только старший бит не обнуляется, а сохраняет предыдущее значение, вот почему, например, число (-4) перейдет в (-2). SAR, таким обра зом, эквивалентна знаковому делению на 2, но, в отличие от IDIV, округление происходит не в сторону нуля, а в сторону отрицательной бесконечности. Так, если разделить на 4 с помощью IDIV, получится -2 (и остаток а если вы полнить арифметический сдвиг вправо числа -9 на 2, результатом будет -3. Сдви ги больше 1 эквивалентны соответствующим сдвигам на 1, выполненным после довательно. Схема всех сдвиговых операций приведена на рис. 7.
Сдвиги на 1 изменяют значение флага OF: SAL/SHL устанавливают его в 1, если после сдвига старший бит (то есть старшие два бита исходного числа не были одинаковыми), и в если старший бит остался тем же. SAR уста навливает OF в 0, a SHR -- старшего бита исходного числа. Для сдви гов на несколько битов значение OF не определено. Флаги SF, ZF, PF назначаются 7,15, Х 7,15, Рис. 7. Сдвиговые операции. Процессоры Intel в реальном всеми сдвигами в соответствии с результатом, параметр AF не определен (кроме случая, когда счетчик сдвига равен нулю: ничего не происходит и флаги не изме няются).
В процессорах 8086 в качестве второго операнда можно было задавать лишь число 1 и при использовании CL учитывать все биты, а не только младшие 5, но уже начиная с 80186 эти команды приняли свой вид.
Команда Назначение Процессор SHRD Сдвиг повышенной точности вправо SHLD Сдвиг повышенной точности влево Приемник (регистр переменная) сдвигается влево (в случае SHLD) или впра во (в случае SHRD) на число битов, указанное в счетчике (число или регистр откуда используются только младшие 5 бит, принимающие значения от 0 до 31).
Старший (для SHLD) или младший (в случае SHRD) бит не обнуляется, а счи тывается из источника (регистр), значение которого не изменяется. Например, если приемник содержит источник - то счетчик равен 3, SHRD даст в результате OlOOOlOlb, a SHLD - (см. рис. 8).
источник SHRD приемник 15,31 0 15, SHLD CF приемник 15,31 0 15,31 О Рис. 8. Сдвиги двойной точности Флаг OF устанавливается при сдвигах на бит, если изменился знак прием ника, и сбрасывается в противном случае;
при сдвигах на несколько битов флаг OF не определен. Во всех случаях SF, ZF и PF устанавливаются в соответствии с результатом и AF не определен, кроме варианта со сдвигом на 0 бит, в котором значения флагов не изменяются. Если счетчик больше, чем разрядность прием ника, - результат и все флаги не определены.
Команда Назначение Процессор ROR Циклический сдвиг вправо ROL Циклический сдвиг влево RCR Циклический сдвиг вправо через флаг переноса RCL Циклический сдвиг влево через флаг переноса Эти команды осуществляют циклический сдвиг приемника (регистр или пе ременная) на число битов, указанное в счетчике (число или регистр CL, из кото рого учитываются только младшие 5 бит, принимающие значения от 0 до 31). При выполнении циклического сдвига на 1 команды ROR (ROL) перемещают каждый бит приемника вправо (влево) на одну позицию, за исключением самого младшего (старшего), который записывается в позицию самого старшего (младшего) бита.
ROR ROL 7,15, RCR 7,15, RCL с 7,15,31 О Рис. 9. Циклические сдвиги Команды,RCR и RCL выполняют аналогичное действие, но включают флаг CF в цикл, как если бы он был дополнительным битом в приемнике (см. рис. 9).
После выполнения команд циклического сдвига флаг CF всегда равен последне му вышедшему за пределы приемника биту, флаг OF определен только для сдвигов на 1 - он устанавливается, если изменилось значение самого старшего бита, и сбра сывается в противном случае. Флаги SF, ZF, AF и PF не изменяются.
Операции над битами и байтами Команда Назначение Процессор ВТ Проверка бита Команда ВТ считывает в флаг CF значение бита из битовой строки, определен ной первым операндом - битовой базой (регистр или переменная), со смещением, указанным во втором операнде - битовом смещении (число или регистр). Когда первый операнд - регистр, то битовой базой считается 0 регистре и не может превышать 15 или 31 (в зависимости от размера регистра);
если оно превышает эти границы, в качестве смещения будет использоваться оста ток от деления на 16 или 32 соответственно. Если первый операнд - переменная, то в качестве битовой базы нужен бит 0 указанного байта в памяти, а смещение может принимать значения от 0 до 31, если оно установлено непосредственно (старшие биты процессором игнорируются), и от до если оно указано в регистре.
Несмотря на то что эта команда считывает единственный бит из памя ти, а процессор - целое двойное слово по адресу База + (4 (Смещение/ или слово по адресу База + (2 х в зависимости от разрядности адреса, все равно не ВТ вблизи от недо ступных для чтения областей памяти.
Процессоры в реальном режиме После выполнения команды ВТ флаг CF равен значению считанного бита, флаги OF, SF, ZF, AF и PF не определены.
Команда Назначение Процессор BTS Проверка и установка бита BTR Проверка и сброс бита ВТС Проверка и инверсия бита Эти три команды соответственно устанавливают в 1 (BTS), сбрасывают в О и инвертируют (ВТС) значение бита, который находится в битовой строке с началом, определенным в базе (регистр или переменная), и смещением, указан ным во втором операнде (число от 0 до 31 или регистр). Если битовая база - ре гистр, то смещение не может превышать 15 или 31 в зависимости от разрядности этого регистра. Если битовая база - переменная в памяти, то смещение может принимать значения от до (при условии, что оно указано в регистре).
После выполнения команд BTS, BTR и ВТС флаг CF равен значению считан ного бита до его изменения в результате действия команды, флаги OF, SF, ZF, AF и PF не определены.
Команда Назначение Процессор BSF Прямой поиск бита BSR Обратный поиск бита BSF сканирует источник (регистр или переменная), начиная с самого младшего бита, и записывает в приемник (регистр) номер первого встретившегося бита, рав ного 1. Команда BSR сканирует источник, начиная с самого старшего бита, и воз вращает номер первого встретившегося ненулевого бита, считая от нуля. есть, если источник равен 0000 0000 0000 то BSF возвратит 1, a BSR - 14.
Если весь источник равен нулю, значение приемника не определено и флаг ZF устанавливается в 1, иначе ZF всегда сбрасывается. Флаги CF, OF, SF, AF и PF не определены.
Команда Назначение Процессор приемник Установка байта по условию Это набор команд, устанавливающих приемник (8-битный регистр или пере менная размером в 1 байт) в 1 или 0, если удовлетворяется или не удовлетворяется определенное условие. Фактически в каждом случае проверяется состояние тех иных флагов, но, когда команда из набора SETcc используется сразу после условия приобретают формулировки, соответствующие отношениям меж ду операндами СМР (см. табл. 6). Скажем, если операнды СМР были неравны, то команда выполненная сразу после СМР, установит значение своего опе ранда в Слова выше и ниже в таблице относятся к сравнению чисел без знака, слова больше и меньше учитывают знак.
Непривилегированные команды Таблица 6. Команды Код команды Реальное условие Условие для CMP SETA Если выше CF = 0 и ZF = Если не ниже и не равно SETAE Если выше или равно CF = 0 Если не ниже Если нет переноса Если ниже Если не выше и не равно Если перенос Если ниже или равно CF = 1 или ZF = Если не выше Если равно Если ноль Если больше ZF = 0 и SF = OF Если не меньше и не равно Если больше или равно SF = OF Если не меньше Если меньше SF 0 OF Если не больше и не равно Если меньше или равно ZF = 1 или SF <> OF не больше Если не равно ZF = Если не ноль OF = 0 Если нет переполнения Если есть переполнение Если нет четности PF = Если нечетное Если есть четность Если четное SF = Если нет знака SETS Если есть знак 2.3.7. Команды передачи управления Команда Назначение Процессор операнд Безусловный переход JMP передает управление в другую точку программы, не какой-либо информации для возврата. Операндом может быть непосредственный адрес для пе рехода (в программах используют имя метки, установленной перед командой, на которую выполняется переход), а также регистр или переменная, содержащая адрес, В зависимости от типа перехода различают:
а переход типа short (короткий переход) - если адрес перехода в пре делах 127 байт от команды JMP;
I Процессоры в реальном режиме а переход типа near (ближний переход) - если адрес перехода находится в том же сегменте памяти, что и JMP;
переход типа far (дальний переход) - если адрес перехода находится в дру гом сегменте. Дальний переход может выполняться и в тот же самый сегмент при условии, что в сегментной части операнда указано число, совпадающее с текущим значением CS;
переход с переключением задачи - передача управления другой задаче в мно гозадачной среде. Этот вариант будет рассмотрен в разделе, посвященном за щищенному режиму.
При выполнении переходов типа short команда JMP фактически преоб разовывает значение регистра EIP (или IP), изменяя тем самым смещение следу ющей исполняемой команды относительно начала сегмента кода. Если операнд регистр или переменная в памяти, то его показатель просто копируется в EIP, как если бы это была команда MOV. Если операнд для JMP - непосредственно ука занное число, то его значение суммируется с содержимым EIP, приводя к относи тельному переходу. В ассемблерных программах в качестве операнда обычно указывают имена меток, но на уровне исполняемого кода ассемблер вычисляет и записывает именно относительные смещения.
Выполняя дальний переход в реальном, виртуальном и защищенном режимах (при переходе в сегмент с теми же привилегиями), команда JMP просто загружа ет новое значение в EIP и новый селектор сегмента кода в CS, используя старшие бит операнда как новое значение для CS и младшие или 32 бит в качестве значений IP или EIP.
Команда Назначение Процессор Jcc метка Условный переход Это набор команд, выполняющих переход (типа short или near), если удовлет воряется соответствующее условие, которым в каждом случае реально является состояние тех или иных флагов. Но, когда команда из набора Jcc используется сразу после СМР, условия приобретают формулировки, соответствующие отно шениям между операндами СМР (см. табл. 7). Например, если операнды СМР были равны, то команда JE, выполненная сразу после СМР, осуществит переход.
Операнд для всех команд из набора Jcc - 8-битное или 32-битное смещение отно сительно текущей команды.
Слова выше и ниже в таблице относятся к сравнению чисел без знака;
сло ва больше и меньше учитывают знак.
Команды Jcc не поддерживают дальних переходов, поэтому, если требуется вы полнить условный переход на дальнюю метку, необходимо использовать команду из набора Jcc с обратным условием и дальний JMP, как, например:
jne local_ far_label ;
Переход, если АХ = 0.
local команды Таблица 7. Варианты команды Jcc Код команды Реальное условие Условие для CMP JA Если выше CF = 0 и ZF = JBE Если не ниже и не равно JAE Если выше или равно CF = 0 Если не ниже JNC Если нет переноса JB ниже JNAE Если не выше и но равно JC Если перенос JBE Если ниже или равно CF = 1 или ZF = JNA Если не выше JE Если равно JZ Если ноль JG Если больше ZF = 0 и SF = OF Если не меньше и не равно JGE Если больше или равно SF = OF JNL Если не меньше JL Если меньше SF 0 OF JNGE Если не больше и не равно JLE Если меньше или равно ZF = 1 или SF 0 OF JNG Если не больше JNE Если не равно ZF = JNZ Если не ноль JNO OF = 0 Если нет переполнения JO Если есть переполнение JNP Если нет четности PF = JPO Если нечетное JP Если есть четность JPE Если четное JNS SF = 0 Если нет знака JS Если есть знак Команда Назначение Процессор JCXZ Переход, если СХ 0 JECXZ метка Переход, если ЕСХ 0 Выполняет ближний переход на указанную метку, если регистр СХ или ЕСХ (для JCXZ и JECXZ соответственно) равен нулю. Так же как и команды из серии Jcc, JCXZ и JECXZ не могут выполнять дальних переходов. Проверка СХ нулю, например, может потребоваться в начале организованного ко мандой LOOPNE, - если в него войти с СХ = 0, то он будет выполнен 65 535 раз.
Команда Назначение Процессор Цикл LOOP метка Процессоры Intel в реальном режиме Уменьшает регистр ЕСХ на 1 и выполняет переход типа short на метку (кото рая не может быть дальше расстояния -128...+ 127 байт от команды ЮОР), ЕСХ не равен нулю. Эта команда используется для организации циклов, в кото рых регистр ЕСХ (или СХ при 16-битной адресации) играет роль счетчика. Так, в следующем фрагменте команда ADD выполнится раз:
loop_start:
add loop loop_start Команда LOOP полностью эквивалентна паре команд dec ecx jnz метка Но LOOP короче этих двух команд на один байт и не изменяет значения флагов.
Команда Назначение Процессор LOOPE метка Цикл, пока равно LOOPZ метка Цикл, пока ноль LOOPNE метка Цикл, пока не равно LOOPNZ метка Цикл, пока не ноль Все перечисленные команды уменьшают регистр ЕСХ на один, после чего вы полняют переход типа short, если ЕСХ не равен нулю и если выполняется условие.
Для команд и условием является равенство единице флага ZF, для команд LOOPNE и - равенство флага ZF нулю. Сами команды LOOPcc не изменяют значений флагов, так что ZF должен быть установлен (или сброшен) предшествующей командой. Например, следующий фрагмент копирует строку из в строку в ES:DI (см. описание команд работы со строками), пока не кончится строка (СХ = 0) или пока не встретится символ с ASCII-кодом 13 (конец строки):
mov stosb Команда Назначение Процессор CALL операнд Вызов процедуры Сохраняет текущий адрес в стеке и передает управление по адресу, указанно му в операнде. Операндом может быть непосредственное значение адреса (метка в ассемблерных программах), регистр или переменная, содержащие адрес пере хода. Если в качестве* адреса перехода указано только смещение, считается, что адрес расположен в том же что и команда CALL. При этом, так же как и в случае с JMP, выполняется ближний вызов процедуры. Процессор помещает значение регистра (IP при 16-битной адресации), соответствующее следую щей за CALL команде, в стек и загружает ь EIP новое значение, осуществляя тем Непривилегированные команды самым передачу управления. Если операнд CALL - регистр или переменная, то его значение рассматривается как абсолютное смещение, если операнд - ближ няя метка в программе, то ассемблер указывает ее относительное смещение. Что бы выполнить дальний CALL в реальном режиме, режиме V86 или в защищен ном режиме при переходе в сегмент с теми же привилегиями, процессор помещает в стек значения регистров CS и (IP при 16-битной адресации) и осуществляет дальний переход аналогично команде Команда Назначение Процессор RET число Возврат из процедуры число число считывает из стека слово (или двойное слово, в зависимости от режима адресации) и загружает его в IP (или EIP), выполняя тем самым действия, обрат ные ближнему вызову процедуры командой CALL. Команда RETF загружает из стека IP (EIP) и CS, возвращаясь из дальней процедуры. Если в программе указа на команда RET, ассемблер заменит ее на RETN или RETF в зависимости от того, как была описана процедура, которую эта команда завершает. Операнд для RET необязателен, но, если он присутствует, после считывания адреса возврата из сте ка будет удалено указанное количество байтов - это нужно, если при вызове про цедуры ей передавались параметры через стек.
Команда Назначение Процессор INT число Вызов прерывания INT аналогично команде CALL помещает в стек содержимое регистров EFLAGS, CS и EIP, после чего передает управление программе, называемой обработчиком прерываний с указанным в качестве операнда номером (число от 0 до В ре альном режиме адреса обработчиков прерываний считываются из таблицы, начи нающейся в памяти по адресу 0000h:0000h. Адрес каждого обработчика занимает байта, вот почему, например, обработчик прерывания находится в памяти по адресу 0000h:0040h. В защищенном режиме адреса обработчиков прерываний находятся в таблице IDT и обычно недоступны для прямого чтения или так что для установки собственного обработчика программа должна обращаться к операционной системе. В DOS вызовы прерываний используются для выполне ния большинства системных функций - работы с файлами, вводом/выводом и т. д. Например, следующий фрагмент кода завершает выполнение программы и возвращает управление DOS:
int 21h Команда Назначение Процессор Возврат из обработчика прерывания Процессоры в реальном режиме Возврат управления из обработчика прерывания или исключения. за гружает из стека значения IP, CS и FLAGS, a IRETD - CS и EFLAGS соот ветственно. Единственное отличие IRET от RETF состоит в том, что значение ре гистра флагов восстанавливается, из-за чего многим обработчикам прерываний приходится изменять величину EFLAGS, находящегося в стеке, чтобы, например, вернуть флаг CF, установленный в случае ошибки.
Команда Назначение Процессор INT3 Вызов прерывания 3 Размер этой команды - один (код что делает ее удобной для до водки программ отладчиками, работающими в реальном режиме. Они записыва ют этот байт вместо первого байта команды, перед которой требуется точка оста нова, и переопределяют адрес обработчика прерывания 3 на соответствующую процедуру внутри отладчика.
Команда. Процессор INTO Вызов прерывания 4 при переполнении INTO - еще одна специальная форма команды INT. Она вызывает обработчик прерывания 4, если флаг OF установлен в Команда Назначение Процессор BOUND Проверка выхода за границы массива BOUND проверяет, не выходит ли значение первого операнда (регистр), взя тое как число со знаком, за границы, указанные во втором операнде (переменная).
Границы - два слова или двойных слова (в от разрядности операн дов), рассматриваемые как целые со знаком и расположенные в памяти подряд.
Первая граница считается нижней, вторая - верхней. Если индекс меньше ниж ней границы или больше верхней, вызывается прерывание 5 (или исключение #BR), причем адрес возврата указывает не на следующую команду, а на BOUND, так что обработчик должен исправить значение индекса или границ, прежде чем выполнять команду IRET.
Команда Назначение Процессор ENTER Вход в процедуру Команда ENTER создает стековый кадр заданного размера и уровня вложен ности (оба операнда - числа;
уровень вложенности может принимать значения только от 0 до 31) с целью вызова процедуры, использующей динамическое рас пределение памяти в стеке для своих локальных переменных. Так, команда enter помещает в стек указатели на стековый кадр текущей процедуры и той, из кото рой вызывалась текущая, создает стековый кадр размером 2 Кб для Непривилегированные команды процедуры и помещает в ЕВР адрес начала кадра. Пусть процедура MAIN имеет уровень ЕВР Х ЕВР вложенности 0, процедура PROCA запускает ЕВР для MAIN ся из MAIN и имеет уровень вложенности 1, и PROCB запускается из PROCA с уровнем локальные вложенности 2. Тогда стек при входе в проце для MAIN дуру МАШ имеет вид, показанный на рис. 10.
Теперь процедура МАШ может определять свои локальные переменные в памяти, исполь зуя текущее значение ЕВР. Рис. 10. Стековый кадр процедуры нулевого уровня На первом уровне вложенности процедура (MAIN) PROCA, как показано на рис. может созда вать свои локальные переменные, применяя текущее значение ЕВР, и получит до ступ к локальным переменным процедуры МАШ, используя значение ЕВР для МАШ, помещенное в стек командой ENTER.
Процедура PROCB на втором уровне вложен ности (см. рис. 12) получает доступ как локаль ным переменным процедуры PROCA, применяя значение ЕВР для PROCA, так и к локальным переменным процедуры МАШ, используя зна чение ЕВР для МАШ.
старый ЕВР MAIN локальные переменные MAIN ЕВР ЕВР для MAIN ЕВР MAIN ЕВР для PROCA локальные переменные для PROCA ESP ESP Рис. Стековый кадр Рис. 12. Стековый кадр процедуры процедуры первого уровня второго уровня (PROCB) Команда Назначение LEAVE Выход из процедуры Команда выполняет действия, противоположные команде ENTER. Фактически LEAVE только копирует содержимое ЕВР в ESP, тем самым выбрасывая из стека Процессоры в реальном режиме весь кадр, созданный последней выполненной командой ENTER, и считывает из стека ЕВР для предыдущей процедуры, что одновременно восстанавливает и зна чение, которое имел ESP до вызова последней команды ENTER.
2.3.8. Строковые операции Все команды для работы со строками считают, что строка-источник находится по адресу DS:SI (или DS:ESI), то есть в сегменте памяти, указанном в DS Со сме щением в SI, а строка-приемник - соответственно в ES:DI (или ES:EDI). Кроме того, все строковые команды работают только с одним элементом строки (байтом, словом или двойным словом) за один раз. Для того чтобы команда выполнялась над всей строкой, необходим один из префиксов повторения операций.
Команда Назначение Процессор REP Повторять REPE Повторять, пока равно REPNE Повторять, пока не равно REPZ Повторять, пока ноль REPNZ Повторять, пока не ноль Все перечисленные команды являются префиксами для операций над строка ми. Любой из префиксов выполняет следующую за ним команду строковой обра ботки столько раз, сколько указано в регистре ЕСХ (или СХ, в зависимости от разрядности адреса), уменьшая его при каждом выполнении команды на Кроме того, REPZ и REPE прекращают повторения команды, если флаг ZF сброшен в О, a REPNZ и REPNE прекращают повторения, если флаг ZF установлен в 1. Пре фикс REP обычно используется с командами INS, OUTS, MOVS, LODS, а префиксы REPE, REPNE, REPZ и REPNZ - с командами CMPS и SCAS. Пове дение префиксов в других случаях не определено.
Команда Назначение Процессор Копирование строки Копирование строки байтов MOVSW Копирование строки слов Копирование строки двойных слов Копирует один байт (MOVSB), слово (MOVSW) или двойное слово из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) в па мять по адресу ES:EDI (или ES:DI). При использовании формы записи MOVS ассемблер сам определяет по типу указанных операндов (принято указывать имена копируемых строк, но можно применять любые два операнда подходящего типа), ка кую из трех форм этой команды (MOVSB, MOVSW или MOVSD) выбрать. Исполь зуя MOVS с операндами, разрешается заменить регистр DS другим с помощью пре фикса замены сегмента (ES:, GS:, FS:, CS:, регистр ES заменить нельзя. После выполнения команды регистры ESI (или SI) и EDI (или DI) увеличиваются на 1, или 4 (если копируются байты, слова или двойные слова), когда флаг DF = О, Непривилегированные команды и уменьшаются, когда DF = 1. Команда MOVS с префиксом REP выполняет копи рование строки длиной в ЕСХ (или СХ) байтов, слов или двойных слов.
Команда Назначение Процессор Сравнение строк Сравнение строк байтов CMPSW Сравнение строк слов Сравнение строк двойных слов Сравнивает один байт (CMPSB), слово (CMPSW) или двойное слово (CMPSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) с бай том, словом или двойным словом по адресу ES:EDI (или ES:DI) и устанавливает флаги аналогично команде СМР. При использовании формы записи CMPS ассемб лер сам определяет по типу указанных операндов (принято указывать имена срав ниваемых строк, но можно использовать любые два операнда подходящего типа), какую из трех форм этой команды (CMPSB, CMPSW или CMPSD) выбрать.
Применяя CMPS с операндами, можно заменить регистр DS другим, воспользо вавшись префиксом замены сегмента регистр ES заменить нельзя. После выполнения команды регистры ESI (или SI) и EDI (или DI) уве личиваются на 1, 2 или 4 (если сравниваются байты, слова или двойные слова), когда флаг DF = 0, и уменьшаются, когда DF = 1. Команда CMPS с префиксами REPNE/REPNZ или REPE/REPZ выполняет сравнение строки длиной в ЕСХ (или СХ) байтов, слов или двойных слов. В первом случае сравнение продолжает ся до первого совпадения в строках, а во втором Ч до первого несовпадения.
Команда Назначение Процессор SCAS приемник Сканирование строки SCASB Сканирование строки байтов SCASW Сканирование строки слов SCASD Сканирование строки двойных слов Сравнивает содержимое регистра AL (SCASB), AX (SCASW) или ЕАХ с байтом, словом или двойным словом из памяти по адресу ES:EDI (или ES:DI, в за висимости от разрядности адреса) и устанавливает флаги аналогично команде СМР.
При использовании формы записи SCAS ассемблер сам определяет по типу указан ного операнда (принято указывать имя сканируемой строки, но можно использовать любой операнд подходящего типа), какую из трех форм этой команды (SCASE, SCASW или SCASD) выбрать. После выполнения команды регистр EDI (или DI) увеличивается на 1, 2 или 4 (если сканируются байты, слова или двойные слова), когда флаг DF 0, и уменьшается, когда DF = 1. Команда SCAS с префиксами REPNE/REPNZ или REPE/REPZ выполняет сканирование строки длиной в ЕСХ (или байтов, слов или двойных слов. В первом случае сканирование ется до первого элемента строки, с содержимым аккумулятора, а во втором - до первого отличного.
Процессоры в реальном Команда Назначение Процессор LODS источник Чтение из строки LODSB Чтение байта из строки LODSW Чтение слова из строки LODSD Чтение двойного слова из строки Копирует один байт (LODSB), слово или двойное слово (LODSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса) в регистр AL, АХ или ЕАХ соответственно. использовании формы записи LODS ассемблер сам определяет по типу указанного операнда (принято указы вать имя но можно использовать любой операнд подходящего типа), ка кую из трех форм этой команды (LODSB, LODSW или LODSD) выбрать.
няя LODS с операндом, можно заменить регистр DS на другой с префикса замены сегмента (ES:, GS:, FS:, CS:, После выполнения регистр ESI (или SI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), когда флаг = 0, и уменьшается, когда DF 1. Команда LODS с префиксом REP выполнит копирование строки длиной в ЕСХ (или СХ), и в аккумуляторе окажется последний элемент строки. На самом деле LODS ис пользуют без префиксов, часто внутри цикла в паре с командой STOS, так что LODS считывает число, другие команды выполняют над ним какие-нибудь дей ствия, а затем STOS записывает измененное число на прежнее место в памяти.
Команда Назначение Процессор STOS приемник Запись в строку STOSB Запись байта в строку STOSW Запись слова в строку STOSD Запись двойного слова в строку Копирует регистр AL (STOSB), AX (STOSW) или ЕАХ (STOSD) в по адресу (или ES:DI, в зависимости от разрядности адреса). При использо вании формы записи STOS ассемблер сам определяет по типу указанного операн да (принято указывать имя строки, но можно использовать любой операнд под ходящего типа), какую из трех форм этой команды (STOSB, STOSW или выбрать. После выполнения команды регистр EDI (или DI) увеличивается на 1, 2 или 4 (если копируется байт, слово или двойное слово), когда флаг DF = О, и уменьшается, когда DF = 1. Команда STOS с префиксом REP заполнит строку длиной в ЕСХ (или СХ) числом, находящимся в аккумуляторе.
Команда Назначение Процессор INS DX Чтение строки из порта INSB Чтение строки байт из порта INSW Чтение строки слов из порта INSD Чтение строки двойных слов из порта Непривилегированные команды ' Считывает из порта ввода-вывода, номер которого указан в регистре DX, байт (INSB), слово (INSW) или двойное слово (INSD) в память по адресу ES:EDI (или ES:DI, в зависимости от разрядности адреса). При использовании формы записи INS ассемблер определяет по типу указанного операнда, какую из трех форм этой команды (INSB, INSW или INSD) употребить. После выполнения команды ре гистр EDI (или DI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), когда флаг DF = 0, и уменьшается, когда DF 1. Команда INS с префиксом REP считывает блок данных из порта длиной в ЕСХ (или СХ) байтов, слов или двойных слов.
Команда Назначение Процессор OUTS Запись строки в порт OUTSB Запись строки байтов в порт OUTSW Запись строки слов в порт OUTSD Запись строки двойных слов в порт Записывает в ввода-вывода, номер которого указан в регистре DX, байт (OUTSB), слово (OUTSW) или двойное слово (OUTSD) из памяти по адресу DS:ESI (или DS:SI, в зависимости от разрядности адреса). При использовании формы записи OUTS ассемблер определяет по типу указанного операнда, какую из трех форм этой команды (OUTSB, OUTSW или OUTSD) употребить. Приме няя OUTS с операндами, также можно заменить регистр DS другим с помощью префикса замены сегмента (ES:, GS:, FS:, CS:, После выполнения команды регистр ESI (или SI) увеличивается на 1, 2 или 4 (если считывается байт, слово или двойное слово), когда флаг DF = и уменьшается, когда DF = 1. Команда OUTS с префиксом REP записывает блок данных размером в ЕСХ (или СХ) бай тов, слов или двойных слов в указанный порт. Все процессоры до Pentium не про веряли готовность порта принять новые данные в ходе выполнения команды REP OUTS, так что, если порт не успевал обрабатывать информацию с той скорос тью, с которой ее поставляла эта команда, часть данных терялась.
2.3.9. Управление флагами Команда Назначение Процессор STC Установить флаг переноса Устанавливает флаг CF в 1.
Команда Назначение Процессор Сбросить флаг переноса Сбрасывает флаг CF в 0.
Команда Назначение Процессор CMC Инвертировать флаг переноса в реальном режиме Инвертирует флаг СЕ Команда Назначение Процессор STD Установить флаг направления Устанавливает DF в 1, так что при последующих строковых операциях регистры DI и SI будут уменьшаться.
Команда Назначение Процессор CLD Сбросить флаг направления Сбрасывает флаг DF в 0, так что при последующих строковых операциях ре гистры DI и SI будут увеличиваться.
Команда Назначение Процессор Загрузить флаги состояния в АН Копирует младший байт регистра FLAGS в АН, включая флаги SF (бит 7), ZF (бит AF (бит 4), PF (бит 2) и CF (бит 0). Бит 1 устанавливается в 1, биты и 5 - в 0.
Команда Назначение Процессор SAHF Загрузить флаги состояния из АН Загружает флаги SF, ZF, AF, PF и CF из регистра АН значениями битов и 0 соответственно. Зарезервированные биты и 5 регистра флагов не изменяются.
Команда Назначение Процессор PUSHF Поместить FLAGS в стек PUSHFD Поместить в стек Эти команды копируют содержимое регистра FLAGS или EFLAGS в стек (уменьшая SP или ESP на 2 или 4 соответственно). При копировании регистра EFLAGS флаги VM и RF (биты 16 и 17) не копируются, а соответствующие биты в двойном слове, помещенном в стек, обнуляются.
Команда Назначение Процессор POPF Загрузить FLAGS из стека POPFD Х Загрузить EFLAGS из стека Считывает из вершины стека слово (POPF) или двойное слово (POPFD) и по мещает в регистр FLAGS или EFLAGS. Эффект этих команд зависит от режима, в котором выполняется программа: в реальном и защищенном режимах с уров нем привилегий 0 модифицируются все незарезервированные флаги в EFLAGS, кроме VIP, VIF и VM. VIP и VIF обнуляются, и VM не изменяется. В защищен ном режиме с уровнем привилегий, большим нуля, но меньшим или Непривилегированные команды IOPL, модифицируются все флаги, кроме VIP, VM и IOPL. В режиме V86 не модифицируются флаги VIF, VIP, VM, IOPL и RF.
Команда Назначение Процессор Запретить прерывания Сбрасывает флаг IF в 0. После выполнения этой команды процессор игнори рует все прерывания от внешних устройств (кроме NMI). В защищенном режиме эта команда, так же как и все другие команды, модифицирующие флаг IF (POPF или IRET), выполняется, только если программе даны соответствующие приви легии (CPL IOPL).
Команда Назначение Процессор STI Разрешить прерывания Устанавливает флаг IF в 1, отменяя тем самым действие команды CLI.
Команда Назначение Процессор SALC Установить AL в соответствии с CF Устанавливает AL в если флаг CF = 1, и сбрасывает в если CF = 0. Это недокументированная команда с кодом OD6h, присутствующая во всех процессо рах Intel и совместимых с ними (начиная с 8086). В документации на Pentium Pro команда SALC упоминается в общем списке команд, но ее действие не описывается (оно аналогично SBB AL,AL, однако значения флагов не Загрузка сегментных регистров Команда Назначение Процессор Загрузить адрес, используя DS LES Загрузить адрес, используя ES LFS Загрузить адрес, используя FS LGS Загрузить адрес, используя GS Загрузить адрес, используя SS Второй операнд для всех этих команд - переменная в памяти раз мером в 32 или 48 бит (в зависимости от разрядности операндов). Первые 16 или 32 бита из этой переменной загружаются в регистр общего назначения, указанный в качестве первого операнда, а следующие бит - в соответствующий сегмент ный регистр (DS для LDS, ES для LES и т. д.). В защищенном режиме значение, загружаемое в сегментный регистр, всегда должно быть правильным селектором сегмента (в реальном режиме любое число может использоваться как селектор).
2.3.11. команды Команда Назначение Процессор NOP Отсутствие операции Процессоры Intel в реальном режиме NOP - однобайтная команда (код которая не выполняет ничего, только занимает место и время. Код этой команды фактически соответствует XCHG Многие команды разрешается записать так, что они не будут приводить ни к каким действиям, например:
ax,ax байта.
xchg ax,ax байта.
lea bx,[bx+0] 3 байта (8Dh, 5Fh, OOh но многие ассемблеры, встретив команду, реально используют более короткую lea с кодом 8Dh eax,0 байта.
eax 5 байт.
Команда Назначение Процессор LOCK Префикс блокировки шины данных На все время выполнения команды, снабженной таким префиксом, будет локирована шина данных, и если в системе присутствует другой процессор, он не сможет обращаться к памяти, пока не закончится выполнение команды с префик сом LOCK. Команда XCHG всегда выполняется автоматически с блокировкой до ступа к памяти, даже если префикс LOCK не указан. Этот префикс можно исполь зовать только с командами ADD, ADC, AND, ВТС, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD и XCHG.
Команда Назначение Процессор Неопределенная операция Р Эта команда всегда вызывает ошибку неопределенная операция (исключе ние #UD). Впервые она описана как таковая для Pentium но во всех предыду щих процессорах UD2 (код OFh не была определена и, естественно, приво дила к такой же ошибке. Команда предназначена для тестирования программного обеспечения, в частности операционных систем, которые должны уметь коррект но обрабатывать такую ошибку. Название команды происходит от команды UD (код OFh которая была определена AMD для процессоров AMD K5.
Команда Назначение Процессор CPUID Идентификация процессора сообщает информацию о производителе, типе и модификации процес сора и о наличии различных расширений. Команда CPUID поддерживается Intel, начиная с процессоров Intel SL, U5S, Cyrix Ml, AMD 80486DX4. Попробуйте установить флаг ID в 1 (бит 21 в регистре EFLAGS) - если это получается, значит, команда CPUID поддерживается.
Результат работы CPUID зависит от значения регистра ЕАХ. Если ЕАХ = О, CPUID возвращает в ЕАХ максимальное значение, с ее можно (2 для для Р5), а регистры EBX:ECX:EDX содержат строку - иден тификатор производителя (см. табл. 8).
команды Таблица 8. Строки производителей в CPUID Производитель Строка в EBX:ECX:EDX Intel UMC UMC UMC Cyrix Cyrixlnstead AMD AuthenticAMD NexGen Centaur Technology CentaurHalls Например, для процессоров Intel регистр ЕВХ содержит Genu ЕСХ - (49656E69h), a EDX - (6C65746Eh).
Если EAX = 1, CPUID возвращает в ЕАХ информацию о версии процессора, а в EDX - сведения о поддерживаемых расширениях. Многие понятия в этом опи сании относятся к работе процессора в защищенном режиме и рассмотрены ниже.
Информация о версии процессора:
Биты 3-0 - модификация.
Биты 7-4 - модель.
Биты - семейство (3 для для для Pentium, 6 для Pentium Pro).
Биты 13-12 - тип (0 - OEM, 1 - Overdrive, 2 - Dual).
Биты Ч зарезервированы и равны нулю.
Поддерживаемые расширения (регистр EDX):
Бит 0: FPU - процессор содержит FPU и может выполнять весь набор команд 80387.
Бит 1:
- процессор поддерживает усовершенствованный режим V (флаги и VIP в EFLAGS, биты VME и PVI в CRO).
Бит 2: DE - процессор поддерживает точки останова по вводу/выводу, бит DE в CRO.
Бит 3: PSE - процессор поддерживает страницы до 4 Мб, бит PSE в CR4, мо дифицированные биты в элементах списков страниц и таблиц стра ниц (РТЕ).
Бит 4: TSC - процессор поддерживает команду RDTSC и бит TSC в CR4.
Бит 5: MSR - процессор поддерживает команды RDMSR и WRMSR и машин но-специфичные регистры, совместимые с Pentium.
Бит 6: РАЕ - процессор поддерживает физические адреса больше 32 бит, до полнительный уровень в таблицах трансляции страниц, страницы по 2 Мб и бит РАЕ в CR4. Число битов для физических адресов зависит от модели процессора. Так, Pentium поддерживает 36 бит.
Бит 6: РТЕ (только для Cyrix).
Бит 7: МСЕ - процессор поддерживает бит МСЕ в CR4.
Бит 8: СХ8 - процессор поддерживает команду CMPXCHG8B.
Бит 9: APIC - процессор содержит встроенный контроллер прерываний (APIC), активизирован и доступен.
Бит 9: PGE (только для AMD).
Процессоры в реальном режиме Бит 10: зарезервирован.
Бит SEP - процессор поддерживает быстрые системные вызовы, команды SYSENTER и SYSEXIT (Pentium II).
Бит 12: MTRR - процессор поддерживает машинно-специфичные MTRR.
Бит 13: PGE - процессор поддерживает бит PGE в CR4 и флаги в PTDE и РТЕ, указывающие элементы TLB, которые принадлежат сразу нескольким задачам.
Бит 14: МСА - процессор поддерживает машинно-специфичный регистр MCG_CAP.
Бит 15: CMOV - процессор поддерживает команды CMOVcc и (если бит О EDX установлен) FCMOVcc (Pentium Pro).
Бит 16: PAT - процессор поддерживает таблицу атрибутов страниц.
Биты 17-22: зарезервированы.
Бит 23:
- процессор поддерживает набор команд ММХ.
Бит 24: FXSR - процессор поддерживает команды быстрого чтения/записи (ММХ2).
Бит 25: SSE - процессор поддерживает расширения SSE (Pentium III).
Биты 31-26: зарезервированы.
Если ЕАХ 2, CPUID на процессорах семейства Р6 возвращает в регистрах ЕАХ, ЕВХ, ЕСХ и EDX информацию о кэшах и TLB. Самый младший байт ЕАХ (регистр AL) определяет, сколько раз надо вызвать CPUID с ЕАХ = 2, чтобы полу чить информацию обо всех кэшах (1 для Pentium и Pentium II). Самый старший бит (бит каждого регистра указывает, содержит ли этот регистр правильную ин формацию (бит 31 0) или он зарезервирован (бит 31 = 1). В первом случае регистр содержит информацию в дескрипторах со следующими значениями:
- пустой дескриптор;
- TLB команд, страницы, 4-сторонняя ассоциативность, 32 элемента;
02h - TLB команд, 4-мегабайтные 4-сторонняя ассоциативность, 4 элемента;
03h - TLB данных, 4-килобайтные страницы, 4-сторонняя ассоциативность, 64 элемента;
04h - TLB данных, 4-мегабайтные страницы, 4-сторонняя ассоциативность, 8 элементов;
06h - кэш команд, Кб, 4-сторонняя ассоциативность, 32 байта в строке;
08h - кэш команд, 16 Кб, 4-сторонняя ассоциативность, 32 байта в строке;
- кэш данных, 8 Кб, 2-сторонняя ассоциативность, 32 байта в строке;
кэш данных, 16 Кб, 2-сторонняя ассоциативность, 32 байта в кэш, 128 Кб, 4-сторонняя ассоциативность, 32 байта в строке;
42h - унифицированный кэш, 256 Кб, 4-сторонняя ассоциативность, 32 байта в строке;
43h - унифицированный кэш, Кб, 4-сторонняя ассоциативность, 32 байта в строке;
Числа с плавающей запятой, 44h - унифицированный кэш, 1 Мб, ассоциативность, 32 байта в строке.
Совместимые с Intel процессоры AMD и Cyrix поддерживают вызов расши ренных функций CPUID со значениями ЕАХ, в которых самый старший бит всегда установлен в 1.
ЕАХ = возвращает в ЕАХ максимальный номер расширенной фун кции CPUID, поддерживаемой данным процессором.
ЕАХ = возвращает в ЕАХ 051Xh для AMD K5 (X - номер модифи кации) или для AMD В EDX эта функция возвращает информацию о поддерживаемых расширениях (указаны только флаги, отличающиеся от CPUID с ЕАХ = 1).
Бит 5: MSR Ч процессор поддерживает машинно-специфичные регистры, со вместимые с К5.
Бит 10: процессор поддерживает команды SYSCALL и SYSRET.
Бит процессор поддерживает команды FCMOVcc.
Бит 24: процессор поддерживает ММХ с расширениями от Cyrix.
Бит 25: процессор поддерживает набор команд AMD 3D.
ЕАХ - 80000003h и 80000004h - последовательный вызов CPUID с этими значениями в ЕАХ возвращает в EAX:EBX:ECX:EDX последовательно четыре части строки - имени процессора. Например: AMD-K5(tm) Processor.
ЕАХ = 80000005h - команда информацию о TLB в регистре ЕВХ (старшее слово Ч TLB данных, младшее слово Ч TLB команд, старший байт Ч ас социативность, младший байт - число элементов), о кэше данных в регистре ЕСХ и о кэше команд в регистре EDX (биты - размер в килобайтах, биты ассоциативность, биты 15-8 - число линий на тэг, биты 7-0 - число байтов на линию).
2.4. Числа с плавающей запятой В процессорах Intel все операции с плавающей запятой выполняет специаль ное устройство - FPU (Floating Point Unit) - с собственными регистрами и набо ром команд, поставлявшееся сначала в виде сопроцессора (8087, 80287, 80387, 80487), а начиная с 80486DX - встраивающееся в основной процессор. FPU пол ностью соответствует стандартам IEEE 754 и IEEE 854 (с 80486).
2.4.1. Типы данных FPU Числовой процессор может выполнять операции с семью разными типами дан ных, представленными в табл. 9: три целых двоичных, один целый десятичный и три с плавающей запятой.
Вещественные числа хранятся, как и все данные, в форме двоичных чисел.
Двоичная запись числа с плавающей запятой аналогична десятичной, только по зиции справа от запятой соответствуют не делению на 10 в соответствующей сте пени, а делению на 2. Переведем для примера в двоичный вид число 0,625:
Процессоры Intel в реальном режиме Таблица 9. Типы данных FPU Количество Тип данных Бит значащих Пределы цифр Целое слово 16 Короткое целое 32 Длинное слово 64 Упакованное десятичное 80 Короткое вещественное 32 Длинное вещественное 64 15- Расширенное 80 вещественное 0,625 - 1/2 - 0, 1/4 больше, чем 0, 0,125 = Итак, 0,625 = При записи вещественных чисел всегда выполняют нор мализацию - умножают число на такую степень двойки, чтобы перед десятичной точкой стояла единица, в нашем случае 0,625 = - х Говорят, что число имеет мантиссу 1,01 и экспоненту Как можно заметить, при использовании этого алгоритма первая цифра мантиссы всегда равна 1, по этому ее можно не писать, увеличивая тем самым точность представления числа дополнительно на 1 бит. Кроме того, значение экспоненты хранят не в виде цело го со знаком, а в виде суммы с некоторым числом так, чтобы всегда было только положительное число и чтобы вещественные числа легко сопоставлялись в большинстве случаев достаточно сравнить экспоненту. Теперь мы можем рас смотреть вещественные форматы IEEE, применяемые в процессорах Intel:
короткое вещественное: бит 31 - знак мантиссы, биты 30-23 - 8-битная эк спонента +127, биты 22-0 - 23-битная мантисса без первой цифры;
длинное вещественное: бит 63 - знак мантиссы, биты 62-52 - 11-битная эк спонента +1024, биты 51-0 - 52-битная мантисса без первой цифры;
расширенное вещественное: бит 79 - знак биты 78-64 - 15-бит ная экспонента +16 383, биты 63-0 - 64-битная мантисса с первой цифрой (то есть бит 63 равен FPU выполняет все вычисления в 80-битном расширенном формате, а 32 и 64-битные числа используются для обмена данными с основным процессором и Кроме обычных чисел формат IEEE предусматривает ных случаев, которые могут получаться в математических операций и над которыми также можно операции:
все биты числа сброшены в а знаковый бит - все остальные биты - нули;
Числа с плавающей запятой знаковый бит - 0, все биты мантиссы Ч О, все биты экспоненты - 1;
О отрицательная знаковый бит Ч 1, все биты мантиссы Ч О, все биты экспоненты - 1;
а числа: все биты экспоненты - 0 для ра боты с маленькими числами для расширенной точности);
а знаковый бит - 1, первый бит мантиссы (первые два для 80-битных чисел) - 1, а остальные - 0, все биты экспоненты - 1;
не-число типа все биты экспоненты - 1, первый бит мантиссы - 0 (для 80-битных чисел первые два бита мантиссы - 10), а среди битов единицы;
не-число типа QNAN (тихое): все биты экспоненты - 1, первый бит ман тиссы (первые два для 80-битных чисел) - 1, среди битов единицы. - один из вариантов а неподдерживаемое число: все остальные ситуации.
Остальные форматы данных FPU также допускают неопределенность Ч единица в старшем бите и нули в остальных для целых чисел, и старшие 16 бит - единицы для упакованных десятичных чисел.
2.4.2. Регистры FPU FPU предоставляет восемь регистров для хранения данных и пять вспомога тельных регистров.
Регистры данных (RO - R7) не адресуются по именам, как основного процессора, а рассматриваются в качестве стека, вершина которого называется ST;
более глубокие элементы - ST(1), ST(2) и так далее до Если, например, в какой-то момент времени регистр R5 называется ST (см. рис. 13), то после запи си в этот стек числа оно будет записано в R4, который станет называться ST, R5 станет называться и т. д.
RO ST(3) R1 ST(4) ST(5) R3 ST(6) R ST TOP= R R6 ST(1) R7 ST(2) FDP Рис. Регистры FPU 3 для DOS Процессоры Intel в реальном режиме К регистрам RO - нельзя обращаться напрямую, по именам, но если про цессор поддерживает расширение ММХ, то мантиссы, находящиеся в этих регистрах, становятся доступны, как - ММ7.
Регистр состояний SR содержит слово состояния FPU:
бит В - занятость FPU - этот флаг существует для совместимости с 8087, и его значение всегда совпадает с ES бит 14: СЗ - условный флаг биты 13-11: ТОР - число от 0 до 7, показывающее, какой из регистров данных RO - R7 в настоящий момент является вершиной стека бит 10: условный флаг бит 9: С1 - условный флаг бит 8: СО - условный флаг О бит 7: ES - общий флаг ошибки - равен 1, если произошло хотя бы одно не маскированное исключение бит 6: SF - ошибка стека. Если 1, произошло переполнение (команда пы талась писать в непустую позицию в стеке), если С1 0, произошло антипереполнение (команда пыталась считать число из пустой позиции в стеке) бит 5: РЕ - флаг результата - результат не может быть представ лен точно бит 4: UE - флаг антипереполнения - результат слишком маленький бит 3: ОЕ - флаг переполнения - результат слишком большой бит 2: ZE - флаг деления на ноль '- выполнено деление на ноль бит 1: DE Ч флаг операнда Ч выполнена операция над числом бит 0: IE - флаг недопустимой операции - произошла ошибка стека (SF = 1) или выполнена недопустимая операция Биты СО - СЗ применяются так же, как и биты состояния в основном процес соре, - их значения отражают результат выполнения предыдущей команды и ис пользуются для условных переходов;
команды fstsw ax sahf копируют значения битов в регистр FLAGS так, что флаг СО переходит в CF, C2 в PF, а СЗ - в ZF (флаг С2 теряется).
Биты 0-5 отражают различные ошибочные ситуации, которые могут возникать при выполнении команд FPU. Они рассмотрены в описании управляющих регистров.
Регистр управления CR:
биты 15-13: зарезервированы;
бит - управление бесконечностью (поддерживается для совместимо сти с 8087 и 80287 - вне зависимости от значения этого би та > биты 11-10: RC - управление округлением;
биты 9-8: PC - управление точностью;
Числа с плавающей запятой биты 7-6: зарезервированы;
бит 5: РМ Ч маска неточного результата;
бит 4: маска антипереполнения;
бит 3: ОМ - маска переполнения;
бит 2: ZM - маска деления на ноль;
бит 1: маска операнда;
бит 0: IM - маска недействительной операции.
Биты RC определяют способ округления результатов команд FPU до задан ной точности (см. табл. 10).
Таблица 10. Способы округления Значение RC Способ округления 0 К ближайшему числу 1 К отрицательной бесконечности 2 К положительной бесконечности 3 К нулю Биты PC определяют точность результатов команд FADD, FSUB, FSUBR, FMUL, FDIVR и (см. табл. И).
Таблица Точность результатов Значение PC Точность результатов 0 Одинарная точность (32-битные числа) 1 Зарезервировано 2 Двойная точность (64-битные числа) 3 Расширенная точность (80-битные числа) Биты 0-5 регистра CR маскируют соответствующие исключения - если кирующий бит установлен, исключения не происходит, а результат вызвавшей его команды определяется правилами для каждого исключения специально.
Регистр тэгов содержит восемь пар битов, описывающих содержание каж дого регистра данных: 15-14 описывают регистр 13-12 - R6 и т. д. Если пара битов (тэгов) равна соответствующий регистр пуст. 00 означает, что ре гистр содержит число, 01 Ч ноль, 10 Ч не-число, бесконечность, ное число, неподдерживаемое число.
Регистры FIP и FDP содержат адрес последней выполненной команды (кро ме FCLEX, FLDCW, FSTCW, FSTSW, FSTSWAX, FSTENV, FLDENV, FSAVE, FRSTOR и и адрес ее операнда соответственно и используются в обработчиках исключений для анализа вызвавшей его команды.
2.4.3. Исключения FPU При выполнении команд FPU могут возникать шесть типов особых ситуаций, называемых исключениями. При возникновении исключения соответствующий Процессоры Intel в реальном режиме флаг в регистре SR устанавливается в 1 и, если маска этого исключения в регис тре CR не установлена, вызывается обычное прерывание INT (если бит NE в регистре центрального процессора CRO установлен в 1) или (INT 75h), обработчик которого может прочитать регистр SR, чтобы определить тип исклю чения (и FIP, и FDP) и команду, которая его породила, а затем испра вить ситуацию. Если бит маски наступившего исключения в регистре CR уста новлен в 1, по умолчанию выполняются следующие действия:
а неточный результат округляется в соответствии с битами RC (на самом деле это исключение происходит очень часто;
например: дробь 1/6 не может быть представлена десятичным вещественным числом любой точно сти и округляется). При этом флаг показывает, в какую сторону про изошло округление: 0 - вниз, 1 - вверх;
антипереполнение: результат слишком мал, чтобы быть представленным обычным числом, - он преобразуется в число;
переполнение: результат преобразуется в бесконечность соответствующего знака;
а деление на результат преобразуется в бесконечность соответствующе го знака (учитывается и знак нуля);
а операнд: вычисление продолжается, как обычно;
а операция: результат определяется из табл. 12.
12. Результаты операций, приводящих к исключениям Операция Неопределенность Ошибка стека Операция с неподдерживаемым числом Неопределенность Операция с SNAN QNAN Сравнение числа с NAN СО = С2 = СЗ Сложение бесконечностей с одним знаком Неопределенность или вычитание - с разным Умножение нуля на бесконечность Неопределенность Деление бесконечности на бесконечность или О/О Неопределенность Команды и если делитель - Неопределенность и С2 = или делимое - бесконечность Тригонометрическая операция над бесконечностью Неопределенность и С2 = Корень или логарифм, если х < 0, log(x+1), если х < -1 Неопределенность FBSTP, если регистр-источник пуст, содержит NAN, Десятичная бесконечность или превышает десятичных знаков неопределенность FXCH, если один из операндов пуст Неопределенность 2.4.4. пересылки данных Команда Назначение FLD источник Загрузить вещественное число в стек Числа с Команда помещает содержимое источника 64- или 80-битная переменная или в стек и уменьшает ТОР на Команда FLD ST(0) делает копию вер шины стека.
Команда Назначение Процессор FST приемник Скопировать вещественное число из стека FSTP приемник Считать вещественное число из стека Копирует ST(0) в приемник (32- или 64-битную переменную или пустой ST(n) в случае FST;
32-, 64- или 80-битную переменную или пустой ST(n) в слу чае FSTP). FSTP после этого выталкивает число из стека (помечает ST(0) как пустой и увеличивает ТОР на один).
Команда Назначение Процессор Загрузитьцелое число в стек целое число со знаком из источника 32- или 64-битная переменная) в вещественный формат, помещает в вершину стека и уменьшает ТОР на 1.
Команда Назначение Процессор FIST приемник Скопировать целое число из стека FISTP приемник Считать целое число из стека Преобразовывает число из вершины стека в целое со знаком и записывает его в приемник (16- или 32-битная переменная для FIST;
16-, 32- или 64-битная менная для FISTP). FISTP после этого выталкивает число из стека (помечает ST(0) как пустой и увеличивает ТОР на один). Попытка записи слишком боль шого числа, бесконечности или не-числа приводит к исключению недопустимая операция (и записи целой неопределенности, если IM = 1).
Команда Назначение Процессор FBLD источник Загрузить десятичное число в стек Преобразовывает BCD число из источника (80-битная переменная в памяти), помещает в вершину стека и уменьшает ТОР на 1.
Pages: | 1 | 2 | 3 | 4 | 5 | ... | 8 | Книги, научные публикации