Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29201
Скачиваний: 1689
Часть I. Знакомьтесь: ассемблер
30
Рис. 3.3. В отладчике выполнена команда mov dx,0109
Почему так происходит? Дело в том, что в процессе обработки нашего файла, про-
грамма-ассемблер (MASM/TASM) подставляет вместо
offset String
реальный адрес
строки с именем
String
в памяти (ее смещение). Можно, конечно, записать сразу:
mov dx,109h
Данная программа будет работать корректно. Но для этого нам нужно высчитать
самим этот адрес. Попробуйте вставить следующие команды, начиная со строки
(07), в листинг 3.1:
...
(07) int 20h
(08) int 20h
(09) String db 'Test message$'
(10) CSEG ends
(11) end _start
Просто продублируем команду
int 20h
(хотя, как вы уже знаете, выполнение
программы прекратится на строке (07)). Теперь ассемблируйте программу заново.
Запускайте ее под отладчиком. В качестве демонстрации воспользуемся отладчи-
ком CodeView, при этом программа может загрузиться в другой сегмент, т. к. от-
ладчики имеют разные размеры и, соответственно, занимают разное количество
оперативной памяти. Пусть теперь сегмент, в который загрузилась наша програм-
ма, будет равен
0A09h
. Выполняйте шаг за шагом программу до тех пор, пока не
дойдете до загрузки смещения строки в регистр
dx
. Вы увидите, что в
dx
загружа-
ется не 109h, а другое число. Подумайте, почему так происходит.
А мы пока подробней рассмотрим, что находится в пределах окна отладчика
CodeView.
В окне Memory (Память) отладчика CodeView (у AFD нечто подобное) вы уви-
дите примерно следующее (табл. 3.2 и рис. 3.4).
Глава 3. Сегментация памяти в реальном режиме
31
Таблица 3.2. Строка отладчика CodeView
1
2
3
4
0A09
:
0000
CD 20 FF 9F 00 9A F0 FE
= Я.
Рассмотрим строку отладчика:
позиция 1 (
0A09
) — сегмент, в который загрузилась наша программа (может
быть любым);
позиция 2 (
0000
) — смещение в данном сегменте (сегмент и смещение отделя-
ются двоеточием (:));
позиция 3 (
CD 20 FF ... F0 FE
) — код в шестнадцатеричной системе, который
располагается, начиная с адреса
0A09:0000
;
позиция 4 (
= Я.
) — код в ASCII (ниже рассмотрим), соответствующий шестна-
дцатеричным числам с правой стороны.
Рис. 3.4. Сегмент, смещение, шестнадцатеричный и двоичный коды программы
из листинга 3.1 в отладчике CodeView
В позиции 2 (смещение) введите значение, которое будет находиться в регистре
dx
после выполнения строки (5). После этого в позиции 4 вы увидите строку
Test
message$
, а в позиции 3 — коды символов
Test message$
в шестнадцатеричной
системе... Так вот что загружается в
dx
(рис. 3.5)! Это не что иное, как АДРЕС
(смещение) нашей строки в сегменте!
Итак, мы загрузили в
dx
адрес строки в сегменте
CSEG
(строки (01) и (09) из лис-
тинга 3.1). Теперь переходим к следующей команде:
int 21h
. Вызываем прерыва-
ние DOS с функцией
9
(
mov ah,9
) и адресом строки в
dx
(
mov dx,offset String
).
Как уже упоминалось раньше, при вызове прерываний в программах в
ah
зано-
сится номер функции. Эти номера желательно запоминать (хотя бы часто исполь-
Часть I. Знакомьтесь: ассемблер
32
зуемые), чтобы постоянно не искать в справочниках, какие действия выполняет та
или иная функция.
Рис. 3.5. Строка Test message$ в памяти
3.3. Наше первое прерывание
Функция
09h
прерывания
21h
выводит строку на экран, адрес которой указан
в регистре
dx
. Изобразим это в табл. 3.3. Далее всегда будем описывать функции
с помощью таблиц.
В столбце Вход мы указываем, в какие регистры что загружать перед вызовом
прерывания, а в столбце Выход — что возвращает функция. Сравните эту таблицу
с листингом 3.1.
Таблица 3.3. Функция
09h
прерывания
21h
— вывод строки символов
на экран в текущую позицию курсора
Вход
Выход
ah = 09h
dx
= адрес ASCII-строки символов, заканчивающийся символом $
Ничего
3.3.1. Что такое ASCII?
Вообще, любая строка, состоящая из ASCII-символов, называется ASCII-
строкой. ASCII-символы — это символы от 0 до 255 в DOS, куда входят буквы рус-
ского и латинского алфавитов, цифры, знаки препинания и пр. (полный список
ASCII-символов различных кодировок см. в приложении 3).
Глава 3. Сегментация памяти в реальном режиме
33
На этом мы заканчиваем рассматривать сегментацию памяти. Если и остались
кое-какие пробелы, то в последующих главах мы их обязательно заполним. Наде-
емся, что вы без особого труда разобрались в данной теме. По крайней мере, уло-
вили принцип сегментации памяти.
3.4. Программа для практики
Теперь интересная программка (\003\prog03.asm) для практики, которая выводит
в левый верхний угол экрана веселую рожицу на синем фоне (листинг 3.2).
Листинг 3.2. Программа для практики
(01) CSEG segment
(02) org 100h
(03) _beg:
(04) mov ax,0B800h
(05) mov es,ax
(06) mov di,0
(07)
(08) mov ah,31
(09) mov al,1
(10) mov es:[di],ax
(11)
(12) mov ah,10h
(13) int 16h
(14)
(15) int 20h
(16)
(17) CSEG ends
(18) end _beg
Многие операторы вы уже знаете. Поэтому рассмотрим только новые.
В данном примере для вывода символа на экран (рис. 3.6), мы используем метод
прямого отображения в видеобуфер. Что это такое — будет подробно рассмотрено
в следующих главах, т. к. эта тема заслуживает отдельного обсуждения. В строках (04)
и (05) загружаем в сегментный регистр
es
число
0B800h
, которое соответствует
сегменту дисплея в текстовом режиме (запомните его!). В строке (06) загружаем в
регистр
di
ноль. Это будет смещение относительно сегмента
0B800h
. В строках (08)
и (09) в регистр
ah
заносится атрибут символа (31 — ярко-белый символ на синем
фоне) и в
al
— ASCII-код символа (01 — это "рожица").
В строке (10) заносим по адресу
0B800:0000h
(это первый символ в первой стро-
ке дисплея — в левом верхнем углу) атрибут и ASCII-код символа (31 и 01 соответ-
Часть I. Знакомьтесь: ассемблер
34
ственно). Обратите внимание на форму записи оператора
mov
в строке (10). Квад-
ратные скобки
[ ]
указывают на то, что надо загрузить число не в регистр, а по
адресу, который содержится в этом регистре (в данном случае, как уже отмеча-
лось, — это
0B800:0000h
).
Рис. 3.6. Результат выполнения программы Prog03.com
Можете поэкспериментировать с данным примером. Только не меняйте пока
строки (04) и (05). В качестве сегментного регистра оставим
es
, хотя можно, ко-
нечно, и
ds
использовать. Более подробно метод прямого отображения в видеобу-
фер рассмотрим позже. Сейчас нам из приведенной выше программы нужно понять
только принцип сегментации на практике.
Э
Т О И Н Т Е Р Е С Н О
Ну и напоследок интересный факт. Вывод символа прямым отображением в видео-
буфер является самым быстрым из всех возможных способов вывода символов или
рисования точки на экране. Выполнение команды в строке (10) занимает 3—5 тактов.
Таким образом, на Pentium 100 МГц можно за секунду вывести 20 миллионов (!) сим-
волов или чуть меньше точек на экран!
3.5. Подведем итоги
Уважаемые читатели! Вот вы и ознакомились с частью I книги.
Итак, давайте подведем итог. В данной части мы рассмотрели следующее:
шестнадцатеричную систему счисления;
двоичную систему счисления;
некоторые регистры микропроцессоров Intel 8086/8088/80186;
основы сегментации памяти в реальном режиме;
операторы ассемблера:
org
— с какого места отсчитывать смещение;
mov
— загрузка данных в регистр или память (переменную);
add
— сложение;
sub
— вычитание;
inc
— увеличение на единицу;
int
— вызов прерывания;