Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf

ВУЗ: Не указан

Категория: Книга

Дисциплина: Программирование

Добавлен: 16.02.2019

Просмотров: 29204

Скачиваний: 1689

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

Глава 3. Сегментация памяти в реальном режиме 

35 

 

функцию 

09h

 прерывания 

21h

 (вывод строки на экран в текущую позицию кур-

сора); 

 

функцию 

10h

 прерывания 

16h

 (ожидание нажатия клавиши). 

В  принципе,  довольно  много,  чтобы  начать  серьезное  и  интенсивное  обучение 

языку ассемблера. Если вы усвоили как минимум 75% материала из данной части, 
то, можно сказать, мы добились того, чего хотели. Если же вы чувствуете, что мно-
гое непонятно, то попробуйте прочитать все еще раз с самого начала, воспользуй-
тесь  отладчиком.  Мы  впоследствии  будем  еще  не  раз  возвращаться  к  материалу, 
изложенному в части I. Если вы что-то не поняли сейчас, то, надеемся, поймете со 
временем. Самое интересное и увлекательное — впереди! 

В случае если вопросов по пройденному материалу у вас не возникло, то можете 

смело приступать к изучению части II "Усложняем задачи"

Увлекательного вам чтения! 
 


background image

 

 

 

 

 

 

Ч А С Т Ь  I I 

Усложняем задачи 

 


background image

 

 

 

Глава 4 

 

Создание циклов 

 

4.1. Еще немного о сегментации памяти 

Рассмотрим часть примера из листинга 3.1. Кое-что в этом примере мы не раз-

бирали: 

(01)    ... 
(02)    mov ah,9 
(03)    mov dx,offset My_string 
(04)    int 21h 
(05)    ... 
(06) My_string db 'Ура!$' 
(07)        ... 

В строке (03) загружаем в регистр 

dx

 адрес строки в памяти. Обратите внимание 

на  запись: 

mov  dx,offset  My_string

.  Вспоминаем,  что  оператор 

mov

  загружает  

в регистр число. Например: 

mov cx,125 

В строке (03) мы видим пока еще неизвестный нам оператор 

offset

. Что же он 

делает? И почему нельзя записать таким образом: 

mov dx,My_string

4.1.2. Введение в адресацию 

В  переводе  с  английского  "offset" —  это  смещение.  Когда  ассемблер 

(MASM/TASM) обрабатывает нашу программу и доходит до строки (03), он заме-
няет 

offset  My_string

 на адрес (смещение) этой строки в памяти. Если мы запи-

шем 

mov  dx,My_string

  (хотя корректно будет 

mov  dx,word  ptr  My_string

, но об 

этом позже), то в 

dx

 загрузится не адрес (смещение), а  первые два символа нашей 

строки  (в  данном  случае  "Ур").  Два  символа,  потому  что 

dx

 —  16-разрядный  ре-

гистр,  в  который  можно  загрузить  два  байта.  А  один  символ,  как  вы  уже  знаете, 
всегда  занимает  один  байт.  Можно  записать  и  так: 

mov  dl,My_string

  (здесь  кор-

ректно будет 

mov  dl,byte  ptr  My_string

). В этом случае, в 

dl

  будет  находиться 

символ "У", т. к. 

dl

 — 8-разрядный регистр и может хранить только один байт. 

Несколько слов про записи вида 

mov dl,byte ptr My_string

 и 

mov dx,word ptr 

My_string

Byte

 —  это  байт, 

word

 —  слово  (два  байта).  Посмотрите  внимательно  


background image

 

Часть II. Усложняем задачи 

40 

на  приведенные  ранее  строки.  Вы  заметите,  что  когда  используется  8-разрядный 
регистр  (

dl

),  мы  пишем 

byte

.  А  когда  16-разрядный  (

dx

) — 

word

.  Это  указывает 

ассемблер-программе, что именно мы хотим загрузить — байт или слово. 

Вспомним, что в реальном режиме для формирования адреса используются сег-

мент  и  смещение.  Данный  пример —  не  исключение.  Для  формирования  адреса 
строки 

"Ура!$"

 используется пара регистров 

ds

 (сегмент) и 

dx

 (смещение). 

Почему  же  тогда  мы  ничего  не  загружаем  в 

ds

?  Дело  в  том,  что  при  загрузке 

COM-программы в память (а мы пока создаем только такие), все сегментные реги-
стры принимают значение, равное значению сегмента, в который загрузилась наша 
программа (в том числе и 

ds

). Поэтому нет необходимости загружать в 

ds

 сегмент 

строки  (он  уже  загружен).  Программа  типа  COM  всегда  занимает  один  сегмент,  
в котором должен уместиться код, данные и пр. А размер COM-файлов ограничен 
64 Кбайт (65 536 байтами). Программы, написанные на "чистом" ассемблере, очень 
компактны, и 64 Кбайт для них — довольно большой объем. 

Приведем  несколько  примеров.  В  свое  время  нами  разрабатывалась  антиви-

русная  файловая  оболочка  типа  Norton  Commander  на  ассемблере  (некоторое  ее 
подобие  будем  изучать  в  части III).  В  итоге  размер  приложения  составил  всего 
36 Кбайт.  Несмотря  на  такой  небольшой  размер,  оболочка  выполняла  многие 
функции  Norton  Commander  (хотя  некоторых  функций  Norton  Commander  в  ней 
не было). 

В качестве другого примера можно привести Volcov Commander первых версий. 

Практически копия Norton Commander, но занимает всего 64 000 байт (в отличие от 
Norton). Если Volcov Commander писали и не на "чистом" ассемблере, то хотя бы 
большую часть кода так точно. Да и работает Volcov гораздо быстрее, чем Norton. 

Но  продолжим  изучение.  В  качестве  эксперимента  попробуйте  перед  вызовом 

прерывания 

21h

 загрузить в 

ds

 любое другое число. Например, так: 

... 

mov dx,offset My_string 

mov ax,10h 

mov ds,ax 

mov ah,9 

int 21h 

... 

My_string db 'Hello!$' 

... 

Вы увидите, что программа выведет на экран не строку "Hello!", а какой-то "му-

сор",  хотя  в 

dx

  мы  правильно  загружаем  адрес  (смещение)  нашей  строки,  но  сег-

мент-то в 

ds

 другой (рис. 4.1). 

Давайте вспомним, что функция 

09h 

прерывания 

21h

 выводит строку, адрес ко-

торой  задается  в  регистрах 

ds:dx

.  На  рис. 4.1  отображено  состояние  программы, 

при  котором  мы  умышленно  загружаем  в 

ds

  число  10.  Обратите  внимание,  что  

в окне 

Memory1

 отображены данные, расположенные в памяти по адресу 

0A09:010Ch


background image

Глава 4. Создание циклов 

41 

а  именно  строка 

Hello!

, которую должна вывести программа. Это и есть полный 

адрес  выводимой  строки,  включающий  в  себя  сегмент  и  смещение.  Однако  про-
грамма  перед  вызовом  прерывания 

21h

  загружает  в 

ds

  число  10.  Следовательно, 

операционная система начнет выводить символы, находящиеся по адресу 

ds:dx

 — 

0010:010Ch

, что является логической ошибкой в программе. 

 

Рис. 4.1. Некорректный вывод строки 

Если все же возникает необходимость в выводе строки, расположенной не в том 

сегменте, в который загружена сама программа, а в другом (такое требуется часто), 
то  после  выполнения  всех  необходимых  операций  следует  восстановить  сегмент-
ный регистр данных 

ds

... 

mov ax,cs 

mov ds,ax 

... 

В табл. 4.1 приведено полное описание функции вывода строки на экран. 

Таблица 4.1. Функция 

09h

 

прерывания 

21h

 

— вывод строки символов  

на экран в текущую позицию курсора 

Вход 

Выход  

AH = 09h 

DS:DX 

= адрес ASCII-строки символов, заканчивающийся $ 

Ничего 

 
С  этим  также  разобрались,  хотя  возвращаться  к  сегментным  регистрам мы бу-

дем еще не один раз.