- •140010, Г. Люберцы, Московской обл., Октябрьский пр-т, 403.
- •Глава 1. Архитектура реального режима
- •1.1. Память и процессор
- •Глава 1
- •Глава 1
- •1.2. Распределение адресного пространства
- •Глава 1
- •1.3. Регистры процессора
- •Глава 1
- •Глава 1
- •9 7H Шестнадцатернчное обозначение числа
- •Глава 1
- •1.4. Сегментная структура программ
- •Глава 1
- •Глава 1
- •Глава 1
- •1.5. Стек
- •Глава 1
- •1.6. Система прерываний
- •Глава 1
- •Глава I
- •1.7. Система ввода-вывода
- •Глава I
- •Глава 1
- •Глава 2. Основы программирования
- •2.1. Подготовка и отладка программы
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.2. Представление данных
- •Глава 2
- •Глава 2
- •2.3. Описание данных
- •Глава 2
- •Глава 2
- •2.4. Структуры и записи
- •Глава 2
- •Глава 2
- •2.5. Способы адресации
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 2
- •2.7. Вызовы подпрограмм
- •Глава 2
- •2.8. Макросредства ассемблера
- •Глава 2
- •Глава 2
- •Глава 2
- •Глава 3. Команды и алгоритмы
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •Глава 3
- •3.2. Циклы и условные переходы
- •Глава 3
- •Глава 3
- •3.3. Обработка строк
- •Глава 3
- •3.4. Использование подпрограмм
- •Глава 3
- •Глава 3
- •3.5. Двоично-десятичные числа
- •Глава 3
- •Глава 3
- •3.6. Программирование аппаратных средств
- •Глава 3
- •37Ah Порт управлсш!я
- •Глава 3
- •Глава 3
- •Глава 4. Расширенные возможности
- •4.1. Архитектурные особенности
- •Глава 4
- •4.2. Дополнительные режимы адресации
- •Глава 4
- •4.3. Использование средств 32-разрядных процессоров в программировании
- •Глава 4
- •Глава 4
- •Глава 4
- •4.4. Основы защищенного режима
- •Глава 4
- •Глава 4
- •Глава 4
- •Глава 4
- •Idiv Деление целых чисел со знаком
- •Imul Умножение целых чисел со знаком
- •In Ввод из порта
- •Inc Инкремент (увеличение на 1)
- •Int Программное прерывание
- •Into Прерывание по переполнению
- •Iret Возврат из прерывания
- •1 Lods Загрузка операнда из строки : lodsb Загрузка байта из строки lodsw Загрузка слова из строки
- •Операнд
- •Xadd память, регистр
- •Xchg Обмен данными между операндами
- •Xlat Табличная трансляция
- •Xor Логическое исключающее или
- •Содержание
Глава 3
Команды и алгоритмы
101
С другой стороны, ее указание не обязывает нас обязательно использовать команды Pentium. Если в программе предполагается использовать лишь дополнительные команды процессоров 486 или 386, то вместо .586 можно написать .486 или ,386.
Указание любого номера 32-разрядного процессора приведет к тому, что по умолчанию программа будет транслироваться, как 32-разрядное приложение, в то время как нам нужно создать обычное 16-разрядное приложение. Для того, чтобы все адреса в программе рассматривались, как 16-битовые, необходимо придать сегментам команд и данных описатели use 16. Для сегмента стека этот описатель не нужен, так как в стеке
нет поименованных ячеек.
Программа состоит из трех сегментов — команд, данных и стека. Имена сегментов выбраны произвольно. Собственно программа обычно состоит из процедур. Деление на процедуры не обязательно, но повышает ее наглядность и облегчает передачу управления на подпрограммы. В рассматриваемом примере сегмент команд содержит единственную процедуру main, открываемую оператором ргос (от procedure, процедура) и закрываемую оператором endp (end procedure, конец процедуры). Перед обоими операторами указывается имя процедуры, которое в дальнейшем может использоваться в качестве относительного адреса процедуры (в сущности, относительного адреса первого выполнимого предложения этой процедуры). У нас это имя выступает в качестве параметра завершающей программу директивы end. Имена процедур, так же, как и имена сегментов, выбираются произвольно.
Если программа имеет сегмент данных с какими-либо данными, то для того, чтобы к этим данным можно было обратиться, необходимо занести сегментный адрес сегмента данных в один из сегментных регистров. Обычно в качестве такого регистра выбирают DS. Таким образом, предложения, с которых начался текст главной процедуры
mov AX,data Инициализация
mov DS,AX ;сегментного регистра DS ;
где data — имя, данное сегменту данных, практически являются обязательными для любой программы.
Точно также обязательными являются и завершающие предложения
mov AX,4COOh lut 21h
;Вызов функции DOS ;завершения программы
в которых вызывается функция DOS с номером 4Ch, Эта функция, как уже отмечалось, завершает программу, освобождает занимаемую ею память и передает управление командному процессору COMMAND.COM. Еще два замечания следует сделать относительно процедуры трансляции и компоновки программы, Если сегмент данных расположить после сегмента команд, как это сделано в нашем примере, то у транслятора возникнут сложности при обработке встречающихся в программных пред-
ложениях имен полей данных, так как эти имена еще неизвестны транслятору. Для того, чтобы такие, как говорят, «ссылки вперед» могли правильно обрабатываться, следует в команде вызова транслятора TASM заказать два прохода. Это делается указанием ключа /т.2.
С другой неприятностью мы столкнемся, если попытаемся включить в программу операции с 32-разрядными операндами (даже и с командами МП 86). Компоновщик TASM по умолчанию запрещает такого рода операции. Чтобы преодолеть этот запрет, следует в команде вызова компоновщика указать ключ /3.
Таким образом, приведенный в гл. 1 командный файл должен выглядеть (для подготовки программы P.ASM) следующим образом:
tasm /z /zi /n /nil p,p,P tlink /x /v /3 p,p
Включение указанных описателей и ключей не обязывает нас использовать новые команды или 32-разрядные операнды, так что приведенные выше тексты командного файла и самой программы можно использовать как образец для подготовки всех приведенных в этой книге программных примеров, даже если они используют только средства МП 86. В дальнейших примерах программ, в основном посвященных системе команд МП 86, эти описатели будут опускаться.
Приведем в качестве еще одного примера простую законченную про-
. грамму типа .ЕХЕ, которая выясняет букву-обозначение текущего диска
!.и выводит ее на экран с поясняющей надписью.
;Пример 3-1. Получение текущего диска ;Опишем сегмент команд assume CS:codc,DS:data code segment main ргос
AX,data ;Настроим DS
DS,AX ;на сегмент данных
mov AH,19h ;Функция DOS получения
int 2 Hi ;текущсго диска
add disk,AL Преобразуем номер в код
;ASCII
mov AH,09h ;Функция DOS вывода на ; экран
DX,offset rnsg ;Адрес строки
21h ; Вызов DOS
АН,0 Hi ;Функция DOS ввода символа
21h ;Вызов DOS
AX,4C001i ;Функция DOS завершения
21h ; программы
mov
mov hit mov int mov int code ends
mov
Глава з
;Опишем сегмент данных
data segment use 16
;Выводимый на экран текст Продолжение текста
msg db "Текущий диск "
disk db "A:",13,10,T
data ends
;Опишем сегмент стека
stk segment stack
:Стек
db 256 dup (0) stk ends
end main
Рассмотрим текст приведенного примера. После настройки сегментного регистра DS на сегмент данных, вызывается функция DOS с номером 19h, которая позволяет получить код текущего диска. У этой функции нет никаких параметров, а результат своей работы она возвращает в регистре AL в виде условного кода. О обозначает диск А:, 1 диск В:, 2 диск С: и т.д. Если, например, пользователь работает на диске F, то функция I9h вернет в AL код 5.
Для преобразования кода диска в его буквенное обозначение, мы воспользовались широко распространенным приемом. В полях данных определена символьная строка, которая будет выводиться на экран. Для удобства работы она разделена на две части, каждая из которых имеет свое имя. Началу строки присвоено имя msg, а той ее части, которая начинается с обозначения диска А:, имя disk (разумеется, имена выбраны произвольно). Если посмотреть на таблицу кодов ASCII (рис. 3.1), то можно заметить, что код каждой следующей буквы ачфавита на 1 больше предыдущей. Таким образом, если к коду латинской буквы A (41h) прибавить 1, получится код буквы В, а если прибавить, например, 5, получится код буквы F. Именно эта операция и выполняется в предложении
add disk,AL ;Преобразусм номер в код ASCII
где к байту с адресом disk прибавляется код, возвращенный функцией DOS.
Выполнив модификацию строки, мы выводим се на экран уже знакомой нам функцией DOS 09h. Она выводит все символы строки, пока не встретится с символом S, которым наша строка и завершается. Перед знаком S в строке имеются два числа: 13 и 10. При выводе текстовой строки на экран любой функцией DOS код 13 трактуется DOS, как команда вернуть курсор в начало строки («возврат каретки»), а код 10 —• как команда на перевод строки. Два эти кода переводят курсор в начало следующей строки экрана. В данном случае, когда на экран ничего больше не выводится, можно было обойтись и без этих кодов, которые включены лишь в познавательных целях.
Между прочим, правильная работа программы основана на том предположении (безусловно правильном), что ассемблер расположит наши данные в памяти в точности в том же порядке, как они описаны в программе. Именно это обстоятельство и позволяет дробить единую строку на
анды и алгоритмы
103
00
10
20
30
40
50
60
70
80
90
АО
ВО
СО
DO
ЕО
FO
00 01 02 03 04 05 06 07 08 09 OAOBOCODOEOF
0123456789: ;< = >? 0ABCDEFGHIJKLMNO PQRSTUUWX¥Z[4]^_ abcdefghijklnno pqrstuvu х у 2: { I > ~ л
АБВГДЕЖЗИЙКЛМНОП РСТУФХЦЧЫЩЪЫЬЭЮЯ абагдемзий клмноп
h
_ л _ I? - II
II
лт
I I
Т
т « I t J
И Р с т
И Ф х цчыщъыьэ w я
«"-=-% ° • • -S № От
Рис. 3.1. Таблица кодов символов.
части, не опасаясь, что в память они попадут в разные места, что привело бы, разумеется, к непредсказуемому результату.
После вывода на экран сообщения о текущем диске в программе вызывается функция DOS с номером Olh. Эта функция вводит с клавиатуры один символ. Если символов нет (мы после запуска программы не нажимали на клавиши), функция Olh ждет нажатия фактически любой клавиши (более точно — любой алфавитно-цифровой или функциональной клавиши). Такой весьма распространенный прием позволяет остановить выполнение программы до нажатия клавиши, что даст возможность программисту посмотреть, что вывела программа на экран, и оценить правильность ее работы.
Наконец, последнее действие носит, как уже отмечалось, сакраментальный характер. Вызовом функции DOS 4Ch программа завершается с передачей управления DOS.
Взглянем еще раз на текст программы 3-1. Если не считать первых предложений инициализации регистра DS, то в программе имеется лишь одна строка, носящая, можно сказать, вычислительный характер — это прибавление полученного кода диска к содержимому байта памяти. Все остальные строки служат для вызова тех или иных функций DOS — получения информации о текущем диске, вывода строки на экран, остановки программы и, наконец, се завершения. Это подтверждает высказанное выше утверждение о важности изучения системных средств и широком использовании их в программах на языке ассемблера. Разумеется, в программе могут быть и сколь угодно сложные и протяженные участки обра-
104