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

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

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

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

Добавлен: 16.02.2019

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

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

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

 

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

52 

(12)        call Out_chars 
(13)        inc al 
(14)        loop Next_screen 
 
(15)        mov ah,10h 
(16)        int 16h 
 
(17)        int 20h 
 
 
(18) Out_chars proc 
(19)        mov dx,cx 
(20)        mov cx,2000 
(21) Next_face: 
(22)        mov es:[di],ax 
(23)        add di,2 
(24)        loop Next_face 
 
(25)        mov cx,dx 
(26)        ret 
(27) Out_chars endp 
 
(28) CSEG ends 
(29) end Start 

Строки  (01)—(08),  (15)—(17)  и  (28),  (29)  опускаем.  Вопросов  по  ним  быть  не 

должно. 

В  строке  (09)  заносим  в 

cx

  число  254,  сообщающее,  сколько  раз  будет  выпол-

няться основной цикл. Строки (10) и (14) — "голова" и "хвост" нашего основного 
цикла  соответственно.  Значение 

di

  будет  меняться  во  вложенной  процедуре,  по-

этому  нам  необходимо  будет  его  постоянно  аннулировать  (строка  (11)).  В  строке 
(12)  вызываем  процедуру,  выводящую  на  экран  символ,  код  которого  находится  
в 

al

  (при  первом проходе цикла это будет символ "рожица" с кодом 01). Все! Те-

перь на экран будет выведен символ с кодом 01. При этом 

di

 будет равно 2001, по-

этому нам и нужно его постоянно обнулять. 

Далее увеличим на единицу код символа, который находится в 

al

. Во второй раз 

al

  будет  содержать  02 —  тоже  "рожица",  но  немного  другого  вида  (строка  (13)). 

Затем  уменьшим  счетчик на 1 и перейдем к заполнению экрана кодом 02 (строка 
(14)). И так далее. Всего 254 раза. 

Теперь рассмотрим работу самой процедуры. В строке (19) сохраняем содержи-

мое регистра 

cx

 (просто перенесем его в 

dx

), т. к. он будет изменен во вложенном 

цикле ниже. Строки (21) и (24) — "голова" и "хвост" вложенного цикла, который 
будет выполняться 2000 раз (именно столько символов вмещается на экране в тек-


background image

Глава 5. Подпрограммы 

53 

стовом режиме 80 на 25). Именно это число заносим в строке (20) в регистр 

cx

. Те-

перь осталось только восстановить 

cx

 (строка (25)) и выйти из подпрограммы (26). 

Итак,  у  нас  здесь  два  цикла:  основной  и  вложенный.  Основной  выполняется 

254 раза, а вложенный — 2000 раз. Итого: 2000   254 = 508 000. Теперь представь-
те, сколько работы выполняет процессор, и обратите внимание, как быстро работа-
ет  программа.  На  современных  компьютерах  вы  не  успеете  заметить  молниенос-
ный  вывод  всех  символов.  Очень  быстро  работает,  хотя  это  далеко  и  не 
оптимальный алгоритм. 

Для  исследования  данного  примера  настоятельно  рекомендуем  вам  воспользо-

ваться помощью отладчика. Лучший вариант в данном случае — AFD. 

5.4. Несколько слов об отладчике AFD 

AFD, безусловно, не совсем актуален для современных программ по следующим 

причинам: 

 

не поддерживает 32-разрядные регистры; 

 

распознает только инструкции 8086—80186 процессоров, а также сопроцессора 
8087; 

 

не поддерживает форматы PE и NE (Windows). 
Зато у него есть преимущества: 

 

удобен и прост в использовании; 

 

показывает в одном окне регистры, код, память и др.; 

 

идеально  подходит  начинающим  программистам  для  исследования  простых 
программ. 
Для изучения работы программ в DOS его больше, чем достаточно. Скачать от-

ладчик  AFD  можно  на  сайте  http://www.Kalashnikoff.ru,  приблизительный  раз-
мер — 64 Кбайта. 

Скачивайте, пробуйте, изучайте, экспериментируйте! 
 


background image

 

 

 

Глава 6 

 

Работа со стеком 

 

6.1. Стек 

Стек  (стэк,  stack) —  это  специально  отведенная  область  памяти  для  хранения 

промежуточных (временных) данных. 

Теперь попробуем разобраться, что именно это такое. Будем считать, что сегмент 

"растет" сверху вниз: 

0000 
0001 
0002 
... 
FFFE 
FFFF 

То  есть  мы  как  бы  погружаемся  под  землю.  Таким  образом —  сверху  вниз — 

выполняется программа, если в ней, безусловно, не встречаются инструкции типа 

jmp

call

  и  т. п.  Стек  же  наоборот  пополняется  снизу  вверх.  Вершина  стека — 

0FFFFh

, а низ (дно) — 

0000h

. Когда мы вызываем какую-нибудь подпрограмму ко-

мандой 

call

,  процессор  заносит  в  стек  адрес  следующей  за  командой 

call

  инст-

рукции.  Как  только  подпрограмма  отработала,  из  стека  извлекается  сохраненный 
адрес возврата, после чего происходит переход по этому адресу. 

Следить за стеком позволяет пара регистров 

ss:sp

. Многие уже, наверное, заме-

тили,  что  при  запуске  какой-нибудь  COM-программы  регистр 

sp

  равен 

0FFFEh

,  

а сегментный регистр 

ss

, как уже неоднократно упоминалось, равен нашему един-

ственному сегменту 

CSEG

 (как, собственно, и 

cs

,

 ds

,

 es

). 

Теперь  вам  необходимо  вооружиться  отладчиком.  Давайте  рассмотрим  выше-

сказанное на примере. Напечатайте программу из листинга 6.1 в редакторе. 

Листинг 6.1. Исследование работы стека 

CSEG segment 
assume cs:CSEG, ds:CSEG, es:CSEG, ss:CSEG 
org 100h 
 
begin: 
call Our_proc 


background image

Глава 6. Работа со стеком 

55 

int 20h 
 
Our_proc proc 
 
ret 
Our_proc endp 
 
CSEG ends 
end Begin 

Запускаем  отладчик  и  сразу  смотрим  на  пару  регистров 

ss:sp

sp=0FFFEh

, т. е. 

указываем на вершину стека (рис. 6.1). 

 

Рис. 6.1. Инициализация стека при старте программы 

Теперь заходим в процедуру. Для CodeView следует нажать клавишу <F8>, для 

AFD —  <F1>.  Регистр 

sp

  изменился!  Он  уменьшился  на  2.  Компьютер  поместил  

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

int 20h

. Проще говоря, коман-

да 

call

  передала  управление  на  метку 

Our_proc

,  поместив  при  этом  в  стек  адрес 

возврата из этой подпрограммы. В нашем случае это число 103 (рис. 6.2). 

Нажимаем еще раз <F8>/<F1>. 

sp

 опять изменился. Но теперь он увеличился на 2, 

стал равным 

0FFFEh

. То есть команда 

ret

 "вытащила" из стека предварительно со-

храненный адрес возврата 

0103h

  и  продолжила работу. А по этому адресу как раз  

и находится следующая за 

call

 инструкция 

int 20h

. В данном случае принято го-

ворить, что стек выровнен. При старте программы он был равен 

0FFFEh

 и остался 

равен этому числу перед выходом — 

0FFFEh

 (рис. 6.3). 

Мы рассмотрели один из вариантов использования стека непосредственно про-

цессором.  Но  на  этом  мы  не  остановимся  и  рассмотрим,  какие  возможности  дает 
стек программисту и как его можно использовать в своей программе. 


background image

 

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

56 

 

Рис. 6.2. Вызов процедуры с занесением в стек адреса возврата из нее 

 

Рис. 6.3. Процедура отработала. Стек выровнен 

Прежде  всего,  разберем  два  оператора,  которые позволяют работать со стеком 

(табл. 6.1 и 6.2). 

Таблица 6.1. Оператор 

push

 

Команда 

Перевод 

Назначение 

Процессор 

push приемник 

Push 

— втолкнуть 

Поместить в стек число 

8086 

Таблица 6.2. Оператор 

pop

 

Команда 

Перевод 

Назначение 

Процессор 

pop приемник 

Pop 

— вытолкнуть 

Достать из стека число 

8086