Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29192
Скачиваний: 1689
Глава 1. Первая программа
15
Можно создать еще одну строку, которую назовем
Mess2
. Затем, начиная со
строки (09), вставим в нашу программу следующие команды:
...
(09) mov ah,9
(10) mov dx,offset Mess2
(11) int 21h
(12) int 20h
(13) Message db 'Hello, world!$'
(14) Mess2 db 'Это Я!$'
(15) CSEG ends
(16) end Begin
Уверены, вы поняли, что именно произойдет.
Обратите внимание на последний символ в строках
Message
и
Mess2
—
$
. Он
указывает на конец выводимой строки. Если мы его уберем, то прерывание
21h
продолжит вывод до тех пор, пока не встретится где-нибудь в памяти тот самый
символ
$
. На экране, помимо нашей строки, мы увидим "мусор" — разные симво-
лы, которых в строке вовсе нет.
Теперь ассемблируйте программу. Как это сделать — написано в приложении 1. За-
метьте, что мы создаем пока только COM-файлы, а не EXE! Для того чтобы получить
COM-файл, нужно указать определенные параметры ассемблеру (MASM/TASM) в ко-
мандной строке. Пример получения COM-файла с помощью Macro Assembler вер-
сии 6.11 и результат выполнения программы приведен на рис. 1.1. При возникновении
ошибок в процессе ассемблирования обращайтесь к приложению 2, где рассматрива-
ются типичные ошибки при ассемблировании программ.
Если у вас есть отладчик (AFD, CodeView), то можно (и даже нужно!) запустить
эту программу под его управлением. Это поможет вам лучше понять структуру
и принцип работы ассемблера, а также продемонстрирует реальную работу напи-
санной нами программы.
Рис. 1.1. Ассемблирование и результат выполнения программы Prog01.com
Часть I. Знакомьтесь: ассемблер
16
Рис. 1.2. Вид программы в отладчике AFD Pro
На рис. 1.2 показано, как эта программа выглядит в отладчике AFD Pro. Пока не
обращайте особого внимания на различие между реальным кодом, набранным ру-
ками, и тем, как эта программа отображается в отладчике. Подробно работу отлад-
чика мы рассмотрим в последующих главах.
1.4. Резюме
Целью данной главы не было разобраться подробно с каждым оператором. Это
невозможно, если вы не обладаете базовыми знаниями. Но, прочитав 3—4 главы,
вы поймете принцип и структуру программы на ассемблере.
Может быть, ассемблер вам показался чрезвычайно сложным, но это, поверьте,
только с первого взгляда. Вы должны научиться строить алгоритм программы на
ассемблере в голове, а для этого нужно будет самостоятельно написать несколько
программ, опираясь на информацию из данной книги. Будем постепенно учиться
мыслить структурой ассемблера, составлять алгоритмы, программы, используя
операторы языка. После изучения очередной главы вы будете чувствовать, что по-
степенно начинаете осваивать ассемблер, будет становиться все проще и проще.
Например, если вы знакомы с Бейсиком, то, ставя перед собой задачу написать
программу, выводящую 10 слов "Привет", вы будете использовать операторы
FOR
,
NEXT
,
и пр., которые тут же появятся в ваших мыслях. Вы строите опреде-
ленный алгоритм программы из этих операторов, который в какой-то степени при-
меним только к Бейсику. То же самое и с ассемблером. При постановке задачи на-
писать ту или иную программу вы мысленно создаете алгоритм, который
применим к ассемблеру и только, т. к. языков, похожих на ассемблер, просто не
существует. Наша задача — научить вас создавать в уме алгоритмы, применимые
к ассемблеру, т. е. образно говоря, научить "мыслить на ассемблере".
* * *
В главе 2 мы подробно рассмотрим регистры процессора и напишем еще одну
простую программу.
Глава 2
Регистры процессора
2.1. Введение в регистры
микропроцессоров 8086—80186
Регистр, как мы уже говорили ранее, — это специально отведенная память для
временного хранения каких-то данных. Микропроцессоры 8086—80186 имеют
14 регистров. В главе 1 мы познакомились с двумя из них:
ah
и
dx
. В табл. 2.1, 2.3
и 2.4 приведен перечень всех регистров, кроме
ip
и регистра флагов, которые бу-
дут рассмотрены отдельно.
2.1.1. Регистры данных
Регистры данных могут использоваться программистом по своему усмотрению
(за исключением некоторых случаев). В них можно хранить любые данные: числа,
адреса и пр. В верхнем ряду табл. 2.1 находятся 32-разрядные регистры, которые
могут хранить числа от 0 до 4 294 967 295 (0FFFFFFFFh). Их мы будем рассматри-
вать позже. Во втором ряду — 16-разрядные, которые могут хранить числа от 0 до
65 535 или от 0h до FFFFh в шестнадцатеричной системе, что одно и то же.
В следующей строке расположен ряд 8-разрядных регистров:
ah
,
al
,
bh
,
bl
,
ch
,
cl
,
dh
,
dl
. В эти регистры можно загружать максимальное число 255 (FFh). Это так
называемые половинки (старшая или младшая) 16-разрядных регистров.
Таблица 2.1. Регистры данных
EAX
EBX
ax
bx
cx
dx
ah
al
bh
bl
ch
cl
dh
dl
Аккумулятор
База
Счетчик
Регистр данных
Мы уже изучили оператор
mov
, который предназначен для загрузки числа в ре-
гистр. Чтобы присвоить, к примеру, регистру
al
число 35h, нам необходимо запи-
сать так:
mov al,35h
Часть I. Знакомьтесь: ассемблер
18
а регистру
ax
— число 346Ah, так:
mov ax,346Ah
Если мы попытаемся загрузить большее число, чем может содержать регистр, то
при ассемблировании программы произойдет ошибка. Например, следующие запи-
си будут ошибочны:
mov ah,123h
максимум FFh
mov bx,12345h
максимум FFFFh
mov dl,100h
максимум FFh
Здесь надо отметить, что если шестнадцатеричное число начинается не с цифры
(12h), а с буквы (С5h), то перед таким числом ставится ноль: 0C5h. Это необходимо
для того, чтобы программа-ассемблер могла отличить, где шестнадцатеричное чис-
ло, а где название переменной или метки. Далее мы рассмотрим это на примере.
Допустим, процессор выполняет команду
mov ax,1234h
. В этом случае в регистр
ah
загружается число 12h, а в регистр
al
— 34h. То есть
ah
,
al
,
bh
,
bl
,
ch
,
cl
,
dh
и
dl
— это младшие (Low) или старшие (High) половинки 16-разрядных регистров
(табл. 2.2).
Таблица 2.2. Результаты выполнения различных команд
Команда
Результат
mov ax,1234h
mov bx,5678h
mov cx,9ABCh
mov dx,0DEF0h
ax = 1234h, ah = 12h, al = 34h
bx = 5678h, bh = 56h, bl = 78h
cx = 9ABCh, ch = 9Ah, cl = 0BCh
dx = 0DEF0h, dh = 0DEh, dl = 0F0h
2.1.2. Регистры-указатели
Регистры
si
(индекс источника) и
di
(индекс приемника) используются в стро-
ковых операциях. Регистры
bp
и
sp
задействуются при работе со стеком (табл. 2.3).
Мы подробно их рассмотрим на примерах в следующих главах.
Таблица 2.3. Регистры-указатели
si
Di
bp
sp
Индекс источника
Индекс приемника
Регистры для работы со стеком
2.1.3. Сегментные регистры
Сегментные регистры (табл. 2.4) необходимы для обращения к тому или иному
сегменту памяти (например, видеобуферу). Сегментация памяти — довольно слож-
ная и объемная тема, которую также будем рассматривать в следующих главах.
Таблица 2.4. Сегментные регистры
CS
DS
ES
SS
Регистр кода
Регистр данных
Дополнительный регистр
Регистр стека
Глава 2. Регистры процессора
19
2.2. Команды сложения и вычитания
Для выполнения арифметических операций сложения и вычитания в ассемблере
существуют следующие операторы:
add
,
sub
,
inc
,
dec
.
2.2.1
. Оператор add
Формат оператора
add
показан в табл. 2.5. Впоследствии мы всегда будем оформ-
лять новые команды в подобные таблицы. В столбце Команда будет описана новая
команда и ее применение. В столбце Назначение — что выполняет или для чего
служит данная команда, а в столбце Процессор — модель (тип) процессора, начиная
с которой команда поддерживается. В столбце Перевод будет указано, от какого анг-
лийского слова образовано название оператора, и дан перевод этого слова.
Таблица 2.5. Оператор
add
Команда
Перевод
Назначение
Процессор
add приемник, источник
Addition
— сложение Сложение
8086
В данном примере оператор поддерживается процессором 8086, но работать ко-
манда будет, естественно, и на более современных процессорах (80286, 80386,
80486, Pentium и т. д.).
Команда
add
производит сложение двух чисел (листинг 2.1).
Листинг 2.1. Примеры использования оператора add
mov al,10 ;загружаем в регистр al число 10
add al,15 ;al = 25; al — приемник, 15 — источник
mov ax,25000 ;загружаем в регистр ax число 25000
add ax,10000 ;ax = 35000; ax — приемник, 10000 — источник
mov cx,200 ;загружаем в регистр cx число 200
mov bx,760 ;а в регистр bx — 760
add cx,bx ;cx = 960, bx = 760 (bx не меняется); cx — приемник,
;bx — источник
2.2.2. Оператор sub
Команда
sub
производит вычитание двух чисел (табл. 2.6, листинг 2.2).
Таблица 2.6. Оператор
sub
Команда
Перевод
Назначение
Процессор
sub приемник, источник
Subtraction
— вычитание
Вычитание
8086