Вы находитесь на странице: 1из 586

П.И.Рудаков, К.Г.

Финогенов

Программиру ем
на языке ассемблера
IBMPC

Обнинск 1997 год


Издательство "Принтер"
ББК 32.973.1
Р83
УДК681.3
Рудаков П.И., Фивоrtвов К.Г.
Р83 Программируем на J13ЫКе ассемблера IBM РС - Изд. 2-е. -
ОбНШiск: Издательство "Пршпер", 1997.-584 с., ИJDI.

Книга JШЛJiетсв простым и доступным дmi широкого круга


пользователей пособием по проrраммированшо на язьJКе
ассемблера дmi персонВЛ;Ьных компьютеров IBM РС. Книга состоит
из трех частей. Первая часть посв.ящена основам
проrраммироваНИJI на взыке ассемблера, моделвм пам.11111,
управленшо апnараn1ыми средствами компьютера, алгориrмам

преобразоваНИJI данных, правШiам написаНИJI резидентных


программ и обработчиков прерываний, использованшо средств
DOS и BIOS. Часть вторав описывает особенности раб6ТЬI и
программироваНИJI микропроцессора в защшценном режиме, часть
третья методику проrраммироваНИJI арифметического
сопроцессора.
Дш1 чиrателей, не Dляющихся профес:сионалами-
программистами, но имеющих дело с переовальными
компьютерами, а также студентов вузов.

ББК 32.973. 1

Учебное издание

Петр Иванович Рудаков


КирИJDI Григорьевич Фнногенов

ПРОГРАММИРУЕМ НА ЯЗЫКЕ АССЕМБЛЕРА IBM РС

Художник А. Косырев

ОРудаков П.И., Фииогенов К.Г., 1997

Подписано к печ1011 J0..06.97r. Формат 60х84/lб


Печ.л.Э6.5 Тираж 1020 эю. Эахаз 611
Иэдатет.сmlо "Прннтер" ИК Н 89 (ОЭ)
249020 r.Обнннсх, ул.КороJJСВа,6
Оmечатано на tабрнхе oфcmtoi nечати
Содержание
Введение ................................................................................................ ?

Чает~t 1. Основы ороrраммировання

Статъя 1. Простсйшая проrрамма на языкс ассемблера .................... 13


Статъя 2. Подrаrовка проrраммы к выnOJUieНИIO .............................. 17
Статъя 3. Регистры процессора ••- ..................................................23
Crlm.JI 4. Интеракrивный отладчик CodeVicw Microsoft ................... 28
Crlm.JI s. Сеrмснmая адресация ~ сеrмснmая cтpYJCIYP&
проrрамм .............................................................................. 34
Crlm.JI 6. Сrек ...................................................................................... 38
Crlm.JI 7. Вывод на экран символьной инфорr.1ации ......................... 4S
Crlm.JI 8. Еsс-nоспедоватсльности....................................................... 49
Статъя 9. ЦИIСЛЬ1 ................................................................................... s1
Crlm.JI10. Ввод с КJiавиатуры СИМВОJПiНОЙ информации .................... ss--
Статъя 11. Анализ данных и условные nереходы ................................. S9
Статъя 12. Пароли и сравнение строк .................................................. 61
Статья 13. Уnравление nроrраммой с КJiавиатуры
и расширенные коды ASCII ................................................ 64
Cra'lblll4. Вывод nростейших rрафических изображений .................. 70
Сrатья 1S. Подпроrраммы ..................................................................... 1S
Статы11б. Механизм вызова подпроrрамм .......................................... 80
Статы117. Преобра:ювание шсстнадцатеричных цифр
в символьную форму .......................................................... 83
Статъя 18. Преобра:ювание беззнаковых двоичных чисел
в символьную форму ........................................................... 8S
Cnm.я 19. Дамn naмm1 и регистров .................................................... 88
Cnm.я 20. Основы орrанизации noroqюrpaмw .................................... 91
Cnm.я 21. Процедуры и nOIIЯ данных .................................. :............... 98
Cqm.s 22. Библи~ки noдпporpaмw ........................ _......................... l04
Cnm.я 23. Вывод на экран текста средствами Bl9S .......................... 106
Cnm.я 24. Косвенные вызовы noдnporpaмw ....................................... llO
Cnm.я2S. Прерывания пользоваrспя ......- ................................ :........ 113
Cnm.я 26. Табличные вызовы nодорограмы ....................................... 117
Cnm.я 27. Макрокоwанды .................................................................... 119
Cnm.я 28. СrруК'I)'ры ........................................................................... 123
4 Содержание

Статья 29. Записи ................................................................................. 130


Статья 30. Способы адресации и оптимизация программ .................. 132
Статья 31. Программы с несколькими сегментами команд ............... 138
Статья 32. Программы с несколькими сегментами данных ............... 144
Статья 33. Директива assume, инициализация сегментных
регистров и замена сегментов ............................................ 148
Статья 34. Программы типа .COM ...................................................... l53
Статья 35. Ввод с клавиатуры десятичных чисел ................................ 155
Статья 36. Знаковые и беззнаковые числа и операции ...................... 160
Статья 37. Обработка двоично-десятичных чисел .............................. 165
Статья 38. Чтение текущего времени из КМОП-микросхемы ........... 173
Статья 39. Работа с видеобуфером ....................................................... 17 5
.Статья 40. Обработка символьных данных ......................................... 182
Статья 41. Создание файла на диске ................................................... 188
Статья 42. Анализ системных ошибок ................................................ 191
Статья 43. Завершение программы и анализ кода возврата
в командном файле ............................................................. 194
Статья 44. Программирование портов. Звук ....................................... 196
Статья 45. Программирование звукового канала таймера .................. 199
Статья 46. Обработчик прерываний от таймера .................................. 204
Статья 47. Резидентный обработчик прерываний от таймера ............ 210
Статья 48. Будильник ........................................................................... 215
Статья 49. Контроллер прерываний и ero программирование ........... 218
Статья 50. Взаимодействие прикладных и системных
обработчиков прерываний ... - ............................................. 227
Статья 51. Резидентный обработчик прерываний от клавиатуры
с подКЛIСчением до системного обработчика.................... 229
Статья 52. Резидентный обработчик прерываний от клавиатуры
с подкточением после системного обработчика .............. 238
Статья 53. Резидентный обработчик прерываний от клавиатуры
с подключением ющ до, так и после системного ............ 241
Статья 54. Динамический дамп ........................................................... 244
Статья 55. Переключеине стека в обработчике прерываний .............. 252
Статья 56. Функция DOS или прерывание BIOS? .............................. 257
Статья 57. Защита резидентной программы от повторной
установки ............................................................................ 263
Статья 58. Выгрузка резидентной программы из памяти ................... 267
Статья 59. Деассемблирование и машинные коды команд ................ 274
Содержание

Часть 2. Проrраммирование защищенноrо режима

Статья 60. Особенности процессорав 80386-i486 ............................... 283


Статья 61. Первое знакомство с защищенным режимом ................... 295
Статья 62. 32-разрядные операнды и .цругие усовершенствования .... 309
Статья 63. Исключения ........................................................................ 316
Статья 64. Исследование исключений ................................................. 327
Статья 65. Обработка аппаратных прерываний
в защищенном режиме ....................................................... 339
Статья 66. Работа с расширенной памятью ........................................ 352
Статья 67. Переключеине задач ........................................................... 363
Статья 68. Дескрипторы-псевдонимы ................................................. 378
Статья 69. Переключеине задач по аппаратным прерываниям .......... 385
Статья 70. Мультизадачный режим с управлением от клавиатуры .... 390
Статья 71. Раздельные операционные среды и таблицы
локальных дескрипторов ................................................... .404
Статья 72. Уровни привилегий и защита по привилегиям ................ .414
Статья 73. Задачи в кольцах защитьr
.................................................. .430
Статья 74. Режим виртуального МП 8086 .......................................... .435
Статья 75. Исследование режима виртуального МП 8086 .................. 449
Статья 76. Эмуляция MS-DOS в режиме виртуального МП 8086 ..... 462

Часть 3. Проrраммирование арифметического


сопроцессора

Статья 77. Основы работьr с арифметическим сопроцессором ......... .483


Статья 78. Работа с действиrельными числами .................................. 487
Статья 79. Отладка проrрамм, работающих с сопроцессором ........... 490
Статья 80. Как определить, есть ли у вас сопроцессор? .................... .496
Статья 81. Выполнение арифметических операций ........................... .498
Статья 82. Использование сопроцессора для реализации операции
возведения положиrельного числа в .цробную степень ..... 503
Статья 83. Вычисление корнянелинейного уравнения F(x)=O ......... 507
Статья 84. Процедура рисования окружности .................................... 510
Статья 85. Управляющие регистры сQпроцессора............................... 514
в Содержание

ПрИJiожеНИJJ

Приложеине 1. Основные команды процессора .............................. ...... 525


Приложеине 2. Основные команды оmадчиха CodeView Microsot\ ...... 544
Приложеине 3 Команды сопроцессора................................................... S46
Введение
Книга рассчитана на пользователей персональных компьютеров 1И­
па IBM РС, коrорые ха:rели бы познакомиться: с ар:хиrепурными осо­
беннОС'l'SТhfи этих машин, системой команд и режимами работы исполь­
зуемых в них микропроцессоров, орrанизацией ввода-вывода и преры­
ваний, управлением аппаратными средствами компыотера, функция:ми
базовой системы ввода-вывода BIOS и операционной системы MS-DOS.
Все эти знания: естественным образом приобретаю-rоя: при изучении
языка ассемблера - языка низкого уровня:, приближенного к аппарат­
ным средствам компьютера и его "натуральным" возможноСТJn~. В книге
будут последовательно рассмоорены основные средства языка ассембле­
ра микропроцессоров lntel 8086 - i486 и его применекие при програм­
мированин задач разного рода: вычислительных, логических, по управ­
лению аппаратурой и .цр.
Как известно, nрограммы, написанные на языке ассемблера (если,
конечно, они написаны грам01Но); отличаю-rоя высокой эффеiСI'ИВ­
ностыо, т.е. минимальным объемом и максимальным быстродействием.
Эrо обстоятельство обусловило широкое использование языка ассем­
блера в тех случаях, когда скорость работы программы или расходуемая
ею память имеют решающее значение. Некоrорые классы программ
(например, программы устанавливаемых .црайверов уСЩ>ойств, 0'1'-
личающиеся :жесткой СЩ>упурой) требуют для своего составления: обя­
зательного использования языка ассемблера. С .цруrой стороны, по­
скольку современные системы программирования: позволяют объеди­
нять в одну выполнимую программу фрагменты, написанные на разных
языках, широко прапикуе'rоя составление комбинированных программ,
в которых основная часть программы ..аписана на языке высокого
уровня, а наиболее крИ1ИЧеские участки - на языке ассемблера. Может
использоваться и обратный метод, когда в программу на языке ассем­
блера .вставJtЯIОТ фрагменты для выполнения: ОIНосиrельно сложных
1J:огических или математических преобразований, написанные на языке
высокого ypoвiUI. Такой метод, в частности, применим при разработке
устанавливаемых .црайверов. Процедуры на языке Си, ВJШIОчаемые в
текст .црай:вера, упрощают проJ:р8ЫМИровавис и аrладку драйвера и
ускоряют процесс его разрабопаl.
Однако, кроме пспребиrельских ка'IССТВ, J1ЗЬПС ассемблера имеет еще
зиачиnшьную мсmщичсскую цоннОС'lЪ. О1ражая ар~аwныо особон-
8 Введение

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


язык ассемблера предоставляет уникальную возможность изучения ма­
шины на "низком уровне", освоения того, что и как умеет делать аппа­
ратура компьютера и что вносит в его работу операционная система.
Знакомство с внутренними возможностями компьютера чрезвычайно
полезно, в частности, для проrраммиста, работающего на языках Пас­
каль или Си, так как позволяет увидеть за формализмом язьiКа высокого
уровня те реальные процессы, которые будут протекать в системе при
выполнении прикладной проrраммы и, следовательно, более осознанно
подойти к разработке структуры проrраммы и 6е конкретных ашорит­
мов.

Язык ассемблера, как и любой другой язык проrраммирования,


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

и облегчить процесс проrраммирования и расширить возможности соз­


даваемых проrрамм. Профессиональная работа на языке ассемблера, ес­
тественно, предполагает детальное знакомство со всеми этими
средствами. Чем лучше пользователь владеет техникой проrраммирова­
ния на языке ассемблера, тем более эффеiсrИВными будут его проrрам­
мы. Однако не менее важной является и другая сторона вопроса -
освоение особенностей применения язьiКа для реализации аппаратных и
проrраммных возможностей компьютера. В этом плане вопросы, на­
шедшие отражение в настоящей книге, можно условно разбить на две
rруппьr. В первую rруппу входят сведения по основам языка и проrрам­
мирования на нем, в частности:

- способы адресации;
- система команд;

- типичные ашоритмы проrрамм на языке ассемблера;


- выполнение арифметических и логических операций;
- иреобразование данных;
- организация подпроrрамм;

- макросредства ассемблера.
Другую rруппу составляют различные аспекты реализации в про­
rраммах на языке ассемблера аппаратных и системных возможностей
компьютера:

- проrраммирование ввода-вывода;

- использование прерываний BIOS и функций DOS;


- проrраммирование арифметического сопроцессора;
- работа в защищенном режиме;
- управление обычной и расширенной памятъю.
Книга рассчитана на самостоятельную прорабurку ее читателем на
переональном компьютере. Уже в первой статье книги дается простей­
шая проrрамма на языке ассемблера, на основе которой рассматривают­
ся наиболее общие архитеrсrурные вопросы. В дальнейших статьях при-
Введение

водиwые приwеры проrрамм постепенно ycлOЖIIJIIO'mJI, обрастают все


новыми дC1'8ЛJDOI и дают воэможн:осп. вводить в изложение новые по­
НJIТИЯ языка и ар.хиrекзуры КOWIIЬIO'Iq)L Авrоры сознааwп.но аnсазались
or традиционною последоВ~ПСЛЬною изложения '1'С0ре111Ческою ~­
риала, эаменив ею рассмтрением большою КОJПIЧССDа пцатсльно по­
добранных (и, по возмоzиОСПI, простых) проrраыиных приwсров, ко­
торые можно и нужно ВЬПIOJIIUI'l'Ь на коwm.ютере по мере ~ИИJI соот-

11е1'С'11l)'ЮЩИХ ~й. Конечно, Т8U8 книrа по сравнеИИIО с ~цtщион.:.


ными учеб~~~~К~Ми выrшщит нескоm.ко леrковссно, однако, как нам ка­
жется, изучение шпериала на базе отиосиrсльно простых проrрамwных
примеров будет стиыулироваm. самОСТОJIТСЛЬную работу чиnrrслей на
компьютере и в конечном счоте приведсn- к более глубоким и прочным
знаниям.

В первом издании КИШ'а, оrчасти по пол:иrрафическим причииам,


была разделена на четыре части. В Н8СТОJПЦем издании две первые
части, тесно сввзан:иые тем8111'1ески, объсДIПiены в одну, и кииrа со­
стоит, таким образом, из трех частей. В первой части даются начальные
(но далеко не всегда элемекrарные) сведения по ар.хиrеП)Iре процессора
и языку ассемблера. Здесь же рассма'lриваются модели памяти, про­
rраммирование ввода-вывода, написание обрабаriИJtОв прерываний,
разработка резидентных проrрамм. Вторая часть посвящена защищен­
ному режиму микропроцессора и таким сме.жиым вопросам, как работа
с расширенной памятью, многооадачносп., защита и др. Наконец, тре­
ТЫI часть описывасn' проrраммироваиие арифметическою сопроцессора.
При подrоrовке второю издания в книгу были внесены
незначите.льные добаапения, уС'lр8Иеиы повторы и испраапеиы за­
меченные опсчаrки.
Часть 1

Основы программирования
Простейшая программа на языке ассемблера 13

Статья 1
Простейwая проrрамма на JIЗыке ассемЬера

Начнем изучение языка ассемблера с рассмаrрсния простой, воэ­


мо:zlщ дuсе н~йшей пjюrрам:мы (пример 1.1), ICOТOpU выводит
на экран 'mрМИНала С1JЮКУ с текстом. Вопросы ввода в компьютер текс­
та проrрам:мы, се 'lр8НСJUЩИИ и компоновки мы рассыоrрим в СJiедУIО­
щей С11П'ЬС, а пока сосредоточимся на C'lpYJCIYPC програм:мы.

IJpшtq J.J.llpoc1uйiiiiUI проqнuи~а.


text eev-ent 'code' ;(l)Ha•ano сеrмеи~а комакд
aaau.eCS:text, DS:text; (2)Сеrмек~ике реrис~к CS и DS
;будут укаsкват• ка сеrмек7 ко~
IIOV АХ, text ; ( З) Адрес сеrмекта комащr auopysiDol
IIOV DS,AX ; (4)ска•апа а АХ, аатек а DS
АН, 09h ; ( 5) Фуикци11 DOS 9h аквода ка эxp-
180V DX,o~faet .-ааа~е;(б)Ацрес акаодиNDrо сооб8енк~~
int 21h ;(7)8кsоа DOS
180V AU,4Ch ; (8)ФуJuсция 4Ch sааерше10111 nporp-
lloOV AL,OOh ; (9)Код О успешиоrо sааерше10111
int 21h ; (10)Вкsоа DOS
--·••9•
text

ellda
'Наука умеет мноrо ~$'; (11)8као~ ~екст
; (12)Коиец сеrм.к~а команд
elld ; (13)Кокец текс~а uporpaмwк
; с укаsаииек то..и ахода

Слсдуеr заысmm., что при вводе исходною текста программы с кла­


ВИ81)'рЫ можно использовать каJС nрописныс, Т8lt и С'1р0'1НЫС буквы:
тpaнCJВI'I'Oi» воспринимает, например, С'lрОКИ text segment и ТЕХТ
SEOMENТ одинаково. Однако с Пс:Jыощью кточа /МL можно застааить
тpaнcmrrop различать прописные и С'lрОЧНЫе буквы в иконах. Тогда
С'lрОКИ tcxt segment и ТЕХТ scgmcnt уже не буiJУТ ЭХВИIIаJIСН'I'ИЫ. Фак­
тически они буiJУТ описЫВIП'Ь два разных ссrмента. НСЭКВИ118Пентносп.
проrшсных и строчных б)'IСВ касается только имен; C'lpOIDI
11o0v da, ах
NaV · DS,AX
110V DS,AX

во всu: CJIY'IIUIX вocпpiiiDIIoOUO'n:Я одинаково.


В IIIC'R)JIЩCЙ кииrе 8 проrраммах И ИХ ОПИС811101Х ИСПОJJЪ3ую'rсЯ
ореикущественио строчные буоы. ПрописНШОI б)'DIIМII ltbl,I{CJICИЫ
обозначения регистров и, иногда, имена проrраммных и IDIЫX файлов.
14 Статья 1

Наша проrрамма содержит 13 строк- предложений языка ассембле­


ра. Первое предложение с помощью оператора segment открывает сег­
мент команд нашей проrраммы. Сегменту дается произвольнос имя text.
Описатель 'code' (так называемый класс сегмента) говорит о том, что
это сегмент команд (слово code обозначает и коды, и команды про­
rраммы). В конце предложения после точки с запятой располагается
комментарий. Таким образом, предложение языка ассемблера может со­
стоять из четырех полей: имени, оператора, операндов и комментария,
располагаемых в перечисленном порядке.

Любая проrрамма должна обязательно состоять из сегментов - без


сегментов проrрамм не бывает. Обычно в проrрамме задаются три сег­
мента: команд, данных и стека, но мы в нашей простой проrрамме пока
оrраничились одним сегментом команд.

Во втором предложении мы с помощью оператора assume сообщаем


ассемблеру (проrрамме-транс.imтору), что сегментные регистры CS и DS
будут указывать на один и тот же ceгмeirn text. Сегментные регистры (а
всего их в процессаре четьq>е) иrрают очень важную ролЬ. Когда про­
rрамма заrружается в память и становится известно, по каким адресам

памяти она располагается, в сегментные регистры заносятся начальные

адреса закрепленных за ними сегментов. В дальнейшем любые обраще­


ния к ячейкам проrраммы осуществляются путем указания сегмента, в
котором находится интересующая нас ячейка, а также номера того байrа
внутри сегмента, к которому мы хотим обратиться. Этот номер носит
название относительного адреса, или смещения. Поскольку в един­
ственном сегменте нашей проrраммы будут размещаться и команды, и
данные, мы указываем ассемблеру оnератором assume (assume - предпо­
ложим), что и сегментный регистр команд CS, и сегментный регистр
данных DS будут указывать на сегмент text. При этом в регистр CS ад­
рес начала сегменrа будет заrружен автоматически, а регистр DS нам
придется заrружать (или, как говорят, инициализировать) "вручную".
Строго говоря, в приведеиной проrрамме, где нет прямых обраще­
ний к ячейкам сегмента данных, не бьшо необходимости сопоставлять в
операторе assume сегмент text с сегментным регистром DS (сопос­
тавление сегмента команд с сегментным регистром команд CS обяза­
тельно во всех случаях). Учитывая; однако, что практически в любой ра­
зумной проrрамме обращения к полям данных имеются, мы с самого
начала написали оператор assume в том виде, в каком он используется в

реальных проrрам.мах.

Первые Д'Ва предложения проrраммы служат для передачи служеб­


ной информации проrрамме ассемблера. Ассемблер восприниыает и за­
поминает ~ информацию и пользуется ею в своей дальнейшей работе.
Однако в состав выпалнимой проrраммы, состоящей из машинных ко­
дов, эти строки не попадут, так как процессору, выполняющему про-
Простейшая программа на языке ассемблера 15

грамму, они не нужны. Другими словами, операторы segment и assume


не транслируются в машинные коды, а используются лишь самим ас­

семблером на этапе трансляции программы. Такие нетранслируемые


операторы иногда называют псеводооператорами, или дире:rсгивами ас­

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


Предложение 3, начинающееся с метки begin, является первой вы­
полнимой строкой программы. Для того, чтобы процессор знал, с какой
строки· начать въmолняrь программу после ее загрузки в память,
начальная метка программы указывается в качестве операнда самого по­

следнего оператора программы end (см. предлqжение 13). Можно поду­


мать, что указание точки входа в программу изmmme: ведь как будго и
так ясно, что программу надо н3;чать выполнять с начала, а закончить,

дойдя до конца. Однако в действиrельности для программ, написанных


на языке ассемблера, это совсем не так! Текст программы может
начинаться с описания вспомогательных подпрограмм или полей дан­
ных. В этом случае предложение программы, с которого нужно начать
ее выполнение, может располагаться где-то в сереДШiе текста програм­

мы. И завершается выполнение программы совсем не обязательно в ее


последних строках, а там, где стояr предложения вызова специальной
программы операционной системы, предназначенной именно для за­
вершения текущей программы и передаче управления системе (см.
предложения 8... 10). Однако начиная от точки входа программа въmол­
няется строка за строкой точно в том порядке, в каком эти строки на­
писаны программистом.

В предложениях 3 и 4 выполняется инициализация сегментного


регистра DS. Сначала значение имени text (т.е. адрес сегмента text) за­
гружается командой mov (от move, переместитъ) в регистр общего наз­
начения процессара АХ, а затем из регистра АХ переносиrоя в регистр
DS. Такая двухступенчатая операция нужна потому, что процессор в си­
лу некоторых особенностей своей apxиrercrypы не может выполнить ко­
манду непосредственной загрузки адреса в сегментный регистр. Прихо­
дится пользоваться регистром АХ в качестве "перевалочного пункта".
Кстати, обратите внимание на то, что операнды в командах языка ас­
семблера записываются в несколько неестественном для европейца по­
рядке - действие командъr осуществляется справа налево.
Предложения 5, 6 и 7 реализуют существо программы :- вывод на
экран строки текста. Делается это не непосредственно, а путем обраще­
ния к служебным программам операционной системы MS-DOS, кото­
рую мы для краткости будет в дальнейшем называть просто DOS. Дело
в том, что в составе команд процессара и, соответственно, операторов

языка ассемблера нет команд вывода данных на экран (как и команд


ввода с клавиатуры, записи в файл на диске и т.д.). Вывод даже одного
символа на экран в действиrелъности представляет собой довольно
18 Статья 1

1тожную операцию, для !iЫПОJПiения которой 'l'J)Сбуется длинная после­


довательность команд процессора. Конечно, . -.лу последовательносп.
команд можно бьшо бы вкmочигь в нашу программу, однако гораздо
проще обратmъся за помощью к операционной системе. В состав DOS
входиr большое количество программ, осуществляющих стандарmые и
часто 'l'J)Сбуемые функции - вывод на экран и ввод с клавиатуры, запись
в файл и чтение из файла, чтение или установка текущего времени, вы­
деление ИJ1И освобождение памяти и мноtие другие.
Для того, чтобы обрапrrься к DOS, надо загруэmъ в регистр общего
назначения АН номер требуемой функции, в другие регистры- исход­
ные данные для выпОJПiения этой функции, после чего ВЫПОJПIИГЬ ко­
манду int 2lh, (int - от interrupt, прерывание), которая передаст управ­
ление DOS. Вывод на экран с1р0ки текста можно осуществигь функци­
ей 09h, которая ч>ебует, чтобы в регистре DX содержался адрес выво­
димой строки. В предложении 6 адрес с1р0ки message загружается в ре­
гистр DX, а в предложении 7 осуществляется вызов DOS.
После того, как DOS выпОJПiит затребованные действия, в данном
случае выведет на экран текст "Наука умеет много гитик" (помните од­
ноименный карточный фокус?), выполнение программы продоткится.
Вообще-то нам вроде бы ничего больше делать не нужно. Однако на
самом деле это не так. После окончания работь1 нашей программы DOS
должна вьmОJПiить некоторые служебные действия. Надо освободить за­
нимаемую нашей программой память, чтобы туда можно бьто загрузить
следующую программу. Надо вызвать системную проJ1)амму, которая
выведет на экран запрос DOS и будет ждать следующей команды оnера­
тора. Все эm действия выnолняет функция DOS с номером 4Ch. Эта
функция предполагает, что в регистре AL находится код завершения
нашей программы, который она передаст DOS. При желании код за­
вершения только что закончиnшейся программы можно "выловить" в
DOS и проанализировать, но сейчас мы этим заниматься не будем. Ес­
ли программа завершилась усnешно, код завершения должен быть равен
О, поэтому в предложении 9 мы загружаем О в регистр AL и вызываем
DOS уже знакомой нам командой int 21h.
После последнего вьmолнимого предложения программы можно
описывать используемые в ней данные. У нас в качестве данных высту­
пает строка текста. Текстовые строки вводятся в программу с помощью
диреiСГИВЫ ассемблера db (от derшe byte, оnределить байт), и за­
ключаются в апос'IрОфы. Для того, чтобы в программе можно бьшо об­
ращап.ся к данным, nоля данных, как правило, предваряются именами.

В нашем случае таким именем является вnолне произвольнос


обозначение message, с которого начинается nредпожение 11.
Выше, в предложении 6, мы через регистр DX nередали DOS адрес
начала выводююй на экран стро101 текста. Но как DOS определкr, rде
Подготовка проараммы к выполнению 17

эта строка закончилась? Хотя нам конец строки в программе оrчетЛИJЮ


виден, однако в машинных кодах, из коrорых состоиr вьmолниыая
проrрамма, он никак не отмечен, и DOS, выведя на экран слово
"nrmк", продолжит вывод байrов памяти, располо.женн~ за нашей фра­
зой. Поэтому DOS следует передать информацию о том, rде кончается
С'J1Юка ~кета. Некоторые функции DOS требуют указания в одном ю
регистров длины выводимой С'J1ЮКИ, однако функция 09h работас)т
иначе. Она выводит ~кст до символа $, которым: мы и завершИJIИ нашу
фразу.
Директива ends (end segment, конец сегмента) в предложении 12
указывает ассемблеру, что сегмент text закончился.
Последняя С'J1Юка программы содержит директиву end, которая го­
ворит программе ассемблера, что закончился вообще весь ~кст про­
граммы, и больше ничего транслировать не нужно. В качестве операнда
этой директивы, как уже отмечалось, обычно указывается точка входа в
программу, т.е. адрес первой вьmолнимой программной строки. В на­
шем случае это метка begin.

Статья 2
Подготовка программы к выполнению

Процесс подrоrовки и отладки Iтрогр<lММЫ на языке ассемблера


uключает этапы подготовки исходного тексТ'а, трансляции, 1юмпоноьки
и отладки.

Подrоrовка исходного текста программы вьшо;шяется с помощью


11Юбоrо текстового редактора. Файл с исходным текстом дOJDICeн иметь
расширение .ASM. При выборе редактора дня подготовки исходного
~кета про1раммы следует иметь в виду, 'fi'O многие текстовые rrроцес­
соры (например, Microsoft Word) добаWIЯют в выходной файл слу:t.:еб­
нуJО информсЩИЮ о формате (размер страниц, тип шрифта и др.). По­
этому следует воспользоваn.ся рещuсrором, выводящим в выходной
файд "чистый теi«."Т", без каких-либо управJIЯющих символов К таким
редакторам относятся, например, широко рш:нр<Х:транс'IНЫе у нас Лек­
сикон, Norton Editor, редактор EDIТ.COM, ВХОJ))IШИЙ в coc·raa nпе~нк­
ошюй си1.:темы MS-DOS и др. П()\,;КОJiьку нр•1 ннтенскьн<>w rrроrрn.\fМИ­
ровани.и ЧШ: ГО ltpИXOilИTcH llt:peHOCКCЬ фpiiПolt:HTЫ ~l(.'-"1'a ИЗ О.IНОЙ ЩЮ-
18 Статья2

граммы в .цругую, желательно, чтобы peдmcrop имел средство целения:


экрана на независимые окна. Таким свойством обладают проrраммы
. Лексикон (10 окон) и Norton Editor (2 окна, что в большинс-mе случаев
ВПОJПiе достаточно) но не обладает peдmcrop EDIT.COM. При рабоrс в
операционной среде какой-либо си~мы проrраммирования, например,
Borland С, можно воспользоваться редактором, ВС'IрОСННЫМ в :ny среду.
Трансляция исходного текста программы состоит в nрсобразовании
CIPOK исходного .азыка в коды машинных команд и выполняется с nо­
мощью 1ранслятора с языка ассемблера (т.е. с nомощью проrраммы ас­
семблера). Можно восnользовап.ся макроассемблером фирмы IBM,
проrраммой TASM фирмы Borland или 'lрЭНслятором МАSМ фирмы
Microsoft. Трансляторы различных фирм имеют нсзначиrельные раз­
личия, в основном, в части описания макросрецств. Однако, входной
язык (т.е. мнемоника машинных команд и .цругих оnераторов и правила
написания предложений ассемблера) для всех ассемблеров одинаков.
После 1рансляции образуется объектный файл с расширением OBJ.
Комnоновка объектного файла выполняется с помощью проrраммы
комnоновщика (редактора связей). Эrа проrрамма nолучила такое на­
звание nотому, что ее основное назначение- nодсоединение к файлу с
основной проrраммой файлов с nодпроrраммами и нас1ройка связей
меж.цу ними. Однако комnоновать необходимо даже простейшие про­
rраммы, не содержащие nодпроrрамм. Дело в том, что у комnоновщика
сеть и вrорая функция - изменение формата объектного файла и преоб­
разование его в вьmОJШимый файл, который может бьrrь заrруж:ен в
oneptmmнyю nамять и выполнен. Файл с проrраммой комnоновщика
обычно имеет имя LINK.EXE, ХО'ПI это может бьrrь и не так. Например,
компоновщик фирмы Borland назван TLINК.EXE. Компоновщик жела­
тельно брать из одного пакета с ассемблером. В результате комnоновки
образуется заrрузочный, или выполнимый файл с расширением .ЕХЕ.
Известно, что проrраммы, вьmолняемые nод управлением MS-DOS,
могут принадлежать к одному из дВух тиnов, которым соответствуют

расширения: имен ВЬШОJПIИМЫХ файлов .СОМ и .ЕХЕ. Основное раз­


личие этих проrрамм заключается в том, что проrраммы тиnа .СОМ со­
стоят из единс-mенного сегмента, в котором размещаются nроrраммные

коды, данные и ~к, а в nроrраммах тиnа . ЕХЕ для собственно про­


rраммы, данных и стека предусматриваются отдельные сеrментьr. В ре­
зультаrе размер проrраммы тиnа .СОМ не может прсвысить 64 Кбайт, а
размер программы типа .ЕХЕ прахrически не оrраничен, так как в нее
может входить любое число сегментов команд и данных. При разработ­
ке программных продуiQ'ОВ чаще используется формат .ЕХЕ, как обла­
дающий большей универсальностью. Однако некоторые специфические
проrраммы (обрабО'Iчихи annapamыx прерываний, рсэиценmые про­
rраммы) обычно пишуrся в формаrе .СОМ.
Подготовка программы к выполнению 19

Если исходная проrраь~ма написана в формате .СОМ, то после


трансляции и компоновки обычным образом ее надо преобразоваТh в
файл mпа .СОМ, для чего используется внешняя команда DOS
EXE2BIN. Позже этот вопрос будет рассмотрен подробнее.
Оrладка готовой программы может вьmолняться разными методами,
выбор которых определяется струкгурой и функциями отлаживаемой
программы. Свою специфику отладки имеют, например, резидентны~
проrраммы, обработчики аппаратных прерываний, драйверы устройств
и другие классы программ. В целом наиболее удобно отлаживаТh про­
граммы с помощью какого-либо интераiсrИВного отладчика, который
позволяет вьmолнять отлаживаемую программу по шагам или с точками
останова, выводИТh на экран содержимое регистров и областей памяm,
модифицироваТh (в известных пределах) загруженную в Памя'IЪ про­
грамму, принудительна измеНЯТh содержимое регистров и выполнять

другие действия, позволяющие в наглядной и удобной форме контроли­


роваТh выполнение программы.

При использовании пакета фирмы Borland следует взять "турбо­


дебаггер" TD.EXE, при трансляции и компоновке программы с по­
мощью пакета фирмы Microsoft - отладчик
Codeview (файл CV.EXE).
Можно воспользоваТhся и отладчиком DEBUG.EXE, входящим в состав
операционной системы MS- DOS, хотя с ним не о<Iень удобно работаТh,
так эта программа не обеспеqивает привычный для сегодняшнего поль­
зователя полноэкранный юrгерфейс.
Следует заметить, что хотя турбо-отладчик, входящий в пахет фир­
мы Borland, имеет весьма бoraThiЙ набор возможностей, он довольно
сложен в освоении. Начинающему программнету удобнее воспользо­
ваТhся отладчиком Codeview фирмы Microsoft. В настоящей книге будет
предполагаТhся, что читатель выполняет предложенные nримеры с П()­

мощью пакета фирмы Microsoft (транслятор MASM.EXE, компоновщик


LINК.EXE, отладчик CV.EXE).
Если файл с исходным текстом программы назван P.ASM, то строка
вызова ассемблера может ИМСТh следующий вид:

МАSМ /Z /ZI /N Р,Р,Р;

(Еще раз напоминаем, что как в тексте программы на языке ассем­


блера, так и при вводе с Юiавиатуры командных строк можно с равкым
усцехом использовать и прописные, и строчные буквы.)
Ключ /Z разрешает вывод на экран строк исходного тексга про­
граммы, в которых ассемблер обнаружил ошибки (без зтого IUDOЧa по­
иск ошибок пришлось бы проводить по лиt..-гингу трансляции).
Ключ /ZI управляет 81СЛЮчением в объеJСТНый файл ноwеров строк
исходной 1rроrраммы и другой информации, не требуемой при выпОJr­
нснии nporpawwы, но ислользуеwой оrладчИJСОw CV.
20 Статья2

Ключ /N. подавляет вывод в листинг перечия символических


обозначений в программе, от чего несколько уменьшается информtrГИВ­
ность листинга, но существенно сокращается его размер.
Стоящие далее параметры определяют имена файлов: исходного
(P.ASM), объеrrnюго (P.OBJ) и листинга (P.LST). Точка с запятой по­
давляет формирование файла P.CRF с перекрестными ссьvrками, кото­
рый нам не нужен.
Сtрока вызова компоновщика может иметь следующий вид:
LINК /СО Р,Р;

Ключ /СО передает в загрузочный файл символьную информацию,


позволяющую отладчику CV выводиrь на экран ПОJПIЫЙ текст исходной
проrраммы, включая метки, комментарии и проч. Стоящие далее пара­
метры обозначают имена модулей: объектного (P.OBJ) и загрузочного
(Р.ЕХЕ). Символ точки с запятой подавляет формирование файла с лис­
тингом компоновки (Р.МАР) и использование библиотечного файла с
объектными модулями подпрограмм.
Как уже отмечалось, компоновщик создает загрузочный, готовый к
ВЫПОJПiению, мо~ль в формате .ЕХЕ. Запуск подготовленной програм­
мы Р.ЕХЕ осуществляется командой

Р.ЕХЕ

или просто

Если программа не работает должным образом, необходимо прибег­


путь к помощи интераiСГИВного отладчика. Оrладчик CodeYiew запуска­
ется командой

CVP

где Р - имя файла с отлаживаемой программой. По умолчанию отладчик


загружает файл с расширением .ЕХЕ. В процессеработы отладчик ис­
пользует также файл с исходным модулем P.ASM, поэтому перед отлад­
кой не следует переименовымгь ни исходный, ни ВЫПОJПIИМЫЙ файлы.
Правила работы с отладчиком CodeView Microsoft и его основные ко­
манды будут описаны в одной из СJiедующих статей.
Поскольку по мере изучения этой книги вам придется написать и
аrладИ'IЪ несколько десятков проrрамм, целесообразно создать команд­
ный файл, авrоматизирующий ВЬПIОJПiение однОТИIПiых операций тран­
сляции и компоновки. Текст командного файла (для подготовки про­
грамм с помощью транслятора и компоновщика фирмы Mi~rosoft) мо­
жет бьm. таким:
nодготовка программы к еыполнению 21

@echo off
masm/z/zi/n р,р,р;
if errorlevel 1 goto err
link/co р,р;
goto end
:err
echo Ошибка ~рансляции!
goto fin
:end
echo Конец сеанса
:fin
echo •
Если транСJUЩИЯ прошла успешно, на экран выводится сообщение
"Конец сеанса" и создаются файлы P.OBJ, Р.ЕХЕ и P.LSТ; при наличии
ошибок в проrрамме на экран будут выведены строки листинrа с ошиб­
ками, а за ними сообщение "Ошибка трансляции!". Поскольку в приве­
деином командном файле имя npoiJ>aю.tЫ указано в явной форме, 'М­
кущий вариант проrраммы всегда должен иметь одно и ro же имя (в
приведеином примере- P.ASM). Конечно, можно составип.командный
файл, воспрШiимающий текущее имя проrраммы в качесmе параметра
при его запуске, однако праrrика показывает, чrо 'ПUaUI ме-rодика замед­
ляет работу и Шiогда приводиr к драматическим ошибкам. Удобнее от­
лаживать проJрамму всегда под одним и тем же именем, а после аmвд­

ки записывать в специально созданный каталог архива под уникальным


именем (например, под именем, соответствующим номеру примера в
книге: 01-01.asm).
Создайте файл с проJраммой из примера 1.1. Подrоrовьте проJраМ­
му к выполнению. Не смущайтесь, увидев на экране сообщение

LINК : warning L4021: no stack segment


Эrо компоновщик сообщает, чrо не обнаружил в проiРаю.fе сегмен­
та стека. Его там действительно нет, и это не очень хорошо, однако ра­
ботать проJрамма будет. Позже мы усовершенствуем проJраМму, допол­
нив ее стеком.

И~учиrе листинг транi:ляции (файл P.LSТ). На рис. 2.1 приведен


несколько сокращенный текст листинга трансляции примера 1.1, из кo­
roporo бьши удалены комментарии. Обраппе внимание на следующие
моменты. .
Команды проJраммы имеют различную длину и располагаются в
памяти вплоmую .цруг к JJPYl'Y· Так, перВШI команда mov AX,text,
начинающав:ся с байта 0000 сегмента, занимает 3 байr. Соотвеwrвснно,
вrорав: команда начШiается с байта 0003. Вторая команда имеот дiomy 2
байт, поэтому трст.я команда начинаетсJI с байтаOOOS и т.д.
22 Статья2

ОтиоСИ'J!епъике адреса комаид О!I!ИООИ!I!епьио иача.па сеrмеита

Е 1амн•- кодк комаид


1
Иcxoдllllil: текст aporp.-

1 1
0000 text aegaent 'code'
aaauae CЗ:text,DS:text
0000 В8 ---- R begin: mov АХ, text
0003 .ев ое I\IOV DS,AX
0005 В4 09 mov АН, 09h
0007 ВА 0011 R mov DX,offaet meaaage
ооол CD 21 int 21h
о о ос В4 4С IIIOV АН 1 4Сh
ооов во 00 IIIOV AL, OOh
0010 CD 21 int 21h
·г---- Кодк аимвопоа, обраs~х наше сообщение

1 1
0012 8D ЛО 13 АА ЛО 20 13 aeasage dЬ 'HaYJCa умее!l! мноrо l'ИТИJС$'
АС Л5 Л5 В2 20 АС AD
AZ ЛЭ AZ 20 ЛЭ А8 В2
А8 АА 24
text enda
end begin
Раsмер сеrмеита а байтах

Рис. 2.1. Листиш mpaНCARцuu npuмepal.J.

Предложения проrраммы с операторами segment, assume, end не


транслируются в какие-либо машинные коды и не находят ооражения в
памяти. Они нужны лишь для передачи 'фанслятору служебной инфор­
мации.

Транслятор не смог полносп.ю определить код команды mov


AX,text.В этой команде в регистр АХ засыластся а.црес сегыента text.
Однако этот адрес станет известен лишь в процессе загрузки ВЫПО1ПIИ·
моrо файла проrраммы в памяп.. Поэтому в листинге на мес-м этоrо ад­
реса сrоит прочерк.

Данные, введенные нами в проrрамм:у, таюке отrранслировались:


вм:есrо символов текста в загрузочный файл попадуr коды ASCII эmх
символов. По.цробнее о кодах АSСП будет рассказано в статъе 1. .
Из листинга транс.ляции легко опредСJIИ'IЪ размер отдельных состав­
mоощих программы и· всей проrраммы в целом. В нашем случае д11И11а
сегмента команд (в который вошли и данные) равна всеrо 2Ah-42 байт
(символ h обозначает, что число эаписано в шесn~аДЦ~ПСричной системе
счисления).
Выполните пробный проrон проrраммы и убедитесь, что она рабо­
тает, ак ожидалось: на экран ВЫ:ВОдm'СJI текст "Наука уwест мноrо rи-
111К". Если этоrо но произоАдет, значит, в программе npиcfiC11Jyeт кa­
IIUI-10 cкpьrru: ошибu, и проrраыму npидC'roJI ОТла:&ИВIП'Ь с помощью
Peгuctnpыnpoцeccqpa 23

отладчика. Работа с интерапивным аrJIВДЧИКОм 'фС6ует некоторых на-.


выков; статья 4 поможет вам освоиrь м.у mrrepecнoe и полезное ин­
С'lрументальное средство.

Статья 3
Реrистры процессора

В статье 1 при описании приведеиной там проrраммы: упоминались


реГИС'lрЫ процессора, в частности, сегментные и общего назначения.
Регистры процессара ЯВЛЯI<>'rоЯ важнейшим инструментом проrраммиста
(между прочим, не только на языке ассеблера, но и на языках высокого
уровня), и необходимо иметь четкое представление о составе регистров
процессора, их названиях и применении. В примере 1.1 в явной форме
использовались лишь три регистра процессора - АХ (и его старшая по­
ловина АН), DS и DX; по мере чтения книги вы столкнетесь с приме­
рами использования остальных региС'lров. Однако для того, чтобы
чкrатель мог получиrь общее представление об этом важном средстве,
ниже дан краткий обзор всей системы регистров процессора. Если в
этом обзоре вам встретятся незнакомые понятия или неясные места - не
огорчайтесь; в последующих ста'I'ЬЯ!: они будуr описаны более подРОб­
но.

Сiрого говоря, приведеиное ниже описание аrносиrея только к


процессарам 8086 и 80286, для которых харакrерны 16-разрядные ре­
ГИС'lрЫ. В· процессарах 80386 и i486 почти все региС'lры 32-разрядные,
что существенно увеличивает возможности этих процессаров и в неко­

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


усложняет). Однако младшие половины регистров этих процессорав
совпадают и по названиям, и по назначению .с 16-разрядными Ре­
гистрами процессара 8086. Поэтому проrраммы, написанные для 16-
раз-рядного процессора, прекрасно работают и на 32-разрядном, хотя и
не используют все его возмож:носm. Попачалу мы оrраничимся !б­
разрядной архитектурой; особенности современных 32-разрядных про­
цессорав будуr описаны позже.
Процессор содержиr двена,цщm. 16-разрJЩНЫХ IIJЮIPaiOOio­
aдpecyeмыx реrиС'lрОв, которые пpmurro обьсдина'11t в три IpyiiiiЬC ре­
l'ИС'1J>Ы общего назначения (или реrистры данных), реrиотры-указm:еJJИ
24 Стаmья3

11 сеrме11'П1ЫС реrиаrры.
Кроме того, в состав процессора вх:одв:r счетчик
ЕОwаид и perиC'Ip флагов (рис. 3.1).

Регис:ТJJЫ'УКа38Т8ЛИ

АХIАН AL ~~I'IAТOP SJ Индекс источника

вхl вн BL l6ааоеь1А реrистр Dl Инаекс f11И8МНИКО

D<lcн а. !счетчик ВР Указатель базы

DXI DH DL j Регистр А.мtЫХ SP Указотель стека

Сеrментные регистры Прочие регистры

:::::::CS:::=~' Регистр сегмента команд IP 1Укаsотель команд


;:::::D;:S::::~I Регистр сеrмента А6tиос 1 FLAGS 1Реrистр tлaroe
ES 1Регистр аополнительного сегмента данньвс
SS JРегистр сегмента стека
Рис. J.J. Puucmptl nJИЩесщю.

В rруппу регистров общего назначения включаю-rоя регие1ры АХ,


ВХ, СХ и DX. Программист может использовать их по своему усмотрс­
НИIО ДIUI временного хранения любых объектов (данных или а.цресов) и
вьmолнения над ними 'lрСбуемых операций. При этом рсгие1ры допус­
кают независимос обращение к старшим (АН, ВН, СН и DH) и млад­
шим (AL, BL, CL и DL) половинам. Так, команда

IIIOV BL, АН

перссылает старший байт регие1ра АХ в младший байт регис1ра ВХ, не


3а1раГИВ1U1 при этом вrорых байтов Э11fХ регистров. Еще раз отметим,
что сначала укаэывас-rоя операнд-приемник, а после зarurroй- операнд­
источник, т.е. команда выполняе-rоя как бы справа налево. Во многих
случаях регистры общего назначения вполне эквивалентны, о.rхнако
предпоЧ'I'Im:ЛЪнее в первую очередь испольэовать АХ, поскольку многие
команды занимают в памяти меньше места и ВЫПОJПUIЮ-rоя быС1рСС, ec-
JIИ их операндом являе-rоя регистр АХ (или его половины AL или АН).
Индексные регистры Sl и Dl так же, как и регистры данных, мoryr
использоваться прuизвольным образом. Однако их основнос назначение
- хранить индексы (смещения) оmосительно некоторой базы (т.е.
начала массива) при выборке операндов из памяти. Адрес базы при
этом обычно нaxoдm'CJI в одном иэ базовых регисtров (ВХ или ВР). В
дальнейшем тuие trp&tмepы будуr 1rриведенu в изобwiИи.
Регистры процессара 25

РегиС'JР ВР служит указателем базы при работе с данными в стеко­


вых C'JP}'IO"YPax, о чем будет речь впередИ, но может использоваrься и
произвольным образом в большинстве арифметических и логических
операций или просто для временного храненщ каких-либо данных.
Последний из груmiЫ регис1р0в-указателей, указm.'СЛЬ стека SP,
стоит особняком or дРугих в том отношении, что используется ис­
КJIЮчительно как указатель вершины стека - специальной C'JP}'IO"YP~,
которая будет рассмотрена позже.
Регистры Sl, Dl, ВРи SP, в оrличие or регис1р0в данных, не допус­
кают побайтовую адРесацию.
Четыре сегментных регистра CS, DS, ES и SS хранят начальные ад­
реса сегментов программы и, тем самым, обеспечивают возможнОС'IЪ
обращаться к этим сегментам.
Регистр CS обеспечивает адРесацию к сегмеН'I)', в котором находят­
ся программные коды, регистры DS и ES - к сегментам с данными
(таким образом, в любой момент времени программа может иметь дo­
C'I)'II к двум сегментам данных, основному и дополнительному), а ре­
гистр SS - к сегменту стека. Сегментные регистры, естественно, не мо­
гуг выс1УПаТЬ в качестве регистров общего назначения.
Указатель команд IP "следит" за ходом вьmолнения программы, ука­
зывая в каждый момент относительный адрес команды, следующей за
исполняемой. Регистр IP программно недос1УПеН (IP - это просто его
сокращенное название, а не мнемоническое обозначение, используемое
в языке программирования); наращивание адреса в нем выполняет мик­
ропроцессор, учитывая при этом ДЛину текущей команды.
Регистр флагов, эквивалентный регистру состояния процессара
дРугИХ вычислительных систем, содержит информацию о текущем со­
стоянии процессара (рис. 3.2). Он ВКJIЮчает 6 флагов состояния и 3 би­
та управления состоянием процессора, которые, впрочем, тоже обычно
называются флагами.
Флаг пере­
1514 13 12 1110 09 ОВ rJl 06 05 04 03 02 01 00 Биты носа CF (Carry
1 1 j 1 joFjDFjiFjтFjsFjzFI jAFj jPFj Jcrl Flag)
ет
индициру­
перенос или

Рис. 3.2. Регистр флагов. заем при выпол-


нении ариф,.:е­
тически:х: операций, а также служит ИНдИкаТОром ошибки при обраще­
нии к системным функциям.
Флаг паритета PF (Parity Flag) устанавливается в 1, если младшие 8
бит результата операции содержат четное число двоичных единиц.
Флаг вспомогательного переноса AF (Auxiliary Flag) испОJIЬЗуется в
операциях над упакованными двоично-десятичными числами. Он ин­
дИЦирует перенос или заем из старшей тетрцы (бита 3).
28 CmamfJIЗ

Флаг нуля ZF (Zero flas) устанавли:васm;я 8 1, если резу~ТIП опера­


ции равен нуто.

Флаг .знакаSF (Sian Flag) показывает энu. резупьте:rа операции,


ycтaн88JIИJIIUicЬ8 l при спр~ном резу~~.
Флаг персполненЮI OF (Overtlow Flag) фИJССирует персполнение, т.е.
выход результата операции за пределы допустимого ДIIJI данного процсс­
сора диапазона значений.
Флаги COC'IOJIНIOI автомапrчсски устанавливаются процессорок пос­
ле выполненИIJ каждой команды. Тах, сели в pcrиC'IpC АХ содсрхиrся
число 1, то после выnолнения команды декремента (уменьшенИIJ на 1)
dec АХ

содержимое АХ станет равно О, и процсссор сразу ОТN:~ этот фaJcr,


установив в perиC'IpC флагов бит ZF (флаг нуля). Если поm.rrаться СJIО­
жить два больших числа, напрИNер, S8000 и 61000, то устаиоВИТСJ~ tлar
персноса CF, так как число 11!ЮОО, получающСССJI а резу.ль~ сложе­
ния, должно эаюrrь больше двончнwх разрядов, чем помещаете• а реrи­
С1р8Х ИШ1 ячейках паюnи, и JОЗникаст "перснос" старшеrо биrа эrого
числа а бит CF pei"ИC''P& фnaroa.
Индицирующие фJIIm процессора дают возмоЖНОС'По проанализи­
РоВIПЬ, сели эrо нужно, резульТIП последней операции и осуществиn.
"развеnшение" проrраммы: например, в случае нулевого резу~те:rа пе­
рейти на выполисине одного фрагмента проrраммы, а в случае иенуле­
вого - на ВЫПО1ШСНИС дpyroro фраrмента. Такие раэктвленИII осу­
ЩССТIWПОТСЯ с помощыо команд условных переходов, каrорые в про­

цессе своего выполнснilя анапизируют состоJIНис perиC'lpa флагов. Так,


команда

jz ze.ro
осущесnw~ет персход на метку ~ro, если рсэульТIП выполнеНИIJ
предыдущей команды ок.uсется равен О (т.с. флаг ZF установлен), а m-
маида

jno okey
вbliiOJJИИl' переход на McntY okey, сели предыдущая команда сбросила
фmlr персноса CF (И1D1 0СТ1ВНЛа его в сброшенном состоянии).
Уtlравлшощий флаг трассировки TF (Тrасе Flq) используете• в oт­
JI8Д'IJDaUC JJ1U1 осущсстмсНИII пошаговоrо выполнснЮI проJраммы. Если
TF•l, то после ВЫП011НСНИ11 каждой команды процессор реализует про­
цоту uptpbl88RИJI1 (через аепор прсрьшания с номером 1).
Управ.JDПОщий фJJar разрсшоНИIJ прерwваний IF (lntenupt Flq) раз­
ретает (сели рuон 1) И1DI запрещает (сели равен О) nроцессору pearи­
poaan. на пpepblii8RIUI ar внсшвих yc'l'pOЙC'IS.
Peauctnp~J процессара 27

YnpмiiJIIOщий флаг напрuлсiПUI DF (Directi.on Flq) исПОJIЪЗуется


особой rp)'l'IIIOЙ команд, прсдназначеНIIЫХ .IUDI обрабсmа1 строк. Если
DF-o, строка обре&m.mастся в DPJDlOК иапрамении, ar меньших адре­
сов к боm.шим; если DF=1, обработка строки идс:r 8 обраmом направ­
Jiснии.
Таким образом, 8 ar.IIИЧIIc ar биrов COC'mllllиa, yпpaaiiJDDщиc флаги
устан8811ИJJ8еТ ИJIИ сбрасываот проrрамм:кст, 8CJDI он хочс:r изменить lta-
cтpoky сисwмы (Н8Пример, 38IIpe'lVI'Ь на кахоо-то врс~а aпnapamblc
прсрьmаmш ИJIИ изыениrь капрамекис обрабспки cтpelt).
Ворнемея 1t примеру 1.1. ДJUJ тоrо, чтобы И101Ц118Ш13ироваm. ссr­
меиmwй рсrистр DS ссrмсlrl'НЫМ адресом toxt нашеrо (е.u;киствснноrо)
ссrмсН'18, значение text зarpy.zae'roJI сначала в реrис1р общеrо наз­
начеНИJI АХ, а из Н81'0 - 8 oerмelmiЬIЙ рсrкстр DS. В принциnс в
качестве "персвалО'IВоrо пуипа" вместо pcrиcnpa АХ можно В3f1ТЬ JПО­
бой spyroй (например, ВХ ИJIИ Sl), одн111Ш НСlЮЮрЫМ тpaиCJIJI'l'OpU( это
может не понрави1'1оСJ1, 'l'8lt что лучше все-таки испот.эоваrь АХ.
В предложении S в рсrистр АН заиосИТСJI номер фунхции DOS,
реализующей вывод на экран строки ~кета. DOS, цоиучиа управление с
помощью команды int 21h, oпpcдeJDicn' номер требусмой фунiЩИИ
именно по соцсржимому pcrиcnpa АН, поэтому 1111DКИМ ,вруrим рсrи­
стром здесь восп0JIЬ30ватьса HCJIЬ3JI. ФунiЩИJI DOS ВЫIIОда строки из­
влекает адрес выводимой строки из рсrистра DX, поэтому в строке 6
испот.зование рсrкстра DX Т8.1С1Се прсдопрсдс.лено. В дейСТIИ'l'СЛЬВ0С111
дс.ло обс'rоиr сJiо.жнсс. Функция 09h npcдп01IIII'8el', что строка с выводи­
мым ~кстом находител в ccrмeilтc, на lЮЮр.ЫЙ ука3ываст ВПОJПiе опрс­
дс.ленньdt сегментный pci"ИC'lp, именно рсrистр DS. Поэтому перед вы­
зовом фунiЩИИ 09h необходимо настроить этот рсrистр, что мы и cдe­
JWIИ в прсдьщущих прсдлож.енiDIХ про1раммы. СвсдеiПUI о том, JWCИc
pci'ИC'IpW 'lрСбуется НастроИТЬ ДJUI ВЬПIОЛНСНИJI ТОЙ ИJIИ ИНОЙ функции
DOS, можно почсрnнуrь из справочниа по ф}'НIЩИJ[М DOS, без кото­
роrо, '1'8КИJо( образом, праJШIЧССКИ невозможно писать про1раымы с об­
ращениями к CIIO'IeNИЪDI средствам.

В прсдлож.еНИSIХ 8 ... 10 осущСС'ПШJiетсJI вызов си~мной фунiЩИИ


4Ch, CJIYDЩcй д.u завсршеНИJI ~кущей про1р8ММЫ. По-проzиему но­
мер_ фунJЩИИ 3811ociП'CJI в pcrиC'Ip АН; кромо этоrо, в AL можно помсс­
'IИI'Ь код завсршеНИJI проrраымы, каrорый в нашем: приморс равен О.
Статья4

Статья 4
ИIП'ерактивиый отладчик CodeView Microsoft
Часто бываеr так, что проrрамма, успешно пройдя этапы 'lр8НСЛЯ-
191И и компоновки, все же работает не так, как ожидалось или вообще
118 работает. Эrо значит, что формально, с точки зрения правил языка
~мирования, проrрамма написана правильно (в ней нет синтах­
сичсок:их ошибок), однако алгоритм ее в чем-то неверен. Для оrладки
1811СtЙ проrраммы следует воспользоваться услугами интерактивною от­
JВЩЧика. ИнтераiСIИВИым он называется потому, что ВCJJ рабоrа с ним
есущССТВJUiется в непрерывном диалоге с пользова-nтем.

Познакомимся с аrладчиком CodeView фирмы Microsoft, воспользо­


вавшись проrраМмой из примера 1.1, которую мы еще раз приводим
.здесь в слегка видоизмененном виде. В проrрамме сокращены коммен­
тарии и предусмоорен вывод на экран латинских, а не русских букв
(отmщчик CV не во всех случuх удовлетворительно работает с русскими
букваМи).

/lpuq 4.1. ЛJIOliНDUia iJu иэуwншr onиaд'IUIUI Cod1Yшv.


~·х~ seg8ent 'code'
ass\lllle CS: text, DS: text
ayproc proc
IIIOV AX,text ;Инкциапиsаци~
IIIOV DS, АХ 1 реrистра DS
IIIOV АН, 09h ;Номер .УJОЩИИ DOS

IIIOV DX,offset аеs;Адрес аывоДИNDЙ строки


int 21h ;ВЫ3оа DOS
outproq:IIIOV АН, 4Ch 1 ВЫ3оа .УJОЩИИ DOS 4Ch
IIIOV AL, Oh 1 sааершеви~
int 21h ;~ек~ей aporpANNК


aypro,c endp
text
eDd

enda
ayproc
Как уже аrыечалось, ДIDI ПOJDIOIO использования возможностей oт­
JDIД'Oilt8 следует при 'lраНСJIЯЦИИ проrраммы указать в числе дРуrих

JРПОЧ /ZI, а при компоновке • КJПОЧ /СО:


МАSМ /Z/ZI/N Р,Р,Р;
LINК/CO Р,Р;
Интерактивный отпадчик CodeV/ew Microsoft 29

Кроме того, следУст убсдиrься, что р PIUJJeм: рабочем: araлorc имеет­


ся и заrрузочный (Р:ЕХЕ), и исходный (P.ASM) файлы, поскмьку от­
ладчик в своей раБоте использует оба этих файла. Вызовем: оттщчих
командой

CVP
На экране появится информационный кадр отлЦчика (рис. 4.1 ).

Flle Ulew Seпch lka11 U.tc:h O,tiOIIS Language Calls Неlр 1 FВ•Тrосе FS=Go
p.ASit t----------т----
1: text вeg~~e11t • сос~е• . АХ • ееее
2: aSSWIII CS :text ,DS: text 8Х • еее8
3: 1111_!ДП'0С proc СХ • 8888
.,.q,
-!1Ji!111~1~'1':~:1,;i.',',~(,~,; '.',)'.,'11\)(,~.' ,',,''.';~~j~~~1·:::;:";";~:1::·;·;;·~:Ж.r.:;
DX = ееее
5: IIOV DS,AX ;реrис;тра DS SF • ееее
6: 110v АН,.,ь DOS
:ttoиep t!Jt!ЩIМ вr .. ееее
7: IIOV DX,offaet IIICS :Адрес 8UIIOдllltoA C'l'pOJCII Sl = еое8
8: lnt Z1h :Вwзов DOS Dl • 0008
': autprog: 110u Att,1Cll :Вwзов t!JtiЩI8t DOS 1Ch DS • 1155
18: 110u AL,e ;,аве~ ES = 1155
:те~ ~

1»1r "
11: l11t Z1h SS • 1165
1Z: •roc endp 'Регистры 11--~~CS 4465
13: 111eS 4Ь 'l'rogru started$' nроцессара = еее8
11: text ends
15: end ayproc ttU ur
16: IФnаги 1El I'L
npoцeccopal---.~ ltZ 1111

-~~==~----------------------------~J ~~
lllci'OIIOlt (R) CocleUiew (R) Uerslon Z.Э
(С) Copyr ght "lcrosoft Corp. 1-...1~. AJI rlghts reserved.
)

Рис. 4.1. НачольныiJ информационный кадр отладчика.

Как видно из рисунка, информационный кадр отладчика содержиr


несколько· полей. Основное поле в центре кадра занято текетои отлажи­
ваемой проrрам:м:ы. Верхняя е1р0ка - это главное меню отладчика. Для
персхода в меню ~еобходим:о нажать клавишу<Alt>, после этого под­
свечившm:я активный пунп меню. Смена аЮ'ИВНОГО пункта выполняет­
ся с помощью клавиш <стрелка вправо> и <стрелка влево>. Если после
выделения: 1рСбуемого пункта нажать клавишу Enter, то под его именем:
JlЫDедетс:я меню данного пункта. Для выбора необходимого действия
надо с помощью клавиш <стрелк,i. вверх> и <стрелка вниз> выделить
нужный пунп и нажап. клавишу Enter.
Управлять процессом: отладки можно 'IрСМЯ способами: с помощью
меню, путем: использования функциональных и управляющих КJЦШШП, а
таюкс с помощью команд отладчика. Часто одно и то же действие мож­
но реализовать несколькими пуDIМИ. На первых порах проще всего
30 с

"110111о30181'11 UOIIIO. Так. НапрИМер, дпя: 388ерШеНИJI раб01


.....-ом -.о 10Атк а I'JIUНOC меню, выбрать пунп File,
.,......~ JIO»(CНIO ~ пуип Exit (т.е. nеремСС'I'IПЬ на 1
Clll'l"'tY и....,... UIIIIDIY <Enter>). На рис. 4.2. приведен ИНI
Ollllldl IIUP ~ с О!КрЫ'I'WМ меню F'tle nеред nOCJieдlll
'IWU DI8IIID Dlter.

Fllel va. ...... . . tatcll Dptlcma .......... Calla ..... , ...!

......... ....- ·-.· ' p.RSII


CSI~.II:text

-.....-·..
1101 llloll -
1811. ,...
мc,t.t ;~МitJ8I
s: ••• :,.."с..,. 11
мt,.,. ;~~амер ..._ IOS
DX,offaet . . :Адрес 111110N1МUA C'I'JIOIIII
lnt 2111 :ВwХJВ DOS

....
CIU\Ji1'8111111'

lllt
мt,о
м.,е
Zth
·:lkiXJВ . . . _ DOS 1Cit
:aue,_...
;~~
~-.
13: .. А ........ atartedS'
14: text .....
15: .... QI'8C
16:

MI8'Q8alt Cl) CW&VI• CJ) U....lcm 2.3


(С) CoPfll'ltht ИICI'Oatt Carp. 1986-1989. /Ш rlgltta reaervei.
)

Рис. 4.2. Внформационаwl IUIOp OIIIAaд'IUIUI с акпшвиэированаwм меню пунх

Вmрой сnособ (исn0JIЬ30вание "горячих клавиш'') предпОJ


nоuинаиие нсжаrорых комбинаций управmпощих клавиш. 1
пушае ltUC',II;oro меню одна буква выделена .цругим цве'IОМ. Вв
ваrуры эюй буквы (nри открьrrом меню) аuаивизируст соот
щий пунu меВJО. Пос~D~~Ьку в пунк:rе File выделена буква F, а
&it • буква 0 1 111U! эаворШОНИJI рабаrы С c:n'JDЩ'UIКOM дQCJa'RJЧi
1rDUбииацию ltii88ИW <Alt>/f/x (моzно Н8D'1'Ь и ~СТИ'J.Ъ <J
-.м 118DТЬ сначала Т, а Э~Dм "х"; можи___9r-110'0тпус1W1 <Alt:
сначала Т, а Э~DМ "х"). .-
Ворнемея с рис. 4.1. Первое вЬШОJПUIUоо пред11оженис ПJ
lblд8UIIo СИIIИМ WtОТОМ. По море пОСJiсдовамльноrо ВЬПЮШIОJ
проrр1ммы cn'JII,Ц'ВIIt 8СОrда ВЫДСJDIСТ ТО DреДIIОЖСНИС, ICai'O]
8ЫП011Ноно в CJIOдYIDЩIIЙ момсиr. Правую сторону информа
а.цра ЭIНИМIW!' пмо, • каrороо 8ЫIO.IUПCJI содержимое pema
цессора нопосродС1'10нно пфод вьmопнонием выдслснноrо про
Интерактивный оtМадчик CodeVIew Mlcrosott 31

IlpOI'JJUO(W. В НИZНеЙ Ч8С1И Э'ЮI'О ПQ1JJI 8 D)'X C'I'OII&&8x 1111.U11U11PYJD


ЗRa'IOIIIUI фл1юв прОцсссора. Ис110111о3JСМ1о1С .......-м JU0111W8
обоэиа•ениs COC'I'OJDIИS флаrов прИIIСдсНW в 'nlбn. 4.1.

Вмво...,.sаа__.

Наsваиие pua
....
eau
о.....,..
аереаоаае-11 or ov w
eau apepмвUIИJI Ir BI DI

......
eau
eau
ауа.
аа~-·
~
zr
Pl'
eau aaapaii.Jie-11 Dr
eau sкuca zr
ZR
PZ
DN
NG
Kl
10
Ut
tJ.
tnu acnoмo~a~en•мoro
перекоса A'l АС М
. .u nерекоса cr СУ NC

Наконец, ниzнсс поле информационною 1С8ДРа ~ д1111 11В0А&


команд ОПера'I'Ора (на самой нижней C'IPOtee) и ПOJIY'ICНWIIIWXOднwx со­
общений отладчика, в часmости, вwвода содсржимоrо 31Д1ННоrо
участка паМАТИ ("дампа" nawrrи). В исходном COC'm&IOI сmuщчика
нижнее поле JIВJUICТCЯ активным: в нем находи'l'СJI мерцаJDщий к.урсор.
Если нужно сделать активным основное поло (с ~~~~ npof'P8Www),
следуст нажать клавш.uу <Fб>. Курсор будет н.ахо.!Оil"Ь" ~ одвой из
C'IPOK профаММЫ (под се номером); порсмещая курсор по проrреммо,
можно расставiUIТЬ rочки останова и управmm. пошаrоiЬlМ выполнени­
см проrраммы.

Рассмщрим типичные действия, к. к.aropww DpiiXOAII'I'CII прибсnm.


по ходу 0'l'J18ДКИ проrраммы.

Поело насатия клавиши <FlO> ВWIIOIIJIJICТCJI одно премоzснио


проrрамwы. Можно выполниrь сразу и цепwй фраrмент проrракыы
(ИОСК.ОШ.КО ItpcДIIOJteHИЙ). Для ЭТОГО ИIДО HUt81'ИCW аааиши <fб> no·
ревости х:урсор в основное поло, помСС"l'И''Ъ eJ'() перед тем прсдоzснисм,
на к.аrором требуется сдстm. остановку, и нааrь IШUIIDIY <F7>. Bw·
1l0111:1Я'МЯ все С1РОКИ программы до.rой, на кcmJpOI )'С'I&ОМС~ х:урсор;
подеветка персместится на му строку. Далее моzно on.n. 8WI10IDUI'l'Ь
1JP01P8101Y ПОС'l'рОЧНО, HuaDWI на кnuиmy <f10> 111111, JVI'UIOIИВ 8
требуомом мegn, курсор, аыпОJJИИl'Ь следУJОщнй фраrмовт, ваав <F7>.
Для повrориоrо ВЫПОJJНСИНII пporpuo&& со сло.цуот "pecтapтoiiiD'ft".
Да этоrо Н1Щ0 выбрm. в rлавном моюо пуикr Run, а • MORIO :rroro
пункта- пуип Jtestart. То же Д00'1'111'М'1а вводом КNODIAW <Alt>/r/r.
32 Статья4

По XOliY вьmолн:ения C'lpOK программы в правос nоле выводится те­


кущее состояние реГИС1рОВ процессара и его флагов. Коmро.дь содер­
жимого реГИС1рОВ и флагов в процсссе nошаrового вьmолн:ения про­
граммы - основной МС'Юд се оrладки.
Не выходя из оrладчика, можно увИдеть результат раб01ы програм­
мы. если она выводиr что-либо на экран. Для этого надо выбрать nунп
меню View, а в нем nодnунп Output. То :же действие выnолняется на:жа­
mем клавиши <F4>. Для возврата в окно оrладчика надо нажать JПОбую
клавшиу.

По ходу nошагового вьmолн:енш1 программы можно изменять со­


держимое рсГИС1рОВ. Эrо даст возможнос'IЪ исправлять обнаруженные
ошибки (если выяснилось, что в какой-то C'lpOKe программы заnолняет­
ся не тот регистр или не тем содержимым), а также динамически моди­
фицировать программу с целью изучения ее работы.
Вьmолн:ите программу 4.1 до предложения int 21 h и просмотрите
содержимое региС1рОв процессора. Вы увидите, что в старшей nоловине
регистра АХ находится число 09 - номер вызываемой функции DOS.
Младшая nоловина регистра АХ заnолн:ена "мусором"- остатком or вы­
nолнения nоследней оnерации с регистром АХ. В регистре DX будет,
скорее всего, число 12h - оmоситсльный адрес nервого байта строки
messagc в сегменте команд. Изменим этот оrноситсльный адрес. Для
этого надо ввести команду

r dx-n
где n - значение (16-ричное), которое требуется заnисатъ в регистр.
Введем команду

R DX•lб

(ИJПI r dx=16). Вьmолн:им следующе предложение программы (клавиша


<FlO>) и nосмотрим содержимое экрана DOS (клавиша <F4>). Будет
выведена С'lрОка

ram started
Действительно, увеличив содержимое регистра DX на 4, мы n~мсс­
'IПЛИ в него оrноситсльный адрес nятого символа напtей строки, с коrо­
рого теnерь и выводится текст.

Отладчик nозволяет таюкс измеНJI'IЪ содержимое ячеек nамяти. Вве­


дем команду pecтavra программы ( <Alt> /R/R) и вьmолн:им се оnять до
предложения int 21h. Теnерь изменим содержимое ячеек nамяти, в ко­
торых хранится выводимая на экран С'lрОка. Для этого надо восnользо­
ваться командой Е, например, в таком варианте:
Е DX+4 ~- 1 1О 1 1 1'
Ииmвракmивныi1 отладчик CodeView Microsoft ээ

В байты памяти, начиная: с а.цреса, на 4 прс:вьппающеrо содержимое


DX, т.е. начиная: с rurroro байта нашего сообщения, 38IIИlll}'roЯ ко~
символов"-", "О" и "1". Если теnерь вьmолнитъ очередную команду (mt
21h), на экран будет выведена строка
Proq-01 started
Еще одной nолезной оnерацией являсm;я вывод содержимого облас­
ти nамяти. начиная: с заданного адРеса ("да.\Ш" nамяти). Выведем со­
держим<ж. nоля message. Для этого вьmолним, как и раньше, проrрамму
до nредложения int 2lh (чтобы в DX nопало смещение message) и вве­
дем команду

DB DX

Здесь D- команда выnолнить да.\Ш nа.чяти, а буква В указывает, что


дамn надо выnолнять по байтам (а не по словам). В нюкнее поле кацра
будет выведено содержимое сегмента данных, начиная с адРеса, содер­
жащеrося в регистре DX. В левой части nоля указываются 16-ричныс
коды, а в nравой - соответствующие им символы. Для того, чтобы уви­
деть весь вывод отладчика, следует нажаrnсм клавиши <F2> убрать на
время изображение регистров и флагов. Вторичным нажатием юtавиши
<F2> восстанавливасm;я исходный режим. На рис. 4.3 приведсн инфор­
мационный кадр отладчика после выnолнения указанной оnерации.

Fite Ulev Scarch Run Uatch Optlons Language Ca11s Нсlр 1r&•Т..асе FS•Go
-------------------------1
1.: text segtoc:nt 'code'
р.~
2: ASSUIOC CS:text,DS:text
Э: '"!IProc proc
о{: 10011 (1)( 1 text : lf~ИO.!IМ 3АЦНI(
5: 111011 DS,II'IX :pcrмctpa DS
6: 111011 АН,ООЬ :HOttep ~"" DOS
7: 111011 DX,offsct acs :Адрес вwво~оА Ctpc:!IIМ
..
m:::~~~!III':!.J"'~c:1"1:~~n'tnt.t 1 .r,:~t: ~Zu.r.:~·.~;щя~:";;-:,:~·:JU)Qn oosJ , :.:,-::. . .'1Ш1dJaAiR.._
.,: outprog: 10011 АН,1Сh :Bw:soa tунхц"" DOS iCh
18: ..011 AL,e ::sоасрuм:е.м
11: lnt Z1h :n:~ nporp-
1Z : IIIIJProc enclp
13: мs •ь •J'roogrм atuto4$' .
И: text encla
15 : . ll1lot I8,IPI'OC
16:

i
.
-------------------------------~-----------------•1

-w.s:&eae se 7Z 6F 67 7Z 61.-6D ze 73 71 61 7Z 7i ьs hogr...•tиte
-t-tьs:oeze
)
Ьi z-t « 12 эе эе 7I O&-te ее ее ее ее м 22 ее •StQ~et· ......... .
Рис. 4.1. Информационный .11.адр отлад'luка noc.1e в11ода коNанды no.tyчeнUA д~U~na na·
.мят и.
34 Cmami;Jl5

Естественно, что возможности отладчика 'не ограничиваются опи­


санными. Перечень наиболее уnотребительных команд оrладчика nри­
~~еден в Приложении 2 в конце кннrn; кроме того, в отладчике имеется
ВС'IрОСННЫЙ сnравочник (состаменный, к сожалению, доволъно nуган­
но), с помощью которого можно nолучиtЪ доnолнителъную информа­
цию о возможностях и командах программы CodeView. Справочник вы­
зывается нажатием комбинации к.лавmп <Alt> fh.

Статья 5
Сегментная адресация и сегментная структура программ

Почему программа дол.:жна обязательно состоять из сегментов?


Лричина этого кроется в архитектурных особенностях микропроцессо­
ров фирмы Intel, которые нам придется здесь коротко рассмотреть.
Важнейшей характерисmкой mобого микроnроцессора (МП) ямяется
разрядность его внуrреиних регистров, а также внешних шин адресов и

данных. МП Intel 8086 имеет 16-разрядную внутреннюю архитектуру и


такой же разрядности шину данных. Таким образом, максимальное це­
лое число (данное илИ адрес), с которым может работать микропроцес­
сор, составляет 216.)=65535 (64K-l). Однако адресная шина МП 8086
содержит 20 юший, что соответствует адресному nространству 220= l
Мбайт. Для того, чтобы с помощью 16-разрядных адресов можно было
обращаться в любую точку 20-разрядного адресного пространства, в
микропроцессоре предусмоч>ена сегментная адресация памяти, реали­

зуемая с помощью четырех сегменn1ьr.х регистров.

Суть се!?1енnюй адресации заключается в следующем. Физический


20-разрядный адрес любой ячейки naмяru вычисляется процессаром nу­
тем сложения начального адреса сеrмеН'J'а naмяru, в котором располага­

ется эта ячейка, со смещением к ней (в байтах) ar начала ceгмetrra, ко­


торое Юlогда называют о-mоситепьным адресом (рис. 5.1). СеrмеJЛ'НЫЙ
адрес без четырех младших битов, т.е. деленньn1 на 16, хранится в од­
ном из сегментных pcrne1poв. При вычислении физического адр<:са
процессор умножает. содержимое сеrмеiЛ'НОГО регистра на J6 и nрибав­
ляет к nолученному 20-разрядному адресу относительный адрес. Умно­
жение базового адреса на 16 увеличивает диапазон адресуемых ячеек до
WIИЧЮIЫ 64 Кбайт • 16..,. 1 Мбайт. .
Сегментная адресация и сегментная структура программ 35

Сегнентньl\1 адрес (е сегментном регистре) Всегда нули


Физжес~ адрес

:16:биу : : : : : : :4 ~: начаnа сегмент о


1 : : : : : : 1 1 е nамяти

+ Смещение (е одном

:16:биу : : : : : : \
из регистров иnи
1 : : : : : : е ячейке m~мятиj ·
-1- Ф изжеский

:2о:биу : : : : 1 : : : 1
20-рарядньtй адрес
1: : : : : : : : одресуемо14 АЧейк.и

Рис. 5.1. Образование физического адреса из сегментного адреса и смещения.

МП 80286, использовавшийся как центральный процессор компью­


теров IВМ РС/АТ, явился усовершенствованным вариантом МП 8086,
допоJШенным схемами управления памятью и ее защиты. МП 80286 ра­
ботает с 16-разрядными операндами, но имеет 24-разрядную адресную
шину, что соответствует адресному пространству 224=16 Мбайт. Однако
описанный выше способ сегме~rrной адресации памяти не позволяет
выйти за пределы 1 Мбайт. Для преодоления этого оrранИ'Iения в МП
80286 (так же, как и в МП 80386 и i486) используются два режима рабо­
ТЪ!: реального адреса (реальный режим) и виртуального защищенного
адреса (защищенный режим). В реальном режиме МП 80286 функцио­
нирует фактически так же, как МП 8086 с nовышенным быстродействи­
ем и может обращаться лишь. к 1 М байт адресного пространства.
Оставшиеся 15 Мбайт памяти, даже если они установлены в компьюте-
ре, использоватъся не мoryr. ,
В защищенном режиме по-прежнему используются сегменты и
смещения в них, однако начальные адреса сегментов не вычисляются:
rryrcм умножения на 16 содержимого сегментных регистров, а извлека­
ются из таблиц сегмеirrных дескриnторов, индексируемых теми же сег­
ментными реrnстрами. Каждый сегментный дескритпор занимает 6
баltт, из которых 3 байта (24 двоИ'Iнъrх разряда) о'ГВОдятся под сегмент­
ный адрес. Тем самым обеспечивасrся поJШос использование 24-
разрядноrо адресного пространства.

МП 80386 и i486 являются: высокопроизводительными процсссора­


ын с 32-разрядными шина.чи данньrх и адресов и 32-разрядной внут­
ренней архитеiСt)'рой. Они, как н МП 80286, мoryr работатъ в реальном
и защищенном режимах. В последнем случае микропроцессор позволя­
ет адресовать до 2з2=4 Гбайт физИ'Iеской памяти. Проrраммирова.нис
защищенного режнма будет подробно рассмслрено в с.ледующНt чacnt
этой книги.
36 Статья5

Итак, обращение к любым участкам памяrи осущеСТI!JIЯется ис­


К100чительно посредством сегментов - лоГИ'Iесюос образований, накла­
дываемых на требуемые участки физического адресного пространства.
Размер сегмента должен находиrься в пределах О байт - 64 Кба.йт
(допустимы и иногда используются сегменты нулевой длины).
Начальный адрес сегмента, деленный на 16, т.е. без младшей 16-ричной
цифры, заносится (как nравило, nрограммистом с помощью соответ­
ствующих nрограммных Clp<>K) в один из сегментных регистров. При
обращении к памкrи nроцессор извлекает из сегментного регистра этот
•базовый адрес, умножает его на J6 сдвиrом влево на 4 двоичных разряда
и скла.цьmает с заданным каким-либо образом смещением, получая 20-
разрядный физический адрес адресуемой ячейки памяти (слова или бай­
та). Эrот nроцесс проиллюстрирован на рис. 5.2 на KOHJCpe'n[OM примере
команды inc тет 1.

Оnе~ТИ8~Я ммять
(слоеа)

·
Сегмент{ §Е к
КОМс'»1А 06FFh
0004h
од команды · mem1
nc
Смещение к АЧеl«е mem1

r--------. ,.-L1 Содержимое DS ·1DE2h


.. тi
r....IA. .
C... ,.-,_,
1DE20h +- Базо8ый адрес сегмента
1DE22h (на границе пармрафа)
данньос ~я=ч-еи_·_к_а_m_е_m-:1:-1 1DE24h +- Физически.:4 адрес АЧейки mem1

Вычисление физическоrо адреса:

1DE2h IC 10h ·1DE20h


+ 0004h
1D2E4h
Рис. 5.2. Формиро,воние физи'lеск.оzо одресо.

Поскольку МJIIЩШая 16-ричная цифра базового адреса сегмента


должна быть равна О, сегмент всегда начш1ается с адреса, краmого 16;
т.е. на rранsще 16-байтовоrо блока nамяти (параrрафа). Число, хра.ня­
щесся в сегментно}.l регистре, называют cerмetmtым адресом. Следует
nомнить, 'П'О сегментный адрес в 16 раз меньше cQO'I1JC'n:ТDyющero ему
физическою а,цреса.
Наличие в микропроцессоре четырех сегментных perиCJpOD опреде­
ляет CipYК'IYPY ripOrpЗ.'dMЫ. В nmичной, не слишком сложной проrрам­
и:с имеются сегмент кома.~.,.ц, сегмент данных и сегмент стека, которые
Сегментная адресация и сегментная структура программ 37

адресуются с nомощью сегментных регистров CS, DS и SS СОО'I'l!е'Т'­


ственно. ДоnолнителЬный сегментный perиCip ES часrо исп011Ь3ус-n:я
для обращения к полям данных, не входящим в nроrра.чму, наnример к;
видеобуферу или системным ячейкам. Однако при необходимости его
можно нас1р0итъ и на один из сегментов программы. В частности, c:cJOf
программа работает с большим объемом данных, для них можно пред­
усмотреть два сегмента и обращаться к одному ю них' через perиCip DS,
а к другому - через ES.
Наша nервая nporpa.\lмa нз статьи 1 содержааа лишь один сеrмекr, в
котором расnолаrались и ко~tанды, и данные. Такая коне7рухция nро­
граммы IШОЛI!е законна, но не очень наглядна. Кроме того, предуемот­
реn в nрогра.чме лишь один сеr~tент, мы оrранИ'iили суммарный объем
команд и данных ВСЛИ'iююй 64К. Разумнее разнести ко~t:uщы и данные
no отдельным ceгмetrra.\t, что nродемонстрировано в примере 5.1.

При.чер 5.1 Программа с дtf}'MR си.чента.чи.


text "egtnent 'code' ; (l)HAч&no cer...,HTA J<O...,.НJI
As.oume CS: text, DS :dAtA; t2) Регистр CS будет YJ<A:SWIIATI> IIIA
;сеr~ект J<ОWАкд, DS - нА сеrwеит дАИИWХ
beqin: DIOV AX,dAta ; (3)Адрес cer~enTA дАнных :sarpy:sкw
IDOV DS,AX ; ( 4) С КАЧАЛА в АХ, :SATe.,. 11 DS
mov АН, 9 ; ( .S) ФуКJ<ЦИII DOS IIЫIIOДA ИА экран
mov DX,ottset me.o"&qe; (б)Адрес аыводиwоrо сообwеии11
int 2lh ; (7)Вы:sов DOS
DIOV AX,4C00h ; ( 8) Фуикци11 DOS :s&вершеииll nporpAWWЫ
;а....,сте с J<Одо ... :s&аершеииll О
int 2lh ; (9)8ы:sсв DOS
text end.o ; (lO)Koкeu сеr....,ИТА J<ОМАИД
dAtA .oegtnent ; (ll)НАЧАЛО CerweИTA ДАИНЫХ
me.o.oAqe dЬ 'НаукА уwеет wкoro rитиJ<$'; (12)8ыводкwый теJ<сТ
data end.o ; (lЗJKoиeu cerweиTA данных
end beqin ; (14)Конец TOI<CTA DporpAWNЫ И ТОЧI<А
: вхо.аа

Пrнnсдснная nрогра.\fма отлИ'Iается от при.мера 1.1 лишь несколь­


юtми деталями (хагя ее CipYJ..."Т}'Pa, можно сказать, отличается радихаль­
но). Вслед за сегментом команд введен отдельный сс:rмеит данных с
nроизnольным именем d;~ta. Эrот сеrмекr открьrвас-n:я в предложении 11
и закрывается в преДI!ожении 13. Измеюuюсь предложение 2 • в нем
указано, что сегмеtrmый регш:тр CS будет укrоьrвап. на сеrмекr команд
а решстр DS - на сегмент данных data. Соответственно изменилось
text,
и предтюжение .3. Теnерь в реrиС1р DS загружается адрес сегмента дан­
ных data, а не: ссrмеш-а команд text, как это бьто в примере 1.1.
Orrpaнcлнponan, скомnоновав и BJ.momнm программу примера 5.1,
можно заметить, что результат работы этой программы в точности тот
же, что и Д11Я nервой, односеrмекmой программы. Действ~m:ЛЬно, вве­
дение отдельного cen.(eкra данных повысило нarJUiдНOC'IЪ программы и
38 Статья 6

·дало нa.l.f возможность (которой мы пока не восполъзовались) увеличить


общий размер програм:мы до 128 Кбайт (64 Кбайт команд и 64 Кбайт
данных). Однако существо программы осталось·без изменения.
Теnерь у нас есть две nростых програ.\fМЫ, одна с одним сегментом,
а другая - с двумя. Зaпyc1'Jft'e nервую проrрамыу (nример 1.1) nод
уnравлением отладчика, выясните, чему равен сегментный адрес сеr­
wента команд и оnредс.лите, в какое место оnеративной памяти загруже­
на проrрамма. Проследпrе за процессом настройки сегментного pe-
rиCipa DS. Oбpa1'Jft'e внимание на то, что перед началом вьmолнения
программы содержимое регистров DS и ES оказывается в точности на
tOh меньше содержимого реrис1ра CS. В дальнейшем этот важный фiucr
nалучит свое объяснение. Зaлyc1'Jft'e под управлением отладчика вторую
nрограмму (nример· 5.1), изучите расположение сегментов nрограммы в
памяти, сопоставьте полученные результаты с размерами сегментов, по­

лученными из листинга 1рансляции.

Статья 6
Стек

В nредыдущих статьях вскользь упоминался стек. Рассм01рим это


нoн.srrne более по.цробно.
Сrеком называют область программы для временного хранения
nроизвольных данных. Отличю-сльной особенностью стека является
своеобразный порядок выборки содержащихся в нем данных: в любой
момсит времени в стеке доступен только верхний элемент, т.е. элемент,
sаrруженный в стек последним. ·Выrрузка из стека верхнего элемента
делает дос1уmц.rм следующий элемент.
Элементы стека располагаются в области п.ам.яти, отведенно'й под
отек. начиная' со дна стека (т.е. с его ма~имального адреса) по послс­
довг:rел:ьно уменьшающимся а,цре~;ам. Адрес верхнего, достуnного эле­
мента хранится в реrиСiре·указаТе.ле стека SP. Ках и любая другая об­
JI&СТЬ памяти программы, стек должен входить в кахой-то сегмент или
образовывать отдельный сегмент. В любом случае cerмelmtый адрес
этого сегмента помещается в сегментный perиc-rp стека SS. Таким обра­
зом, пара регистров SS:SP описывают адрес досrупной ячейки стека: в
SS хранится сеrменщый а.л.рес стека, а в SP ·- относJmлыtый 8Jtpec до-
Стек
39

С1)'ПНОЙ (текущей) Я'!ейхи (рис. 6.I,a). Oбpanrrc внимание на то, что в


исходном состоянии указатель стека SP указывает на ячей.ку, лежащую
под дном стека и не входящую в него.

SS-+~ SS -+~ SS -+~ SS -+~ SS -+~


~: +-SP DS DS
РХ +-SP ,...,.. РХ +-SP дХ
а +-SP б 8 r д +-SP
Рис. 6. 1. ОрzанизацUJ/ стека: а • исходное состмни1t, 6 • llfC/1/t ЗOlf1Y31CU одною м•­
мента (• данном пример~ • содержимою pezucmpa АХ,), • L nOCIIIt заzрузки emopozo
ЗЛt.lrleнma (содержимом ptlиcmpa DS), z - nOCile ewzpy3кu одном ЗЛt.lrlltнma, д • nOCI/It
eЬJZf1Y31CU д~ злt.lrleнmOf и еозерата • исходное состОАНиt.

Загрузка в стек осущеста11яется специальной командой работы со


стеком push (nротолкнугь). Эта команда сначала уменьшает на 2 содер·
.жимос указателя стека, а затем помещает операнд по адресу в SP. Если,
например, мы хотим временно сохранить· в стеке содержимое pentcтpa

АХ, следует выполнить команду

pu.sh АХ

Стек переходкг в состояние, показаинос на рис. 6.1,6. Видно, что


указатель стека смещается на два байта вверх и по этому адрссу записы­
вается указанный в команде проталкивания операнд. Следующая ко­
манда заrрузки в стек, напрУ-мер,

pu.sh DS

персведет стек в состояние, показаинос на рис. 6.1,в. В стеке бyuyr те­


nерь храниться два элемента, nричем дОС1УtШЫМ будет только верхний,
на который указывает указатель стек.1 SP. Если спустя какос-то время
нам: понадобилось восстановить исходнос содср.жюfос сохраненных в
стеке реrис1р0в, мы должны выnолнить команды выrрузки из стека рор

( вьrrолкнугь):
рор DS
рор АХ

Состояние стека после выnолнения первой комiЩДЫ ПОJСа38НО на


рис. 6.I,r, а поелс второй- на рис. 6.1,д. Для nравильного восстаноме­
ния содержимого регистров выrрузка из стека должна вьmолкяться в
порядке, строго противоположном эаrрузке • сначала выrружастся ЭJIO·
мент, заrруженный последним, затем предыдущий ЭJiсмснт и т.д. ·
Обраnпс внимание на то, что после вьпрузки сохранениш в стеке
данных они физически не стерпись, а остались в област11 стека на cвoiiX
40 Статья б

а.ссстах. Правда. при "стандартной" работе со стеком они оказываются


недосrупны:ми. Действкrсльно, поскольку указатель стека SP указывает
под дно стека. стек счm-ается пусТhiМ; очередн"ая команда push поместит
новое данное на место сохраненного ранее содержимого АХ, затерев
ero. Однако пока стек физИ'Iески не затерт, сохраненными и уже вы­
бранными из него данными можно пользоваться, если помюrrь, в ка­
ком nорядхе они расположены в стеке. Этот прщ:м часто используется
при работе с nодпрограммами и в дальнейшем будет оnисан подробнее.
В примерах 1.1 и 5.1 мы не заООmлись о стеке, поскольку, на пер­
вый взгляд, нашей программе стек бьm не нужен. Однако на самом деле
это не так. Сrек автомаТИ'Iески исnользуется системой в ряде случаев, в
'18С1110С111, nри nереходе на подnрограммы и при вьmо.лнении команд

прерьmания int. И 'в том, и в .цруrом случае nроцессор заносит в стек


адрес возврата, чтобы после завершения вьmолнения подпрограммы или
программы обработки nрерыванюr можно бьио вернугься в ту точку вы­
зывающей программы, откуда произошел переход. Поскольку в нашей
программе есть две команды int 21h, оnерационная система nри вьmол­
нении программы дважды обращалась к стсжу. Где же бьm стек про­
rраммы, если мы ero явным образом не создали? Чтобы разобраться в
м-ом вопросе, изменим nример 4.1, введя в неrо строки работь1 со сте­
ком.

ПрШ4ер 6. 1. ПJIOlpaм.va, ра6отающаJ/ со стеком.


tex1: aeq~nent
'code' 1 ( 1) На'IАЛО сеrwента ко.uа.кд
aasumeCS:text,DS:data; (2)CS->cerweит коwаид,
IDS->cerweит данных
beqinr IIIOV АХ, data ; (3 )Адрес сеrиекта данных sarpy:sиw
IIIOV DS, АХ ; ( 4) CKA'IAIIA 11 АХ, :saтew 11 DS
puah DS ; ( 5) Эarpy:sиw 11 стек содер:JIИМ:)е DS
рор IS 1 ( 6) Bыrpy:sиw ero иs стека 11 IS
IIIOV АН, 9 ; ( 7) Фуикци11 DOS 11ы:аода И а :»кран
IIIOV DX,offset ~ssaqe; (8).\дрес llbllloдиworo сообщеки11
int 21h 1 (9)Вы:sоа DOS .
IIIOV АХ, 4COOh 1 110) Фуикци11 :sа11ершеки11 nporpUA.~Ы
;с ука:sкиеw кода sа11ершеки11 OOh
int 21h 1 (ll)Bыso11 DOS
text ends 1 (12)Кокец сеrиекта ко.uаид
data aepent 1 113) Начапо сеrwеита дaJUtWX
a.aaaqe dЬ 'Наука умеет wмoro rиткк$'1 114)ВЫаодиwwй текст
data ende 1 115)Коиец сеrwекта даикwх
•nd beqin 1 1161~онеЦ текста nporpawwк с
Jукаsакнаw то~ входа

В предложении S содержимое DS ~охраняется в стеке, а в следую­


щеа.с прсможении выгружается из стека в ES. После :пой операции оба
ceNelf11fыx pernC1pa. и DS, и ES, будуr указывать на один и тот же сег­
а.сент данных. В нашей nрограмме эти строки не имеют прахтическоrо
смысла, но вообще здесь продемонстриромн удобный rтри~м nереноса
Стек 41

содержимого одного сегмеН'J1{ого регистра 8 другой. Выше уже аг­


мечалось, что 8 силУ особенностей архиrепуры мюqюnроцессора ДIIJI
сегмеН'J1{ЫХ реrие1р0в действуют некаrорые оrраничения. Так, в сеr­
меН'J1{ый реrие1р нельзя непосредственно заrрузип. ащрес сегмекrа;
нельзя таюке перенесm число из одного сегмеН'J1{ОГО регистра в другой.
При необходимосm выполнип. последнюю операцию 8 качестве
"перевалочного пунiСI'а" часто используют стек.
Заnустите под управлением отладчика проrрамму 6.1. Посмоорsm.
чему равно содержимое реrие1р0в SS SP. Вы увИДJm, что 8 SS нахо­
и
диrся тот же адрес памяти, что и в CS; аrсюда можно сделать вывод,
что сегмеН'lЪI: команд и стека совпадают. Однако содержимое SP равно
О. Первая же команда PUSH уменьшиг содёржнмое SP на 2, т.е. помес­
тит в SP -2. Значиг ли :по, что стек будет pacm, как ему и положено.
вверх. но не внуrри сегмента команд, а над ним, по адресам -2. -4. -6 и
т.д. относ~mльно верхней rраницы сегмента команд? Оказывается, :по
не так.

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


послать в него два вычигающих импульса, то после первого импульса 8
нем окажется число FFFFЪ, а после IПОрого - FFFEh. При желании мы
можем рассмiЩ)ивать число FFFEh, как -2 (что и имеет место при рабо-
1С со знаковыми числами, о которых будет ид11{ речь позже), однако
nроцессор при вычислении адресов рассмач>ивает содержимое perи­

C'lpOB, как целые числа без знака, и число FFFEh оказывается эквива­
ЛеН'J1{ЫМ не -2, а 65534. В результате первая же команда занесения дан­
ного в стек поместит :по данное не над сегментом команд, а в самый
его конец, 8 последнее слово по адресу CS:FFFEh. При дальнейшем ис­
пользовании стека его указатель будет смещаться в сторону меньших
а.о:ресов, проходя значения FFFCh, FFFAh и т.д.
Таким образом, если в ~rрамме отсуrотвует явное обьявление сте­
ка, система сама создает стек по умолчанию в конце сегмента команд.

Рассм<nренное явление, когда при уменьшении адреса после адреса


О у нас получился адрес FFFFh, т.е. от начала сегмента мы прыrнули
сразу в его конец, носиг название ЦИIСЛИЧеского возврата или обо­
рачивания адреса. С ЭП1М явлением приходиrся стаJIКИВЮЪСJ~ довольно
часrо.
Расположение стека в конце сегмента команд не приводиr к каким­
:nнбо нспрИЯ'l110С'ТЯМ, пока размер nроrраммы далек or JраНичной вc­
JDIЧIO{bl 64К. В :пом случае начало сегмента команд занимают коды ко­
wанд. а конец - стек. Если, однако, размер проrраммы приближается к
64К. то ДIIJI стека остается все меньше места. При ~нсивном исполь­
зовании стека в nроrрамме может получиться, Ч'ГО по мере занесения 8
стек новых данных, стек дорастет до последних кома.чд сеrмента команд
и начнет заrирать 3111 команды. Очевидно, что :пого HCJJЬ311 допуска:rь.
42 Статья в

В ro же время си~ма ие провсряет, чrо nроисходит со ~ком и никак


не реаrирует на затирание команд или данных. Таким ооразом, оценка
.размеров собственно проrраммы, данных и емка JDUUICТCЯ важным эrа­
пом разрабапси проrраммы.
Современные проrраммы часто имеют значительный размер (даже
не помещаясь в один сегмент команд), а ~к иногда испОJJЬЗуется дл.я
хранения больших по объему массивов данных. nоэrому целесообразно
ввесm в проrрамму отдельный сегмент ~ка, определив его размер, ис­
ходя из -rребований конкретной проrраммы. Эrи и сделано в следующем
примерс.

ВыполНJIJI проrрамму 6.1 по шагам, пронабтодайте, как команды


push и рор измен.яют содержимое регистров SP и ES. Выведите на экран
дамп памяти начиная с адреса SS:FFFOh. Убедитссь, чrо содср.жимое DS
действительно записалось в память по адресу SS:FFFEh, и так и оста­
лось там после извлечения содержимого ~ка и восстановлениs ero
указатсл.я.

Чrо еще имеется в нашей двухссгменm:ой проrрамме, кроме ссгмен­


rов команд и данных? При заrрузкс проrраммы в память она будет вы­
ГЛSJДСТЬ так, как это показано на рис. 6.2.
05раз программы в памяти
ES,DS-+ начинается с очень важной
Преt~«с~
C1pYJCI'YPЫ данных, которую мы
(PSP)
будем называть префиксом про­
25615.w
cs,ss-+ +-SP•O rраммьt. В ориrинuыюй лиrсра­
Сегмент турс эта с1рупура носит не
команд очень удачное название Program
Segment Prefics (или сокращенно
Сегмент PSP), т.е. "префикс проrраммно­
данных rо сегмента". PSP oбpaзye'ICJI и
загОЛНJiстся системой в процсссе
заrрузки проrраммы в 118МJ1ТЬ; он
hc. 6.2. 06ра3 ntiAUIIIUI npoqtiМJIIW .ЕХЕ
CD CllleiUUI 110 YMO/IWINUIO. всегда имеет размер 256 байт и
содержит ПOJIJI данных, исполь­

зуемые си~мой (а часто и самой проrраммой) в процессс ВЫIIOJIНeHИJI


программы. К составу полей PSP мы еще не раз будем JеЗвращап.ся в
~йкииrс.
Вслед за PSP pacJIOЛai'8IO'R)J[ сегменты проrраммы. Поскмьку oбь­
JIВIIeНИJI ссrмснrов сделаны нами н~йшим образом (опсраrоры
scgment но сопрово~ операндами-опис&ТМJ~МИ), пор.u;ок размо­
щони.я ссrменrов в 118М11Т11 совпадает е порядком их обwlмСНИJI в про­
rраымо, чrо упрощает исследование и отладку проrраммы. Для боль­
шинства ороrрамм но имеет значени.я, в каком порJЩКС вы буд~ oбь­
JJIUDII'III ссrменты, хам встрс'Ч81С)WЯ программы, ДJUI ltOropblX перцок
Стек 43

сегментов сущсствсн. Дли таких программ llpCJVIOЖeНIUI с операторами


segment будут выrлядеn. СJiожнсс.
В проЦСССС заrрузки программы Ц память СеГМеН'IЯЫе рсrиС1рЫ ав­
томатически инициаЛизируются СJiедующим образом: ES и DS указы­
вают на начало PSP (что дает возможность, сохранив их содср:хсимос,
обращаться ЭЮ"СМ в программе к PSP), CS - на начало сегмента команд.
SS, как мы эк.спериментально убедились, 1'8IСЖе в нашем случае указы­
вает на начало сегмента команд. Как мы увидим: позж:е, вepXНJIJI поло.:.
вина PSP занята важной дл.я системы и самой программы информаци­
ей, а HИЖНJIJI половина (128 байт) практически свободна.
Поскольку ПOCJie заrрузки программы В память оба сеГМеН'IЯЫХ pe-
IИC'Ipa данных указывают на PSP, сегмент данных программы оказы­
ваtrоя не ацресуемым. Не забывайте об этом! Если вы позабудете ини­
циализировать peiИC'Ip DS так, как это сделано в предложениях 3-4 на­
шей программы, вы не сможете обращаться к своим данным. При этом
'IРанслятор не выдаст никаких ошибок, но программа будет выполнять­
ся неправильно. Поставь~ поучиrельный эк.сперимент: убериrс из ~к.с­
та программы 6.1 С'IРОКИ инициализации peiИC'Ipa DS (проще всего не
сmрать эти С"IРОКИ, а поставить в их начале знак комментария - символ
Оnранслир~. скомпо~ и выполните такой вариант програм­
";").
мы. Ничего ужасного не произойдет, но на экран будет выведена какая­
то ерунда. Возможно, в конце этой ерунды будет и C'IPOU "Наука умеет
много rиrик.". Почему так получилось? Когда начинает ВЫПОЛНJIТЬСЯ
фунКЦИJI DOS 09h, она предполагает, 'ПО полный двухСJiовный а,прео
выводимой на экран С'IРОКИ нахоДиrся в pemC'Ipax DS:DX (в DS - ссг­
меН'IЯый а.црсс, в DX- относиrельный). У нас же сегментный peiИC'Ip
DS указывает на PSP. В результа~ на экран будет выводиl'ЬСJI содержи­
мое PSP, к.оrорый заполнен адресами, кодами команд и другой
чиСJiовой (а не символьной) информацией.
Расом01рим ~перь программу с 'IPCМJI сегментами: команд, данных
и стека. TIUWI C'Ipyкrypa широко используется ДJIJI относительно не­
СJIОЖ:НЫХ программ.

ЛрU114ер 6.2. ПfJOlPflAUia с трии1 симентоми.


text seqшent 'code' 1 (l)Ha•ano сеrwевта хо~
asswae CS:text, DStdat&l (2)CS->cerweвт хо~,
JDS->cerweвт даввкх
b89inl IIIOV AX,data 1(Э)Адрес сеrwевта даввкх аuруаим
IIIOV DS,AX 1(t)cвa•ana • АХ, аатеw в DS
puah DS 1(51 Заrруsим • стеJС содер-.ое DS
рор IS 1(6)Вкrруsим ero иs стеJСа а IS
IIIOV АН, 9 1( 7) ФуJuщи11 DOS 8IIDIOД& ва •acp-
IIIOV DX,offset aessage1 (8)Адрео амаодкNDrо соо6••ви•
int 2lh 1 (9)8raoa DOS
IIIOV АХ, 4C00h 1 (lO)ФyJuщиll s&88p1D8НИII aporpU881
int 2lh 1 (ll)lhlsoa DOS
Статья в

·t•xt eada 1(12)Ховец cerw.•~• комавд


ciata aev-ent ;(13)Ha•ano cerw.•~• д&ВККХ
dЬ 'Н.)'Ita :v-и 880ro l'И'I'ИК$'; (141Вiao.IIIOAIЙ ~екс~
enda 1 С15)Ховец cerw.в~• даавмх
ae~t atack •atack'IC16)Ha•ano cerw.•~• с~ека
dv 128 dup (011 (17)Под с~- ~••аево 128 cnoa
atk eada 1(18)Ховец cerw.•~• с~ека
ead beqin 1 С 191 Ховец ~екс~а ароrрамм

В проrрамме 6.2 вслед за ссrмеиrом данных объолен еще один сег­


мент, катрому мы дали 1001 stk. Так же, хак и другие ссrменты, сег­
мент стека можно назмn. как. угодно. Сtрока описания: ссrмекrа стека
(преДJЮжение 16) д011.1СНа содср~ так называемый пm обьсдинения:, в
данном случае описатель stack. Тип обьсдинения: указывает компонов­
щику, каким образом д011.1СНЫ об'ЬсДИIIЯТЬСя одноименные ссrмснты
разных проrраммных мо.цулсй, и испОJIЬ3устся главным образом в тех
CJI)"'aяx, когда оrдсльныс части проrраммы располагаются в разных ис­

ходных файлах (например, 11ИI1fYreЯ несколькими проrраммистам:и) и


обьсднiUIJО'n:Я на этапе компоновки. XOТJI дл.я одномо.цульных программ
11111 обьсдинсния: обычно не имеет значения:, дл.я сегмента стека обяза­
'IМЬно указанис пmа stack, поскольку в этом случае при загрузке про­
rраммы выполняется авrоматичсская инициализация: регистров SS
(ссrмсНПfым ацресом стека) и SP (смещением конца сегмента стека).
В предложении 16, объявляющем сегмент стека, имеется еще один
описатель. Слово 'stack', стоящее в апострофах после оператора segmcnt,
определяет класс сегмента (в принi{ИПС имена классов можно выбирать
произвольно). Классы ccrмclfi'Oв анализируются компоновщиком и ис­
ПОJIЪЗ)'Ю"rеЯ им при компоновке загрузочного мо.цуля: сегменты, при­

надлежащие одному классу, загружаются в памятъ рядом. Для простьtХ


проrрамм, входящих в единственный файл с исходным текстом и
ВКЛIОчающих по одному сегменту команд, данных и стека, указанис

класса не обязательно, однако дл.я правильной работы компоновщиков


и оrладчиков желательно, а в некоторых случаях и необходимо ухазакис
классов ссгмсиrов:
'code' дл.я сегмента команд и 'stack' дл.я сегмента сте­
u. Так, оrладчик
CodcVicw не сможет реализовать некоторые ю своих
режимов вывода на экран текста проrраммы без указания: класса 'codc',
а компоновщик TLINK не будет инициализиромn. ссrмент стека, ссли
не обьявлен его класс 'stack'.
В приведеНIIОМ примере ДIUI стека зарезервировано 128 слов П8МJIТИ,
'1'Ю более чем достаrочно ДIUI несложной проrраммы.
3амС111М, '1'Ю получившаяся у нас проrрамма JIIWICТCЯ типичной и
аналогичная '-1PYICJYPA будет исп0JIЬ30ваться в большинстве последУЮ­
щих примеров.

Подrаrовьте программу 6.2 к выполнению. Запустите ее под управ­


лением оrладчика, изучите расположение сеrмеиrов проrраммы , в
8ыеод на экран символьной информации

пaмJml, обр«mв особое внимание на содержимое реrистров SS и SP.


Убе~ь. что в программе образовался отдельный ссrмснт стека раз­
мером 100h байт (128 слов= 256 байт). Поинтерссуmсь, rдс сохраняет­
ся значение DS при выnОIПiснии прсдложенИJI S.

Статья 7
Вывод на экран символьной информации

Представим себе, что мы создаем обучающую программу и нам по­


надобилось вывесm на экран несколько строк из виедсния 1t этой JtНИrC.
Сооrвсmmsующая программа привсцена в примере 7.1.
Прuер 7.1. Вw•oiJ на ЭI'JIOH информационного coo6щ111UJ1.
text aeqaent ;Начапо сеrмекта ~оwака
aaa\.lllle CS:text,DS:data
begin: 1110v АХ, data ;Ииициалиsаци11 сеrмекткоrо
IIIOV DS, АХ ; реrистра DS
IIIOV АН, 9 ; ФуиJЩИII DOS 1111110.11& ка 811Ср&К
IIIOV DX,offaet аеаааgе;Адрес ~ДИNDro сооа.еки•
int 21h ; BIDOII DOS
IIIOV АХ, 4C00h ; Зааерше101е пporp.-
int 2lh
text enda ; Конец сеrwекта ~оwака
data aeqaent ;Начапо сеrwента даанмх
. . . aage dЬ 1 Друrу» rруппу состаап~ раsпичкые аспе~тк реапиаацми 1
dЬ 1 • проrр-.-х на 11sыке ассембпера asшapaтiiiiX и 1
dЬ 1 сист8)81ЫХ 8оsмо:аиостей персокапьноrо ~oNUь-.epa:'
dЬ 1- ПроrрU88Ср08АИИе 880,1111.-IIШSO.II&I 1
dЬ 1- исnопъsо8ание прершsаний BIOS и •уккций DOS;'
dЬ '- проrрАNNИроваиие арифметичес~оrо сопроцессора;'
dЬ '- работа в saiQИIIIeннoм ре-; 1
dЬ '- упраапеиие oбloNlloЙ и paciiiНpe-oA а-•••· $ 1
data enda ; Конец сеrмента даанмх
atk ae~nt atack 1 atack';Haчano сеrмеи-.а ст~а
dw 128 dup{O) ;Стек
atk enda ; Конец сеrмекта отека
end begin ; Конец -.екста проrр.-

3амСТЮI, что эта программа написана стандарn~ым образок: в ней


имeiO"roJJ сегменты команд, данных и стека. Tu хс будут С0С'1'1В1U11'ЬС и
программы последующих примеров этой книrи.
Текст, предназначенный для вывода на экран, вКJUОчсн в программу
в помощью дирсtаИВы db (nпределить байт). ПосКОIIЬку длина текста
46 Статья7

.превышаст ширину экрана. он разбиr на nроизвольвые по длине


учас1101, 1WЦЫЙ из коrорых формально составляет отдельное предло­
жение sзыка ассемблера. В конце текста вКЛIОчен знак "$", харахrери­
зующий конец строки дru1 функции DOS 09h.
Подrотовив и выполнив му проrрамму, мы увидим, 'fiO весь текст
вьmеяся на экран сплошной последовательностью символов без разбив­
ки на строки и абзацы. HenpИ.II'l1lo также и то, 'fiO 11аш текст вывелея на
"грязный" экран с ОС'I'а11(8МИ предыдуших выводов. Для получения более
удобочитаемою вывода в символьную строку следует вКЛIОчить коды
управления куреором:

09 - табуЛ.11ЦИ.11;
10- перевод строки;
13- "возврат каретки", т.е. возврат курсора в начало строки экрана.
С очисткой экрана дело обстоит сложнее. Единственное, 'fiO пока
можно сделать - это вывести на экран столько C'rpOK пробелов, чтобы,
перемещаась по мере вывода вверх по экрану, они очистили всю ero
верхнюю часть.
В примере 7.2 представлено описание модифицированной строки
mcssage (все остальные предложения проrраммы не измeii.IIIO'roя).

Пример 7.2. Bwsod на Э"fЮН форматированного me"cma.


aessaqe dЬ 80*18 dup (' '1
dЬ 9, 1 ДpyrYJO rpynпy C:OC:Tai!IJIIUOТ paSJDI'ЧIНble аСП81СТЫ peAJIИSAL\JIИ 8 1

dЬ' пporpANNAx на',10,13,' ~sыке ассембпера аппаратных и•


dЬ 1 систеиsых воsмоzностей персона.n:ьноrо ICONПЬIO'l'epa: ', 10,13
dЬ 9,'- проrр&NNИрование ввода-вывода;',10,13
dЬ 9,'- испопьsование прерываний BIOS и функций DOS;',10,13
dЬ 9,'- проrраwwирование арифмети'ЧiесJСоrо сопроцес:сора;',10,13
dЬ 9,'- работа • sаши.енном реЕКМВ;',10,13
dЬ 9,'- ynpai!IJieниe обЬl'Чiной и расширенной п~ть•.$'

Пробелы (18 строк по 80 пробелов в C'rpOKe) описаны с помощью


оператора dup (duplicate, дублировать). Перед словом dup указывается
коэффициент поJПОрения (в каюром можно использовать арифме­
mческие выражения), а после оператора dup в скобках - повrоряемая
строка (СОСТО.IIIЦая не обяэательно из одноrо символа). Коды табуJIЯЦИИ
создадут отступы красных строк. Для тоrо, чтобы текст выгтщм на эк­
ране аккураmо, мы в середину первоrо абзаца ВКJПОЧИЛИ коды 10 и 13
перехода на следующую строку.

Кроме обычных алфавИПiо-цифровых символов и .цругих знаков,


имеющихся на к.лавюrrуре компьютера (например, знаков < 1>(){)
и .цр.) на экран мОzно выводить сИМВОIIЫ псевдоtрафики. Таких симво­
лов всеrо 48; им COCJI'ВC'l'C'11YIOТ коды от 176 до 223. Так, например, дru1
формироВ8НН.11 на экране двойной рамки используются следующие
коды:
Вывод на экран симвопьной информации 47
1 186 , 187 .в 188 L 2оо r 201 - 2о5
Наконец, если в строку, выводимую на экран, включить код 7, про­
звучиr короткий звуковой сиrнал.
В примере 7.3 приведсна символьная: строка, вывод каrорой с по­
мощью функции 09h DOS приведет к выводу ДliJmmЬHoгo звуковОго
сиrнала и изображению приблизитеп:ьно в центре чистого экрана слова
"Внимание!" в рамке.

Пример 7.~ Вывод на ЭI<JIOH информационн020 IUliJpa.


messaqe dЬ 25 dup (7)
dЬ 80*12 dup (' ''1
dЬ 35 dup (' '), 201,9 dup 1205), 187,10,13
dЬ 35 dup (' '),186,'Виимание1',186,10,13
dЬ 35 dup 1' '),200,9 dup (205),188,10,13
dЬ 10*80 dup (' '), '$'
В приведеиных выше примерах некоторые символы вводились в
программу в виде их изображений (букв), а другие
- с помощью их ко­
дов. В действительности все символы, отображаемые на экране терми­
нала или выводимые на печать, имеют закреWiенные за ними коды, ко­

торые называются кодами ASCII. Каждый код ASCII занимает один


байт и может принимать значение от О до 255. Совокуnность всех 2SS
кодов вместе с изображениями символов составляют кодовую табJПщу
ASCII (рис.7.1).
Очевидно, что описывать в проrрамме текстовые строки с помощью
кодов ASCII по меньшей мере неудобно. В то же время для вывода на
экран псецдоrрафических изображений или других mоаоrрамм, для ко­
торых нет соответствующих К11&ВИШ, приходится пОJIЬЗОваться кодаыи

ASCII. Однако ИМС'IЪ в виду соответствие символов и кодов ASCII при­


ходится довольно часто. Например, упорядочивание символов или сим­
вольных строк по алфавиту фаiсrически ВЫПО/ПIЯСТСЯ по кодам .ASCII.
Для усвоения ВЫШСИЗJIОЖСННОГО выведите На Экран строку, ОIПiсаR­
ную в примере 7.4. В ней все символы, и алфавиmые, и ПССIЩоrра­
фические, и записаны в виде кодов ASCII. В теGТ строки вк:рались
ошибки. Найдиrе их. ·
/IpШiq U. Вывод на Э1СJН1Н NIU:IriO, OIIIICIIННDttJ IUJilau ASCIL
.....9. dЬ 25 dup (7), 80*12 dup (32)
dЬ 35 dup (32),201,9 dup (205),187,10,13
dЬ 35 dup (32 )., 186, 130, 173, 168, 172, 160, 173, 236, 63, 186, 10, 13
dЬ 35 dup (32),200,9 dup (205),188,10,13, 10*80 dup (32),'$'
48 Статья7

oom~~~reoo~~~ oom~ro~~oo~m~
000 g 8 • • 9 • • а о 130 В r а Е 1 э и А к n
· 01 о 1 ff е r 11 • s
11 140 н н о n Р с т !1 • х
.,. .,.
020 • § - 1 t ~ • +
L. • 150 ц ч 11 .. ь .. ь э • я
оэо .а. У $ :-с а 11 160 а 1 а г а е • s и •
t •• 1
~О ( ) • • · - ./81170 к•ннonlllll
~о 2 э 4 s 6 7 в 9 : ; 180 ~ i ~1 .. , t 1 1 • Jl е.
000 < =
> ? Cl А
В С D Е 1g) .1 1 L ~ т ~ - f 1 t
~О FGHI.JXLHHO 200 lo.Uvl•f.&.Aт

ооо • Q R s т u u u х У 210 • в L r • 1 J r 1 +
090Z[,J""' 'aЬc220 8 ll 8 pcтu•x
100 с1 е r tr h 1 J k ·1 " 230 && " 111 111 • .. ь :. • А
110 • о • q 1" s t u u w 240 :t 6 » « " • + - • •
120 х !:1 z ( 1 } - 11111 А S 250 • ..Г 1Ф а •

00 01 02 ОЗ 0-105 06 07 08 09 OAOBOCODOEOF
.оо g 8 • • • • • а о 1 , , ,. 11 •
1о *
.. .. 11 .. § - 1 t ... • + L. • . . у
20 t •• 1 $ :-с а 11 ( > • • , - • /
зо в 1 2 э 4 s 6 7 8 9 : ; < >? =
o10&ABCDEFGHI.JKLHHO
50 • Q R s т u u w х ' z [ ' ] А -
60 .. а ь с cl е r • h 1 J k 1 " • о
70 • q 1" • t u u w х !:1 z ( 1 ) - 6 б
80АSВГаЕZЭИАКn ННОП
~РСТУ•хцч••ьньэ•я
дОаСSагаеааиА к11нноn
вoUIII ~il..,,ll1 1 • .. ,
coL~т•-+tl•••vl-t.a.
оо.ат w • L r .t+J rl .1 1•
ЕО р с т " •
FO :1:6»« .. •
х
+-· ..
1& " .. • • .. llt :.
.,f!ФD•
.. А

Pllc. 1.1. ~tlllmti6AII1411dм ношd CIIIJНIIIW: t1 - Ш 1UJOtм ASCll• iet:1unii'IIIOМ n,.Ь­


CIItiiCМIUIII,
1- • ~'fНON.
Еsс-поспвдовательности 49

Статья 8
Еsс-последовательности

Из рассмотрения примеров статьи 6 видно, что возможности DOS


по управлению экраном весьма скудны. С помощью функции 09h мож­
но выводиrь на экран символьные строки, вкmочая в них управляющие
символы и символы псевдографики. Позиционирование курсора, как и
очистку экрана приходиrся ВЬПIОJШЯТЬ с помощью пробелов. В DOS нет
никаких функций, с помощью которых можно было бы проrраммно
установить курсор в заданнос место экрана; нельзя также изменить цвет

выводимых символов (это-rо при цветном мониторе!).


Вкmочение в систему устанавливаемого .црайвера терминала (файл
ANSI.SYS) дает пользователю дополнительные возможности управления
экраном и клавиатурой. Если в символьной строке, выводимой на эк­
ран, встречается код клавиши <Esc>(27, или lBh), за коrорым: следуст
символ "(",ro АNSI-.црайвер персхватывает последующие символы и ин­
терпретирует их, как команды управления экраном или клавиатурой. С
помощью Еsс-последовательностей можно очищать экран, персмещать
по нему курсор, выбирать цвета фона и символа, изменять видеорежим:,
а также переопределять клавиши клавиатуры.

Еsс-последовательности можно использовать в прикладных про­


граммах для формирования на экране требуемого изображения. В этом
случае они вкmочаются в строки, выводимые на экран операrорами rого

языка, на котором написана проrрамма. Эrо дает возможность выводить


строки текста в заданные места экрана, изменять их цвет, заставJIЯ'l'Ъ

мерцать или выделяться яркостью и т.д.

Для управления экраном используются такие Еsс-последоватсль­


ности:

Esc(2J - очистка экрана и персмещение курсора в левый верхний


угол;

Esc(K -очистка строки ar курсора до конца строки;


Еsс(стро"а;поэицияН - установка позш.щи курсора. Параметр строка
обозначает У-координату курсора в пределах 1... 2S, параметр noэuцUR -
Х- координату в пределах 1... 80 (для видеорежима 80x2S симвоЛов);
Еsс("од_l;"од_2;код_Зm - выбор атрибуrов символов. Параметры
"од_l, "од_2 и "-од_З мoryr принимать значения:
О- нормальнос изображение (белые символы на черном поле);
5О Статья В

1- ВЫДСJiеНИе яркостью;
S- выдмение мерцанием;
7- инверсное изображение (черные сИМВОЛЬI на белом: nоле);
30 -черные символы; 40 - черный фон;
31 -красные символы; 41 - красный фон;
32 -зеленые сИМВОЛЬI; 42 - зеленый фон;
33 -коричневые сИМВОЛЬI; 43 - коричневый фон;
34 - синие символы; 44 - синий фон;
35- фиолетовые символы; 45- фиолетовый фон;
36 - бирюзовые сИМВОЛЬI; 46 - бирюзовый фон;
37 -бСJiые символы; белый фон.47 -
Еsс(числоА- персмещение курсора на число строк вверх;
Еsс(числоВ- nерсмещение курсора на число строк вниз;
Еsс(числоС- персмещение курсора на число nозиций вnраво;
Esc( числоD - персмещение курсора на число позиций влево;
Esc(s - сохранение ~кущих к.оордиюrr курсора в специальном буфе-
ре;

Esc(u - восстановление сохраненных в буфере координат курсора


(исnолъзуе-rоя вм:~ с предыдущей nоследовательносn.ю для тоrо,
!IТОбы вывсети чrо-то на экран в .цруrом м~, а потом всрнуn. курсор
в пре.хсн:юю позицию);
Помимо персчисленных, имеются Еsс-последовательности, служа­
щие для выбора видеорсжим:а, персопредмения клавиш клавиатуры и
.цругие.

Модифицируем ~кст выводимой С"lрОКИ проrрам:мы 7.3, вкmочив в


него Еsс-последоватепьности управления экраном.

Прuмер 8.1. JlhpoiiAeниe экраном с nОАiощью &c-nocлeiJнameлfiiiOCIМil.


-88age dЬ 10 dup (7) ; ЗISYJCOBOЙ CИX'ИIUI
dЬ 27, • [2J', 27, 1 [Э115а' 1 О.Ист~еа 111:краиа и sадаии .. цвета
dЬ 27,'[121Э5И',201,9 dup (205),1871По~ициоиироваиие и симаопн
dЬ 27,'[1Э;Э5И',186, 1 Вкиwаиие1',1861Поsициоиироваиие и аимаопк
dЬ 27,'[14;Э5h',200,9 dup (205),1881 Поsициоиироааиие и симаопк
dЬ 27, ' [О., 27, ' [2SI1И$' 1 Отмена цвета и аоsициоиироааиие
Циклы 51

Статья 9
Циuw

ЦИЮIЫ (т.е. выпОJШение некаrороrо участка nрограммы заданное


число раз) относятся к числу важнейших элементов nрограмм на любых
языках nрограммирования. Для демонС'lрiЩИИ техники организации
циклов рассмоорим фрагмент nрограммы, в котором создаеrся и выво­
диrся на экран ТСС'ЮВЫЙ символьный массив, запОJШенный кодами ал­
фавитно-цифровых и псевдографических символов. Эrи символы имеют
коды от 32 (пробел) до 254 (сrшошной квадрm:'ИК). Такой массив можно
создать в полях данных nрограммы вручную с помощью оператора dЬ:

eymЬole dh З2,ЗЗ,З4,З5,Зб,З7,З8,З9, •••

однако nроще запОJШиrь его данными программным образом (пример


9.1). Для удобства читателей программа примера 9.1 приведсна ПОJШос­
'IЪЮ, однако в дальнейшем в примерах будуr приводиться только содер­
жательные фраrмеНТЬI программ. Весь "антураж" (объявления сегментов,
инициализация сеrмеН'Пiоrо регистра DS, завершение программы), ко­
торый всегда остается пракrически неизменным, будет опускаться.

ОрШ1ер 9.1. ЦUICAЬI.


text eeqaent 1 (1)Начапо се~wента коwанд
aes\.IIМICSatext,DS:dat&l (2)
beqinl IIIOV AX,dat& 1 (З)Иющиа.JDIS&ЦЮI Cei'NeHTHOI'O
IIIOV DS, АХ 1 ( 4 ) реrистра DS
1По~отоВИN асе необхоДJО8)е .J&mJ ор~аниsации IDDCII&
IIIOV СХ,223 1 (5)Чис.по ШIU'08 8 IDDCII8
IIIOV SI, О 1 (б)Индекс адресуемоrо -еwента
1 а sano.ru&lleмoм массмае
~~~~:~v AL, 32 1 (7)1Сод aepaoro ~ona - аро6-а
1Теаерь собственно цикп, • который аходиТ 4 коwакдм
fill1 8DV symЬole[SI],ALI (8)Занесение очередноrо кода
1• байт wассиаа с индексом SI
ino AL 1 ( 9 1СоsдадИМ код c.ne.II)'IQIЦero CID80.11&
inc SI 1 (10)Cд8JU1eu::.ll • аассиае на 1 байт
loop fill 1 (11)1Сомамда IINIUia иs СХ 111&1'08
1 В.. едем .J&mJ контроn.11 аопучениый cиwaonьllllli маесна на 8JCP&X
IIIOV АН, 40h '(12)Функци.11 DOS 81118ОД&
1110v ВХ, 1 1 113)Стандарт11111i дескриатор екрана
IIIOV СХ, 223 1 (14)Чис.по -OJIИМIX баАтоа
IIIOV DX, oftaet ер!Ьоl81 (15)Адрес 8W80IIИNI)~O сооб81енм.
int 2lh 1 116181аоа DOS
52 Статья9

;Завершим про~р~
DIOV АХ, 4C00h 1 (17)
int 21h ; (18)
text ends ; (19)Коиец сеrwеита хо~
data seg~~~ent ; (20)Начапо се~wеита дакиых
1 По.п.11 даииых про~р&МОI
aymЬols dЬ 223 d\.tp ('*' 1 ; (21)Заuо.пияеМ11о!Й .массив
data ends ; (22)Коиец сеrwеита данинк
atk seqment stack 'stack'; (23)Начапо сеrwеита стека
dw 128 dup (0); (24)Стек
atk ends ; (251Коиец сеrwеита стека
end beqin ; (26)Коиец текста nporp&МOI

Рассмотрим содержательную часть проrраммы. Счсnиком шагов


цикла служит регистр СХ. Поэтому в него надо занести tребуемое число
шагов цикла (предложение 5), равное длине запОJШЯемого массива. Ра­
бота с массивом осуществляется, как правило, с помощью одного из
ШIДексных регистров (SI иm1 Dl), в которых храниrся и наращивается
ШIДСКС адресуемого элемента массива, т.е. номер байта массива, к кото­
рому осуществляется обращение в данном шаrе цикла. Поскольку мы
начинаем обрабатывать массив с самого начала, в предложении 6 в ре­
гистр SI заносиrся О. Регисtр AL выбран нами для хранения текущего
кода символа, отправляемого в массив. С таким же успехом эту роль
мог бы выполнить любой дРУГОй байговый регисtр- АН, BL, ВН, DL
ИJП1 DH (регисtры CL и СН, входящие в состав регисtра СХ, уже заня­
ты). В предложении 7 в регисtр AL заносиrся код первого символа -
пробела. Подготовив все необходимые реrисtры, можно составить само
тело цикла. В предложении 8 код из AL отправляется в элемент (байт)
массива symbols, номер которого определяется содержимым ИНдексного
perиctpa SI. Эrо так называемая имексная адресация, у которой су­
ществует несколько разновидностей. В частности, в качестве ШIДексно­
го регистра с тем же успехом можно бьuю использовать ВХ или Dl. В
первом шаrе цикла заполниrся элемент массива с индексом О. В сле­
дующих двух предложениях выполняется инкремент (увеличение на 1)
кода очередного символа и ИНдекса в массиве. Наконец, команда loop
(петля) (предложение 11) возвращает управление на метку Шl, причем
делает это ровно 223 раза, в соответствии с исходным содержимым СХ.
Чтобы увидеть результаты работы проrраммы, выведем полученный
массив на экран. Для этого нельзя воспользоваться уже знакомой нам
функцией 09h, потому чтр где-то в массиве будет содержаться код знака
S,а он, как мы уже знаем, не может бьm. выведен на экран функцией
09h. Поэтому для вывода мы воспользуемся дРугой функцией DOS, с
номером 40h, которая позволяет выводить информацию в файлы и на
уС1рОйства, в часmости, на экран. Приемник выводимой информации
определяется числом, заносимым в регистр ВХ, и называемwм дескрип­
тором (или файловым индексом). На этапе инициализации DOS экрану
Циклы 53

присваивается дескрmпор 1, который носит специальhое название "де­


скрmпор стандартноГо вывода". Работа функции 40h с .цруrими де­
скрmпорами будет рассммрсна в дальнейшем. Кроме дескрипrора,
функция 40h требует, чтобы в реrистре СХ находилось число выводи­
мых байтов, а в реrистре DX (точнее, в паре реrие1р0в DS:DX) - щсс
выводимой информации (см. С'JРОКИ 14 и 15). Наконец, команда int 21h
передаст упргмение DOS, которая и выпОJmЯст требуемую операцию.
В полях данных программы объямен массив байтов (епсратор db),
который инициализирован кодами символа ...... Эrо очень удобный и
распространенный прием, который облегчает отладку программы. Если
в силу каких-то ошибок в программе массив будет заполнен не весь или
не заполнен вообще, на экран будут выведены звездочки. Если же про­
грамма работает правильно, исходные звездочки затруrся заполняю­
щими символам:и.

В заключение отмстим еще одну особенность проq1аммы 9.1. Это


первая проrрамма, в которой выполняется прямое обращение к ячейкам
сеrмента данных (предпожение 8, rде заполняется массив с именем
symbols). В предыдущих статьях подчеркивалось, что адрес любой ячей­
ки памяти обязательно имеет два компонента: сеrмеН111ЫЙ адрес, хра­
нящийся в одном из сеrмеН111ых реt·истров, и относительный адрес, или
смещение, которое, часmости, может указываться в команде в виде

мнемонического обозначения ячейки. В преддожении 8 имеется ссылх.а


на ячейку symbols, т.е. указывается смещение. Каким ссrмеН111ым реrи­
С1рОМ будет пользоваться процессор при выnо.анении этой команды?
Если в команде не указан в явной форме сеrме1m1ый реrистр, по умол­
чанию исnолыуется DS. Соб"·твенно, именно в этом предnоложении
мы в начапе программы инюrиализировали репtстр DS адресом сегмен­
та данных, в котором расположен массив symbols. Однако JI)1Я тоrо,
чтобы указанное умолчание дейсТIЮвало, необходимо с nомощью опе­
ратора assume сопоставить DS именно с этим сеrменrом. Таким обра­
зом, определение DS:data в операторе assume стало необходимым только
в этой проrрамме, во всех предыдущих можно было oбoftnrcь без неrо.
Рассмотрим теnерь моженные циклы на примере организации
ПJЮграммной задержки. Программные задержки широко исnользуются
в.'I\Ж с~. коrда в какой-то точке программы надо приостановить ее
вьшопиение на некоторое время. Такая необходимость часто возникаст
при проrрщмировании относительно медленной аппаратуры компыоте­
ра. Ec;n, в аппаратуру посылается последовательно несколько управ­
JVПОЩИХ команд, то JI)1Я тоrо, чтобы дать аппаратуре время их выпол­
НИ'l'Ъ, между ними включаiО"rоя программные задержки (на время
несколько едИНIЩ или десятков михросек:унд). Проrраммные задержки
значительно большей величины, порядка нескольких секунд, удобно
использовать при отладКС проrрамм, ВЫIОДIПЦИХ на экран некоторую
54 Сmатья9

. (возможно, отладочную) информацию. Задержка дает возможность


программнету проследmь результаты вьmОJШения каждого шага про­
граммы. В примере 9.2 приведен фрагмент именно такой проrраммы. В
дальнейшем часто будут даваться не пОJШые тексТhi програм:м, а лишь
рассма1риваемые фрагмеНТhi.

Прuмер 9.2. Программноя задержка.


1 Орrаииsуем дем:>нстрАЦИоннЬIЙ цикп и:s 10 шаrов, которые бy,II}"Z
IВЫПопияться с sадерхкой nopЯ,IIICA нескольких секунд
mov СХ, 10 1 ( 1) Число шаrов в деъю-цикпе
cycle : pu.sh СХ ; ( 2 ) Сохраним этот счетчик в стеке
; Blilleдeм на э~ераи контропьнУJО строr<у и:s трех СИNВопов
IIIOV АН, 09h ; (3)
mov DX, off.set .strinq; ( 4)
int 21h ; (5)
;Орrаии:sуем nporpaиwнYJO :sадерхку
mov СХ,100 ; (6)Счетчик внешиеrо цикпа
outer: pu.sh СХ ; ( 7) Сохраним ero в стеке
:mov СХ,65535 ; (8) Счетчик внутреннеrо цикла
inner: loop inner ; ( 9) По11торм комаиду loop 65535 pas
рор СХ ; ( 1 О) Восстановим внешний счетчик
loop outer 1 (11)Повторим все это 100 pa:s
рор СХ ; (12)Восстановим счетчик деъю-цикпа
loop cycle 1 (13)Повторим демо-цикл СХ•10 pa:s
;Поля данных (в сеrменте данных)
strinq с:1Ь 1 <> $ 1 ; ( 14 1

В примере 9.2 с помощью функции DOS U9h (предложения 3.. 5) на


экран выводится е1р0ка "<> "с периодом, определяемьш программной
задержкой. Задержка создается с помощью двух аложенных циклов.
Внуrренний предстааляет собой просто команду loop, повторяемую
65535 раз (nредложение 9); внешний цикл служит для повторения внуr­
реннего 100 раз. В результате команда loop вьmолняе'IСя 6553500 раз,
что, в зависимости от скорости конкретного компьютера, дает задержку

приблизительно от одНой до нескольких десятков секунд.


Поскольку команда loop вьmолняется всегда СХ раз, этот реrис1р
приходится исnользоваТh в каждом цикле заново. Перед входом во
внуrренний, аложенный цикл текущее значение сч~ика внешнего
цикла (содержимое СХ) сох:раняе'IСЯ в стеке командой push, а nеред ко­
мандой loop внешнего цикла восстанаwпmается командой рор ·(nары
01р0к 2,12 и 7,10). РазумСС'IСя, сох:ранИТh значение СХ можно где угод­
но (в любом .цругом реrиС1рС или в ячойке nамяти), ОдНако команды со­
хранения в стеке и восстаноаления из сn:ка эффеiСI'ИВнее .цруrих в
смысле времени вьmОJШения и расходуемой nамяти.
Подготовив к ВЬПIОJПiению пример 9.2, nоэкспериментируйте с дли­
тельностью задерЖJСИ, изменяя число шагов внешнего цикла (nредложе­
ние 6).
Ввод с клавиатуры симвапьной информации 55

Статья 10
Ввод с клавиатуры символьной информации

Рассмотрим возможности ВQОда в проrрамму данных с клавиатуры.


При нажатии на клавишу код ASCII нажаrого символа (вместе с его
скен-кодом, отражающим номер нажаrой клавшuи) поступает в буфер
ввода с клавиатуры, находящийся в системной области оперативной па­
мяти и доступный функциям DOS. ЗапОJШение буфера клавиатуры про­
исходит по мере нажатия клавши и никак не связано с вьmОJШЯемой
проrраммой. Если проrрамме 1}Jебуется ввести с клавиатуры определен­
ную информацию, она ставит запрос к DOS на ввод с клавиатуры одно­
го символа или целой с1}Jоки. Запрошенная функция DOS обращается к
буферу ввода (не непосредственно, а посредством системного дРайвера
клавиатуры CON и прерывания BIOS, но для нас Э'Ю не очень суще­
ственно) и при наличии в нем символов передает первый из поступив­
ших символов в проrрамму. При этом символ изымается из буфера,
освобождая там месrо для последующих символов.
Если к моменту вызова функции DOS буфер ввода оказывается
пуст, DOS начинает непрерывно опрашивать его состояние, ожидая по­
явления в буфере очередного кода, в результате чего проrрамма остана­
вливается до нажатия клавиш~-4.
Таким образом, в проrрамму при вводе с клавиатуры всегда посту­
пают коды ASCII, закрепленные за нажимаемыми клавишами, т.е. сим­
вольные сrроки. Если в проrрамму 1}JСбуется ввести число, ro посту­
пающую символьную информацию следует преобразоватъ в числовую.
Эrа процедура будет рассмотрена в послс.в.ующих статьях.
Рассмотрим любопьrmый пример использования в проrрамме сим­
вольных данных, вводимых с клавиатуры. Вспомним, чrо цвет символов
на экране можно задавать с помощью Еsс-.последоваrельностей, причем
эти последовательности представляют собой символьные С'IJЮКИ (за ис­
ключением кода Esc). Таким образом, ввоц с клавиатуры параметры
Еsс-nоследователъностей и посылая их Затем на экран с помоЩJ.ю под­
ходищей функции DOS, можно с клаDИIП')'J)Ы задаваn. цвет изобр8женп
на экране. Модифицируем llpOI'piМNf примера 8.1, 'I"NC)ы 010 моzно
бblJio ynpa8IIJl1Ъ с клавиатуры 'lq)минала.
56 Статья 10

.Приwер 10.1. Вао~ с клааиатуры скwаоnьной информации.


10.Исткw 3крак и аыае~ам раwку с текетои беs цвета
IIIOV АН, 9 ; ( 1) Функци11 DOS выао~а на экран
шоv DX,offset clear; (2)Ацрес аыаодиwоrо сообщения
int 21h ; (З)Выsоа DOS
1Bae~ew с клааиатуры параwетр Еsс-nоспе~оаатепьности дпя s~аиия
1 цаета раwки
a9ain: шоv АН, 01h ; ( 4) Функци11 вво~а с клааиатуры
int 21h ; (S)Выsов DOS
шоv co1or, AL ; ( 6) Перва11 цифра цаета
IIIQV АН, 01h ; ( 7) Функци11 авода с клавиатуры
int 21h ; (8) Выsоа DOS
шоv color+ 1, AL ; ( 9) Вторая цифра цаета
1 Выве~еw на 3кран цветнУJО раwку
шоv АН, 9 ; ( 1 О) Функция DOS выао~а на экран
mov DX, offset message; ( 11) Адрес выаодим:>rо сообщения
int 21h ; (12)Выsов DOS
jmp again ; (13)Бескокечиый цикл nоиторекия
mov АХ, 4C00h ; ( 14) Завершение nporpawwы
int 21h ; ( 15) Выsоа DOS
1 Поnя ~аииых
clear dЬ 27, 1 [2J 1 ; (16)
measaqe dЬ 27, 1 [ 1 ; (17)
color dЬ 1 00 1 ; (18)
dЬ 'm', 27, 1 [12; ЗSН 1 , 201,9 dup (205) ,187 ; (19)
dЬ 27, 1 [13;35Н 1 ,18б,'ВНИWАНИе1 1 ,186 ;(20)
dЬ 27,' [14; З5Н 1 , 200, 9 dup (205), 188 ; (21)
dЬ 27,'[0m 1 ,27, 1 [25;1Н$ 1 ;(22)

Первыми С11ЮКЗМИ приведеиного фрагмента с помощью функции


DOS 09h и Еsс-последовательности с именем clear очищается экран
(предложения 1... 3).
Далее в предложениях 4... 9 осуществляется ввод с клавиа'I)'ры кода
цвета и, наконец, с помощью еще одного вызова функции DOS 09h
(предложения 10 ... 12) на экран выводится сообщение message с Еsс­
последовательностями задания цвета и позиционирования курсора, а

также отображаемыми сч>оками (коды рамки и слово "Внимание!").


Команда безусловного персхода jmp (предложение 13) возвращает
управление в точку ввода нового значения кода цвета, организуя тем

самым бесконечный цикл. ПользоватеJIЬ может многокраmо вводить


код цвета и наблюдать результат этоrо на экране. Для завершения про­
граммы и выхода в DOS надо ввести с клавяа'I)'ры сочСтание
<Ctrl>/<C>.
Сч>ока message JI)IЯудобства программирования разбита на части. Те
два байта Еsс-последовательности, которые определяют код цвета, выде­
лены в отдельное предложение ассемблера с именем color. Далее с по­
мощью четырех операторов db описан ОС'ГIП'ОК выводимой С11ЮКИ до за­
вершающего вывод символа"$".
Для ввода с клавиатуры одного символа используется функция DOS
Olh. Эrа фуню~ отображает вводимый символ на экране, что дает
Ввод с кпавиатуры символьной информации 57

возможность контролировтъ ввод. Код ASCII нажатой IСЛ8ВШПИ воз­


вращается ею в perиc'lpC AL. В рассматриваемом примере функция: Olh
вызывается дважды. Результат первого вызова (первый введенный с кла­
виатуры символ) перссылается в байт с именем color. Второй введенный
символ помещается по адресу color+1, т.е. в СJJедующий байт. В резуль­
тате в Еsс-последователъности задания цвета исходный код цвета '00'
(что обозначает исходную комбинацию: белые символы по черному по­
лю) заменяется на коДЬI ASCII двухразрядного десятичного числа, вве­
денного с IСЛ8Виатуры (например, 31 - красные символы при исходном
цвете фона, 44- синий фон при исходном цвете символов и т.д.). С та­
ким же успехом можно было, не вьщеляя байты кода цвета, переслать
первый символ по адресу message+2, а второй - по адресу message+3,
однако приведенный вариант проrраммы нагляднее.
В примере 10.1 сохранены строки завершения проrраммы
(предложения 14-15). Однако в действительности они в этой проrрамме
не нужны. В самом деле, проrрамма представляет собой бесконечный
цикл и сама по себе никогда не завершится. Если же мы завершаем ра­
бО'Iу проrраммы нажатием сочетания <Ctrl>/<C>, то функция заверше­
ния проrраммы вызывается ИЗНУJРИ DOS. Таким образом, строки про­
rраммы после предложения 13 с командой безусловного перехода ни­
когда выполнены не будуr, и их можно удалить.
Если ввод в проrрамму с клавиатуры осуществляется с помощью
одной из функций DOS посимвольного ввода, например, 01h, то для
ввода нескольких символов 'Л"f функцию приходится выполнять по­
вторно. В тех случаях, когда в пjюrрамму требуется ввести сразу rpyrmy
символов без их промежуточного контроля, удобнее воспользоваться
функцией 3Fh, которая позволяет ввести с IСЛ8Виатуры символьную
строку длиной до 126 символов. Количество символов лимитируется
длиной системного буфера, куда эти символы сначала поступают. Си­
стемный буфер имеет длину 128 байт, но последние два байта резерви­
руются под коды 10 и 13, которые посылаются в буфер при нажатии
IСЛ8ВШПИ <Enter>. Функция ЗFh вводит символы до нажатия IСЛ8ВШПИ
<Enter>. Получив код этой клавшuи, системные программы переносят
содержимое системного буфера с введенной строкой (и кодами 10 и 13)
в буфер пользователя, адрес которого указываtrся в регистре DX. Рас­
смотрим пример использования этой функции.

Пример 10.2. Ввод с клавиатуры симвмьной cmpoiШ


; ВU!Ieдeu иа r»краи CJOalo.n sanpoca
IIIIOV АН, 02Ь 1 ( 1) Фуикци11 IIIDO.IIA CJOalon&
IIIIOV JL, '> 1 ; (2) В~о~~~о,IIИМоiЙ CJOalo.n

int 21h ; (31


;Поставим sanpoc на 11110.11 строки с кпавиатурw
IIIIOV АН, 3Fh 1 ( 4) Фуикци11 IIIIOДA
mov ВХ, О ; 15) Дескриnтор кnaвJrAтypw
58 Статья 10

IIIOV СХ,128 ; (6)Вводиы не бо.пее 128 CИWIIOJIOB


IIIOV DX,offset inЬuf; (7)Адрес буфера ввода
int 21h ; (8)
IIIOV actlen,AX ; (9)Сохраиим чиспо фактически
;введенных сИМ!Iо.пов

; ВШ!Iедем Mll контрол11 на экран введеииУJО строку друхоиы цветом


mov АН, 4 Oh ; ( 1 О) Функци11 ВШ!Iода
mov ВХ, 1 ; ( 11) Дескриnтор экрана
mov СХ, actlen ; ( 12) Сто.пько сИМ!Iо.пов вве.пи
add CX,esc-2 ; (13)Прибавиы esc-CR-LF
mov DX,offset outbuf; (14)Адрес BbllloДИNDA строки
int 21h · ; (15)
;Перейдем на~ад в wонохромиый реzкы
DIOV АН, 0 9h ; ( 16) ФуИКЦИII BbliiOдa
mov DX, offset reset; (17 )Адрес ВЫIIОДИNDЙ строки
int 21h ; (18)
; По.п11 данных
actlen dw О ; ( 19) Ячейка MJI чиспа вве.uеиных CИWIIOJJOB
outbuf dЬ 27,' [34;46m' ; (20)Вsс-nоспедоватепьиость sадаии.11 цвета
esc•$-outbuf ; (21)Дпина этой Вsс-nоспедовательиости
inЬuf dЬ 128 dup ('*'); (22)Буфер ввода
reset dЬ 27,' [Om$'; (23)Вsс-nоспедовательиость от~иы цвета

В начале приведеиного фрагмента с помощью функции DOS 02h на


экран вьmодкn:я символ-запрос ">" (nредложения 1... 3). Появление
этого символа на экране удостоверяет, 'fiO программа запустилась пра­

вилъно и ждет реакции пользователя. Далее ставкrся запрос на ввод с


клавиа'JУРЫ символьной строки. Функция ЗFh может вводить данные из
устройства (клавиа'JУРЫ, последовательного порта) или файла. Источник
данных определяется дескршпором, засылаемым в регистр ВХ. При
загрузке системы клавиатуре присваивается дескршпор О, коrорый но­
скг название "дескрюпор стандар11юго ввода". В регистр СХ засылается
число, на 2 большее максимально возможного числа символов, так как
в буфер пользователя факntчески ПОС1УПаiОТ, кроме введенной строки,
еще и коды 13 (возврат каретки, CR) и 10 (nеревод строки, LF). Регистр
DX содержкг адрес буфера ввода. В процессе ввода строки DOS 0'1'06-
ражает вводимые символы на экране (эхо), а после завершения ввода
возвращает в регистре АХ число введенных символов плюс два. Для
дальнейших оnераций с введенной строкой ее длину следует сохранить
(предложение 9).
Для коmроля введенной строки в примере 9.2 предусмотрен вывод
ее на экран с помощью функции вывода 40h. Для большей наглядности
вывод выпwшяется в цвете, для чего непосредственно перед буфером
ввода (предложение 22) в пмях данных записана Еsс­
последовательность задания цвета символов (предложение 20). По­
скольку в качестве адреса буфера вывода указан адрес этой Еsс­
последовательности outbuf, на экран (точнее, в драйвер ANSI.SYS) по­
ступает сначала команда задания цвета, а затем введенная строка. Число
выводимых символов скорректировано командой add (сложение) на
Анапиэ данных и условные переходы 59

длину &с-последовательности (константа esc) и кодов CR и LF, кото­


рые, такиt.1 образом, на экран не поступают.
Для определения длины &с-последовательности (предложение 21)
использовано понятие счетчика текущего адреса, который имеет симво­
лическое обозначение $. Счетчик текущего адреса фа.IСГИЧески представ­
ляет собой ячейку памяти в программе 1ранслятора, в которую, по мере
1рансляции программы, заносиrея смещение 1ранслируемой в данный
момент с1р0ки программы (напомним, 'fiO смещение, или относитель­
ный адрес - это номер соответствующего байта от начала данного сег­
мента). По окончания 1рансляции предложения 20 значение счетчика
текущего адреса рано номеру первого байта после нашей &с­
последовательности (т.е., между прочим, смещению начала буфера вво­
да inbut). Имена же полей данных actlen, outЬuf и дР· получают
значения, равные смещениям эrих полей от начала сегмента. Поэтому
величина esc=$-outЬuf, сели ее вычислить сразу вслед за предложением,
описывающим буфер outbuf, окажется равной длине этого буфера. Такая
методика определения длин С1рОК текста позволяет легко модифициро­
вать эти с1р0ки. Действиrелъно, если изменить состав С1рОКИ outbuf и
пере1ранслировать программу, константа esc автоматически получит но­

вое значение.

Если содержаrелъную часть программы завершить в этой точке, то


заданный в программе цвет символов останется "навечно". Чтобы этого
не произопшо, в конце программы с помощью функции 09h на экран
ВЫВОдИl'СЯ &с-последовательность отмены цвета (предложения 16... 18).
С помощью рассмооренных средств в программу можно вводить не­
длинные С1рОКИ текста: имена файлов, дату или время, режимы работы
программы и т.д. Естественно, в программе должны быть предусмооре­
ны средства обработки эrих данных.

Статья 11
Анализ данных и условные переходы

При выполнении программы из предыдущей статьи чиmтеш. моr·


обратить внимание на незащищеннОС1Ъ программы от неправильноrо
ввода. Если вместо цифры случайно ввести букву, то Еsс-пос:Jедов..'\I~ЛL­
НОС1Ъ потеряет смысл и будет рассма1риваться АNSI-драйвсром, как
во Статья 11

обычная символьная С'lрОка. Эrо привед~ к сбою в рабоrе проrраммы.


Очевидно, что при вводе с клавиатуры: в про:rрамме следу~ предусмат­
ривать анализ вводимой Шlформации и О'l'браковку ошибочной. Внесем
сООТВС'.rоТВующие допОJШения в программу примера 10.1.
Прuмер 11.1. Ажlлиз символьной информации, вводимой с клавиатуры.
1 Очистим эJСраи и IIIDe.x.eм puacy с тексток беs шsета

1В11~ем с кnа!IИатурк napaweтp Еас-аоспе.х.о11атепьиости с ero


;аиа.пиsом

aqain: mov АН,О1h ;(1)Фуикци11 1111ода с кпавиатурк


int 21h ; ( 2 ) Вкsо11 DOS
сшр AL, 1 4 1 ; (3)Ваедеи симаоп > 1 41 ?
)а aqain 1 (4)Да, DOII!I.'OpИN 111\ОД
cmp Al, 1 3 1 ; (5)Ваедеи симаоп < 1 3 1 ?
:)Ь aqain ; (б)Да, повторим ааод
mov color,AL ; (7)Ваедеи доаусТИNЫЙ ко.х., nepemneм
; ero а строку
аушЬ2: mov АН, 01h ; (8) Фуикци11 ааода с кпавиатурк
int 21h 1(9)Вкsоа DOS
сшр AL, 1 7 1 1(10)Введеи симао.n > 1 7 1 ?
:)а аушЬ2 ; (1l)Да, nовторим 11аод
сшр AL, 1 0 1 1 (12)Ваедеи CИМIIOJI < 1 0 1 ?
:)Ь symЬ2 ; (13)Да, повторим ввод
mov color+1,AL; (14)Ваедеи доаус!I.'ИNНЙ код, nерешлем
; ero а отроку
mov АН,9 ; (15) ФуИJЩИII DOS IIIDOдa иа ЭJСрАИ
mov DX,offaet meaaaqe; (1б)Адрес аЫJtодимоrо сообщени11
int 21h 1(17)Вкsоа DOS
:Jmp aqain ; (18)Бескоиечннй цикп nо11торени11
;ПOJIII даииых
clear dЬ 27, 1 [2J 1
meaaaqe dЬ 27, 1 [ 1
color dЬ 1 00 1

dЬ 1 а 1 ,27, 1 [12;35Н 1 ,201,9 dup (205),187


dЬ 27,'[13;35Н 1 ,18б, 1 Виимаиие1 1 ,18б
dЬ 27, 1 [14;35Н 1 ,200,9 dup (205),188
dЬ 27, 1 [0m 1 ,27, 1 [25;1Н$'

Рассмотрим процедуру проверки правильиости вводимых данных.


После ввода первого кода (предложения 1-2) вьmолняется сравнение с
помощью команды: cmp (compare, сравнение) содержимого регистра AL
с символьным значением 4 • Поскольку коды цвета могут принимать
1 1

лишь значения в дИ1U18Зонах от 30 до 37 и от 40 до 47, первый симВС\11


не дOJDtCeн бьrrь больше 4 Еспи это не так, командой ja (jump if аЬоvе,
1 1

переход, если выше) осуществляется возврат на метку again с целью по­


вrорного ввода символа. Еспи же проверка прошла успешно, содержи­
мое AL сравн~я с нижней границей допустимого диапазона 13'. Ес­
ли введенный код меньше 131, командой JЪ (jump if Ьelow, переход, если
ниже) осуществля:ется возврат на 1У же метку again. Таким образом,
проrрамыа буд~ 'lрСбовать повrорного ввода до тех пор, пока не будут
Пароли и сравнение строк 61

нажmы клавиши <З> или <4>. Послепроверки введенный символ пере­


сьшае-rоя в байт с имЬнем color (предложение 7).
Далее с клавиатуры вводится втораsr цифра кода цвета. Эrа цифра
проверяется на вхождение в диапазон от О до 7и в случае правильиости
переносиrоя в байт с адресом color+l. При вводе неправильного симво­
ла функция ввода ВЫЗЫВае'rоЯ повrорно.

Статья 12
Пароли и сравнение строк

Идея простейшей зашиты проrраммы от несанкционированного за­


пуска заключается в том, что где-то в проrрамме записывается ключевое

слово-пароль, и проrрамма, начав работать, 'lребует ввода этого слова с


клавиатуры. Если пользователь ввел пароль правильно, проrрамма про­
доткаст работать. Если пароль введен неверно, проrрамма заверmае-rоя.
Таким образом, проrрамма доткна сравнить введенное слово с храня­
щимся в ней и фиксировать совпадение или наличие XO'DI бы незначи­
тельной разницы. Рассм01рим проrрамму ввода и анализа пароля.
Вообще говоря, ввод пароля можно осуществить любыми функция­
ми ввода с клавиатуры. Однако обычно пароль вводят одной из функ­
ций, не отображающих вводимые символы на экране. ТаiСИХ функций
две и 08h. Разюща между ними заключается в том, что функция
- 07h
08h, зафиксировав ввод пользователем сочетания <Ctrl>/<C>, аварийно
завершает· проrрамму, функция .же 07h к <Ctrl>/<C> нсчувствитсльна.
Поскольку обе эти функции вводят лишь одшi символ, Д1Ш ввода паро­
ля их надо использовать в цикле. Выход .из цикла можно организоваrь
по-разному: после ввода обуслоwrенного числа символов, по нажатшо
клавиши <Enter>, либо как-то иначе. Рассм01рим простую проrрамму
ввода с клавиатуры и анализа введенного слова.

Пример 12.1. Вв~ nafiOAJIII сравнение симвмьньа cmpo~e.


;Внвед- SADpOC pr0111pt С ПONOЩioJO фушсции DOS 09h

; Введ- паропъ
llliOV вх, о 1 ( 11 Иницка.nиsиру- ИllдeкCJIIIЙ pei'ИC!I:P
pass1 llliOV АН,ОВh 1(2)~ ввода беs аха
int 2lh 1 (Э)Выsов DOS
0111р AL, 13 ;(4)<Вnter>?
62 Статья 12

jе compare ; 15) Да, и а сравнение


1110v string[ВX) ,Ю.; lб)Нет, сохр&ИИ14 симао.п
inc ВХ ; 17)Иккремеит ииаекса
jmp pass ; 18) Повтор11ть
; Будем сравнивать строки
compare: push DS ; 19) Настроим ES на наш
рор BS ; 110)сеrмеит даиинх
SI,offset string; lll)Сыещеиие одной строки
IIIOV
DI,offset password; 112)Сыещеиие друrой строки
IIIOV
cld ; llЗ)Hanpa:aneииe вперед
IIIOV СХ,ВХ ; 114)Инициапиsируем счетчик цикла
repe c:mpsb ; 115)Сра:аиеиие
jne err ;llб)Строки ие ра:акы
;Вк:аедем сообщение ok, подтверждающее правильиость пapo.JIII

exit: IIIOV АХ, 4C00h ; 117)Завершение nроrраммы


int 21h ; 118)и выход в DOS
err: jmp begin ;119)Повторить ввод паро.п11
;Пo.JJII ДАИКЫХ
passworddЬ 'camel' ; 120)Оzидаеыый паро.пь
string dЬ 80 dup 171 ; 121)По.пе д.n11 ввода паро.п11
prompt dЬ '>>$' 1 122)Запрос
ok dЬ 'Работаем!$'; 123)Сообщение об успешном вводе napo.n11

Работа проrраммы начШiается с вывода на экран запроса проrрам­


мы. В данном случае запрос имеет вид ">>". Далее Шiициализируется
регистр ВХ, который будет использоваться в качестве ШIДексного, и
ставится запрос к DOS на ввод символа без эха (предложения 2-3). Вве­
денный код сравнивается с кодом клавиши <Eнter> (предложение 4), и
в случае равенства кодов командой je Gump if equal, переход, если рав­
но) выполняется переход на участок сравнения строк.• Если же нажата
любая дРУгая клавиша, ее код ASCII заносится J:S поле strillg со смеще­
нием 0111осительно начала этого поля на число байтов, равное содер­
жимому регистра ВХ. Выполняется Шiкремент регистра ВХ и командой
безусловного перехода jmp управление передается в точку pass на ввод
следующего символа.

При нажатии клавиши <Eнter> выполняется настройка регистров


для выполнения операции сравнения. Для сравнения последовательно­
стей байтов или слов предусмотрены специальные команды cmpsЬ
(compare strillg byte, сравнение строк по байтам) и cmpsw (compare string
word, сравнение строк по словам). Сiрокой применительно к эти ко­
мандам называется любая последовательность байтов или слов безО'Пiо­
сительно к ее содержимому. Первая строка адресуется через пару реги­
С1'JЮВ DS:SI, вторая - через регистры ES:DI. Однокраmое вьшолнение
команды сравнивает лишь одну пару элементов строки (один байт или
одно слово). После операции сравнения регистры SI и DI получают по­
Jtшккrелъное или отрицательнос прирщцение, величина которого со­

стuвляет 1 или 2 в зависимосrn от размера сравшшuсмых ЭJiемснтов.


Знак приращения зависит от состояния фдаl'R прщ•ессоrа DF. Если этот
Пароли и сравнение строк 63

флаг сброшен, что осуществляется с помощью команды cld (clear


direction 8ag, сброс флаrа направления), то приращение имеет положи­
тельный знак, т.е. элементы строки в процессе операции сравнения
просматриваются вперед, от меньших адресов к большим. Если флаг DF
установлен (с помощью команды std - set direction Oag, установка флаrа
направления), то приращение отрицательно, и строки просматриваются
в сторону меньших адресов, от конца строки к ее началу.

Таким образом, перед выполнением команды cmpsЬ(w) необходимо


предварительно настроmъ регистры DS, Sl, ES и Dl, а таюке флаг DF.
Реmстр DS мы обычно нас'lраиваем в самом начале проrраммы. По­
скольку обе сравниваемые стро·ки находятся в одном и том же сегмен-n:
данных (а могли бы находиться и в разных сегментах), сегментный ре­
mстр ES следует настроmъ так же, как и DS. Передача содержимого DS
в ES осуществляется через стек в предложениях 9-10.
В предложениях 11-12 реmстры Sl и Dl запОJПIЯЮТСя относитель­
ными адресами сравниваемых строк, а в предложении 13 командой cld
устанавливается направление сравнения- от нача.11а строки к ее концу.

Для того, чтобы сравнmъ целую строку, команда cmpsЬ или cmpsw
предваряется префиксом повторения. В примере исполЬ3уется префикс
repe (repeat wltile equal, повторение, пока равно). В этом случае опера­
ция сравнения выполняется до тех пор, пока символы двух строк совпа­

дают, но не более СХ раз. Поэтому требуется еще настроить и реmстр


СХ. В нашем случае в него заносится коне•шое содержимое регистра
ВХ, т.е. длина введенной с клавиатуры строки.
Выход из цикла повтореtiИЯ комшщы cmpsЬ происходит либо после
обнаружения песовпадающих байтов (и тогда ясно, что строки не сов­
падают), либо по исчерпmшю счетчика цик.1а СХ. В последнем случае
все байrы строк, кроме после;щих, наверняка совпадают, однако резуль­
тат сравнения последней пары байтов неясен. Таким образом, сама по
себе команда сmрЮ, выпо.;шяемая в цикле, не яозволяет судить о ре­
зультатах сравнения. После этой команды необходим анализ результата
сравнения последней пары байтов одной из команд условного перехода.
Исп0ЛЬ30ванная в проrрамме команда jne (jump if not equal, переход,
если не равно) в случае неравенства передает управление на метку еп и
весь цикл вывода запроса и ввода пароля повторяется. Если же строки
полностью совпадают, выводится контрольное сообщение, после чеrо
может начаться выподнение содержательной части проrраммы.
Как уже отмечалось, ддя ввода пароля, наряду с функцией 08h,
можно было использовать и функцию 07h, которая тоже осуществляет
ввод с клавиатуры одного симво.:1а без эха, но при этом не рсаrирует на
ввод комбинации <Ctrl>/<C>. В нашей про1-раммс, где ввод пармя вы­
ПОJIНЯется в бесконечном цик.1е, использование функции 07h привело
бы к тому, что ПОЛЬ3Ователь, не знающий паролъ и запустивший
64 Статья 13

nроrрамму, бьш бы вынужден для продолжения работы перезагружать


компьютер. В системе MS-DOS не предусмотрено никаких средств вы­
хода из зациклившейся проrраммы, кроме перезагрузки системы. В ре­
альных проrраммах часто задают максимальное число попыrок ввода

пароля, после чеrо проrрамма сама завершается.

Статья 13
Управление проrраммой с клавиатуры и расширенные
КОДЬI ASCII

Проrраммы для переопальных компьютеров носят, как правило,


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

том, что должна делать проrрамма дальше. При этом алфавитно­


цифровые клавиши обычно используются для ввода в проrрамму тек­
стовой информации, а управление проrраммой осуществляется с по­
мощью функциональных клавиш <F1> ... <F10>, <Home>, <PgUp>,
<PgDn> и дР. или комбинаций управляющих клавиш с функциональ­
ными и алфавитно-цифровыми, например, <Alt>/<1>, <Shift>/<F1>,
<Ctr1>/<F1>, и 'l'.д. Вся эта техника основана на использовании расши­
ренных кодов ASCII.
Как бьmо упомянут<:) в статье 10, при нажатии алфавитно-цифровой
клавиши в буфер ввода с клавиатуры поступает двухбайтовый код, в ко­
тором старший байт соответствует скен-коду нажатой клавиши, а млад­
ший - коду ASCII закреiUiенноrо за ней символа. Проrраммы DOS,
примимающие данные с клавиатуры (функции 01h, 07h, 08h, ЗrЪ и др.),
передают в проrрамму только код ASCII, оставляя скен-код без внима­
ния. Однако это относится только к тем клавишам, которые закреiUiены
за символами, отображаемыми на экране (буквы, цифры, знаки п:репи­
нания и др.). Кроме них, на клавиатуре п:ерсональноrо компьютера
имеется ряд клавиш, которым не назначены какие-либо отображаемые
на экране символы. Это, например, функциональные клавиши
<F1> ... <F10>; клавиши управления курсором <Home>, <End>, <PgUp>,
<PgDJt>, <Стрелка вправо>, <Стрелка вниз> и дР. Очевидно, что всем
этим клавишам назначены определенные скен-коды. Но как их скен­
коды преобразуются в коды ASCII?
Упра8Ление проараммой с клавиатуры 65

В таблице преобразования~ с ~рой работает системная nрограмма


обслуживан:ия клавиатуры~ всем таким сксн-кодам cOO'l'ВCmmlyeт нуле­
вой код ASCII. Поэтому nри нажатии~ наnример~ КJiаВИШИ <Fl> (скен­
код 3Bh) в кольцевой буфер ввода пoc'lYfiliCТ двухбайтовый код 3BOOh~ а
nри нажшии клавиши <Home> (скен-код 47h) - двухбайтовый код
4700h. Двухбайтовые коды, содержащие на месте кода ASCII ноль~ на­
зываются расширенными кодами ASCII.
Все функции DOS, предназначенные 1IJIЯ посимвольного ввода дан­
ных с клавиатуры~ позволяют работlпь и с расширенными кодами
ASCII. Для приема с клавиатуры расширенного кода ASCII nро1рамма
дQЛЖНа вызвать функцию DOS дважды. Первый вызов возвращает
младший байт расширенного кода ASCII~ т.е. О. При втором вызове воз­
вращается старший, значащий байт. При этом возникает некоrорая не­
однЬзначность. При нажатии "обычных" клавиш каждый вызов функции
DOS вводит код одной клавиши. Если же нажата функциональная кла­
виша~ то на ввод кода нажатой клавиши требуется два вызова DOS. По­
этому nро1рамма, ожидающая поступления расширенных кодов ASCII~
должна проверять каждый введенный код и nри поступлении кода О вы­
полнять ввод вторично.

Широкое использование икrеракrивных средств пооребовало рас­


ширения возможностей ввода с клавиатуры управляющей информации,
которую nро1рамма дWIЖна легко отличать от вводимого текста. С этой
целью в компьютерах типа IВМ РС расширенные коды ASCII генери­
руются не только функциональными клавишами и клавишами управле­
ния курсором, но и всеми алфавитно-цифровыми клавишами, если они
пажимаются вместе с клавишей <Alt>. Помимо этого, функциональные
клавиши и клавиши управления курсором генерируют различные рас­

ширенные коды ASCII в зависимости от того, нажаты ли они в оди­


ночку или в сочетании с клавишами <Alt>, <Ctrl> или <Shift>. В табл.
13.1 ... 13. 5 приведсны значения информационных байтов расширенных
кодов ASCII 1IJIЯ наиболее упооребительных клавиш и их сочетаний.

Tatfllицa 13.1. Информационные tfoйmы расширенных 1U1дог ASCII фующиональных


КАОflиШ

Кла8И111а Код Кла8И111а Код Кла8И111а Код


Dec Нех Dec Нех Dec Иех

<1'1> 5"9 3Вh <1'5> 63 31'h <1'9> 67 43~


<1'2> 60 3Ch <1'6> 64 40h <1'10> 68 44
<1'3> 61 3Dh <1'7> 65 41h <!'11> 133 8Sh
<1'4> 62 3Eh <1'8> 66 42h <!'12> 134 86h
66 Статья 13

Таблица 13.2. Ннформацио1111w tiolimw rюсшире1111ьа f((J(}oв ASC/1 фующионольньа


КдаtlиШ tl CO'Iemaнuu С КAatlишeiJ <ShiJI>
'
ICnaiUIIIIa Ко.11 ICnaiUIIIIa Ко,11 ICnaiUIIIIa Ко.11
Dec Нех Dec Нех Dec Нех

<F1> 84 54h <!'5> 88 58h <!'9> 92 5Ch


<1'2> 85 55h <!'б> 89 59h <1'10> 93 5Dh
<!'3> 8б 56h <!'7> 90 5Ah <1'11> 135 87h
<!'4> 87 57h <!'В> 91 5Вh <!'12> 13б 88h

Таб.tица 13.3. Ннформацио1111wе tioiimw JЮСШиренньа 1eoдotl ASCII фуН1еционольньа


КдQtlиШ t1 CO'Iemaнuи С К.Лаtlишеii <CII'I>

ICnaiUIIIIa Ко.11 ICnaiUIIIIa Ко.11 ICnaiUIIIIa Ко.11


Dec Нех Dec Нех Dec Нех

<!'1> 94 5Eh <!'5> 98 б2h <!'9> 102 ббh


<F2> 95 5Fh <!'б> 99 63h <!'10> 103 б7h
<!'3> 9б бОh <1'7> 100 б4h <1'11> 137 89h
<!'4> 97 б1h <!'8> 101 б5h <!'12> 138 8Ah

Таблица 13.4. Ннформацио1111611 6oiim61 rюсширенньа f((J(}oв ASC/l фуюсциОНtlllьньа


I(AQtlиШ tl СО'Iеmании С КAatiUШeii <AJt>

ICnaiUIIIIa Ко.11 ICnaiUIIIIa Код ICnaiUIIIIa Код


Dec Нех Dec Нех Dec Нех

<!'1> 104 б8h <!'5> 108 бСh <!'9> 112 70h


<!'2> 105 б9h <!'б> 109 бDh <1'10> 113 7lh
<!'3> 10б 6Ah <!'7> 110 бЕh <!'11> 139 8Вh
<!'4> 107 6Вh <!'8> 111 б!'h <!'12> 140 ась

Тоб.tицо 13.5. Ннформаци01111wе 6oiimw rюсшире~~~~ьа ltOiJtи ASC/l tuфot~иnuю­


цифJIOtiWX КАаtJиш • co'lemaниu с КАа•ишеii <AJJ>


ICna-

А
в
с
Dec
30
48
46
Код
Нех

1Eh
30h
2Eh

ICna-

J
к
L
Dec
36
37
38
Ко.11

24h
25h
26h
Нех


ICna-

s
't
u
Dec
31
20
22
Код
Нех

1!'h
1ih
16h

ICna-

1
2
3
Dec
120
121
122
Код
Нех

78h
79h
7Ah
D 32 20h н 50 32h v 47 2!'h 4 123 7Вh
1 18 12h N 49 31h w 17 1lh 5 124 7Ch
r 33 2lh о 24 18h х 45 2Dh б 125 7Dh
G 34 22h р 25 19h у 21 15h 7 126 7Bh
н 35 23h Q 16 10h z 44 2Ch 8 127 7!'h
I 23 17h R 19 13h о 129 81h 9 128 80h
Управпение программой с клавиатуры 67

Рассмотрим несколько примеров упра81Iсния про1})8Ммами с кла­


вшпуры. Пусть наша программа вводиr с клавиатуры rекстовую Шiфор­
мацию, и мы хотим предусмотреть возможность аварийного завершения
программы при нажатии на фунiЩИональную клавишу <FlO>.

Пример 13.1. Завершение nJIOllНlЮIЫ по <FJD>


; BIIIISeдeм на экран sапрос nporpUAAI prOJ\IPt
JIIQV BX,o~f.set tхt;Инициапиsациll баsовоrо
JIIQV SI,O ;и иидекскоrо реrистров
inpt: JIIOV АН, Olh ; Фуккци11 ввода СИNВО.Ла с эхом
int 21h ;Выsов DOS
cmp AL,O ;Расширекннй ASCII-кoд?
je ех ascii ; Да, на акапиs
IIIOV [аХ] [SI] ,АL;Нет, СИNВО.Л в буфер
inc SI ; Иккреа~ект иидекса
jmp inpt ;И бесконечно повтор11ть
ех a.scii:1110v АН, 08h ; Ввод СИЫI!IО.Ла беs эха
- int 21h ;Внsов DOS
cmp AL,44h ;<FlO>?
je exit ;Да, на выход
jmp inpt ;Нет, ка продо.mЕение ввода
exit: ;Завершение nроrраымн
; По.л11 данных
prompt с:1Ь '>>$'
txt с:1Ь 80 dup (?)

Программа выводит на экран свой запрос Шiициализирует "> >",


регистры ВХ и Sl, которые будут исполъзовап.ся при записи прШiи­
маемых символов в буфер проrраммы, и ставит запрос к DOS на ввод
символа с клавиатуры с отображением его на экране (функция Olh). Ес­
JШ код принятого символа равен О, программа переходит на метку
ex_ascii для приема второго байта расширенного кода ASCII и его ана­
JШза. ЕсJШ же пос1j'ПИЛ код алфавитно-цифровой клавиши, он записы­
вается в буфер txt. В программе исполъзуется эффепивный способ за­
ШIСИ элемента массива с помощью команды mov с базово-индексной
адресацией. В этом случае адрес определяется как сумма содержимого
обоих используемых в команде регистров. В одНом из них (в данном
случае ВХ} хранится базовый адрес массива, в другом (SI) - индекс, т.е.
смещение or начала массива. Эффепивность команды определяется
rем, что испОJПiительный адрес, т.е. адрес, по которому происходит об­
ращение, не надо извлекать из памяти: его составляющие уже хранятся
в регистрах процессора. После занесения введенного символа в буфер
txt выпОJПIЯется инкремент индекса, после чего программа возвращается
на ввод очередНого символа.

В случае нажатия клавиши ИJШ сочетания клавиш, вырабатывающих


расширенный код ASCII, программа переходит на метку ex_ascii с
целью вторичного вьmолнения функции DOS ввода символа. Использо-
вв Статья 13

ванне здесь функции 08h, которая работает без эха, позволяет избавить­
ся от отображения на экране в виде бессмысленных символов вторых
байтов расширенных кодов ASCII. Лринягый функцией 08h код срав­
нивается с расширенным кодом ASCII клавиши <FlO> (44h) и в случае
равенства осуществляется выход из проrраммы. Если нажата другая
функциональная клавиша, ввод текста продолжается.
Лриведенный пример не полон в том отношении, что при аварий­
ном завершении программы результаты ее работы безвозвратно теряют­
ся. В реальной программе после ввода пользователем команды заверше­
ния (нажатие клавиши <FlO>) следует предусмотреть сохранение на
диске результатов ее работы, вывода на экран предупреждающих сооб­
щений и проч.
Использованный в примере 13.1 метод управления программой ха­
рактерен тем, что воздействовать на ход вьmолнения программы можно
лишь в тех точках проrраммы, где она ожидает ввода символа с клавиа­

ТУРЫ. Во многих случаях желательно иметь средство управления про­


граммой, в частности, ее аварийного завершения, в то время, когда
программа выполняет некоторые циклические действия, например, об­
рабатывает и выводит на экран графическое изображение. Если в такой
цикл включить вызов функции DOS О 1h или Ogh, программа, вместо
того, чтобы выводить на экран изображение, остановится в ожидании
нажатия клавиши. Однако в DOS предусмотрены средства ввода коман­
ды с клавиаТУРЫ без остановки программы. Для этого используется
функция Обh, которая может работать в .цвух режимах: ввода одиночных
символов с клавиаТУРы и вывода одиночных символов на экран. Эrа
функция позволяет программе "заrлянуть" в буфер ввода с клавиаТУРЫ и
при наличии в нем символа ввести его в программу, а при ОТСуrС"mИИ

такового просто продолжить выполнение. Индикатором наличия или


отсуrствия ожидающего символа является флаг нуля ZF. Если функция
обнаружила ожидающий ввода символ, флаr ZF сбрасывается. Если
символа нет, флаr ZF устанавJiивается (обнаружено О символов).
В примере 13.2 продемонстрировано использование функции DOS
06h для управления программой в цикле. Управление, как и в
предыдущем примере, заключается в аварийном завершении программы
при нажатии определенной клавиши (конкрсmо сочетания <Alt>/<Q>).
Пример 13.2. Зо~ершение циКАи'lеской програА~МЬI по <Alt>/Q
contrl1 IIIOV АН, 09h ; Будем 11 liИIUie
IIIOV DX,offaet atring;l!lыaoдить JIA :.хр-
int 21h ;строJСу .strinq
IIIOV сх,о ;Пporpa..asa11
qqql loop qqq ; sa.uepJD<a
IIIOV АН, 06h ; ФуJощк11 QpiiNOJ.'O I!II!IOДA

IIIOV DL,OI'Fh ;Ре»ое I!II!IOДA


int 2lh ;Вкsо11 DОЗ
Управпение программой с кпавиатуры 69
jnz sушЬ ;Вспи симвоп есть, nереход
j111p contrl ;Симвопа нет, nродопкить uикп
sушЬ: Clllp AL, О ;Расширекннй ход ASCII?
jne contrl ;Нет, nродопкить цккп
IDOV .АН,06h ;Да, надо ввести второй байт
mov DL, OI'Fh ; Реюсм ввода
int 21h ;Выsов DOS
Clllp AL, lOh ;Нажато <Alt>/<Q>?
je exit ;Да, на выход
j111p contrl ;Нет, продопкить uикп
exit: ;Завершим проrраммы
; Попя данных
strinq dЬ 'ВЫnопи~~:ется цикп $'

В качестве бесконечного цикла, из которого осуществляется ава­


рийный выход по нажатию <Alt>/<Q>, использован пер~:,~одичесfСИЙ (с
небольшой задержкой) вывод на экран строки -rекста.
Для осуществления аварийного выхода из программы в цикл
ВЮIЮчен вызов функции DOS ОбЬ. Эrа функция может работать в двух
режимах - ввода с клавшnуры и вывода на экран. Режим определяется
содержимым регистра DL в момент вызова функции. Любой код в DL,
кроме FFh, приводпr в выводу на экран соответствующего этому коду
символа. Код FFh (в таблице кодов ASCII ему аrвечает "пустой" сим­
вол) включает режим ввода с клавиатуры. Команда jnz (jump if not zero,
переход, если не нуль) анализирует результат выполнения функции ОбЬ.
Если за время прохождения -rекущего шага цикла не было нажmпй кла­
виш, эта команда "не срабатывает", и следующей командой jmp contrl
осуществляется переход на начало цикла. Если же за время шага цикла
была нажата какая-либо клавиша, функция ОбЬ сбрасывает флаr ZF, и
команда jnz передает управ.аение в точку symb. Здесь прежде всего сле­
дует проверпrь, какой код ASCI I ожидает ввода в программу - обычный
или расширенный. Если код обычный (не равный О), он иrнорируется и
цикл продолжается. Между прочим, функция DOS ОбЬ работает без эха,
и введенный символ не искажает изображение на экране. Если введен
расширенный код ASCII, функция ОбЬ вызывается повторно для ввода
вrорого, информационного байта. Далее командой cmp ВЫПОJUIЯется
анализ этого байта. КодlOb - это значащая часn. расширенного кода
ASCII сочетания <Alt>/<Q>. Естественно, в качесmс "клавиши завер­
шения• можно было выбрать JIIOбoe другое сочетание. Если нuarro
<Alt>/<Q>, программа завершается; в праmвном случае ЦИКJI продм­
хастся. В peзym.'l'll're программвый ЦИКJI не воспринимает никакис нa­
JШJ1IJI клавиш, кроме <Alt>/<Q>.
70 . Статья 14

Статья 14
Вывод простейmих rрафических изображений

В предыдущих статьях бьшо показано, что для осуществления ввода


с клавиатуры и вывода на экран символьной информации приходится
прибегать к функциям DOS. При этом выяснилось, что возможности
DOS довольно скромны. DOS не поддерживает ни позш.щонирование
курсора, ни смену цвета выводимых символов. В текстовом режиме
расширИIЪ возможности DOS можно с помощью .црайвера ANSI.SYS. С
rрафическими изображениями дело обстоит хуже, так как в DOS нет
никаких rрафических функций. Нет их также и в .црайвере ANSI.SYS, за
исключением возможности перевода видеоадаптера в rрафический ре­
жим (с помощью Еsс-последователъносm Esc(=peжuмh). Для того,
чтобы вывести на экран rрафическое изображение, необходимо вос­
пользоваться нижним уровнем операционной системы - базовой систе­
мой ввода-вывода (Basic In-Out System, BIOS). Проrраммы BIOS нахо­
дятся в постоянном запоминающем устройстве (ПЗУ) BIOS, которым в
обязательном порядке комrшепуется любой компьютер. В отличие от
DOS, ко всем функциям которой мы обращаемся с помощью прерыва­
ния2lh, в BIOS за каждым устройством компьютера закреrшено свое
прерывание. Так, проrраммирование диска осуществляется с помощью
прерывания int 13, клавиатуры - int l6h, экрана - int IOh. Прерывание
int lOh обеспечивает все функции видеоадаптера: смену видеорежима,
вывод символьной и текстовой информации, смену шрифrов, настройку
цветовой палитры, рабооу с rрафическим изображением и т.д. Восполь­
зуемся прерыванием int 10h для перехода в rрафический режим и выво­
да простейшего rрафического изображения.

ПpUAiep 14.1. Вывод на эк,ран zориэонтальной прямой.


1Устаиоаиw rрафичесхий реzим BGA
IIIOV АН, 00h 1 ( 1) Фуикци11 :sадаии11 реаоа
IIIOV AL, 10h 1 (2)Графичесхий peJIИiol BGA
int 10h ; (З)Вы:sов BIOS
1Нарисуам пр~ ~ в цикле по Х
aov SI,l50 1 (4)Начаnьиа11 Х-координата
IIIOV СХ,ЗОО 1 (5)Чиспо точек по rори:sонтапи
line: pu.sh СХ 1 (б)Сохраним ero в стеке
IIIOV АН, ОСЬ ; (7) Фуикци11 вшsода пиксела
IIIOV .AL, 4 ; (8) Цвет J<:расиый
Вывод простейших графических изображений 71

JDOV ВН, 0 ; (9)Вкдеостраиица


JDOV СХ, Sl ; (10)Х-коордкиата (пер~ииаR)
JDOV DX, 175 ; (ll)У-коордкиата (константа)
int lOh ; (12)Выsов BIOS
inc SI ; (lЗ)Иикремеит Х-коордкиаты
рор СХ ; (14)ВосстАиовиы счетчик шаrов
loop line ; (15)Цккп И3 СХ шаrов
;Остаиовиы пporpawwy дпR наблмдеииR ре3уnьтата ее работы
JDOV АН, 08h ; (lб)ФуикциR ввода с клавиатуры бе3 :IIXa
int 2lh ; (17)8Ы30В DOS
;Перекпю~ видеоадаптер иа3ад в текстовый р~
mov АН, OOh 1 (18)ФуНКЦИR 3АДАИИR рехиw&
mov AL,OЗh ; (19)Текстовый реккм
int lOh ; (20)Выsов BIOS

В nредложениях 1... 3 с nомощью функции OOh nрерывания BIOS


IOb осуществляется nерек.лючение видеоадапrера в графический режим.
Поскольку номер режима заносится в байтовый perncтp AL, всего мо­
жет существовать 256 различных текстовых и графических режимов, из
которых на сегодняшний день использую~я (апnаратурой р83Личных
фирм) около ста. Режим 10h обеспечивает вывод графического изобра­
жения 16 цветами с разрешением 640х350 точек и широко используется
с видеоадапrерами EGA и VGA.
Изображение рисуется по точкам (в BIOS не nредусмоорено nро­
граммных средств вывода каких-либо геометрических фигур или хотя
бы линий, как нет и средств закрашивания областей экрана). Для выво­
да на экрiiН цвсшой точки (пиксела) используется функция ОСЬ nреры­
вания IOb. Эта функция требует занесения в perncтp AL кода цвета, в
ВН -номера видеостраницы, в СХ- Х-координаты выводимой точки в
диаnазоне 0 ... 349, а в DX- У-координаты точки в диаnазоне 0 ... 639. По­
скольку perncтp СХ используется, как счетчик шагов в цикле, для хра­
нения Х-координаты зарезервирован perncтp SI.
Прямая горизонтальная линия в примере 14.1 рисуется nyreм вызо­
ва функции ОСЬ в цикпе, в каждом шаге которого значение У­
координаты остается неизменным (175 в примере), а значение Х­
координаты увеличивается на 1 (nредложение 13). После завершения
цикла формирования изображения в программе nредусмоорена останов­
ка (nрещюжения 16-17) для того, чтобы nользова-n:ль мог, оставаясь в
графическом режиме, проанализировать результаты рабоrы программы.
Для остановки nрограммы используется функция DOS 08Ь ввода одного
символа с клавиа'I)'РЫ. Функция 08h, как уже отмечалось, не отобрцсает
введенный символ на экране и, тем самым, не искажает графическос
изображение. Нажаmе любой клавшnи (кроме уnрааляющих • Ctrl, Alt,
Shift и др.) возобновляет вьmолнение nрогра.ммы.
В конце рассматриваемого фрагмента nредусмоорено nсрекл:Ючение
видеоадатера в стандартный текстовый режим с номером ОЗh
(nредложения 18 ... 20). Если такое nсреJОПОчение не выnолнить, видсоа-
72 Статья 14

·дапrер останется в !р&фическом: режим:сt 'fiO м:ожет пом:сшатъ правиль­


ном:у ВЫПОJПIСНИЮ прИКJI8ДНЫХ проrрам:М.
Рассм:сnрим кратко парам:е1ры вызова функции ОСЬ прерывания
10h. В регистр ВН заноскrоя номер видсостраницы:t на каrорую выво­
диrся данная точка. Графический адатер EGA обеспечивает хранение и
аrображсние двух rрафических страниц. По умолчанию видимой
(8Ю'ИВной) делается страница О, однако рисовать изображение можно
как на видимой, так и на певидимой странице. Для переключсиня стра­
mщ предусмотрена функция OSh прсрывания 10h.
В регистр AL заноскrоя код цвета точки. Адатер поддерживает 64
цве'rаt хотя в каждый момент времени изображение на экране может со­
дер.хаm. только 16 цветов. Этот набор из 16 цветовt выводимых на экран
(цветовая палиrра), задается проrрам:мно и может логко изменяться.
При заrруэке машины устанавливается стандартная палиrра, коды цве­
тов каrорой приведсны в табл. 14.1.

Таблица 14.1. Коды цветов стандартной цветовой палитры EGA ·

Код Цвет Код Цвет


Нех Dec Нех Dec

о Oh Чep.IUIЙ 8 Bh Серый
1 1h СИний 9 9h ГОJIУбОЙ
2 2h Эе.п:еинй 10 .Ah Са.патовЬIЙ
з Зh ВИрiОSОВЬIЙ 11 Вh Светпо-бир10sовЬIЙ
4 4h I<расиЬIЙ 12 Ch РоsовЬIЙ
5 5h ФиопетовЬIЙ 13 Dh Светпо-фиопетовЬIЙ
6 бh Коричиевнй 14 Bh Же.п:тЬIЙ
7 7h Бе.пнй 15 Fh Ярко-бепЬIЙ

Теперь вы умее-rе выводить на экран точку и м:оже-rе при желании


сформ:ироватъ любой рисунок. Режим ЕОА можно использовать прак­
mчсски с любым современным видсоадапrером. Исключение составля­
ют JППIIЬ м:онохромныс адапrеры, имеющие специальное примсненис, а

'l'IUCJI:C устаревшие и почти не встречающиеся адапrеры СОА


Однако большинС'ПЮ из выпускающихся сейчас видеоадапrе~в аг­
носятся к классу SVOA (Super VOA). Хотя они и допускают использо­
вание режимов ЕОА и VOA, однако позволяют выводить rрафическис
изображения со значительно лучшими харакrсристиками. В таблице
14.2 приведсны некоторые режимы видсоадапrеров SVOA
К сожалению, SVOA не является стандарrом:t как ЕОА или VOA.
Хаrя стандарт ДЛJ1 SVOA был предложен ассоциацией по стандартиза­
ции в видеоэлектроникс (Video Electronics Standards Assotiation, или со­
кращенно VESA), 011 поддерживается большинством, но не всеми изro­
ТOBifl'CJlЯMИ ВИДе(ЩДIUrrеров.
Вывод простейших графических изображений 73

Если стандарт VESA nо.идерживается, то оnределенные им фунiЩИИ


заnисываются nроизводиrелями видеоадаnтеров в ПЗУ самого адаnтера.
Они называются расширением nрсрывания BIOS lOh - VESA BIOS
Extcntion или VВЕ. Для вызова фунiЩИИ VВЕ в регистр АН необходимо
заnис!П'Ь 4FЪ, а в регистр AL номер фунiЩИИ. При этом функция может
не вьmОJШитъся no нескольким nричинам. Она может отсутствоВIП'Ь в
вашей версии VВЕ. Может бьrrь и такая сmуация, nри которой в VВЕ
эта функция есть, но се не nо.идерживает апаратура видеоадаnтера. Если
VВЕ nо.идерживает му функцшо, то в регистре AL возвращается
значение 4Fh. Иначе возвращае-ооя другое число. В случае усnешного
вьmОJШения фунiЩИИ в AL возвращатся О, а nри ошибке - 1. Если в
регистре АН возвращается 2h, это означает, что данную функцшо не
nо.идерживает annapaтypa видеоадаnтера.

Таблица 14.2. Не~еоторые режUАIЫ видеоадаптеров SVGA

Раsрешение в пиксепах Копичество цветов, иs которых Ноыер


м::~:кио выбирать при в~о~~~оде ка рuюа
э:краи, то есть nапитра

800*600 256 103h


800*600 16777216 115h
1024*768 65536 117h
1280*1024 256 107h

Сnеюр хараперистик видеодатеров SVOA очень широк, nоэтому


составление nроrраммы, формирующей графическое изображение и
сnособной вывести его не на один конкретный видеоадатер а на любой
из заданной груnпы, особенно учитывая отсуrствие стандарта, может
nредставлять достаточно 1рудоемкую задачу. ФунiЩИИ VВЕ nозволяют
оnределить nm установленного видеоадатера и разрешенные гра­
фические режимы. Для nростоты nредnоложим, что исnользуемый нами
режим nо.идерживается видеоадатером и nосм01рим как изменкrоя

nриведенный выше фрагмент nрограммы вывода на экран горизонталь­


ной nрямой. Выберем режим IOЗh.

ПpUAiep 14.2. Вывод но Э"JЮН zоризонтальной прямой 11 режиме JOЗh SVGA


;Устаиовим rрафИ'Iеский реаим 103h SVGA
IIIOV АН, 41'h ; (l)Функция IIЫ:Soвa Video BIOS Bxtention
IIIOV AL, 02h ; 12 1ПодфУJОЩИя устаиовiСИ rрафИ'Iескоrо
;рuюа

IIIOV ВХ,103h ; (З)ГрафИ'IеСКИЙ pe.1DO& SVGA


int lOh ; (4)tlpeplolllaниe BIOS
с111р АН, О ; ( 5 1При oDDCбiCe
jne errDLea1 ; (6)nереход ка сообщение
;Устаиоаим 11 реrистре 150 таеnицм цветов sепекнй Ulleт максиwапьиой
;яркости
74 Статья 14

IIIIOV АН, lOh ;(13)Фуккци4 упраапеии4 реrистрами


;папитры
IIIIOV AL,lOh ; (14)По~tуихци4 устаковки реrистра
;цветов
IIIIOV ВХ,150 ; (15)Номер реrистра табпицы цветов(О­
;255)
IIIIOV DH,O ;(16)Иитеасиакост• краскоrо цвета (6
;бит)
IIIIOV CH,l27 1 (17)Иитексиакост• seneкoro цвета (6
;бит)
IIIIOV CL,O 1 (18)Иитексивкост• сикеrо цвета (6 бит)
J.nt lOh ; (19)Црер1118аиие BIOS
;Нарисуеw пр~ пики. в ЦJOCJJe по х

IIIIOV SI, 0 1 (20)Начап•ка4Х - коор~ата


IIIIOV СХ, 800 ;(21)Чиспо точек по rориsоктапи
lJ.ne1 push СХ 1 (22)Сохраким ero в стеке
IIIIOV АН,ОСh ; (23)Фуикци4 Blll8o~a пиксаnа
IIIIOV AL, 150 ;(24)Цает sепекый
IIIIOV ВН,О ;(25)8кuеостраиица
IIIIOV СХ, SI 1(26)Х- коор~ата (переwекка•)
IIIIOV DX, 300 - коор~ата
1 (27)У (константа)
int 10h ;(28)ВIIIsoв BIOS
inc SI 1 (29)Иихремент Х - коор~каты
рор СХ 1 (30)Восстаноапеиие счетчиха •aroa
loop line ; (31)Цикп иs СХ •aroa
1Остановиw пporpawwy дп4 ка~ени• реsуn•татоа ее работы
• IIIIOV АН, 08h 1 (32)Фуикци• аао~а с хпааиатуры беs аха
int 2lh ; 133) Выsоа DOS
;Пере~ виаео~аптер каs~ а текстовый раккм
IIIIOV АХ, 3 ; (34)Устаноака текстоаоrо рекима
int lOh ;(35)Выsоа BIOS
:i!ll' output ; (36)
8r.n&e8ll
JIIOV АН, 09h ; (37) Фуикци• alll8o~a соо68ени•
IIIOV DX,offset messaqel; (38)Сwещеиие сообщени4
int 2lh ; (39)ВIIIsoa DOS
out:put: 1

Сначала необходимо установИ'IЪ 1ребуемый режим работы. Для


эroro восnользуемся функцией 02h. Заrрузим в регистр АН • 4Fh, в ре-
111С1Р AL • 02h, а в регистр ВХ номер режима VESA и вьmолним преры­
ванис BIOS JOh. Если графический режим установлен, ro после вьmол­
нения прерывания в регистре АН возвращается О. Поэrому в предложе­
нии S мы проверяем содержимое регистра АН, и в случае неудачи вы­
водим соообщснис об ошибке· предложения 37, 38, 39.
Перед выводом отрезка прямой нам tребуется опредСJIИ'IЪ се цвет.
Поскольку мы установИЩt режим 103h, в котором испОJIЬЗуется 256 цвс­
rов, ro определим цвет с помощью фунlЩИИ 1Oh установки регистров
namnpы. Вызов эrой функции· вьmолняется в предложениях 13 - 19. В
предложении 14 ОПреДС.ЛЯетсJr номер подфунlЩИИ, тоже lOh, каrорая
позВОЛJiет непосредственно задать цвет для JDOбoro из 256 реmстров
Подпрограммы 75

таблицы цветов. И~тнсивности красной, зеленой и синей составляю-
щих задаются в регистрах DH, СН и CL. Поскольку мы решили вывсс­
'IИ линшо зеленого цвета с максимальной яркостью, то в рсrистр СН
заносим максимальнос значение 26·1=127, а в остальные регистры ну­
ли. Номер регис'lра таблицы цветов определяем в рсГИС'JРС ВХ.
Остальные предложения практически идеН'IИЧНЫ соответствующим
предложениям фраrмекrа, приведеиного в примере 14.1, за ис­
юпочением предложений 20, 21, 24 и 27. Поскольку линшо будем рисо­
вать с самого края и до конца экрана, в предложении 20 в регистр SI
заносим О, а в предложении 22 в регистр СХ - 800. Чтобы располоЖИ'IЪ
линшо по середине зкрана при выбранном разрешении в 600 точек по
верrикали, в предложении 27 в регис'lр DX заносим 175. Для определе­
ния цвета в AL заносим номер регистра таблицы цветов, содержимое
которого мы определили в предложениях 13 ... 19, а именно 150.

Статья 15
Подпроrраммы

В предыдущих примерах нам удалось ПОС'JРОИТЬ простейшсе изоб­


ражение, вюпочив фрагмент вывода на экран точки в ЦИЮI. Однако при
ПОС'JРОСНИИ более сложных изображений с не столь упорядоченным из­
менением координат про1рамма окажется очень IрОМоздкой. Суще­
ственного упрощения C'JPYJCI'YPЫ про1раммы можно достичь, используя
в ней подпро1раммы.
Модифшuq>уем про1рамму из примера 14.1, разбив се на процедуры
и организовав в ЦИЮiе обращение к подпроrрамме с персдачей ей пара­
метров. Поскольку введение процедур несколько изменяет струкrуру
про1раммы, пример 15.1 приведен не фрагментарно, а полносп.ю,
вюпочая описания сегментов.

Пример 15.1.Вывод но экран горизонтаАьноiJ llpJUioil с nuощью llti01IJI02IНIAUIЬI.


text seqment' code' ; ( 1) Haч&llo се1'18КТ& коwакд
ass\.llll.e СЗ: text, DЗ :dat 1 (2)
;Подпроrрамwа вывода одной точки. Пар&Nетрк nри вкsове каход~тс• в
;~чеЙJСах ПАМRти: color - цвет точки, vpaqe - аидеостраиица,
IX - Х-коордиката, у- У-координата
draw proc ;(З)Об~яапеиие npoцeдypк­
;noдnporpuea~
76 Статья 15

IIIOV АН, OCh ; ( 4) Функция ISЬП!Iода DИJCce.na


IIIOV AL, color : ( S) Цвет
IIIOV ВН,vраqе ; (б)ВИдеостраиица
JDOV СХ, х ; ( 7) Х-коордииата
IIIOV DX,y : (81У-коордииата
int 10h : (9)Bы3ozs BIOS
ret ; (10)Коыаида !IIIIXOдa И3 DOДDp01'pU881
drav endp : (111Кокец процедуры
;Гпавиая процедура, с которой иачииается zsыпопиеиие проrраммы
main proc ;(12)Об~яzsпеиие rnazsиoй процедуры
JDOV AX,data ; (13)Икициапи3аци11 сеrмеитиоrо
IIIOV DS,AX 1 (14)реrистра DS
; Устаиоzsиы rрафичесхий реzим EGA
JDOV АН,ООh ; (15)Фуикция 3адаиия режима
IIIOV AL, 10h ; (161Графичесхий реzим EGA
int 10h ; (17)ВЫ3011 BIOS
;Нарисуем rориsоитапЬИУ» пиии» 11 цихпе по Х
IIIOV СХ,300 ; (181Чиспо точек по rори3оитапи
line: push СХ ; (19 1Сохраииы ero 11 стеке
call drav 1 (20)Выsов noдпporpU881
inc х : (211Иикремоит х-коордииаты
рор СХ ; (22)Восстаио!IИЫ счетчих шаrов
loop line ; (23) Цихп иs СХ шаrов
; Остаио!IИЫ проrр~ дnll иаб.mодеиия реsупьтата ее работк
JDOV АН, 08h ; (24 1Функция II!II')Дa с хпа-атуры
int 21h 1 (2SIBЫ301S DOS
;Перекпмчим -.аеоадаnтер ка3ад в текстоzsнй pezиw
IIIOV АН,ООh 1 (26)Фуикция SадАИИII pezиwa
IIIOV AL,03h ;(271Текстовнй pezкw
int 10h ; (28 1Вы3ов BIOS
IIIOV АХ, 4C00h ; (29) Завершекие проrраммы
int 21h ; (301
main endp ; (31)Коиец rпавиой процодурм
text onds ; (321Коиец сеrмоита хомакд
data segaent ; (331Начапо соrмеита даиннх
х dv 150 ; (341Текуща11 Х-хоордииата
у dv 175 ; (35)Текуща11 У-координата
color dЬ 14 ; (361Цвет точек
vpaqe dЬ О ; (371ВИдеостраиица
data ends ; (381Коиец сеrмеита даиинх
stack aegaent stack ;(391Начапо сеrмеита стека
dv 128 dup (01 ; (401Стех
stact ends 1 (411Коиец сеrмоита стека
end main ; (421Коиец техста пporpU881

Наша программа состокr теперь из двух процедур • главной с име­


нем main и процедуры-подпроrраммы с именем draw. Каждая процедура
начинается опервrором proc, перед которым указЬIВ&С'rоя имя процеду­

ры, а заканчивается операюром endp (end procedurc, конец процеду­


ры)(пары nредложений 3, 11 и 12, 31). Порядок проце.цур в проrрамме в
больmинсmс случае не имеет значения, однако имя главной процедуры,
с которой начинается ВЫПОJПiсние проrраммы, должно бьrrь указано в
качссmс операнда дирс1СJ11ВЫ cnd, завершающей -мкст программы
(nредложение 42).
Подпрограммы 77

Подпрограммы вызываются оператором call (вызов); каждая под­


программа должна заКанчиваться командой ret (retum, возвргr), которая
передает управление в точку возврата, т.е. на команду вызывающей
программы, следующую за командой call.
Подпрограмма draw выводит на экран одну точку. В качестве вход­
ных параметров она должна получить две координаты точки, ее цвет, а
также номер видеостранJЩЫ, на которую выводится изображение. В
языке ассемблера нет установленных правил передачи параметров под­
программе. Их можно передать через регистры общего назначения, стек
или ячейки памяти. В примере 15.1 испОJIЪЗуется последний способ, не
самый быстрый, но наиболее наГлядный. Для хранения и модифиtсации
параметров в сегменте данных предуСМО'JРСНЫ ячейки х, у, co1or и vpase.
В данном примере вывода горизонтальной линии в трех ячейках хра­
нятся константы, и лишь ячейка х модифицируется.
При использовании подпрограммы основной ЦИICJI уррощастся.
ФаiО'И'Iески в нем лишь две содержательные строки: вызов подпро­
граммы draw и инкремент Х-координаты в ячейке х. Однако сохранение
в стеке и восстановление регистра СХ является обязательным, потому
Ч'Ю он используется в подпрограмме для заданияХ-координаты.
Выделив вывод точки в подпрограмму и существенно упростив ЦИКJI
основной проrраммы, мы облегчили задачу ее модификации. В примере
15.2 показано (уже фрагментарно), как мо:жно, в допОJПiение к горизон­
тальной, вывести на экран пахлонную и вертикальную линmо.

Прuер 15.2. Вь~tюд но экран nywra линий.


;Нарисуем rориsонтапън)'IО .nиJOOO, идУ111УJ0 и:s иачапа коордива'l'
шоv СХ,640 ; (l)Чиспо точек по rори:sоитапи
line: puah СХ ; ( 2 ) Сохраниы ero а стеке
call drav ; ( 31 Вы:sоа подпроrрuое~
iьс Х 1 ( 41 ИнкремеНТ X-KOOp.IIIOiaТЫ
рор СХ ; ( S 1Воеставовик счет'IИК ID&r08
loop liьe ; ( 6) Цих.n и:s СХ 111&1'08
1 Нарисуем IIAJUJ0-)'10 .JIИIIJIID
шоv х,О ; (7)Восстаиовик начапъное sна•емке Х
воv CX,3SO ; (8)Чиспо точ•к
linel: puah СХ 1 (9)Сохраниы ero а стеке
puah х 1 (10)0тправик sначе-е Х
рор у 1 ( 11 ) 11 IJЧeЙJ<y У
call drav ; (121Bы:soll подпроrрuое~
inc х ; (131Инкремеит x-кoop.IIIOI&Тbl
рор СХ 1 (14)Восстаиоаик счеТ'IИК ID&I'08
loop ·linel 1 ClSIЦиx.n н:s СХ 11&1'011
воv СХ, 640 1 (16)Чиспо 'I'ОЧ- по rориsонта1111
;Нарисуем 8ертюсапън)'IО .JIИIIJIID
DOV х,о ; (171Восстаиоаик исходное :sна•е-е Х
воv у, о ; (18)Восстаиоаик исходное ана•емке У
DOV СХ, 350 1 (19)ЧJCcno 'I'O'IOK
line2: puah СХ ; (20)Сохраним ei'o 11 cтe-
call drav ; (21)81Do8 иодпроrр.-
78 Статья 15

inc у 1(221Иикремент У-координаты


рор СХ 1 (231Восстаиоаиы счетчик шаrов
loop line2 1 (241Цикп иs СХ шаrов
; По.п11 дAIUIIIX
х dv О 1 (251Teкymall Х-коор.цииата
у dv о ; (261Teкymall У-координата
color dЬ l4 1 (271ЦJsет точек
vpage dЬ О ; (281Видеостраиица

Рассм01рим некоторые важные детали программ 15.1 и 15.2.


В поля:х: данных программ имеются 4 ячеЙIСИ с параметрами подпро­
граммы. Две из них (co1or и vpage) описаны с помощью уже знакомой
нам дирсЮ'ИВЫ db (определить байт); для двух других: (х и у) использо­
вана дирсrсrиваdw (defme word, определить слово). Почему дирсЮ'ИВЫ
разные? Дело в том, что числа из ячеек co1or и vpage цо ходу выполне­
ния программы загружаются в байтовые реrис'lры AL и ВН; числа из
ячеек х и у загружаются в 16-разрядные (славные) реrис'lры СХ и DX.
Данные, описанные в программе, должны участвовать в операциях в со­
ответствии со своими описаниями. Ассемблер фиксирует ошибку если,
например, данное, описанное как байт, участвует в операции со словом.
По~му при определении данных следует заранее подумать, в какие
реrис'lры э-m данные будуr загружаться.
В предложениях 10-ll примера 15.2 содержимое ячеЙIСИ х копирует­
ся в ячейку у через стек. Вообще rоворя, здесь надо было бы вьmолнить
команду mov у,х. Однако в микропроцессорах 80х86 запрещена опера­
ция непосредственной перссылки операндов из одной ячеЙIСИ памяти в
другую. Такую перссылку можно осуществить только с помощью про­
межуrочноrо perиC'lpa

mov АХ,х
mov у,АХ

или через сrек, как ~ сделано примере 15.2 (можно было бы также
воспользоваться командой перссылки C'lpOK movs, но это сложнее).
Программа вывода на экран трех линий состоит из трех схожих по
C'lJ>YJCI'YPC циклов. Начальные точки этих циклов обозначены схожими,
но все же различающимися метками line, line1 и line2. В исходном reк.c­
re программы не должно бьrrь нескольких одинаковых меток или имен
ячеек памяти (даже если они относятся к разным процедурам или про­
граммным сегментам).
Каким должно быrь взаимное расположение главной процедуры и
подпрограмм? В обоих примерах главная процедура и процедура­
подпрограмма располагались друг за друrом, причем первой была опи­
сана процедура-подпрограмма. Такая С'lрупура не явля:ется обязатель­
ной. Процедуры мoryr располагаться в программе в любом порядке, при
Э'rом их можно вкладывать друг в друга. Например, возможен такой ва­
риант C'lpYICI}'PЫ проrрамt.IЫ:
Подпрограммы 79

text segment 1 code 1 1Нача.nо сеrwента коиаид


шain proc 1Об~яапеике rпавной процедуры
;Текст rпавной процедуры
IIIOV АХ, 4C00h ; Завершекие nporpuaA~
int 2lh
draw proc ;Об~яааеике процедуры-подпроrр&NNК
;Текст подпроrраwwы
ret 1 JCOМAИJia ВЫХОда ИS ПODDpOrpuaAII
draw endp ;Конец nроцедуры
шain endp ;Конец rпааной процедуры
text ends ;Конец сеrwента КОМАИJI
end шain

Здесь процедура-подпрограмма draw располагается внуrри главной


процедуры main после строк завершения программы (вызов функции
DOS 4Ch). Последний момент является принципнально важным. Под­
программы следует располаrать таким образом, чтобы они не могли
начать выполняться "сами по себе", без вызова командой call. Привс­
денный пример удовлетворяет эrому 1ребованию. Дейс-mительно, вызо­
вом функции завершения 4Ch управление персдается системе, в нашу
программу уже никогда не вернется, и строки, сrоящие после команды

int 2Ih сами по себе выполняться не будуr. В ro же время привсденный


ниже пример грубо неверен:

text segment 'code 1 ; Начало сеrмеита комаИJI


шain proc 1 О&ь11апеике rпавиой процедуры
draw proc ;Об~явпеике процедуры-подпроrрАNWН
;Текст подпроrрамwы
ret ; Комаида аыхоnа иs подпроrрамwы
draw endp ,Конец процедуры
;Текст rпавной процедуры
IIIOV АХ, 4COOh ;Завершение проrрамwк
int 2lh ;
-in endp ;Конец rпааной процедуры
text ends ;Конец сеrмеита комаиn
end -in

В такой программе после ее шсmвизации сразу же начнется выпол­


нение процедуры draw. Сq>ашно здесь не ro, что эта процсдура выпол­
нкn:я "вне очереди", когда еще не установлен графический режим и не
настроены параметры подпрограммы, а ro, что она завершкn:я выпол­

нением команды ret, обра'П{ОЙ по аmошснию к команде call. Однако


команды call у нас не было и такая "непарная" команда rct приведет к
зависанию системы. Для roro, чтобы понять, что здесь происходит, на­
до разобJЖГЬСЯ в механизмах вызова подпрограмм и возврата из них.
Эrот вопрос будет рассмоrрсн в следующей статье.
Наконец, последнес замечание связано с ролью процедур вообще.
Вспомним пример 1.1. В нем процедур ко было, а в качестве точхи вхо­
да в программу фиrурировала метtаi begin. Лроцс.цурьt но Являются обя-
3аТСЛЬНЫМ элемсiПОМ программ на языке ассемблера, они лишь
во Статья 16

·повьппают их наглядность. Пример 15.1 с подпроrраммой тоже можно


было ПОС1рОИТЬ без применения процедур, обозначив точки входа в
главную проrрамму и подпроrрамму метками:

text aegment 'code' ;Начапо се~мента команд


drav: ;Точка BXORa В ПОRПроrр~
;Текст подпро~рамwн
ret ; Коwанда внхода иs подпро~р.-
~~~ain: ; Точка входа в ~.naaнYJO про~р~
;Текст ~.павной процедуры
call drav ;Вкsов подпро~раымы

IIIOV AX,4C00h ;Завершение про~рамwк


int 2lh 1
text enda ;Конец се~wента коwанд
end ШAin

Исходный "nЖСТ проrраммы палучится даже короче, так как из него


будут изъяты предложения proc и endp (заrрузочпый модуль проrраммы
ел эroro не изменится). Важно rолько соблюспl условие, о кагором уже
говорилось выше: подnроrраммы ДОJIЖНЫ размещатьсЯ таким образом,
чтобы переход на их ВЫПОJПiение осуществлялся иск.лючиrельно с по­
мощью команд call. Попьrrка ВЫПОJПIИТЬ подnроrрамму, как фрагмент
главной проrраммы, с бОJIЬmой вероятностью приведет к зависанию си­
стемы на команде ret.

Статья 16
Механизм вызова подпроrрамм

Рассмотрим механизм выnОJПiения конкрсm~ых команд call draw и


rct из примера 15.1. На рис. 16.1 приведсны фрагменты заrрузочноrо
иодуu проrраммы 15.1 с указанием расположения некаrорых команд,
их кодов, смещений, мнемонических обозначений и описания их дей­
ствия. Показана 1'8JOI[e часть сеrменrа данных.
Сегмент команд начинается с процедуры draw. Первая команда этой
процедуры mov АН,ОСЬ имеет поэrому смещение (аrносительный адрес
в cerмetm команд) ООООЬ. Процедура draw занимает 14h=20 байт с ел­
носитсльными адресами ел ООООЬ до 001ЗЬ. Последней командой проце­
дУРЫ draw JIВJUIC'roЯ однобайтовая команда ret с кодом СЗh.
Механизм вызова подпрограмм 81

CNellleкиe Код Пpeд.IJOJI:811ИII Дейстаие


IСОNАИДЫ проrрuем IСОNАИДЫ

text ae~nt 'code'


aaaume CS:text,DS1data
0000 draw proc
0000 В4 ОС IIIOV АН, OCh

0013 С3 ret ------+ иs стеха 0026 ____. • IP


0014 draw endp
0014 ~~~ain proc
0014 88 4476 IIIOV АХ, data
0017 8Е D8 IIIOV DS,AX

0023 Е8 FFDA call draw 1) IP•0026h ____. • стек


21 0026h+FFDA•OOOO -+ 8 IP
0026 FF Об 0000 inc х

003С IIIAin endp


text enda
data aegment
0000 0096 х dw 150
0002 OOAI' у dw 175

0006 data enda


Рис. 16.1. Фрагменты загрузочн020 мrЮум nро2раммы 15.1 с noяCНRIOщeiJ информацией.

За процедурой draw распалаrается главная процедура main. Ее пер­


вая команда mov AX,data имеет смещение 0014h. Код команды включает
код операции mov (B8h) и значение имени data, равное сегментному
адресу сегмента данных. При загрузке проrраммы под управлением 01'-
ладчика CodeView сегментный адрес data оказался равным 4476h.
Команда call draw расположена по адресу 0023h. В ее полный код
входит код операции call (E8h) и адрес процедуры draw, на каrорую на­
до осуществить переход. Эrот адрес записан в виде смещения к началу
процедуры draw относиrельно текущего содержимого IP, т.е. относи­
тельно адреса следующей команды (в нашем случае команды inc х).
Смещение это знаковое и в цанном случае сnрицательное, так как про­
цедура draw располагается до процедуры main. Поскольку адрес draw ра­
вен О, а адрес следующей команды равен 26h, в коде команды записано
число -26h, которое по правилам записи сnрицательных чисел выра­
жается кодом FFDAh (знаковые числа будут рассмсnрены в cmm.e 36).
Главная процедура занимает 18h=24 байт, а первый свободный байт
после конца этой процедуры имеет смещение ООЗСh. На этом за­
канчивается сегмент команд. С ближайшего адреса, кра:rного 16 (44760h
в нашем случае), начинается сегмент данных. Оmосиrельные iщреса в
нем опять начинаются с О, поэтому смещение первой переменной х
равно О, смещение следующей переменной у - 2 и т.д. Весь се1·мент
данных занимает всего 6 байт.
82 Статья 16

Вернемся к рассмоорению команд call и ret. При вьшолнении ко­


манды call процессор помещает а.црес возврата (содержимое IP, т.е. ад­
рес следующей команды) в стек, а в IP заносит относительный адрес
процедуры draw, который находится суммированием текущего содержи­
мого IP и смещения, записанного в коде команды call. В резульnrrе
указатель стека SP смещается вверх на одно слово, а процессор перехо­
дИТ на выполнение подпроrраммы.
Команда ret выполняет обраmую операцию - извлекает из верхнего
слова с-rека (с восстановлением исходного состояния указателя стека
SP) а.црес возврата и заrружает его в IP, в резульnrrе чего процессор
возвращается к выполнению вызывающей процедуры.
Из сказанного ясно, что если в подпроrрамме используется стек, с
ним надо работать очень аkК.уратно: все, что заносиrся в стек в процес­
се выполнения подпроrраммы, должно быть обязательно снято с него
до выполнения команды ret, иначе эта команда извлечет из с-rека и за­
rрузит в IP не адрес возврата, а какое-то данное, что заведомо приведет
к нарушению выполнения проrраммы.

Рассмооренный нами вызов подпроrраммы носит название прямого


ближнего (или внуrрисеrментного) вызова. Прямым такой вызов назы­
вается потому, что адрес перехода хранится непосредственно в коде ко­

манды (а :по, в свою очередь, получилось потому, что мы указали в


качестве операнда команды call имя подпроrраммы). Если бы адрес
подпроrраммы хранился в каком-то другом месте (именно, в регистре
или в ячейке памяти), то вызов бьm бы Еоевенным. Мы столкнемся с
Еоевенными вызовами подпроrрамм в последующих статьях. Вторая ха­
рахrериС1111Са вызова говорит о том, что вызываемая подпроrрамма на­
ходиrся в том же сегменте, что и вызывающая процедура. В эrом случае
JliiЯ перехода на подпроrрамму надо знать лишь "половину" полного ад­
реса подпроrраммы, именно, относительный а.црес точки перехода.
Сегментный а.црес остается тем же; он не фшурирует в ctpOJCC вызова
подпроrраммы и аrсуствует в коде команды. В дальнейшем мы рас·
смотрим и другой ВИд подпроrрамм - дальние подпроrраммы, д1U1 об­
ращения к которым следует применять мс.ж:сеrмекmьrе вызовы.
nрвобраэованив шестнадцатеричных цифр в симвапы 83

Статья t7
Иреобразование mеетиадцатеричиых цифр
в символьную форму

При аrладl(С сложных проrрамм, таких, как обработчики nрерыва­


ний, драйверы и др., возникает необходимость динамического, no XOJJY
вьmOJПieHWI аrлаживаемой nроrраммы, вывода на экран содержимого
реmстров nроцессора ШIИ ячеек nамяти. Такого рода информацию
удобнее всего nолучать в 16-ричной форме. Однако, как мы уже выяс­
нили ранее, на экран должны nостуnать не числа, а коды ASCII выво­
димых цифр. Таким образом, возникает задача nреобразованWI
двоичного 16-битового числа в четыре 16-ричные цифры, заnисанные в
символьной форме. В настоящей статье будет раёсмотрена nервая часть
этой задачи - nреобразование одной 16-ричной цифры в символьную
форму. Преобразование в символьную форму всего 16-битовоrо числа
будет оnисано в слеJJУЮщей статье.
Одна 16-ричная цифра оnисывает 4 двоичных разряда. Мы должны,
в зависимости ar содержимого ~ четырех двоичных разрядов, nо­
лучать код ASCII соответствующей 16-ричной цифры ar 'О' до 'F. Под­
nроrрамма, реализующая му оnерацию, nриведсна в nримере 17.1.

Пример 17.1. Пpeo6pQ3081Jнue шестнадцатери'IНой цифры в ASCII


hexa.sc proc
;nодпроrраыыа п~ени• симвопьаоrо предстаапеаи• •етмрехбитовоrо
; чиоnа.На входе 1 исходкое ЧИСJJО в Мllадшей поповиае AL, адрес
строJСИ, худа аадо поместить ре:sупьтат, в DS:SI. На выходе:
;АSСII-предстаапеаие п~еааоrо чиоnа в ПАNRТИ по адресу DS:SI
;Исходное coдepZИNDe реrистра AL ра:sрушаетс•
pu.sh ВХ ;Сохрахим испопь:sуем.ай .реrистр
JDOV ВХ, offaet tЫhех;ВХ•адрес таб.пицы трааоn•ции
xlat ; !CoiiAJiдa таб.шnаой трааоn11ции
IIIOV [SI] ,AL ;Сохрахим ре:sупьтат
рор ВХ ; Воеставовик реrистр ВХ
ret ; 8оsврат в JUDIIIIUIII)IIO пporpuefV
hexaao endp
ШAin proc

IIIOV AL,15 1 rtpeoбpa:sy•юe чиоnо


IIIOV SI,off.set re.sult;Hacтpoиы SI
call hexasc ;Выsов noдnporpawиы
IIIOV АН,О9h ; Фуахци11 вывода строJСИ
84 Статья 17

mov DX,offset result


int 21h

.-ain endp
; По.п11 .zrаииых
tblhex dЬ '0123456789АВСDВ!''
result dЬ ;Внао-..й тeJCc:!:t'
'*h', 10, 13, '$'

Пусть исходное число находится в младшем nолубайте реrис1ра AI".


Для преобразования этого числа в код ASCII мы воспользуемся коман­
дой табличной 1рансляции xlat, которая позволяет осуществить выборку
байта из таблицы по его индексу. Эта команда для своей paб<m.r 1ребует
Нас'lрОЙКИ 1рех реГИС1рОВ. В реrиС1рах DS:BX должен находиrься пол­
ный двухсловвый адрес таблицы 1рансляции (естественно, в реrис1ре
DS - сегментный адрес, а в perиC"Ipe ВХ - аmосительный), а в реrис1ре
AL- смещение в таблице к выбираемому бай1у, т.е. его индекс. Коман­
да xlat выбирает из таблицы указанный байт и возвращает его в регис1ре
AL, разрушая тем самым его исходное содержимое. Условимся, что nри
вызове подпроrраммы преобразования hexasc в perиC"Ipe AL должно на­
ходиrься исходное преобразуемое число, а в реrис1ре SI - адрес ячейки
памяти для результата преобразования.
В таблице с именем tblhex мы запишем (по байтам) символьные
представления шестнадцатеричных цифр от 'О' до 'F. Для результат.!
преобразования предусмоорим е1р0ку result, в первый байт которой бу­
дет пересьmаться полученный символ. Для наглядного представления на
экране результата работы программы с1р0ка result дополнена знаком
шестнадцатеричного числа "h", кодами возврата каретки и перевода
С1рОКИ, а также завершающим для функции DOS 09h символом"$".
В главной процедуре main мы засЬVIаем в региС'Iр AL произвольнос~
число от О до 15, в реrис1р Sl - смещение поля result и вызываем под­
программу hexasc. Далее для контроля nравильиости проведеиного npe ..
образования е1р0ка result выводится на экран.
Рассмоорим теперь рабо1у процедуры hexasc. Поскольку это проце ..
дура общего назначения, которая может быть вызвана из любого места
проrраммы, ее надо написать таким образом, чтобы она не нарушатL
ход вьmолнения вызывающей программы. Для этого в первом же пред··
ложении процедуры сохраняется в стеке используемый в ней регистр
ВХ. Далее ВХ нас1раИВ8етсЯ на смещение таблицы 1раRСЛЯЦИН. По­
скольку в perиC'IpC
AL уже находится nреобразуемое число, которое,,
согласно построению таблицы tЬlhex, ЯВ11Яется индексом требуемого
символа, можно выполнить команду xlat. Результат nреобразования ИЗ•
реrиС1р8 AL отправляется в ячейку памяти, на которую указывает ре·
ГИС'Iр SI. Обозначение (SI) означает, что адресуется ячейка памяти,
смещение которой находится в perиC"Ipe SI. Такой способ адресации но­
сит название косвенного (более конкреmо - косвенного индексного,
Првобраэование двоичных чисел в символьную форму 85

ПОСКОЛЬку ДЛЯ адресации ИСПОJIЪЗУСТСЯ ОДИН ИЗ IUIДeКCHЬIX реГИС1рОВ).


Далее воостанавiiИВiiется сохраненный реrие1р ВХ и командой ret
управление передастся в ВЫ3ывающую проце.цуру.

Небольшое 38Мечание оmосиrельно сохранения реrие1р0в. Ках


правило, в начале подпрограммы сохраняются, а в конце восстанавли­

ваются re реrие1ры, содержимое которых разрушаt\ТСЯ в процессе рабо­


ты подпрограммы. Обычно это не оmосится к: реrие1рам, чере3 которые
передаются параметры. При этом в 3а8Исимости от алгоритма подпро­
граммы содержимое реrие1р0в с параметрами может сохраниrься, но

может и разрушиться. У нас получилось, ч-rо в процессе выполнения


подпрограммы hexasc исходное· содержимое реrие1ра AL, чере3 которые
передастся преобразуемое число, разрушается. Эrо обстоятеJIЬС1110 сле­
дует иметь в виду при вк:лючении данной подпрограммы в программ­
ный комплекс.
Написав потtый текст программы, выполните ее несколько раз, 3&-
нося в реrие1р AL разные чИсла. Если Э111 И3менения ВВОДАТСЯ в исход­
ном тексте, каждый раз программу следует 38НОВО транслировать и ком­
поновать. Можно ПОС1)'ПИТЬ иначе - 3аПУСТИ'IЪ программу под управле­
нием отладчика и в нем после выполнения команды основной процеду­
ры mov AL, 15 И3менятъ содержимое регистра AL.

Статья 18
Преобразование беззнаковых двоичных чисел
в символьную форму

Рассмотрим rеперь программу преобразования в символьную форму


всего 16-биrового числа. Подпрограмма hexasc И3 предыдущей СТВ1'ЬИ
преобразует в 16-ричную цифру младшую четверку биrов реrие1ра AL.
Полное 16-биrовое слово содержит четыре четверки биrов. Таким обра­
зом, нам нацо последовательно прttложить проце.цуру hexasc ко всем
Э111М четверкам, предварительно выделяя их ю всего слова и помещая в

младший полубайт реrие1ра AL. ЭJу операцию выполняет подпрограмма


binasc (пример 18.1), которая, выделив очередную четверку биrов и
установив указатель Sl на соответствующий байr выходной C1p0tal, вы­
зывает подпрограмму hexasc для получения одной 16-ричной цифры.
Таким образом, программа 18.1 содержит, кроме основной проце.цуры
86 Статья 18

main, две процсдуры-подпроrраым:ы и является одновременно ШJJIЮ­


С'JР&ЦИСЙ IШОЖСННЬIХ ВЫЗОВОВ ПОдпроrрамм.

Пример 18.1. Прео6JЮ3ование Oгourutoгo 'ШСI/а t1 16-ри'IН)'ю символьную форму


hexaac: proc:
; На вхоае: ЧиQ.IIo 11 NJiaдllleй по.п:овиие AL
;А.цр~с: с:тро101, куаа иаао поыес:тить реsу.пьтат, 11 SI
;СМ. прJО48р 17.1
ret
hexaac: endp
binaac: proc:
;Поапроrрамма преобраsоваиия авоичиоrо с:пова 11 16-ричиую
; с:JD~Во.n:ьиую фо~. При выsове: АХ•преобраsуем::>е "'Иc:no,
;DS:SI•aapec: с:троки, куаа поwещаетс:я реsу.пьтат преобраsоваиия
pu.sh СХ ; (11 Сохраины ис:попьsуе.wый реrис:тр
pu.sh АХ ; (2) Сохраиим наше чис:по в' с:теке
and АХ, OI!'OOOh ; ( З 1Вы;це.пиы с:таршуJО четверку битов
шоv CL,12 ; (4)Счеrчик сдвиrа
ahr АХ, CL ; ( 5) Сдвиr вправо на 12 бит
call hexa.sc ; (б)Преобраsуем в симвоп и отправим
;по ааресу {SI]
рор АХ ; (?)Вернем в АХ ис:ходное чис:по
pu.sh АХ ; (8)И снова с:охраиим в стеке
and AX,O!'OOh ; (9)Вы;цепим вторую четверку битов
шоv CL,S ; (10)Счетчик савиrа
shr AX,CL ;(ll)Сдвиr вправо на 8 бит
inc SI ; (12)Сдвинемся к спедующему байту в
; (lЗ)строке реsу.пьтата
call hexasc ; (14)Преобраsуем в симвоп и отправим
;по ааресу [SI]
рор АХ ; (15)Вернем в АХ исходное чиспо
push АХ ; (lб)И снова сохраним в стеке
and AX,OJ!'Oh ; (17)Вы;цепим третью четверку битов
шоv CL,4 ; (18)Счетчик сдвиrа
shr AX,CL ; (19)Сдвиr вправо на 4 бита
inc SI ; (20)Сдвинеыся к с:педующему байту в
;строке реsу.пьтата

call hexasc ; (21)Преобраsуем 11 симво.п: и отправим

;по ааресу [SI]


рор АХ ; (22)Верием 11 АХ исходное чиспо
pu.sh АХ 1 (2З)И снова сохраним в стеке
and AX,OI!'h 1 (24/Вьще.пкм младшую четверку битов
inc SI ; (25)Сдвииемся к спеаующему байту в
;строке реsу.пьтата

call hexasc 1 (26)Преобраsуем в симвоп и отправим

;по ааресу [SI)


рор АХ ; (27)Восстаиовим стек
рор сх 1 (28)Вос:отаиовим реrистр сх
ret ;(29)Воsврат а выsвавшую процедуру

binaac endp
JU.in proo
810V АХ,92C4h ;Преобраsуеuое чиспо
DIOV SI,offaet result;Hacтpoим SI
oal1 binasc ;Выsов nодпроrра.84Ы
Преобраэование двоичных чисел в симвапьную форму 87

JIIOV АН, 09h ; ФуиJщюк 81111ода етроiСИ


JIIOV DX, o.tfaet reau.lt;Aдpee 81111Од108)Й етроJСИ
int 2lh

шain endp
; По.п11 дiUUIJiiX
reau.lt с:\Ь '****h',l0,13,'$';BIIIIIo.IDDAIЙ текст
tblhex с:\Ь '0123456789AВCDEF'

Пусп. исходнос число находится в регистре АХ.. Поскольку нам


придется многократно обращаться к нему с целью выде.ления четверок
биrов, оно сразу сохраняется в стеке (предложение 2). Перед этим со­
храняется в стеке содержимое используемого в подпроq>аМме регистра

СХ, чтобы подпрограмма не нарушила рабаtу основной проq>аМмы, в


которой этот регистр тоже, возможно, исполмустся. Команда ло­
гического умножения and (предложение 3) обнуляет все биrы первого
операнда, в данном случае АХ., сооrветствующие сброшенным биrам ее
вrорого операнда (в данном случае числа FOOOh) и оставляет без изме­
нения остальные биrы первого операнда (рис. 18.1).

ИCXOJtHOe ч:исnо 9 2 С 4h (lб-ричное npe_tc'laвneнкe


,.-L-. ........... ,.-L-. ~
..
Исхо ное ч:испо 1001 0010 1100 0100 (~1омчиое прежсtа.пение)
Onepaн,J;-кacJta 1111 0000 0000 0000
1001 0000 0000 0000
Рис. 18.1. Рпультот дtйамШI комондw ond.

Мы вьщелили старшую четверку биrов исходного числа, однако она


находиn:я в самом старшем полубайте perиC'lpa АХ., в то время, как для
правильной работы подпроrраммы hexasc прсобразуемая четверка дотк­
на располаrаться в младшем полубайте AL. Команда логического сдвига
вправо shr (silift right, сдвиr вправо, предложение S) сдвигает вправо все
содержимое операнда (в данном случае АХ.) на число битов, указанное с
помощью реrи'--тра CL "Выпавшие" с правого конца perиC'lpa биrы те­
ряются (е1р0го говоря, последний вьпlавший бит сохраняется в флаrс
CF, но для данной проrраммы это значеНИJI не имеет), а осво­
бо.ждающиеся биrы с левой стороны операнда зап011НJП0ТСЯ двоичНыми
ну.'IЯМИ. Сдвинув старший полубайт АХ. на 12 разрядов, мы псремССПIЛИ
его на место младшего полубайта AL.
что и 1рсбустся для подпрограм­
мы hexasc. Поскольку по условиям вызова пoдnpol'piUIOiW binasc роrистр
SI уже должен указывать на начало символьной С'IрОКИ, к:у.- ~
результаты преобразования, можно вызwm. подnроrраыму hexasc, кото­
рая запОЛНИТ ПерВЫЙ баЙl" ВЫХОДНОЙ C'lpOJal (прод110ZСНИС 6).
В преддо.женмх 7... 14 вьmолкястся обрабаrка следующей четверки
битов. Снача.'lа в реrистр АХ. из стека ~ ero исходное
88 Статья 19

содержимое, которое 1yr же снова сохраняется в стеке. Далее выделяет­


ся вrорая слева четверка битов, которой сооrветствует операнд FOOh ко­
манды and (предложение 9) и которая сдвигается уже не на 12, а на 8
разрядов (предложения 10-11). Результат трансляции эrой 16-ричной
цифры дОJIЖен бьm. записан в следующий байт выходной строки, по­
эrому командой inc (increment, инкремент) указатель SI получает при­
ращение 1. Вызовом процедуры hexasc завершается этоr фрагмент про­
граммы.

В предложениях 15... 21 аналогично вьiiЮЛНЯется обработка третьей


слева четверки битов, в предложениях 22 ... 26 - самой правой четверки.
Далее восстан118JIИВ11е'1Ся содержимое регистров АХ и СХ (предложения
27-28), после чего командой ret управление возвращается в вызы­
вающую программу.

В полях данных программы предусматривается та же таблица тран­


сляции tЬlhex. Выходная строка result расширена, поскольку в нее запи­
с~я четыре 16-ричные цифры.
В главной процедуре main двухбайrовос исходнос · число (92C4h в
примере) записывается в регистр АХ, в регистр SI заносится адрес стро­
ки для результата преобразования и вызывается подпрограмма binasc,
которая в свою очередь четырежды вызывает подпрограмму hexasc для
преобразования каждой из четырех 16-ричных цифр исходного числа.

Статья 19
Дамп памяти и реmстров

Разработанную нами программу вывода на экран символьных экви­


валентов 16-ричных чисел можно использовать для получения дина­
мического дампа интересующих нас ячеек памнm: или регистров в про­

цессе выполнения проrраммы. · Пусть, например, мы хотим: узнать, где в


памяти находwrся наша программа.

Любая программа, загруженная в память, включает три важных для


программиста компонента: окружение, префикс программы PSP и соб­
ственно программу, которая (в случае программы типа .ЕХЕ) может со­
стоять из нескольких сегментов. Поскольку окружение и сама програм­
ма (включая PSP) рассматриваются DOS, как отдельные блоки памяти,
и та. и другая струК"IWа предваряются блоками уnравления шшщ·и
Дамп памяти и регистров 89

(Momory Control Block, МСВ) размером 16 байт. С помощью М'ИХ бло­


ков DOS ведеr учеr свободной и зawrroй памяти (рис. 19.1).
Окружение представляеr собой об-
.---------.+- ES:(2Ch] ласть памяти, в которой в виде сим-
НСВ
ВОJIЬНЫХ счюк записаны значения nо­
tжруzеиие Р. ЕХЕ ременных, называемых nерсменными
окружения, наnример, РRОМРТ=
$p$g. Здесь РRОМРТ - nерсменная
исв окружения, а $p$g - ее конк:реn~ое
J---------1 +- ES значение, которое МQжет бьnъ и дру-
PSP
J - - - - - - - - - 1 +- cs rим.
Про11роииа Р. ЕХЕ Начальное окружение комаидиого

Рис.19.1. Память, эанимаемшr


""щюммой.
:r:~oprio~~==м:er: =~=
nерсменные COMSPEC, РRОМРТ и
РАТН, которые заносятся в окружение из файла АUТОЕХЕС.ВАТ. Эти
nерсменные исnользуются командным процессо-ром при его работе.
Пользователь можеr вкmочиrь в окружение строки определения допол­
ниrельных персменных с помощью команды SET. Часто в качестве
значений: таких персменных указываются пути к каталогам с вспомога­
'ЮЛЬНЫМИ файлами или кmочи, задающие режим работы nроrраымы.
При заrрузке прикладной nроrраымы содержимое начального окру­
жения копируется в создаваемое окружение прикладной проrраымы, ко­
торая, таким образом, имееr дос"IУП как к системным персменным
(которые, скорее всего, ей не нужны), так и к nеременным,
вКJIЮченным в окружение пользователем и адресованным именно ей.
Вопросы использования блоков управления nамятью и окружения
будуr рассмоорены в дальнейших статьях. Здесь мы рассмотрим nро­
rраыыу, коюрая после запуска выводит на экран терминала сегментные

а.цреса окружения, префикса nроrраымноrо сегме}:IТа и сегмента команд.


После заrрузп проrраымы в память сегментные регистры ES и DS
указывают на PSP, сегментный регистр CS - на сегмент команд, а в
слове со смещением 2Ch от начала PSP содсржиrся сегмеRТНый адрес
окружения проrраымы.

\) nримере приведсна только главная процедура main. Процсду­


19.1
ры-подпроrрамыы и bin.asc, требуемые ДJIЯ работы про!раымы,
hc.xasc
бЬDIИ рассмоорены в С11П'Ы1Х 17 и 18.

IDAiD proc
IIIICIV AX,data
llliCIV D8, АХ
1Вкведем адрес окруаеви~. Он находите~ ао адресу 2СЬ ~ •••an• ISf
IIIICIV АХ, BS 1 [2Ch]
fiO Статья 19

воv S%,o~~•et envir+lO


call . binaac
воv АН,О9h
IIIOV DX, o~~aet envir
int 21h
IВIIaeд- IUIP8C PSP. OJI М&ХОДИ7С• 8 :ВS.
воv АХ,:ВS
воv SI, o~~aet pap+lO
call binaac
IIIOV АН, 09h
воv DX, o~~aet рар
int 21h
1В11ае.11- IUIP8C Cln'N8M'.rA KOМIIJUI, 0J1 МАХОДИ70. 8 CS
IIIOV AX,CS
воv SI,offaet caaeg+lO
call binaac
IIIOV АН,09h
IIIOV DX,offaet С8889
int 21h
IDOV АХ, 4C00h 1 Фуluщи11 DOS SIUiep111811И• nроrрамм
int 2lh 1В1Dов DOS
aain endp
1 IIo.na aaJUUIX
envir dh 'Окру.кекие•****h',10,1Э,'$'
рар dЬ 'Црефикс• ****h',lO,lЭ,'$'
саае9 dЬ 'Цporp&NN&•****h',l0,1Э,'$'
tЫhex dЬ '012Э4S6789АВСD:Вr'

Для повьпuсния наглядности вывода в программе прс.цусмотрены


три отдельные символьные строки для выводимых ссrмс~m~ых ацрссов.

Каждая строка начинается с текста, поясняющего, какой именно ацрсс


выводится в данной строке. Поля строк. предназначенные для хранения
прсобразованных ацрссов, начинаются с байта 10 от начала каждой
строки.

Главная процсдура состоит из трех прак:rически одинаковых


участков, в каrорых ВЫПОJIНЯСТСЯ занесение в perncтp АХ преобразусмой
величины, настройка perncтpa Sl на начало поля для результата преоб­
разования, вызов подпрограммы binasc и вывод с помощью функции
DOS 09h всей строки на экран.
Обратите внимание на коман.цу mov AX,ES:(2Ch). В ней указано не
символическое имя адресусмой ячейки (cerмe1rr с PSP формируст си­
стема, и у его ячеек нет никаких имен), а известное нам числовое сме­
щение 2Ch от начала PSP. Кроме тоrо, явно указано, что ацрссоватъся
надо к согмсшу, адрес кaroporo находится в ES. Такой способ 3811НСИ
адреса, когда вместо подразумеваемого по умолчанию сеrмс~m~ого ре­

mстра DS явно указывается другой сеrме1rmый регистр, используется в


практичсском проrраммировании очень часто и носит спсциаш.нос на­
звание замсны соn~снта.
Основы органиэвции подпрограмм 91

Статья 20
Основы орrавиэацви подпроrрамм

Подnрохраммы, разрабаrаиные нами в предьrдущих C'l'a'l'bliX, могуr


ока:шrься весьма полезньш инсnруwентальным средством ДJUI об­
леrчения аrладки проiраМм и изучения их функционирования. Однако
cnpyкrypa проrраммного коt.аШек.са, в котороы они использовались,. 11е
выдсрживаеr никакой крИ'IИКИ. Действиrельно, в едшu.IЙ файл с исход­
ньш тек.стоы входят наравне и главнu проrраыыа, и подnроrраымы. Xo-
'DI поля данных и выделены в отдельный сегыент, однако в нем часть
данных относятся к главной про~дуре, часть же (конкретно, таблица
1рансляции) является необходимым элементом фунiЩИонирования од­
ной из подnроrраыы. Для того, trroбы использовать процедуры hexasc и
binasc ДJUI отладки какой-то другой проrраымы, нам придется вкmочиrь
их исходный текст в исходный текст новой проrраыыы, а также доnол­
нить сегыент данных программы описанием таблицы 1рансляции.
Обычно подnрограммы общего назначения оформляют в виде от­
дельных файлов (исходных модулей), 1ранслируют независимо от
основной проrраммы, а Зln'eM полученные обьеiаНые модули подnро­
грамы присоединяют с помощью компоновщика к объеiсrНому модулю
основной программы, в результате чего образуется еДIПIЫЙ выполнимый
модуль, в состав которого входит и главная процедура, и процедуры­

подnрограммы. Эrа широко распрОС1раненная методика имеет целый


ряд вариантов и требует специальных программных средств.
Начнем paccмorpeJ:Jиe этих средств на примере простой подrqю­
граммы, которая не требует передачи параметров и не работает с поля­
ми данных.

В примере 14.1 исnользовался распрОС1раненный прием остановки


nроiраМмы до нажатия произвольной клавюпи. Оформим фрагмент
остановки программы в виде отдельной процедуры-подnро~
сначала в составе eДIПioro исходного модуля.

HJIIDI•P 20.1. Лoд1IJIOIPfJIOia 6а napaNarpot~ • COCIIUI•• единtмО ut::l«<ддююo мtiOy.u.


text 8egaent'code' ;Ha•ano общеrо се~~• коwамд
&88\.IIIUI cs: text, DS :data
JIYp0&&8Jn'P&•uoдпporpu.ea ос,.аво•- 81a10.JUieiiИII до вааа-.
проиsаоп•вой кпааиши
8top proc
92 Статья20

laOV АН,О8h 1Фувкци• ааода с кпааиатурм


int 21h 1Вм:sоа DOS
ret ; Воsарат а aмsмaiUOIII)'IO npo:rp~
·•top endp
1rnaaиa. nроцедура
..Ш p.roc
JaOV АХ, data ; и-шranиsaQИJI Сеl'мен~ко:rо
шоv DS,AX 1ре:rистра DS
1Ор:rаниsуем бес~оне...А амаод на э~ан тестоао:rо сооО.еНИR
begin: шоv АН, 09h 1ФvнJщиа амаода
шоv DX,offset ~ssage;Aдpec сооО.евиа
int 21h 1Вм:sоа DOS
call stop 1 Вм:sоа подnро:rр-
jшр beqin 1Вес~оне...А Ц10UI
. .tn endp
text ends 1 ICoнel& оО.по сеl'мента ко-.д
data
··~t'<> 1 Н.•апо се:rмента дiUUIIIX
~·••9• dЬ $'
data ends 1К011ец спмекта дiUUIIIX
8tll: se~nt atack 'atack'
dv 128 dup (01
atJt ends
end -in
В главной процедурс (коrораи в данном приыере носит чисто де­
монС1р8ЦИонный харапер) осущСС'ПWiстся непрерывный (в цикле) вы­
вод на экран ~вой rруппы сныволов "<> ". В цикл ВJСJПОчен вызов
подпроrрам:мы остановки, поэrому ПOCJte вывода очередной 'rеСI'ОВОЙ
rруппы проrрам:ма останавJIИВIIС'rея до НutаТИЯ moбoiiCIIaВИUIИ. Для за­
вершения проrраымы следуМ" нажать <Ctrl>/<C>
(в проrрамме даже не
прс.цусиаrрсны стандар111Ые строrси завершения с помощью функции
DOS4Cb).
Оm1щив приведеиную проrрамму и убедившись, чrо она рабаrаст
правильно, приС'lу~ к модификации ее тсkста.

Ilpuмep 20.2. Оаииlная IIJIOlPfUUifl 11 lloiJitpolJнlюlfl, офоршен~ШI 1 IUM omiJIA611WJt: IIC-


xoiJNWJt: NtiOyAiil.

;~ 'llr8aO\I 008oaiiOA llpOI'p...., Ctalin P.ASN)


text ••IJID8nt puЫic 'oode'
•••~ CS:text, DS:data
ext.rn stopap.roc; Sудет амsмаат•с• ltИtiiiiiiRR nроцедура atop
;rпаанаа nроцедура
-1n p.roc
IIIOV AX,data
IIIOV DS,AX
1 Op:raниsyew амаод на ·~- строк те~с'l'а
beqin1 ·шоv АН, 09h
D:IV
int
DX, offset
21h
-•••q•
call 8top 1 Вlаоа noдnpo:rp-
jq~ begin
. .tn endp
Основы организации подпрограмм 93

text ends
data segment
messaqe dЬ ' <> $'
data eьds
stk aeq~~~ent stack 'atack'
dV 128 dup (0)
stk enda
end ~~~ain ;Оператор end с то.хой axoDa
;Jiklиoдail текст подароrр- atop (фalin Pl.ASМ)
text aeq~~~ent puЬlic 'code' ;Поапроrрамwа atop Donxкa аойти
;а сеrмеит text
ass\llll.e CS: text ;Реrистр DS
sаесь не испоnьsуетс•
puЫic atop ;Процедура общеrо поnьsоа~
stop proc
IIIQV .АН,О8h
int 21h
ret ;Воsарат • аыsыа~ пporpawwv
stop еьdр
text enda ;Конец сеrмеита хомаиа
end ;Оператор end 6es то.хи входа

Разделение элементов nроrраммного комiШекса по оrдельным ис­


ходным модулям с целью их последующего обьединения компоновщи­
ком потребоrsало внесения определенных изменений в тексТhl обеих
nроцедур. Поскольку текст главной nроцедуры у нас невелик (заметно
меньше 64К), разумно включ1rrь подпрограмму в тот ж.е сегмент ко­
манд. При этом отдельные часпr одного сегмента описываются в раз­
ных исходных модулях, и в задачу компоновщика входит их слияние в

один cerмe•rr. Для того, чтобы компоповшик правильно выпо.:1нил это


слияние, сегt.rент команд должен иметь описатель puЬlic (публичный,
общего пользования). Эrо ТаА называемый тип объединения сегмента.
Тип puЬlic обозначает, что все сегменты эТого типа с одним именем
(text в нашем случае) будут сливаться последовательным подсоединени­
ем дРуr к дРУrу (конкатенацией), причем, что очень важно в данном
случае, адреса таких слившихся частей будут оrсчитываться относитель­
но ca.\foi-o начала па:Iучившеrося объединенного сегмента. Без описате­
ля puЬlic сегменты тоже объединяrся, но адреса каждой часп1 будут
аrс:ч1rrыватьс:я от ее начала, что приведет к дублированию а,црссов и не­
правильным обращениям из одной части сегмента в дРугую.
&ropoe новшество касается особых строк с объявлением подnро­
граммы как в главной (вызывающей) nроцедуре, так и а самой подnро­
грамме. Для того, чтобы 1ранслятор не воспринял, как ошибку, CCЬIJIКY
в тексте главной nроцедуры на имя nроцедуры {stop) из другого модуля,
это имя следует обышИ11о внешним, для чего предусм01рен оператор
extm (extcmal, внешний). В поле оператора extrn перечисляются все
внешние имена, если их нескалько, nричем: после каждого именИ необ­
ходимо указать cro тиn. Паскальку stop • процедура, для нес указ~
ся тиnproc. Дpynro типы внешних имен будут описанъ1 в дальнейшем.
94 . Статья20

• Опсраор extm, как и мноrис .цруmе ди:рспивы ассемблера, ы:ох~ сто­


Я'I'Ь а JПОбоы месте теКЩ"а основной проrрамы:ы, 1IIQ.Ce в .цруrом с:сrмонтс
или вообще за пределами с:сrментов.
В файле с исходныи текстом подпроrрамы:ы се иыя до.п:жно бьm.
объопено с помощью дирепивы puЬiic. Такое обьявление заставиr
'ф8НСJIЯТОр занести JПiформацшо об зтоы: иыени в обьек:rный файл. Эrо,
в свою очередь, позво.mrr компоновщику определить, в каком модуле

содсржиrоя даннаJ1 анеШНJВI ссьmка. Дирсв:rива puЬiic, как и ди:рсв:rива


cxtm, может С1ОJП'Ь в JIЮбом месте текста подпроrрамы:ы.
Oroиr замсmm., '1'10 дирсimП18. puЬiic, с помопn.ю которой иыена
обьсlm)в (подnроrрамы:, меток, констант, псрсмеННЪIХ) обыmлmотся
иы:енами общего по.льзования, не иы~ прямого отношения к однои­
ы:енному описатсшю public, с помощью которого определяется ТШI объ­
едm~ения КОНiфСmlого сегмента.
Наконец, третья особенность многомодульных проrрамм - обьявле­
ние точки входа. Хотя все исходные модули до.п:жны заканчиваться ди­
реiСIИВОЙ конца 'lpSНCJUJЦИИ end, 'ЮЛЬКО в одном из них, содержащем
главную процедуру, указЬIВае'rоя точка входа - иыя главной процедуры
или входная мепса. Остальные дирсiСmВЫ end не иыеют операндов.
Подготовьте файлы P.ASM и Pl.ASM. Файлам можно дать JIЮбые
иыена и, возможно, разумнес бьrло бы присвоить иы иыена МAIN.ASM
и SТОР .ASM, совпадающие с иыенами содер.жащихся в них процедур.
Выбором иыен Р и Pl мы просто подчеркнули отсуrствие связи между
иыенаыи мoдyJIJI и содер.жащейся в кем процедуры. Отrранслируйте оба
мoдyJIJI командами

МJ\SM/ZI Р,Р,Р;
МASМ/ZI Pl,Pl,Pl;

Образуются два обьеJаИЫХ мoдyJIJI P.OBJ и Pl.OBJ. Компоновка их


в единый заrрузочный 111одуль с иыенем COMPLEX.EXE осуществля:~
СЯКОМаидОЙ

LINК/CO P.OBJ Pl.OBJ,COМPLEX.EXE;

Имя резульmрующего ы:oдYJIJI выбрано нами впОJШе произвольно.


Можно бьrло назначиn. ему, например, иыя Р.ЕХЕ, совпадаюЩее с
именем исходного файла с гпавной проце.цурой. Расширения OBJ и
ЕХЕ можно не }'К83ЫВ~r~Ъ, Т8lt как. они ДСЙС1'Ву10Т по уы:олчанию.
Эапуспm проrрамму COMfLEX.ExE, убсдитесь в правильиости се
рабоп.L -
Имея обьеiСI'ИЫЙ ы:одуль с 0'1'.118ЖСИНОЙ подпроrраммой, ы:ожно леr­
хо подсосДИIIJ11"Ь се на ~ хом:поновки к JIЮбым проrраммам. Есте­
ственно, что а основной, вызывающей проrрамме в нужных м:естах
дOIDDIЬI им:сться С'lрОКИ вызова подпроrрамм:ы nma call stop.
Основы организации nодпрограмм 95
Рассм:сприм ~перь вопрос о рсаm.ном: расп011ожеliии в пам:J1ТИ зле- .
м:скrов нашеrо прОrрам:мноrо ком:пnеiССL ЗапуС'!'IIМ проrрамм:у
COMPLii.X.EXE под управлением: 0'Ш8Д'111Ка и npocмcnpиre вывоДИМЫЙ
на экран резупьТIП' дсасссмблированИR. На рис. 20.1 приведен возмож­
ный вариант cnpcдaiCПipOВ811HOl'O ВЫВОда аmад'1ИХа С ПOfiCHeiiiDDOI
(рисунок получен с помощью отладчика DEBUO).
г Ка•апо 081'-Т& ICOМIUUI

OF8A:OOOO 888DOF МОV AX,OF8D .ov AX,data


ОF8А:ОООЭ 81D8 МОV DS,AX
OFb.\: 0005 8409 МОV АН, 09 · be9in1 .ov АН, 09h
OF8A:0007 ВАОООО МОV DX,OOOO .ov DX,offaet a.aaaCjJe
OFBA:OOOA CD21 INТ 21
OF8A:OOOC 181100 CALL 0020 оа1.1 atop
OF8A: OOOF 18Ft JМР 0005 jllllp be9in
OF8A:0011 0000 ADD [ВX+SI),AL

}-·
OF8A:0013 0000 ADD [ВX+SI),AL
OF8A:0015 0000 ADD [ВX+SI),AL
OF8A:0017 0000 ADD [ВX+SI),AL
OF8A:0019 0000 ADD (ВX+SI),AL
OF8A:0018 0000 ADD [ВX+SI),AL
OF8A:001D 0000 ADD [ВX+SI),AL
OF8A:001F 008408tD ADD [SI+CD08],DК 00 .ov АН,О8h int
OF8A:0023 21СЭ AND ВХ,АХ 21h жеt
OF8A:0025 0000 ADD [ВX+SI),AL l_
OF8A:0027 0000
OF8A: 0029 0000
OF8.A: 0028 0000
ADD [BX+SI),AL
ADD [ВX+SI) ,AL
ADD [ВX+SI) ,AL
JИуnи а sarpyso. .oм~ay.ne
до ва•апа сu. .вта д&ВIUIX
ГНа•апо сu. .нта д&ВIUIX
OF8A:002D 0000 ADD [BX+SI},AL
OF8A:002F ООЭС ADD [SI),ВИ 00 '<'
OF8A:0031 31 DS: '>'
OF8A:0032 2024 AND [Si),AН 1 $'

OF8A:0034 0000 ADD [BX+SI),AL }


OF8A:0036 0000 ADD [ВX+SI],AL
OF8A: 0038 0000 ADD [BX+SI], AL Иупи а supy:so. .oм ~дуnе
OF8A: ООЭА 0000 ADD [ВX+SI] ,AL до JCOIШ& се.r. .вта JIAВIIIIX
ОF8А:ООЗС 0000 ADD [BX+SI),AL
ОF8А:ООЗЕ 0000 ADD [BX+SI),AL ~вец се.r. .вта даинмх

Рис. 20.1. Ре:lулыпат деасамблированшr nJIOlJНlAlAIЬI COMPLEX.EXE.

Сегмент команд получшt сеп,t:ентный а,црсс OF8A. Заrруэочный мо­


дуль начШiастся с главной процедуры main не поrом:у, что она главная,
а лишь потому, что в С1JЮКС вызова компоновщиu модуm. P.ASM с
этой процедурой бЫJI первым: в списке объектных модулей. При жела­
нии порядок пр(щедур в заrруэочном модуле можно изменить. Послед­
няя команда процедуры main jmp begin занимает аmосmсльные а,цреса
OOOFh и OOIOh. Далее до адреса OOIFh заrруэочный модуль запОJПiеН нy­
JJJIМИ (которые отладчик ПЬ1Т8С'1СЯ деассембпировать в командЫ add
(BX+SI),AL), а с ццрсса 0020h начинаются команды подпроrраммы.
Подпроrрамм:а закакчивастся в байrе с а.црссок 0024h (команда rct),
96 Статья20

·после чего опять идет посп:сдо~носп. нулей до адреса 002F.


Начиная с относительного адреса 0030h отладчик выводит некоrорые
бессмысленные команды, хотя петрудно доrад!ПЬСя (воспользовавшись
таблицей кодов ASCII), чrо здесь распОJI8Г8Ю'Юя данные проrраммы, т.е.
ее сеrмекr данных. Реально данные эанимают всего 4 байта.
Разрыв в сеrменrе команд (15 байrов нулей) согласуется с командой
call stop, которая выглядит в колонке вывода отладчика, как call 0020h.
Процедура stop как раз и начинается с относительного адРеса 0020h.
Чем объясняется столь неэкономное расходование памяти?
Прежде всего заметим, чrо сеrмекr команд начинается на rранице
параграфа (по относительному адресу OOOOh). Это естественно, так как
физический адрес начала сеrмента вычисляется процессаром пуrем
умножения сегментного адреса на 16, чrо вы:равнивает·сегмекr на гра­
ницу 16-байrового участка, т.е. параграфа. По той же причине
начинается на границе параграфа и сеrмент данных. Огладчик не смог
определить, где кончаются команды и начинаются данные, поэтому
сеrмекr данных в выводе отладчика никак не вьщелен. Однако его
начало (OF8Ah:0030h) действительно находиrоя на границе параграфа и
соответствует сегментному адресу OF8Ah+Зh=OF8Dh. Таким образом,
участок нулей в загрузочном модуле по относительным адРесам 002Sh-
002Fh вполне объясним.
Обратим теперь внимание на то, чrо процедура stop тоже
начинается на границе параграфа (относительный адРес 0020h). Про­
изошло так потому, чrо компоновщик, формируя загрузочный модуль,
по умолчанию выровнял все встретившисся ему куски сегментов на

границу параграфа. На работоспособность получившейся программы


это нисколько не влияет, однако с точки зрения расходования памяти

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


подпрограммы это, конечно, не очень важно, но при наличии десятков

или сотен коротких подпрограмм сумма nустых: участков программы

может оказап.ся весьма значиrельной.


Для того, Ч100ы исправить положение, следуст указать компонов­
щику, чrо выравнимrь отдельные участки сеrментов надо не на пара­
граф, а на слово или, еще лучше, на байт. Эrо делается пуrем указания
еще одного опис~ в предложении с оператором segment- типа вы­
равнивания. 1Ип выравнивания может принимiПЪ значения byte (байт),
wont (слово),dword (douЬle word, двойное слово), para (paragraph, пара­
граф) и page (страница, 256 байт). Таким образом, для сокращения раз­
мора програш.rы еегменты команд в процедурах следуст описывап. опе­

раторами такого аида:

text ••~nt 'code' byte


На рис. 20.2 привсден вывод отладчика ДIUI такой программы.
Основы организации подпрограмм 97

1
оrвл: оооо 8BBcor моv AX,OFBC IIIOV АХ, data
оrвл: оооз ввDв моv DS,AX
01'8А:ОО05 8409 моv АН,О9 begin: JIIOV АН, 09h
01'8А:ООО7 ВАОООО моv DX,OOOO IIIOV DX,offaet шеаааgе
OI'BA: ОООА CD21 INТ 21
OFBA:OOOC В80200 CALL 0011 са~~ atop
оrвА: ooor :s8r4 JМР 0005 j111p beqin
OFBA: 0011 8408 моv АН,О8
01'8А: 0013 CD21 INТ 21
0!'8А:0015 СЗ RВТ
OFBA: 0016 0000 ADD [ВX+SI),AL
01'8А: 0018 0000 ADD [ВX+SI),AL
0!'8А: OOlA 0000 ADD [ВX+SI] ,AL
OF8A: 001С 0000 ADD [ВX+SI) ,AL
0!'8А: 001В 0000 ADD [ВX+SI),AL
01'8А: 0020 ЗСЗВ СМР АL,ЗВ '<>'
01'8А: 0022 2024 AND [SI) ,АН 1 $'

:в модупе
OI'BA: 0024 0000 ADD [8X+SI) ,AL
OF8A: 0026 0000 ADD [ВX+SI) ,AL
01'8А:ОО28 0000 ADD [8X+SI) ,AL Hymc sarpyso-oac
OI'BA: 002А 0000 ADD [BX+SI) ,AL } до хонца сеrасеита даииых

OF8A: 002С 0000 ADD [ВX+SI],AL


0!'8А: 002В 0000 ADD [ВX+SI),AL -----коиец сеr~ита даиинх

Рис. 20.2. Результат деассеА16лирогания программы COMPLEX.EXE при выравнивании


сименто JWМанд 1Ш байт.

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


ти вrшотную .цруг к .цругу. Со0ТВСТС'I11Снно изменился и оператор вызова
подпрограммы, он передает управление на байт с адресом OOllh вместо
0020h. Что :ж:е касается сегмента данных, то он попре:ж:нему наЧШiается
на границе параграфа (относительный адрес 20h), так как по умолчанию
для сегментов действует выравнивание на параrраф. Указание для сег­
мента данных типа выравнивания byte ликвидирует и второй пустой
участок в загрузочном модуле. Рекомендуем читате.лю задуматься над
вопросом, как же сегмент данных мо:ж:ет начаться не точно на границе

параrрафа? Видоизмените проrрамму, объявив сегмент данных операто­


ром

data aeqшent byte

Просм<nрите проrраыму в отладчике, обраrив внимание на. сег­


мекmый адрес сегмента данных и на аmосиrсльный адрес находRЩИХся
в нем данных (поле с именем mcssage).
98 Статья21

Статья 21
Процедуры и поля данных

Вернемся к примеру 18.1, в котором бьщ описан проrраммный


коммекс, обеспечивающий вывод на экран содержимого ячеек памяm
или perиc1JIOB. В отличие от примеров nредыдущей статьи, где рассмат­
ривалась одна nодпроrрамма без параме-rров, в примере 18.1 бьщо две
подпроrраммы, причем для работьr одной из них требовалось специ­
фическое поле данных (таблица трансляции). В таком более общем
случае вьщеление подпроrрамм из состава основной проrраммы и
оформление их в отдельные файлы 7ребует решения ряда методических
вопросов.

Если у нас имеются несколько подпроrрамм общего назначения, их


можно оформить тремя различными сnособами:
1) для каждой подпроrраммы иметь отдельный файл с исходным
текстом и, соответственно, отдельный объеiСmый модуль. При этом
подпро11)аммы могут образовывать отдельные сегменты команд или
описываться в сегментах, одноименных с сегментом основной про­
rраммы;

2) объединить все подпроrраммы в один исходный файл и иметь,


соответственно, один объеiСmый модуль со всеми rюJщроrраммами, ко­
торые могут при этом входить в единый сегмент команд, а могут со­
СТilRЛЯТЬ несколько сегментов. Последняя возможность важна в тех
случаях, К()Гда подПJХЩ)аммы оолики по размеру или их много и они не

помещаются в один сегмент (64К);


3) объединить объектные модули всех rюдщюrрамм в составе объ­
СК'Пtой бибJш~ки. которая создается специальной nроrраммой­
библи~карем.
Второй, прямо не см31Uшый с количеСТ\Юм подпроrрамм, вопрос
касасm.:я полей данных, испnльзуемых подпроrраммами. Если через по­
ля данных лодпроrрамме персдаются какне-то IШра~tетры из вызы­

вающей проrраммы, эnt no:tя данных естественно n ней и расположить.


Однако подпроrраммы могут использовать в своей работе поля данных,
которые вызывающей nроrрамме не нужны. Было бы ее гесгвенно рас­
положить данные такого рода rдe-ro в тексте rюдпроrраммы. Здесь так­
же вооможны два варианта:

1) данные расnолаrаются в ссrменп команд JIOJliiporpaммы;


Процедуры и поля данных 99

2) данные помсщаiО'l"Ся в ссrмскr данных, либо общий с ВЬIЗЫ­


вающсй проJраММой, либо специально созданный для обслуживаиии
подпроrраммы.

Рассмоорим сначала вопрос о размещении внуtренних данных под­


проrраым. В качесmе рабочего ма'lq)иала мы используем проrраымный
комiШскс, разрабаrан:ный в статьях 18-19. Разнесем процедуры ком­
IШскса по отдельным исходным файлам: МAIN.ASM для главной про­
цедуры main, HEX.ASM для процедуры bcxasc и BIN.ASM для процеду­
ры binasc (напомним, что имена файлам с процсдурами можно наз­
начаТЪ произвольно). При этом внуtреннис поля данных процедуры
hexasc расположим в общем для всего комiШскса сегменте команд tcxt.
Для облегчении участи ЧlrraтcJUI в примере 21.1 приведсны полные
тексты всех проrрамм.

Пример 21.1. ОсногнаJI программа и подпрограммы, оформленные в виде отдеАьньа ис­


х.одньа модулей. Поля данных подпрограммы размещены в сегмеН~М JWМанд.

ИохоДJDIЙ !l!eKO'J! ооаоваой uрожор- (фаА;n NAIN. АSМ)


text aeqшent'code' puЬlic byte
aaaume CS:text, DS:data
extrn binaac: proc; Описание виешией процедуры,
;выsываеwой иs даииоrо файпа
Jll&in proc
IIIOV AX,data
IIIOV DS,AX
; ВЫведеы адрес оJСру:кеииll. Он иахотстс11 ао адресу 2Ch от aa"'ana PSP
IIIOV АХ, :&S: [2Ch]
mov SI, offaet env1r+l0
call binaac
IIIOV АН, 0 9h
mov DX,offaet envir
int 2lh
;Выведем адрес PSP. Он аахотстс11 а BS
IIIOV АХ, :& S
mov SI, offaet рар+8
call binasc
IIIOV АН, 0 9h
IIIOV DX, offaet рар
1nt 2lh
1Вкв~еы адрес оеrм.кта коwама. О. махо~с• а CS
IIIOV АХ, CS
1110v SI, offset caaev+lO
call Ыnаас
IIIOV АН, 09h
IIIQV DX, offaet o•••v
int 2lh
,з-~пporpaa.w.v
IIIOV АХ, 4COOh
int 2lh
-1n endp
text enda
data aecpunt
100 Статья21

envir dЬ 'Окру.кение•****h',10,13,'$'
рвр dЬ 'Црефккс•****h 1 ,10,13,'$'
caaeg dЬ 'Цporpawwa•****h',lO,lЗ,'$'
c:lata enda
atk aegment atacll:
dv 128 dup (0)
atll: enda
end main ;Конец те•ста проrрамwк с точкой входа

HaxoдDJA !1:-0'ir IIO,IIDpOI'p- BINASC (фalin BIN.ASN)


text aegment 'code' puЫic byte
AIIIIWI18 CS 1 text
puЫic Ыnаас 1 Oб'lo1111ne-e даввой процедуры
1процедурой общеrо попьsовАКК!I
extrn hexaac:prociODИc.-e --ей процедуры,
IВКSква....Ж в даивом файпе
binaao proc
;Подароrраwма преобраsоа.-11 даом.коrо cnoaa а 16-ричвУ»
10108опьнУ» форыу. Цри акsоае: АХ•преобраsу8М)е 'Uicno,
1SI•aдpec строки, куда DON8Щ&eтcll pesynьo:raт преобраsоа.-...
push СХ
push АХ
and АХ, OI'OOOh
IIIOV CL, 12
shr AX,CL
call hexasc
рор АХ
push АХ
and АХ, O!'OOh
IIIOV CL, 8
shr АХ, CL
inc SI
call hexasc
рор АХ
push АХ
and АХ, O!'Oh
IIIOV CL, 4
shr AX,CL
inc SI
call hexa.sc
рор АХ
puah АХ
and AX,OI'h
inc SI
call hexa.sc
рор АХ
рор СХ
ret
Ыnаас endp
text enda
end 1Конец те~со:rа пporpawwм бе3 точки входа

ИaxoДIIIoiiЙ те~от DОдпрожр- DXASC (фalln DX.AВN)


text seg~~~ent'code' puЫic byte
as.swne CS:text
puЬlic hexaac 1 O&ьll~~n•-• даввой процедуры
1процедурой общеrо nonьsoa.-11
Процедуры и паля данных 101

hexasc proc
;Подпроrрамма попучения симаопьноrо пре~стаапеНИ4 четнрехбитоаоrо
; чиоnа. На вхо~е: Чиоnо а МJJадшей по.поJIИНе AL, адрес corpoJCИ, ICYJI&
;н~о по~стить реsупьтат, в SI
push ВХ ; (l)CoxpaJDO& испопьsуемiЙ реrистр
IIIOV ВХ, offset tЫhex; (2) ВХ•адрес табпицк траноnяuии
push DS ; 13) CoxpaJDO& наш DS
push CS ; ( 4 ) ОтпраiiИW адрес сеr~кта ICOМUUI
рор DS ; (S)в DS
xlat ; ( 6) Комzuща табпичной транспяции
рор DS ; 17 1ВoccтaнoiiJQC DS
JDOV [SI],AL ; (В)Вернеы реsу.пьтаож преобраsования
рор ВХ ; ( 9 1ВoccтaнoiiJQC реrистр
ret ; (lО)Воsарат в IIЫSЫJIIUIIIII)'IO проrр&М14"
tbLhex dЬ '0123456789AВCDEF'; (ll)Табпица транс.п4QИИ
hexasc endp
text ends
еnd;Конец техста проrрамwы беs точки ахо~а

Файл с исходным текстом основной программы назван МAIN.ASM.


Из него удалсны обе процедуры-подпрограммы, разнесенные по аr­
дельным исходным файлам. В исходном тексте основной программы с
помощью дирсiСI'ИВЫ cxtm указано, что символическое обозначение
ВСiрСчающссся в тексте главной процедуры, являе-rоя именем
binasc,
внешней процедуры. Поскольку вложенная процсдура hexasc не вызы­
вается из rтшной процедуры непосредственно, она в ней и н~ описана.
Текст главной процедуры не претерпел никаких изменений, за ис­
ключением того, что в сегменте данных отсуrствует таблица "lрансляции.
Файл с исходным текстом процедуры binasc назван BIN.ASM. В нем
с помощью дирсiСI'ИВЫ public объявлено, что данная процедура являе-ооя
процсдурой общего пользования, а с помощью дирсiСI'ИВЫ extm описано
внешнее имя hexasc. Оставшаяся Час'IЪ программы не измснилась.
В файЛе HEX.ASM с подпрограммой hexasc объявлено, что это про­
цедура общего полъзования. Ее текст отличается от примера 18.1, так
как изменилось местоположение таблицы "lрансляции tЬlhex: из сегмен­
та данных она перекочевала в ссгмепr команд, что избавило нас от нс­
обходимосm, составляя текст основной программы, заботиться о внуr­
ренних полях данных вызываемых процедур. Любые поля данных в со­
ставе сегмента команд должны располагаться таким образом, чтобы ис­
ключиrь их "выполнение", как программных С"lрОК. В нашем примере
таблица tЬlhex расположена после команды ret. Можно было бы размсс­
пm. ее и в начале программы, до оперiПОра proc.
Как О"lрЗЗИТСЯ на тексте программы размещение "lрСбуемых ей дан­
ных в сегменте команд? В нашем случае к :n1DI данным обращается
команда :xlat, для правильного функционирования которой необходимо,
чтобы адрес таблицы"lрансляции находился в perиC"lpax DS:BX. Поэто­
му на время выполнения этой команды в pcrиC"lp DS следует занСС'IИ
адрес того сегмента, в каrором реально находится таблица траисmщии,
102 Статья21

· т.е.
ссrмекrа ком:ан.ц. С эrой целью в предложении 3 процедуры hexasc
сохраиястся текущее значение DS, каrорый в насrоящий момент указы­
вает ка ссrм:ент даиных основной проrраммw:, а заrсм в предложениях 4
и S содержимое CS зarpyж.ae"ro.s: (через стек) в DS. После вьmОJПiения
ком:анды xlat немедленно восстан8ВJIИВ8СТСя старос содержимое pcmCipa
DS (предложение 7). Оставшаися часn. процедуры не изменилась.
Дм подrоrовки загрузочного модуля: описанного проrрамм:ного
ком:мекса следуст ВЫПОJПIИП. раздельную tpaнCJUЩИIO всех tpex исход­

ных файлов и объеАИНИ'l'Ъ процедуры на :mme компоновки:


МASМ/ZI/Z/N МAIN,МAIN,МAIN;
МASМ/ZI/Z/N BIN,BIN,BIN;
МASM/ZI/Z/N НЕХ,НЕХ,НЕХ;
LINК/CO МAIN BIN HEX,PRN_ADDR;

Здесь результирующему загрузочному модуmо присваивастся


(произвольное) имя PRN_ADDR.EXE.
РассмОtрСннаи методика размещения данных в сец.~енте команд ис­
пользуется очень широко, так как во мноmх случаях в проrрамме, ис­

пользующей нсбоm.шой объем локальных данных, нецелесообразно за­


ВОдИ'l'Ъ собственный сеrм:ент данных. Однако часто оказывается более
удобным собрать все данные - и главной процедуры, и подпроrрамм, в
едином: сегменте данных. Такой способ организации данных позволяет
всем составляющим проrраммного комплекса обращаться ко всем дан­
ным:, и собственным, и "чужим". Если при эrом отдельные поля данных
присущи конкретным подпроrраммам, целесообразно обьявлять их не в
основной проrрамме, а в rекстах подпроrрамм. Тогда в случае компо­
новки проrрамм:ного комплекса в дРугом: варИ8Н"R: (с дРУГИМ составом
подпроrрамм:) состав полей данных измениrся авrоматичсски.
Рассм01рим вариант организации того ж:е проrрам:м:ного комплекса,
в каюром подпроrрам:ма hexasc имеет доступ к общему ccrм:emy дан­
ных и может вносип. в него свой вклад.

/Ipшl•p 11.2. OcнoвiiDJI np«JНUU~a и noiJnpoгptJAIAiы, офорш•нны• • вид• отдlл~~НЪ~Х uс­


жоднwх модулей. ЛOIUI данных подпрогрtJА~А~ы pti3JIIeщeны • ctlltllнme данных.

JfmmДIDPir !NROII о0808110А llpCII'p- Ctdrn IAIN. ASN)


text aegaent 'cocle' puЫic byt:e
aaatae CS:text, DS:data
extrn binaac: proo
-in proo

oall binaao

-tn endp
text end
data aepent puЬlic
envir dЬ 'Окру.кение•••••h',lО,lJ,'$'
Процедуры и поля данных 103

рар dЬ 1 Црефикс•****h 1 ,10,1З,'$ 1


С8889' dЬ 1 Цро~аwма•****h 1 1 10,13, 1 $ 1

data aeqment puЬlic


stacll: seqшent stacll:

stack enda
end D~Ain; Конец текста про~.- с :yJCasaнx- то._ ахо,.а

ИOXnJ(J'NA -~ DOдnpal'p- BDWIC Ctal'al ВIN.МК)


text seqшent code 1 puЬlic
1

ASSI.DIIe CS; text


puЬlic binasc
extrn hexasc: proc
Ыnasc proc

call hexasc

ret
Ыnasc endp
text ends
еnd;Конец текста проrрамwы беs :уJСаsаки~ то._ ахо,.а

HaxoJIJDIЙ техот DOдnpal'p- DXASC (фal'al DX.ASN)


data seqment puЬlic
tblhex dЬ 1 0123456789AВCDBF 1

text seqment 'code' puЬlic byte


asswne CS:text
puЬlic hexasc
hexasc proc
P"'•h ВХ ;Сохраикм иcnonьsyewыA реrистр
IIIOV BX,offset tЫhех;ВХ•ацрес табпицк траксп~ции
xlat ;Коwакда табпичиой трансп~ции
IIIOV (SI),AL ;Вернем реsультат преобраsоа~
рор ВХ ;Восстановим реrистр
ret ;Воsврат в выsыв~ aporpaмwv
hexasc endp
text ends
еnd;Конец текста проrрамwы беs :уJСаsаки~ то.хи ахо,.а

В рассматриваемом варишm: текст основной программы изменился


ЛШIIЬ одной деталью: сегмент данных data объявлен с:: 1ИПОМ обьедm~е­
ния puЬlic и с типом выравнивания byte. Указание nma обьединеНИJI
потребует от комnоновщика с::цешrrь вместе. отдельные части сегмента
данных, объявленные в разных исходных модулях. Указание типа вы­
равнивания byte nозволит получmъ оптимальную по расходованию па­
МЯ11f nporpa.\lмy, в которой все составляющие с::еrмекrов примыкают
друr к друrу вnлотную. При оп:уrствии опис::~ byte компоновщик
позиционирует отдельные вхоцения в сеrмент данных по умолчанию

на rраницу параrрафа, что приведет к возникновению в эаrрузочном


модуле пустых участков.

Подпрограмма Ьinasc, которая не рабоrаст с:: ПOJUDCИ да11НЬ1Х, не пре­


терпела никаких изменений.
104 . Статья22

В тексте подпроrраммы hexasc появились строки объявления сег­


мента данных data, в котором размещена таблица 'lрансляции tЬihex.
Существенно, что этому сегмеН'lj' дано то же имя, что и у сегмента дан­
ных основной проrраммы. Только в этом случае компоновщик присое­
динит поле данных tЬihex к сегмеН'lj' данных основной проrраммы.
Процедура hexasc несколько yпpoC'l'ИJffiCь. Поскольку к момеН'lj' ее
вызова сегментный perиC'lp DS заведомо указывает на общий для всего
комплекса сегмент данных, O'ПUl1Ia необходимость в нас'lрОйке DS.
В результе:rе мы получили проrраммный комiDiекс, где каждая под­
проrраима может имеn. в общем сегменте данных собственные данные,
которые описываются в ее тексте и о которых не нужно забоnrгься при
составлении текста основной проrраммы.

Статья 22
Библиотеки подпрограмм

Оформление каждой подпроrраммы в виде отдельного модуля допу­


стимо munь в тех случаях, когда число подпроrрамм невелико. При
большом количестве подпроrрамм, что типично для современного про­
rраммного обеспечения, их лучше объединиrь в один файл. Как уже
отмечалось в cnnъe 20, это мо:ж:но вьmолниrь двумя способами, на
уровне исходных текстов и на уровне объектных модулей.
Структура файла с двумя подпроrраммами binasc и hexasc, взятыми
из примера 21.2, приведсна в примере 22.1. Исходные тексты подпро­
rрамм просто следуют друг за другом. Если в какой-то подпроrрамме
описаны несколько сегментов, они могут располагаться в любом поряд­
ке. В конце всего текста помещается завершающая (и единственная)
дирепива end без указания точки входа.

Пpwtep 12.1. Обидинение исходных meкcmOfl подпрограмм • один моду.сь.


text aeg111.8nt 'code' puЫic byte
aaa'Uiae CS 1 text
puЫicbinaac
binaac proc

ret
binaac endp
hexaac proc
Библиотеки подпрограмм 105

ret
hexaac endp
text enda
data aegment puЬlic byte
tЫhex dЬ '0123456789AВCDZF'
data enda
end ; ЭaвepшAJIIQaJI директива end
По сравнению с примерам 21.2 в ",кеты подпроrрамм внессны не­
коrорые "организационные" изменения. В описании процедуры Ьinasc
изъят операrор extm, обыпwоощий подпрограмму hexasc внешней про­
цедурой. Действиrельно, ",перь эта подпроrрамма распаложена в том
ж:е модуле, что и вызывающая ее процедура Ьinasc, и транслятору в про­
цессе трансляции Ьina.~ не составит 1РУда найти имя hexasc. По n1й же
причине нет необходимосm o6ъluwrrь hexasc процедурой общего поль­
зования (оператором public).
Файлу с подпрограммами дается произвольнос имя (например,
SUBS.ASM) и он транслиру-т:я обычным образом:

МASМ/ZI suвs,suвs,suвs;

Компоновка объеiСПIЫХ файлов осуществляется так же, как и в


случае нескольких файлов с подпроrраммами. Если объеiСПiый файл
основной программы имеет имя МAIN.OВJ, а результирующему загру­
зочному модулю решено дать имя PRN_ADDR.EXE, строка вызова
компоновщика будет выrляде11> тах:

LINК/CO МAIN SUВS, PRN_ADDR;


При разработки сложных программных комrurексов большие
удобс.:тва предоставляет иснользоеание объектной библиотеки подпро­
грамм. Объектная библиотека создается специальной про~раммой­
библиотекарем (наприиер, LIB.EXE фирмы Microsoft ИJIИ TLIB.EXE
фирмы Borland). Включение о6ьек:n1ых файлов с nодпрограммами во
вновь создаваемую объе~Сmую библиотеку выnолняется следующим об­
разом !для библиотекаря LIB.EXE Microsoft):
LIB НYLIB.LIB +BIN.OBJ +HEX.OBJ, НYLIB.LST

В этой строке LIB - имя проrраммы-биб.лиотекаря, МYLIB ЕХЕ -


имя создаваемой объеmtой бибдиотеки, BIN.OВJ и HEX.OBJ - имена
помещаемых в библиотеку объеmtых файлов, а МYLIB.LST- IOUI соз­
даваемого файла с каrалогом библиотеки. Зн81СИ "+" обозначают, что
указанные объекmые файлы добавruоотся в библиотеку. Все расшире­
ния, кроме рш:ширсния файла с каrалогом, можно onyC'l'И'I'Ь, так как по
умолчанию прсдп0J181'810ТСЯ именно указанные в примере расширения.
Статья23

Если объсiСrНая библиотека уже имеется, и мы хотим добавить в нее


вновь созданные объсiСrНые модули, в строке вызова библиоrекаря надо
в качестве последнего параметра еще раз указать имя библиотеки:

LIB МYLIB +NEWl +NEW2, МYLIB. LST, МYLIB

Здесь первый параметр (МУLIВ) определяет имя исходной библио­


теки, а последний (тоже МYLIB) - имя создаваемой библиотеки, рас­
ширенной за счет добавления новых модул~й. Эrо имя может совпадать
с именем старой библиотеки, но может и отличаться от него.
В процессе отладки проrрамм часто возникает необходимость заме­
НИ'IЪ некоторый объсЮ'Ный модуль в библиотеке на его новый вариакr.
Для этого надо сначала удалить из библиотеки старый вариакr модуля, а
згmм добавить в нес новый вариакr. Эти действия можно выполнить
одной командой:

LIB МYLIB.LIB -BIN.OBJ +BIN.OBJ, МYLIB.LST, МYLIB.LIB

При наличии обьсЮ'Нсй библиотеки в команде вызова компонов­


щика следует указать имя библиотеки. Оно указывается в качестве
ч~рrого параметра команды:

LINК/CO МAIN.OBJ, PRN_ADDR.EXE, PRN_ADDR.МAP, МYLIB.LIB

В приведеином примере МAIN.OВJ - объектный файл с основной


проrраммой, PRN_ADDR.EXE - образуемый компоновщиком выпол­
нимый модуль, PRN_ADDR.МAP - листинг компоновки, а МYLIB.LIB
- обье~m~ая библиотека со всеми подпроrраммами, вызываемыми из
основной проrраммы и се подпроrрамм. Как и в предыдущих примсрах.,
все расширения можно опустить, так они предnол8J'810'rоя или наз­

начаются по умолчанию.

Статья 23
Вwво.ц на экран текста средствами BIOS
В прсдw,цущих C1'8'l'LЯX этой книrи были описанw: различные спосо­
бы вывода на экран символьной (текстовой) информации. Для этого
моzно воспольюваться функциями DOS, например, функцией 09h, кo­
rop&JI выводиr текст до знака "$", или функцией 40h, ДIIJI которой за­
дастсJI длина выводимой С'I}ЮКИ (или нескольк:их C'I}IOK). Оцнако, воз-
Вывод на экран текста средствами BIOS 107

можности DOS весьма ограничены: DOS не имеет функций для изме­


нения цвета выводиМых символов и позиционирования курсора. По­
этому текст, выводимый средствами DOS, представляет собой сrтош­
ную последовательность черно-белых строк, появляющихся .цруr за
.цруrом с нижнего края экрана. Кроме того, с помощью DOS можно вы­
водить не все символы кодовой таблицы.
Для вывода цветных информационных кадров можно воспользо­
ваться расширением системного дРайвера консоли - устанавливаемым
дРайвером ANSI.SYS. Включение в выводимые на экран строки Еsс­
последовательностей позволяет очищать экран, изменять цвет выводи­
мьrх символов, позиционироваТь курсор и вьшолнять .цругие полезные
действия. При этом необходимо иметь в виду, что программы, исполь­
зующие для вывода информации Еsс-последовательности, при от­
сутствии в системе .црайвера ANSI.SYS будуr работать неправильно.
Все возможности видеосистемы ко~шьютера можно реализовать с
помощью функций прерывания IOh BIOS, которым мы уже пользова­
лись в статье 14 дпя вывода на экран rрафнческих изображений. Про­
граммирование с помощью средств BIOS громоздко, однако большие
возможнос1и и высокая (по сравнению с функuиями DOS) скорость
вывода обуславпивают широкое испо.1ьзование этого метода в прикаад­
ных програ.\fмах. Стоит еще заметить, что средства DOS начинают
функционировать только после полной загрузки операционной си­
стемы, а средства BIOS, записанные в ПЗУ, можно использовать даже в
условиях отсутствия или неработоспособносnt DOS.
В BIOS юtеется целый ряд функций д.1Я обс:rуживания текстового
режима. Многие из них требуют задания атрибута выводимьrх символов.
Атрибут символа зани~1ает один байт и опреде.1Яет цвет символа и фона
под ним, а также некоторые дополнительные харм...·теристики изображе­
ния на экране. Структура байта атрибутов приведсна на рис. 23.1.
В биты 0... 2 байта атрибутов
7 б 5 4 3 2 О Биты записывается код цвета символа.,

а бит 3 при исходной настройке

l lUвет символа видеоадаrm:ра управляет яр­

Uвет tоНа костью символа. Таклм образом,


каждый сю.tвол, независимо от
Яркость симеом .цруrих, может принимать любой
Мерц.м симеом/яркость фОна из 16 возможных цветов. Коды
Puc.2J.J. Структура байта ampu6ym0t1. stрибутов (совпадающие с кода­
ми цветов при выводе гра­

фической информации) были приведсны в табл. 14.1.


Биты 4... 6 байта stрибутов задают цвет фона под данным символом.
Что хе касается последнего биrа 7, то он, в зависимости от режима ви­
дс:оадапrера., определяет либо JlрКСХ.'ТЬ фона под данным симвалом (и
108 Статья23

'ТОГда фон м:ожот nринимать 16 разных цветов), либо мерцание символа.


Так, в режиме мерцания значение старшего полубайта аtрибуrа 8h
обозначает не серый фон, а черный фон nри мерцающем: символе (цвет
кагорого попрежнему опрсделя:стся младшим: полубайтом); значение Ch
- не розовый, а красный фон nри мерцающем: символе и т.д.
Если видеоадаптер поставлен в режим мерцания символов, то фон
может nринимать rолько 8 цветов, соответствующих левой половине
nриведеиной выше таблицы. Для переключекия назначения бита 7
nрсдусм:оорсна подфункция ОЗh функции 10h драйвера BIOS
(nрсрывание lnt 10h). При включении компьютера устан~я ре­
жим уnравления мерцанием:.

В nримере 23.1 показано использование некоторых наиболее


упоорсбительных функций BIOS для работы с экраном: (прсрывание
10h).
Пример 2J.J. Вwвод но эк.ран СШIВольной информации средствами BIOS
1 Очистим акрак, кano:asa ка кеrо черко-6е.пое окио
IIIOV АН, 06h ;ФуiUЩИЯ :S&ДI&КИЯ ОJСИА
IIIOV A'L, 0 ; Рехим со:sдакия (ке прокр}"J.'КИ)
IIIIOV ВН, 07h ;Атриб}"J.' асех сиwвс;.поа а окие - •/б
IIIIOV СН,О ;Верхняя У-коордииа~а
IIIIOV CL,O ;Левая Х-коордииа~а
IIIIOV DH,24 ;Ниzкяя У-коордииа~а
IIIIOV DL, 79 ;Прааая К-координата
int lOh ; ПрерШ1акие BIOS
1 Нарисуем иа :.кране небо.пьшое цаетное окио
IIIIOV АН, 06h ; Функция :saдaiSИJI ОJСИа
IIIIOV AL, 0 ; Реzим со:sдаКИJI (Не прокрутJСИ)
IIIIOV ВН, lEh ; Атриб}"J.' :ае.птый no сиием,у
IIIIOV СН,5 ;Верхняя У-координата
IIIIOV CL, 40 ;Левая Х-коордииа~а
11110v DH, 9 ;Ни:аияя У-координата
IIIIOV DL, 7 5 ; Правая К-координата
int lOh ;ПрерШiаНие BIOS
;Поаиционируем курсор
IIIIOV АН, 02h ;Функция по:sициониро:вания
IIIIOV ВН,О ;Видеостракица
IIIIOV DH,7 ;Строка
IIIIOV DL, 45 ;Стопбец
int lOh ;Црерыааиие BIOS
; BIIUieдeм а окио строку сиwвопо:в бе!l атриб}"J.'о:а (т.е. с атриб}"J.'U81
/ОКИ&)
IIIIOV CX,lenl ; Дnина строки
IIIIOV BX,offaet 111811l;Адрес строки сиwвопоа
IIIIOV АН, OBh ;Функция BШIO.IIA одноrо cИNaona
vr 1 IIIIOV A'L, (ВХ] ICИWВon а AL
inc 8Х 1Сд:винеwся по строке
int .lOh 1Црерыааиие BIOS
loop vr ; ЦJuc.n по строке
;I!.IIUieд.м строку - • окиа, :sадаа атрибутк cиwaonoa
IIIIOV АН,13h 1 ФуКJЩИя :ВШiода строки
llliOV AL,O : Реаиw ( а~риб}"J.' • 8L 1
Вывод на экран текста средствами BiOS 109
--------------------------
шоv ВН,О ;Вид6осжраиица
шоv BL, 04h ;Атрибут всех CИЫIIO.JIOII
1110v СХ, len2 ; ДпИкасжроки
ШОV DH, 16 1Начапька11 DI)SИlU'JJI - строка
ШОV DL, 25 ;Ha'IIIIJIЬИAJI DOSИЦИII - стопбец
pu.sh ps ; НасжроИ14
рор ES ; ES иа каш сеrыект дакиых
1110v BP,offaet aes2;ES:BP ->вbllloдиwall сжрока
int 10h ; ПрерЬlllаиие BIOS
; Поsициоиируеu курсор 11 качапо поспедкей сжроки :tкраиа
JIIOV АН, 02h 1 ФуJuщи11 DOSИЦИOIIИpOIIILIIИJI
JIIOV ВН,О ;Видеостраиица
JIIOV DН, 24 ; Строка
IIIOV DL, 0 ; Стопбец
int 10h 1ПРерЫ11акие BIOS
1 По.п11 даиквх
Dl881 dЬ 16, 1 Строка, 1111111едекка11 11 о:кио 1 , 17
len1•$-JDea1
Dl882 dЬ 22,22,22, 1 Строка, llbllleдeккall вне о:киа 1 ,22,22,22
len2•$-JDes2

Опишем К})атко возможности использованных в примере функций


BIOS.
С помощью функции 06h в заданном месте экрана дисiDiея создает­
ся UDe'Пioe прямоуrольное окно заданного размера. Если в созданные
ранее окна выведен какой-либо текст, то с помощью этой же функиии
текст можно прокручивать вверх (функция 07h позволяет прокручивать
цвет вниз). При этом текст, уходящий за край окна, пропадает, а из-под
противоположного края по.являются пусть1е строки с заданными атрибу­
тами. Для заnОJПiения появляющихся строк текстом следует использо­
вать подходящие функции BIOS.
Функция 02h позволяет позиционировать текстовый курсор, задавая
его местоположение в виде номера строки (0 ... 24) и номера столбца
(0... 79). ВидеодРайвер поддерживает 8 независимых курсоров - по од­
ному на каждую видеостраницу, причем функция 02h позиционирует
курсор на любой заданной странице, независимо от того, какая страни­
ца является активной.
Для вывода на экран символов и символьных строк предусмотрены
функции 09h, OAh, OEh и lЗh. В примере 2J 1 исполь.зованы функции
OEh (вывод символа) и lЗh (вывод строки).
Функция OEh фильтрует управляющие коды 07h (звуковой сиmал),
08h (возврат на шаг), lOh (перевод строки) и lЗh (возврат каретки), вы­
ПOJIНJUJ соответствующие им действия. После вывода каждого символа
курсор персмешается на следующую позицию, что дает возможность

выводить целые строки (исподьзуя вызов функции в I..(ИКIIe). Однако ат­


рибут симвоJiа установИТЪ ИCJIЬЗJI, выводимый симвал приобретает атри­
буr той позиции, куда он выводится.
110 Статья24

Функция 13h предназначена д.'IЯ вывода с1р0к с указанием атрибу­


rоа как каждого символа в отдельносm, так и всей С1рОКИ. Функция:
~ожот ВЫПОЛНJIТЬСЯ в четырех вариантах в зависимост от кода режима,
указываемого а регистре AL. В режимах О и 1 атрибуг символов указы­
вается: сразу для: всей С'IрОКИ в регистре BL, причем в режиме О курсор
не смещается в процессе вывода, а в режиме 1- смещается: на длину
С'IрОКИ. В режимах 2 и 3 атрибугы символов включаются в выводимую
С'IрОку, в которой, таким образом, чередуются: коды атрибуrов и коды
символов, что усложни~ формат С'IрОКИ, но позволя:ет устанавливать ат­
рибуn.~ для: каждого символа независимо. Режим 2 отличается от режи­
ма 3 тем, что в первом случае курсор после вывода не смещается, а во
втором смещается на длину С1рОКИ.

При вызове функции 13h в регистре DX задаются координаты


начала выводимой с1р0ки (в DH - строка экрана и в DL - столбец), а в
регистре СХ- длина выводимой с1р0ки, которая в режимах 2 и 3 оказы­
вается за сч~ байтов с атрибуrом в два раза больше даины С'IрОКИ, ре­
ально появляющейся на экране. Несколько необычно указывается адрес
выводимой с1р0ки. Он должен быть помещен в регистры ES:BP (ES -
сегментный адрес и ВР - смещение в пределах сегмента).
Функция: IЗh выводит не все символы, так как коды 07h, 08h, OAh и
ODh рассматриваются ею, как управляющие.
При выводе на экран текста средствами BIOS необходимо иметь в
виду, что ввод с клавитуры <Ctrl>/C не приводит к завершению про­
граммы. Следует опасаться бесконечных циклов вывода на экран - вы­
ход из них возможен толъко пугем перезаrрузки компьютера.

Статья 24
Косвенные вызовы подпрограмм

До сих пор при вызове подпрограмм мы пользовались командой call


с указанием в качестве ее операнда имени вызываемой подпрограммы.
Такой вызов подпрограммы называется прямым; он нагляден, но не от­
личается rибкосn.ю. ДсйС'1'8JП'СЛЬно, для того, чтобы той же С'IрОКОй вы­
звать друrу10 подпрограмму, необходимо измсниn. исходный текст и
псретранслиjювать программу. Большей гибкостью обладают косвенные
вызовы, в каrорых адрес перехода извлекается не из кода командЫ, а из
Косвенные вызовы подпрограмм 111

JIЧCCK II8МJml или регистров; в коде команды содержится иифорМ8ЦЮI о


том, где нахоДИТСJI адрес псрехода. ИзмеНЯJI nроiраММИЬIМ образом со­
держимое адресуемых командой call .ячеек или реrисrров, т.е. зacЬIJDUI в
них адрес той или ЮIОЙ подпрограммы, мо:жно проtраМмно К8С1JЮИ'l'Ъ
коиаиду call ка вызов 'lребуемой в настоящий момент подпроrраммы.
В примере 24.1 дана ИJDПОС'lрация косвенною вызова с использова­
нием для: ацрсса вызываемой подпрограммы .ячейки паыти.

Пример 24.1. КоаJеННыii t1ЬI30tl noдnJI02JIOAlAI


-in proc

;s.Dедем с IION:IIIIЬJO flyиJЩJOC DOS 09h сообще~а~е pro~~pt

;Поста- ааарос на 880):1 CJDaSOJJa


inpt 1 1110V АН, Olh ; Фующи11 а:аода CJDaSOJJa с ахок
int 2lh
0311р AL, 'у' 'у• ?
1 Наа:ата к.naiSИIIIa
je IIIOde doa ;Да, работаем с DOS
0311р AL,'n' ;Наа:ата к.naВИIIIa 'n'?
je IIIOde bios ; Да, работаем с BIOS
j~~p inpt- ;Наа:ато не у/х, ao:aтopwl'• BIIOJI
.ode dos:шov addr,offset dоs1Эашпем адрес nроцедуры dos
- j~~p cont ;и на apo):lo.n:&eiDie
.ode Ыоs:шоv addr,offset Ыоs;Эашпем адрес nроцедуры Ыоs
cont1 call DS: addr ; Кос:аеикый 1110011 DpOЦeJIYPЫ
1 За11ераос nporp~

~ endp
dos proc 1 Процедура :аыаоDа срцствамс DOS
шоv АН,О9h
IIIIQV DX, offset -•1
int 2lh
ret
dos endp
Ыоs proc ;Процепура :аыао):lа срцствамк BIOS
1 О.Истим акр ан
шоv АН,О6h ; Фуикци11 saд&IDIII окиа
IIIIQV AL,O 1Рехиы COIIДAIQIII ОIСИа
шоv ВН,О7h ;Атрибут всех cиwaOJJoa в окие С•/б)
IIIIQV СХ,О ;Координаты верхи~о neao~o уrпа
IIIIQV DH, 79 ;Ниzая11 У-коордИНата
шоv DI.,2t ;Правая х-коордииаоrа
int lOh ;Прерыааиие BIOS
; Выае):lем строку
IIOV АН, 1Эh ;Функция вывода с~оак
шоv AL, О ; Рехиы О (атрибут а ВI.)
IIOV ВН, О ; ВИ):Iеостраиица
IIOV ВI., ОВh ;Атрибут :асех CID80JJ08
IIOV СХ, len ; Дпииа строаси
IIIIQV DН, 12 ;На•ап•ная аоsИЦИII - строка
JIIOV DI., 20 ;На•ап•наЯ DOSJЩJCII - СТОJJбец
push DS 1 HacтpoJDC IS на HAID
рор IS ; сеrмеит JIIUUIЫX
шоv BP,offset aes2;1S:BP ->аыаоаим&ll строка
112 Статья24

int lOh 1Прерыаание BIOS


1Поsиционируем курсор 11 начапо поспе.z:rней C'J:'pOJCИ :tкрана
IIIOV АН, 02h ;Фуихци.с поsиционироааки.с
IIIOV ВН, 0 ;ВИ.z:rеос'lраница
IIIOV DН, 24 ;C'J:'pOKa
IIIOV DL, 0 ;Сто.пбец
int lOh ;Прерыаакие BIOS
ret ; 8оsврат иs прерыааки.с
bios endp
; По.п.с .z:rаииых
ad.dr dw О ;По.пе .zrn.c a.z:rpeca по.z:rпроrр.-
prompt dЬ 'Драйаер ANSI.SYS устаноапен? [Y/N] : $'
111es1 dЬ 27, 1 [2J',27, 1 [12;20Н',27, 1 [31;1111 1
dЬ 'Начинаем работать, испо.пьsу.с cpe.z:rcтaa DOS'
dЬ [25;1Н$'
27,' [0111',27,'
111es2 dЬ 'Начинаем работать, исnо.пьsу.с cpe.z:rcтaa BIOS'
len•$-111es2

В проrраммс имеются главная процсдура main и две процсдуры­


подпроrраммы dos и Ьios. Обе выполняют очистку экрана и вывод в се­
редину экрана "своей" цвсmой строки "Начинаем работать ... ". Процеду­
ра dos использует для очистки экрана, позиционирования курсора и за­
дания цвета Еsс-последовательности и, следовательно, может фующио­
нировать только при наличии в системе драйвера ANSI.SYS. Процсдура
Ьios выводит на экран то :.е самое, но средствами BIOS и не требуст
драйвера ANSI.SYS. В цслт: наглядности в процедурах для выводимых
символов используются разные цвета.

Основная процсдура выводит на экран вопрос о наличии в системе


драйвера ANSI.SYS и вводит в проrрамму ответ пользователя в виде
символов у (ycs, да) или n (no, нет). Далее введенный символ анализи­
руется и, в зависимости от ответа пользователя, осуществляется персход

на метки mode_dos или modc_Ьios. В предложениях с этими метками


ячейка addr заrружается адресом требусмой подпроrраммы. После на­
стройки ячейки addr выподняется команда call DS:addr, которая и осу­
ществляет косвенный переход.
Указание перед именем ячейки памкnt обозначения сеrмсНТ11оrо
ре111стра, в данном случае DS, задает косвеннОСТh вызова. Другой спо­
соб задания того же - описатель word ptr (word pointer, указатель на сло­
во):

call word ptr addr

Косвенные вызов1..r можно выполнять с помощью широкого набора


способов адресации. Тах, сели адрес вызываемой подпроrраммы занССПI
в один из базовых или индексных реrис7р0в, то команда вызова упро­
щается:

IDOV ВХ, O.ff8et ЬiО81 В 8Х a.upeo CoUIC>Й DO.JUJpOl'p . . . . .


call ВХ 11Сосве1111111А вкsов
Прерывания попьзователя 113

PerиC'IpOВaR адресация возможна и в том случае, когда адрес под­


программы находитСя в ячейке памяти:
IIIIOV SI, offset addr; В реrистре SI IIJIPec 11чейхи
;с IIJIP•coм uоипроrраммк

call [SI] ;Косаеккый аыsоа

Статья 25
Прерываиия пользователя

Программы обработки прерываний (или попросту обработчики пре­


рываний) относятся к важнейшим проrраммным средствам переаналь­
ных компьютеров. Запросы на обработку прерываний мoryr иметь раз­
личную природу. Прежде всего различают аппаратные прерывания от
периферийных устройств или ;труrих компонентов системы и про­
rраммные прерывания, вызываемые командой int, которая используется,
в частности, для проrра.\fмного обращения к функциям DOS и BIOS.
Сигналы, возбуждающие аппараn1ые прерывания, мoryr инициировать­
ся цепями самого процессора, например, при попытке выпо;шения опе·

рации деления на ноль (такие прерыв:шия называются внуrренними,


или отказа.\fи), а мoryr прихощrrь из периферийного оборудования
(внешние прерывания). Внешние аппараn1ые прерывания вызываются,
например, сиrна.аа.\!И микросхемы таЙ)>!ера, сишалами от принтера или
контроллера диска, нажаn1ем или оmусканием клавиши. Таким обра­
з-ом, можно говорить о прерываниях 1рех пшов: внуrренних, внешних и

проrра.\fмных. Независимо от источника, действия процессара по об­


служиванию постушшшего прерывания всегда выполняются одинаково,

как дпя апнараniЫХ, так и дш1 проrра.\fмных прерываний. Эrи действия


обычно называют пронедурой прерывания. Подчеркнем, что здесь идет
речь лишь о реакции самого процессара на сигнал прерывания, а не об
алгоритмах обработки прерывания, предусма1риваемых пользователем в
обработчике rrрерываний.
Объекты вычислите.аьной системы, принимающие участие в проце­
дуре прерывания, и их взаимодействие показалы на рис. 25.1.
Самое начало оперативной памяти от адреса OOOOh до ОЗFFЬ отво­
дится под веrсrоры прерываний - четырехбайтовые области, в которых
хранятся адреса программ обработки прерываний (ПОП). В два старших
114 Статья25

байта каждого вercropa заnисывается сеrмеН'Пiый адрес ПОП, в два


младших - оmосительный адрес точки входа в ПОП в сегменте. ВеК"rо­
ры, как и соответствующие им прерывания, имеют номера, nричем век­
тор с номером О располагается, начиная с адреса О, вercrop 1 - с адреса
4, вercrop 2 - с адреса 8 и т.д. Bercrop с номером N занимает, таким об­
разом, байты памяти от N*4 до N*4+3. Всего в выделенной под веrсrоры
o6лacnt: памяти помещается 256 ве~о.'ТОров.

Адреса ммяти

°2 ~I:::Р-:п::-:о=-=п:-:о::--1
cs поп о
j+- Вектор прерывения о
4 IP ПОП 1 +-Вектор прерьеания 1
6 CS ПОП1
Процессор

IP
cs
Флаги IP
CS
J+- Вектор nрер~ого
nроцесса
Флаги

Рис. 25.1. Процедура npepыtJOHШI.

Получив сиmал на выполнение процедуры прерывания с оnреде­


ленным номером, процессор сохраняет в стеке выпошiЯемой проrрам­
мы текущее содержимое трех регистров nроцессора: perиC"Ipa флагов, CS
и IP. Два nоследних числа образуют полный адрес возврата в прерван­
ную проrрамму. Далее процессор заrружnет CS и IP из соответствую­
щего ~rcropa nрерываний, осуществ.'IЯЯ тем самым переход на ПОП.
Проrрамма обработки nрерывания обычно заканчивается командой
возврата из прерывания iret (interrupt retum, возврат из nрерывания),
выполняющей обратные действия - заrрузку IP, CS и perиC'Ipa фдаrов
из стека, 'fJ'O nриводит к возврату в основную программу в ту самую

точку, rде она была прервана.


Большая часn. веrсrоров прерываний nредназначена для выnолнения
определенных действий и автоматически заполняется адресами систем­
ных nрограмм nри заrрузке системы; часn. веrсrоров зарезервирована

для будущих nрименений, а часть (.;он~о.'J>С'IНО с номерами 60h... 66h)


свободна и может использоваться в nрикдадных проrраммах.
Для того, 'fl'Обы nрихладной обработчик получал уnравление в ре­
зуm.ТIПС прерь1118ИИЯ, его ад;рс(: СЛедует ПОМССПIТЬ 8 COO'J1IC'I'Cl'DyJOЩИЙ
Прерывания пользователя 115

вer:rop прсрываиия. Хаrя содержимое вer:ropa прсрываиий м:ожио изм:с­


НИ'IЪ простой командой mov, однако nрсдnочnпельнсс исп0JIЬ30вать
специально nрсдусмспрснную фунiЩИЮ DOS 25h. При вызове функции
2Sh в pcrиCip AL помещается номер модифицируемого вer:ropa, а в рс­
ГИСiрЫ DS:DX - ПОJПIЫЙ двухсловный адрес нового обработчика.
Рассмотриw методику использования в прикладной проrрамм:с nрс­
рывания пользо~.

ЛpШtllfJ 25.1. Odpa6olfl/tQ пр~рw•аиий поль:юнтwr


n - 6Sh p.roc
; Проце.аура капоzеки11 ка ахран ЦВеТКОХ'О OICJia д.IJII mut._,.8CKOЙ
; о-стки :~~крана по ходу BIIIDOJIK8КИII DpOX'pUAМ
JIIQV АН, 06h ; Фyluauc11 :sадакх11 окка
IIIOV AL, 0 ;Реzим со:sдакх11 окна
JIIQV 8Н, lВh ; АтрИб)"l' ВСОХ CИNIIIOJIOB В OICJIO:
;Светпо-бир»:sовые сИNВопы, синий фок
JIIQV сх,о ;Координаты верхке:t"о neвoro yrna 0,0
JIIQV DН,24 ;Нкzк1111 У-координата
JIIQV DL,79 ;ПpaBall Х-координата
int lOh ;Прерываиие BIOS
i.ret
n - 6Sh endp
-1п p.roc
JIIQV AX,data
JIIQV DS,AX
;Заnопниw вектор прерывакх11 no.nь:soвaтen11 адресом хашеrо
обработ~а
JIIQV АН, 2Sh ; Фyluauc11 :sадо.пхеки11 вектора прерыаакх11
IIIOV AL, 6Sh ;Ho1W18p вектора
IIIOV DX, offeet nеw_65h;Сыещекие прикпадко:t"о обработ~а
puah DS ; Сохраним DS
puah CS ;Настроим DS ха се:t". .кт ко~ (В
рор DS ;котором хаходитс11 каш обработ~)
int 2lh 1Вы:sовем DOS
рор DS ; Восстановим DS
1 Вудем в цracne выводить к" :~~кран строки с предваритепьхой
1 о-сткоА ахрана
gogo 1 int 65h ;ВЫ:sов прикпадхо:t"о обработ~а (о-стка
;акраха перед выводом текста)
;По:sкцкокируем курсор
JIIQV АН, 02h 1 Фyluauc11 по:sкцкокировакх11
JIIQV ВН,О ;Видеостракица
IIIOV DН, line 1 Строка
JIIQV DL, colo\.lllln 1 Сто.nЬец
int lOh 1 Пр ерывакхе BIOS
1 Вмведем ка :~~крах строку CИNВOJIOB
IIIOV АН, OAh ; Фyluauc11 вывода CИNIIIOJJa бе:s атриб)"l'а
IIIOV AL, е уа ; СИN80.11
JIIQV ВН, О ; Видеостраница
aov СХ,60 ;Ко•ффициеит повтореки11
int lOh ; Прерывакие BIOS
1 и:s. .иим CИNIIIOJJ и по:sИЦИJО и sацикпим пporpaaaq с аоsасzхостыо ••
I:Saвepweкиll по каzа~ кnааи8 <Ctrl>/C
inc •уа ; cne~ cИNВOJJ по табпице ASCII
116 Статья25

inc line ; CJrO.II)IJIIIIIUI C'l'pOICa 81Cpalla


IIIOV »1, 08h ;Фунхци• ввода беs аха, чувствует
int 21h <Ctrl>/C
jlllp qoqo ;ВесJСовечннй ~
IIIAin ondp
;Пoror данккх
lino dЬ 2 ;Строка
colo\111111 dЬ 10 ;Стопбец
SYJII dЬ Olh ; lilшso.JXJQOIЙ cюason

Процедура ncw_65h, вызываемая с помощью проrраммного прсры­


вания (для которого выбран вeicrOp 65h), выполняет простую операцию
- очищает экран, накладывая на него окно с заданным атрибуrом.
В основной проrрамме прежде всего заполняется вeicrOp прсрывания
65h. Поскольку функция запОJШения вeicrOpa 25h требует, чrобы адрес
прикладного обработчика содержался в паре регистров DS:DX, а DS у
нас указывает на сегмент данных, перед вызовом DOS в DS следуст за­
нести сегмекrный адрес того сегмента, в котором находиrся обра­
ботчик, т.е., в нашем случае, общего сегмента команд. Эror адрес из­
влекается из CS.
Далее в бесконечном цикле выполняется вызов нашего обработчика,
позиционирование курсора с помощью функции 02h BIOS и вывод на
чистый экран строки символов (функцией OAh BIOS). Эта функция не
позволяет задавать атрибугы выводимых символов. Символы приобре­
тают атрибуr тех позиций, куда они выводя.тся, т.е., в нашем случае, ат­
рибуr окна. После вывода на экран строки выполняется изменение кода
символов и номера строки экрана, куда эти символы выводятся.

Функция DOS 08h (ввод символа без эха), включенная в цикл, вы­
полняет две задачи. Во-первых, она останавливает вьmОJШение про­
rраммы и позволяет изучить содержимое экрана в каждом шаге цикла.

Для того, •П'Обы продОJJЖИТЪ выполнение проrраммы, достаточно нажа1Ъ


на любую клавишу. Во-вторых, эта функция, будучи чувствительна к
вводу с клавиатуры сочетания <Ctrl>/C, позволяет завершить проrрам­
му, которая в противном случае выполнялась бы вечно.
Табпичные вызовы подпрограмм 117

Статья 26
Табличные вызовы подпроrрамм

В тех случаях, когда программа с вюпоченными в нее подпрограм­


мами вьmолняется всегда по более или менее определенному алгоритму,
вызывая подпрограммы в заданном заранее порядке, подпрограммы

можно разместить в <Уrделъных процедурах (или назначиrь им входные


метки) и вызывать по именам. В более гибких программных комплексах
бьпsает удобно предусмотреть механизм вызова 'JрСбуемой подпрограм­
мы по ее номеру. Такая ситуация типична, в часmости, для программ
DOS и BIOS. ДействЮ'СЛЪно, для вызова требуемой функции DOS мы
задаем (в регистре АН) ее номер и вызываем с помощью прерывания int
2lh диспетчер DOS. Диспетчер извлекает из регистра АН номер функ­
ции и ахтивизирует по этому номеру соответствующую программу из

числа содержащихся в DOS. Так же вызываются и функции BIOS.


Рассмотрим упрощенную имигацию диспетчера DOS. Пусть мы
имеем в програм:ме группу подпрограмм и Х<УI'ИМ вызывать их так же,

как вызываем функции DOS - с помощью какого-либо прерывания


пользователя, указывая в регистре АН номер "функции". Тогда в нашей
программе, кроме собственно подпрограмм, должен быть еще и дис­
петчер, вызываемый с помощью прерывания и предающий далее управ­
ление на подпрограмму с заданным в perиC'JpC АН номером. Адрес
этого диспетчера должен бьnъ занесен в какой-либо из свободных век­
торов. Используем так же, как и в примере 25.1, вепор пользоВ~mШЯ
65h.
Пример 26.1. Та6ли'lнwй /JЫЗOfl noдnpozpOIOI
;ДИспет•ер прерывани~ 65h
new 65Ы puah ВХ ; An~ пор~дка coxpa-.r
- puah DX ;испопь:sуем.rе реrистрк
IIIIOV BL, АН ; • ФуИJЩИJО" отпра:ви.м 11 8L
IIIIOV ВН,О ;Теперь номер фунхцим 11 ВХ
shl ВХ, 1 ;Умио:ким ка два
call addr _ tЫ [ВХ] ; Вы:sовем noдnporp.....,
рор DX ;Восстако:ви.м
рор ВХ ;реrистрк
iret ; Во:sврат и:s nрер118авк•
;Подпроrраwwы-•tуикции•
•uЬО: IIIIOV АН, 9
IIIIOV DX, oftset •••О
118 Статья28

int 21h
ret
аuЫ: IIOV АН,t
IIOV DX,offaet -·1
int 21h
ret
аuЬ2: IIOV АН,t
IIOV DX,offaet -·2
int 21h
ret
аuЬЭ: IIOV АН,9
IDOV DX,oftllet ... э
int 21h
ret
аuЬ4: IIIOV
IIOV
int
АН,t
DX,offaet
21h
.....
ret
-in proc
1Исаопьsуем ареркаавие попьаоаа~еп. 65h ~ акsоаа подпроrраww по
1ко~у. Установиw арикпадной обработчик преркаани• б5h
mov АХ, 2565h ; Ф)"JuщJcll sадопне-11 аеJСтора (65h)
mov IЖ, oftaet new б5h
pWih cs ; Настроим os
рор DS 1 ка сеrмеит JСомаид
int 21h
mov AX,data 1Ннкцхапиsаци11 сеrмектиоrо
mov DS,AX ;реrистра DS
1Вкsоаем поспедоаа~епько наши подпроrрамwк
1Номвр подпроrрамwк а реrистре АН
IDOV АН, OOh
int б5h
IDOV АН 1 01Ь
int 65h
DIOV АН, 02h
int 65h
IIIOV АН, ОЭЬ
int 65h
IDOV AН,Oth
int 65h
1 ЗааерD~М aporp.....v
IIIOV АХ, 4C00h
int 21h
aain endp
Д&.НИIIХ
1 Ilolla
l'r&6nицa а.аресоа пoдпporp­
addr tЫ dv аuЬО
- dv auЬl
dv аuЬ2
dv аuЬЭ
dv auЬt
1Вкаоаимме оооб•емм•
... о dЬ 27,' [Эl.о.работапа аодпроrрамwа номер 0',10,13,27, '$'
. . . 1 dЬ 27,'[32.о.работапа аодпроrрамwа номер 1',10,13,27, '$'
...z dЬ 27,'[3180тработапа подпроrрамwа номер 2~,10,13,27, '$'
... э dЬ 27,'[3480тработаnа подпроrрАNWА номер 3',10,13,27, '$'
..... dЬ 27,'(35.0тработапа подпроrр&NW& номер 4',10,13,27,' [08$'
Макрокоманды 119

В диспетчере прерывания int 6Sh сохраняются используемые в нем


и в подпроrраммах регистры, после чего номер вызываемой "функции"
пересылас"rоя нз байтового регистра АН в словвый регистр ВХ, который
в дальнейшем будет использоваrъся в качестве индексного. Далее ко­
мандой shl (shift lcft, арифмС'mЧсский сдвиг алсво) содержимое ВХ
сдвнгасn'СЯ алсво на 1 дВОИЧНЫЙ разряд, что эквивалскmо умножению
на два. Теперь содержимое ВХ можно рассматрНВil'П> как индекс в таб­
лице адресов addr_tЬl, в которой записаны смещения (0111оснп.льныс
адреса) подпрограмм в порядке, опредСJUПОщсм их номера.
Команда

call addr_tЫ(BX]

косвенного вызова передаст управление на "Jребуемую подпрограмму.


После восстаноалсния регистров диспетчер завершаст;я командой iret,
возвращая управление в основную процедуру.

Вес использованные в примере подпроrраммы практически одина-


. ковы. Они выв6дят на экран некОторые сообщения с помощью функ­
ции DOS 09h. Для каждой подпроrраммы предуСМО'JрСНО собственнос
сообщение, в которые д1IJI красоты включены Еsс-послсдОВIП'СJIЬНОСТИ
установки цвета.

Алгоритм основной процедуры main не содержит ничего нового. В


ней устанавливается прикладной обрабО'rшк прерывания int 6Sh (можно
было, разумеется:, выбра1Ъ и дРУГОЙ вектор нз диапазона 60b... 66h), сеr­
мскmый регистр DS настраивается на сегмент данных и, наконец, с
ПОМОЩЬЮ KOMIUЩ int 6Sh ВЫЗЫВIUОТС.Я: ПОСЛедовательно ПОдпроlр8ММЫ 1
номера которых указываются с помощью регистра АН.

Статья 27
Махрокомаиды

Проrраммы, написанные на языке ассемблера, часто содержат по­


вrорJПОщиеся участки текста с одинаковой струiСl)'рОй. Такие участки
текста можно оформИ'IЪ в вкде так называемых махраопределений
(макрокомшщ, макросов), хараlСI'Срнзующихс.я: пронзвольными именами
и списками форма.1ЬНЫХ парамстров. После того, как махроопрсдслеиие
сделано, появление в программе строки, содержащей имя ы:акроопрсдс·
120 CmamЬR27

ления и список фаJСmчсских: парамС1JЮв, приводиr к rенсрации всего


tребуемого ~ксrа, называемого макрорасширением. Варьируя: фак­
mческие парамеtры, можно, сохраняя неизменной C'lpYJCl'YPY макро­
расширения, изменsrrь отдельные его элементы.

Пример MolqiO~UJA~oнOtl • COCIIUI•e программы


27.1.
text 8eqment 'code'
a88UIIIe CS: text, DS :data
;Махрооuреде.пеиие NAJCPOKOМAIUIII write а111111ода строки на 3краи
write mAcro 8tr
mov АН,О9Ь
mov DX,offset str
int 2lh
endJII
mAin proc
write stringl
write string2
mAin endp
;Поля данных
atringl dЬ '8ыаод текста с nоыо=ь~ wакрокоwаидн',10,13,'$'
8tring2 dЬ 'Еще одна строка',lО,lЗ,'$'

Макроопределение начинаеn;я с директивы macro, перед которой


ухазывае-n:я имя макрокоманды (write в нашем случ:1е). После оператора
macro можно указаТh одно или несколько произвольных имен, которые

воспринимаю-n:я ассемблером, как имена формальных аргументов. В


случае указания нескольких nараметров они разде:t'lю-n:я заnятыми. За­
канчивае-n:я макрооnределение оnератором endщ. Расnо.1оже1ше макро­
определения не имеет значения, так как оно не транс:rир}ется, а только

заnоминае-n:я транслятором ддя nоследующего ис1ю.1ьзоваJшя. О;J.нако


макроопределение должно nредшествовать строка.\f его вызова.

Текст макроопределения пише-n:я так же, как и -rекст ,1юбой nро­


граммы. Формальные аргументы исnо.·Iьзуются в макрокоманде так, как
сели бы это были обычные элемснть1 прщра.\IМiюй строки. В нашем
примере исnользуется один napaмe'lp str, который служит для nередачи
в макрорасширение имени выводимой на экран С'lроки. Вообще napa-
MetpЫ макрооnределения моrут заменять собой любые элементы языха:
обозначения pentc'IpOв, команд, описа-rелей, констант и т.д.
Хотя исnользование макрокома.~щ обычно упрощает программу и
делает ее нагляднее, это аmоси-n:я только к исхо;:~;ному -rексту програм­

мы. Объектный и загрузочный модули не изменяю-n:я. Эrим макроко­


манды отличаю-n:я от подnрограмм, которые позволяют сокрапrrь раз­

мер выполнимой программы за счет описаiiИЯ повторяющихся участков


лишь однажды (в ~к~ подnрограммы). Однако макрокоманды nредо­
ставляют гораздо большие возможности изменения -reкcra макрорасши-
Макрокоманды 121

рения в зависимости от значений факгических параметров. В целом


можно сказап., ч-rо макрокоманды служат для упрощения процесса

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

цшо требуемою алrоритма.


В примере 27.1 текст макрокаопределения вкточен непосредствен­
но в текст программы. В тех случаях, когда макрокоманды оrmсывают
некоторые стандартные процедуры широкою назначения, например,

программную задержку или вывод на экран С1JЮКИ текста, целесообраз­


но тексты макроопределений поместип. в макробиблиаrеку.
Макробиблиотека представляет собой файл с текстами макроопреде­
лений. Макроопределения заrmсываются в этот файл точно в таком же
виде, как и в текст программы. В примере 27.2 приведен текст файла
макробиблиотеки с произвольным именем МАС.МАС, содержащей
четыре макрокоманды write, outprog, delayи stop.

Пример 27.2. Содержимое файла МАС.МАС с ма"роопределенШIАiи.


write D\Acro atr ;Начало wакроопр~деnенил write
IIIOV АН,О9h
DX,offaet atr
IIIOV
int 2lh
endm
outprog D\Acro ;Начало ыахроопредепенил outprog
II\OV AX,4C00h
int 2lh
endm
delay D\Acro ti.Jne ;Начало NАКрQОаредепенил delay
local outer,inner
puah сх
IIIOV СХ, ti.Jne
outer: puah сх
IIIOV CX,6553S
inner: loop irmer
рор сх
loop outer
рор сх
endm
atop DIACro ;Начало wакроопредаnенил atop
push АХ
IIIOV АН, 08h
int 2lh
рор АХ
endJn

Макрокоманда \\'rite, рассмаrренная вьппе, осуществдяет вывод на


экран текстовой С1JЮКИ.
Макрокоманда outprog вызывает функцию DOS завершения про­
граммы 4Ch. Почти каждая щюrрамма должна заканчиваться вызовом
этой функции, поэтому использование макрокоманды outprog при ин­
тенсивном программировании мож~ привести к некО'rорой экономии
времени.
122 Статья27

Макрокоманда delay реализует задержку на зацаиное параме1р0м


timc время. Кон:креmая величина задержки зависит or nma компьюrера
и дОJDКНа быть определена экспериментально. В тексте маJфООпределе­
ния есть особенность, связанная с использованием циклов. Поскольку
метки outer и inner не ЯJWООТСЯ формальными параметрами, при по­
вторном вызОве этой макрокоманды они повторятся в тексте макрорас­
ширения, что приведет к ошибке трансляции (множественное объявле­
ние имени). Для roro, чrобы избавиrься or множественноrо объявления,
метки outer и inner объявлены с помощью диреJсr'ИВЫ local локальными.
В процессе макрорасширения локальные имена преобраз)'Ю'rея в симво­
JIИЧеские обозначения вида ??0001, ??0002 и т.д. и при мноrокраnrых
вызовах будут разлИ'Iаться:. Эrа макрокоманда написана несколько
изя:щнее предыдущих в rом отношении, что в ней предусмотрено со­
хранение (в начале) и восстановление (в конце) используемою в макро­
команде perncтpa СХ. Таким образом, :ny макрокоманду можно безбо­
язненно использовать в JIЮбых местах программы - ее вызов не приве­
дет к разрушению реrnстров.

Макрокоманда stop служ:ит для: приостановки выпОJIНения програм­


мы до нажаmя: любой КJiавиши. Для: этоrо использована функция: DOS
OSh, коrорая ожидает ввода с КJiавиатуры символа, а получив символ, не
оrображает ero на экране. Таким образом, макрокоманда не будет иска­
жать текущее содержимое экрана. В ней так же сохраняется: и восстана­
вливается: используемый pc:rncтp АХ.
Файл макробиблиотеки должен храниться в исходном виде, ero не
медует транслировать. В примере 27.3 приведсна проrрамма, исполь­
зующая некоrорые макрокоманды из файла МАС.МАС.

Пример 27.3. Вьlэов мarqюltOJiaнд uз макробиблиотгки.


text seqment 'code'
include JDAC,JDAC ;Сообщение травсл.11тору ИNВIDI файпа
;с макробибпиоте~ой
ass\DIIe CS:text, DS:data
JDAin proc
IIIOV AX,data
IIIOV DS,AX
write strinq1 ; Вкsо1111
delay 200 ; NaКpOKOIМJUI
write strinq2 ;с ~oJUCpeTK1oD81
de1ay 500 ; арrумектАNИ
write strinq3
outproq
8Ain endp
text enda ; Конец сеrмекта комаид
; Пon.ll JIAИIIIIX
atrinq1 dЬ 'Стро~а 1',10,13,'$'
atrinq2 dЬ 'Строка 2',10,13,'$'
atrinq3 dЬ 'Строка 3',10,13,'$'
Структуры 123

Для тою, чтобы 1pa11cmrrop подставил на место имен макрокомаид


их макрорасширсНIUI, в тсGТС прсирам:м:ы следуст обы1виrь им:я: м:ахро­
библиоrсiСИ с помощью дирсiСIИВЫ includc. После мою в проrрам:м:с
можно исПОJIЬЗОваm. .mобыс м:акроmм:анды из этой макробиблиоrсiСИ.

Статья 28

Сlрукrуры предСТ8ВЛJDОТ собой шаблоны с оiUiсаниями форматов


данных, которые можно накладывать на разпичныс участки 118МЯ'111,

чтобы затем обращiП'ЪСя к полям этих участков с помощью мнемо­


нических имен, определенных в оiUiсании сnрупуры. Сrрупуры осо­
бенно удобны в тех случаях, когда мы обращаемся к обласп1м 118МЯ'111,
не входящим в cerмelfl'ЬI проrраммы, т.е. к областям, поля которых
нельзя oiUicaть с помощью символических имен. Рассмотрим в качестве
примера задачу определения метки тома (дискеты или Же<:'IКОЮ диска).
Для решения этой задачи нам приде-rея сначала познакомиться с рядом
новых понятий.
Метка тома создае-rея обычно с помощью команды DOS l.AВEL
Метка может иметь до 11 символов, разрешенных в именах файлов, т.с.
большую часть знаков кодовой таблицы (вкmочая русские буквы и
псевдоrрафические символы), хотя рекомендуе-rея использовать в метке
только цифры, латинские буквы и некоторые специальные знаки, на­
пример, -, _, -, $, 1, @, #, %.
Метка занимает один из блоков данных корневою юrra.лora, пред­
назначенных для заiПiсей о создаваемых в корневом uталоrс файлах и
подкаталогах и представляе-rея системе. как: один из файлов этою ката­
лога. Чтобы ОТJIИЧИТЬ метку тома ar файла, ей присваивае-rея юрибуr 8;
кроме тою, в записи о метке в поля длины и начальною ICII8C'I'Cpa зано­
ся.тся нули. в то же время метка, как: и обычный файл или uталоr, xa-
pa!Qq)ИЗyeтcJI даrой и временем создания. Метка всегда с()ЗД8С'nт в
корневом каталоге; на каждом томе может быть только одна м:сmса.
Для тою, чтобы определить метку тома, надо просмаrретъ корнсвой
каталог диска и попьrrаться найти в нем заiПiсь с мрибуrом 8. Если та­
кая заiПiсь имсе-rея, это и С(.'ТЬ заiПiсь о метке. Если такой записи ист,
это значиr, что данный диск не имеет метки.
124 Статья28

Для поиска файлов на диске в DOS предусм01рены две функции -


4Eh (поиск первоrо файла) и 4Fh (поиск следующих файлов). Обычно
.эти функции используются Д1IJI поиска всех файлов, СООТ'IIС'ООТВующих
указанному шаблону rрупповой операции, например, всех проrраммных
файлов (шаблоны •.ЕХЕ или •.СОМ) или всех файлов с определенным
именем и любыми расширениями (МYPROG.*). Кроме тоrо, можно
указывать а1рибуты искомых файлов. При поиске rруппы файлов снача­
ла вызывается функция поиска первоrо файла, для которой в качестве
входных па~аме1ров указывается rрупповос имя искомых файлов и их
mрибут. После нахождения первоrо файла из rруппы вызывается (в
цикле) функция поиска следующих файлов; ддя нее входные параметры
отсутствуют. Поиск следующих файлов ведется до тех пор, пока функ­
ция установкой флага CF не сообщит, что больше файлов нет.
Обе функции поиска, найдя первый или очередной файл, передают
cro характеристики (имя, размер, а1рибуты, дату и время создания) в
специальную системную область, которая называется дисковой облас­
тью передачи данных (disk transfer area, или сокращенно DTA). По
умолчанию эта область располагается в префиксе проrраммы (PSP) со
смещением от ero начала8i>h. Если пользователя почему-то не уС'lраи­
.вает такое расположение DTA, DH может создать альтернативную DTA в
своем сегменте данных, для чеrо предусм01рена функция DOS с номе­
ром IAh. Имеется также и возможность определения адреса текущей
DTA (функция 2At).
Функции поиска файлов возвращают информацию о характериС'ПI­
ках найденных файлов в определенном формате. В таблице 28.1 приве­
дсны адРССа полей данных DTA, заполняемых этими функциями.

Таблица 28.1. 001/R даннш DTA noc.re заполнения их функцшwи 4Eh ши 4Fh.

Смещение Число байтов Содерхкмое

OOh 21 Недокумеи~оааииа~ область


1Sh 1 Атрибуты файла ипи катапоrа
16h 2 8peNR соsдаии~ файпа
18h 2 Дата соsдаии~ файпа
lAh 4 Лоrический paswep файпа а байтах
1Вh 13 ИNR и расширение файпа а формате ASCIIZ

Имя и расширенttе файла записываются в DTA прописными буква­


ми и раздСЛЯIО"rоЯ точкой (отсутствующей в записи каталога). Специфи­
кациs завершается байтом с двоичным нулем. В отличие от формата ка­
талога, сели в имени меньше 8 символов, оно не допОJIНЯется пробела­
ми. Такиы образом, спецификация может иметь длину от одноrо байта в
позиции IAh (плюс нуль в позиции 1Bh) до 13 символов (8 символов в
Структуры 125

имени, точка, 3 символа в расширении и нуль), занимающих все отве­


денное для специфИкации файла место от 1Eh до 2Ah.
Форматы записи даты и времени создаJ\'ИЯ файла (рис. 28.1) совпа­
дают с соответствующими форматами каталога.
Метка записьmаСтся
151413121110 9 8 7 6 5 4 3 2 1 о в поле DTA точно так
же, как и имя файла.
1 1 1 11 1 1 11 1 1 111 1 1 1 Поэтому если в метке
Г од Месяц ..1_ День _J больше 8 символов, то
15 14 1з 12 111 о 9 8 7 6 5 .4 3 2 1 о между первыми 8-ю и
последними 3-мя сим­
1 1 1 1 1 1 1 1 1 1 1 ~ 1 1 1 1 1 вола.\iи метки стоит

1._ Часы - - ' - - Минуты __L Секунды/2 J точка (код 2Dh). Эrо
необходимо иметь в ви­
Рис. 28.1. Фор.wаты записи даты и времени созда­
ду в случае проrраммно­
ния файла в каталоzе и в дисковой области пере-
го анализа найденной
метки тома.

Пример 28.1. Структуры. Чтение ;wетки тома


; Оnределение структуры
dta struc ; ll)Начало оnределения
wild ca.rd dЬ 15h dup (7); (2)Заре~ервированы
attrЗ:b dЬ 7 ; ( 3) Атрибуты фаW!а
f~le t~:ne
dw 7 ; t4)Вреыя со~дания
file-date dw 7 ; (5)Дата со~дамия
file-size dw 2 dup (7) ; (6) Ра~мер файла
file- nam.e dЬ 12 dup (7) ; ( 7) Имя и расширение
dta - ends ; t8)Конец оnределения
anain proc ; (9)Начапо rлавной nроцедуры
mov AX,data ; (10/Инициалиsация cerweи~иoro
anov DS, АХ ; (11)реrистра DS
;Найдем wе~ку тоМА
mo•.r АН, 4Eh ; (121Функция nоиска первоrо файла
mov сх, е ; (13JАтрибут wетки тома
mov DX,offset dnAme; (14)Сnецификация искомых файлов
int 2lh ; ( 15)
jc nolaЬel ; (lбJМеткА отсутствует
;Настроиw::я иа DTA (ES после ~arpy~юt nporpiUo04bl yxasblJiaeт 11& PSP)
mov ВХ, 80h ; ( 17) ES: ВХ-адрес DTA
;Настроиw реrистры для коиаИд работы со строкамк
push ; (18)0бwеияем содер:к:ююе
DS
push ; ( 19) реrистров DS и ES, чтобы
ES
рор ; (2u)DS уха~ывап на PSP, А ES
DS
рор ES
; (21) иа сеrwеит даи.ных пporpiUo04bl
mov lЬl1 ; (221ES:DI -> попе дпя иwеки файла
DI,offset
; (wетки тома} в пporp.-
lea SI, (BX].file nam.e; (23}DS:SI -> иwя wе~кк в DТА
cld ; (24)Двиzекие вперед по строке
;Будем переwеща~ъ wе~ку иs DTA в nporp~ посиwаопъио до иупя
DIOVlЬl: lodsb ; (2510чередиой сиwвоп -~кк в AL
сшр AL,O ; (261Метка коичипасъ?
128 . Статья28

je CJ81 1 (27)Да, 81а BIIXOД ИS ЦИIUia


atosb 1 (28)Нет, отправиw симвоп в пpo~awwv
jJII) IIIDVlЬl 1 (29)На nовторение
golc 11DV АХ, [ВХ] .file date; (30)Пo.JIY'OIМ дату COSДaJQCa
pWih 11 1 (31) Восс'fuовиw а.чресу~сть д08111Х
рор Dl 1 ( 32)череs cerмeнтiiiiiЙ реl'истр DS
pWih АХ 1 ( 331 Сохраним дату
1Црео6раsу.м день
· and. АХ, 11'Ь 1 (341Оставим в АХ топьм:о би'l'К дна
IIIDV DL, 10 1135)Подепим ка 10. АL-астиое (чиспо
div DL J(3б)десатков дией), АН•осоrаоrок(чиспо
lдИ.Й)
add АХ, 1 00 1 ; (37)И oro, и друrое npeoбpasy.w в
;символы

111DV 1Ьl3+1,АН ; 1381 Отправим в пporpawwv


IIIDV 1Ь13+0,АL ; (З9)Поыес'l'ИМ 11 сообщение день месаца
;Цреобраsу.ммесац
рор АХ 1 (40)Восстuоаим дату в АХ
puah АХ 1(411И скова сохр~
and AX,110h 1 (42)0ставим в АХ тоnько биты месаца
111DV CL, 5 ;(43)Sудет сдВИl' 81а 5 бит
shr AX,CL 1 (44)Сдвикеы 11nраво к иачапу F•'l'истра
IIIDV АН,АL ; (45)Скоnируеы номер мес1ща в АН
add АL,АИ 1 (46)Прибавим ero же
add АL,АИ ; (47)И еще pas, т. е. умножим ка 3
suЬ AL,3 ; (48)Скорректируеы
сЬw ;
(49)Преобраауеы 11 спово
IIIDV DI,off•et lЬlЗ+З; (SO)ES:DI -> nопе дпа имени ыесаца
ШDV SI,offset months; (Sl)DS:SI -> табпица имен ыесацев
add SI,AX ;(52)Прибавим номер ыесаца*З
ШDV СХ,3 ;(SЗ)Будеы переыещать 3 сиывоnа
rep movsb ; (54)Поыестим в сообщение ыесац
рор АХ 1 (55)Еще раа восстановим дату в АХ
and AX,OI'IOOh ; (56)0ставим в АХ только биты rода
ШDV CL,9 ; (57)Будет сдвиr на 9 бит
•hr AX,CL ; (58)Сдl!lииеы вправо к иачапу реrистра
add АХ,80 ;(59)В дате rод от 1980. Попучиы
;правипьинй rод (от 1900)
div DL 1 ( 60) Подепим ка 10. АL-чиспо десатков
;пет, АИ•остатоJС (чиспо единиц пет)
add АХ, 1 00 1 ; (61)И то, и друrое преобраsуеы в
ICИNВonbl
IIIDV 1Ь13+10,АИ 1 (62)Отпрааим 11 пporpawwv
IIIDV 1Ь13+9, AL 1 ( 63) Поместим в сообщение rод
1 Отредактиру.м мв-у - убереw точку перед nocneДИIDIИ треыа
ICИNВonU81
IIIDV SI,offset 1Ь11+91 (64)DS:SI->cИNВon sa ТОЧКОЙ
IIIDV DI,offset 1Ьll+81 (65)ЕS:DI->точка
IIIDV СХ, 3 1 (бб)Переыещать 3 симвопа расширенна
~-.р IIIDVsb 1(67)Переыестим
IIIDV .1.Ьl1+11, 1 1 1 ( 68) Затреы пробепоы nоспедниА симвоn
IIIDV BP,offset lЬl 1 (69)ВР->сообщеиие о найдеиной метке
IIIDV СХ, lЬl len 1 (10) Дпииа сообщеииа
jJII) outшes- 1 ( 71) На вывоn сообщеииа ка акре
1 06pa60'f!Ca OIIIИбiCII - на дисм:ете иет NeТJCII
DOlaЬel:IIIDV ВР, offaet aes; (721 ВР->сообщеиие об отсутст11ии NeTial
IIIDV CX,aes_len 1 (731Дпииа эororo соо6щеииа
Структуры 127

:Выведем сооб111еиие о найденкой аетке тома ИIDI об ее отс)"''С!!ВИИ


out-s: IIIOV АН, 40h ; 17 4 ) Фуикци11 811110.11& на NСран
IIIOV ВХ,1 1 (75)Дескриатор ставдарткоrо вывода
воv DX,BP : (76)ВР->соо0щекие о NeТJCe
int 21h ; (77)
;ЗаверВIИЫ пporpaмwv
1 Поп11 даикмх
dn.- dЬ 'А:\*.*',0 ;Просмотрим все -•• 11 А:\
-~~ dЬ 10,13,'На дискете нет метки1',10,13
-~~ len•$--s
lЫ- dЬ 10,13,'Метка А: '
lЬll dЬ 12 dup (. • ) , 10, 13
1Ь12 dЬ 'Дата COSDAНИRI 1

1Ь13 dЬ 19 •,10,13
lЬl len•$-lЬl
вonths dЬ

Программа начинается с определения С1рупуры dta, в каrорой опи­


саны поля обласm передачи данных (см. рис. 28.1). Наложение С'lр)'К­
"IУРЫ на реальную область переда'I.И данных позволит использоВIП'Ь в
программе вмесrо числовых смещений к соаrветствующим полям более
наглядные мнемонические обозначения (например, Шe_name - имя
файла); кроме того, мы избавляемся от необходимости использоВIП'Ь
описатели word ptr и byte ptr, которые обычно требуются при обраще­
нии к "безымянным" учас.:ткам памяти.
С помощью функции 4Eh поиска первого файла в корневом катало­
rе диска А; ищется первый (и, естественно, единственный) файл с аnри­
буrом 8- метка тома. Если DOS не нашла такого файла, перед возвра­
том из функции 4Eh устанавливается флаr CF. В этом случае команда jc
(jump if carry, переход, если перепое) предложения 16 передает управле­
ние на вывод сообщения об отсутствии на диск~ МС11СИ тома. Если
метка найдена, ее имя и характеристики помещахm:я системой в теку­
щую DTA
В pernC1p ВХ заносится смещение DTA в сегменте PSP (число 80h,
предложение 17). Теперь в ES: ВХ находится полный двухславный ацрсс
текущей DTA.
Вывести MC'IX)' на экран можно непосредственно из DTA, однако
удобнее перенести имя метки из DTA в область данных программы, rде
к имени можно прибавить дополнительный текст.
Для обработки цепочек (е1р0к) байтов или слов в процессаре пред­
уемтрена специаJiьная группа команд. Одну из таких команд, команду
сравнения байтов С1рОК cmpsЬ, мы уже рассматривали в СТ1П'ЬС 12. В
примере настоящей статьи используются еще две команды той же груп­
пы: stosЬ (store string byte, сохранение байта строки) и movsЬ (move strins
byte, перссылка байта строки). Как и команда cmpsЬ, они имеют разно­
видности для обработки слов (stosw и movsw). Все команды обрабсmси
128 Статья28

отрок. имеют ряд общих черт. Операнд-источник. адресуется ими через


регистры DS:SI, а операнд-приемник. - через регистры ES:DI. Команды
ВЬПIОJIЮПОТ операцшо над единичным байтом (или словом); если трс­
бу~я BЬПIOJDIИ'IЪ операцшо над последовательностью элемекrов стро­
ки, перед командой следуст поставИ'IЪ один из префик.сов повторения и
поместиrь в регистр СХ требуемое число повторений. После каждого
единичного выпОJПiения команд указатели Sl и Dl получают положи­
тельнос или отрШJ;атсльнос приращение в зависимости от состояния

флага направления DF.


К настоящему моменту регистр DS H8C1JIOCH на сегмент данных
программы, а регистр ES на сегмент с областью передачи данных
(фшсrически- на PSP). Для персмещения имени метки из DTA в про­
грамму с помощью команд работы со строками содержимое DS и ES
дOJDICНo бьm. обратным. Обмен содержимого DS и ES осуществля~я
наиболее экономным способом - через стек. (предложения 18 ... 21). В
регистр Dl помещается смещение поля в программе для имени метки.
В предложении 23 использована команда lea (load effective address,
заrрузка эффеimmного адреса). Эта команда заrружает в регис'I'р, ук.а­
занНJ,IЙ в качестве первого операнда, относительный адрес вrорого опе­
ранда (не значение операнда!). Команда lea факгически эквивалентна
команде mov reg, offset mem, однако имеет больше возможностей опи­
сания адреса интересующей нас ячейки и особенно удобна в тех
случаях, когда трсбу~я определить адрес ячейки, не имеющей мнемо­
нического имени. В нашем случае команда

lea SI,[BX].file_naшe

загружает в регистр SI смещение к имени файла в DTA Для указания


смещения используется мнемоническое обозначение из С'I'рую)'рЫ dta.
При эrом базовый адрес DTA уж:е находкrся в регистре ВХ, что и даст
нам право использовать его в качестве базового. Точка перед мнемо­
ническим обозначением смещения file _nате указывает на использова­
ние обозначения из определения С'I'руктуры.
Персмещение имени метки из DTA в программу за'I'руднено тем,
что неизвесn~а длина метки. Если переносить в программу всегда 12
байт, ro в случае короткой метки в программу может скопироватьсЯ му­
сор. Поэrому метка переносится посимвольно с проверкой каждого
символа на О. Команда lodsЬ (преДJrожение 25) заrружает очередной
символ из строки-источника в реГИС'I'р AL с автоматическим инкремен·
rом индексного регистра SI; команда stosЬ (предложение 28) помещает
содержимое регистра AL в С'I'рОку-приемник. с а.втомаrnческим инкре·
мекrом индексного регистра DI. Как rолько в реrис1р AL nопадет байг
с двоичным нулем, завершающий имя файла в DTA, командой je gol
осуществляется выход из цикла на продолжение проrраммы.
Структуры 129

В предложении 30 дата С03Д8НИJ1 файла ~ из DТА в ре­


rистр АХ. Эдесь omirь исп011Ь30вано мнемоническое обозначение из
CIPYJCI'YPЫ dta. При отсуrотвии определения струпуры нам прИШJIООЬ
бы написать
8110V АХ, vord ptr [8Х) +18h
(см. табл. 28.1), что, конечно, гораздо менее наrJIЯДНо. Между прочим,
еще одно преимущество исnользования струпур закmочаtn::я в том, что

при изменении расnоложения данных, на которые накладывается струк­

тура, и, СООТВСТС'I'ВСННО, их смещений, дОО'11rl'Очно внести коррсiСl'ИВЫ в


определения cтpYJClWЫ и nсретранслировап. проrрам:му. Если же при
проJ:1>аммировании исnольэошnЪ смещения в численной форме, то при­
дется выискивать в проJ:1>8Мме и коррсiСmрОвать все ссьvпси на изме­

ненные nоля. Другой сnособ избавиться ar эrой работы - дать числовым


значениям смещений мнемонические имена, наnример, в начале про­
J:1>ЗММЫ определить констаmу ft.le_date=18h и заrсм исn011Ь30вать не
численное, а мнемоническое значение смещения.

В nредложениях 31-32 выполняется восстановление адресуемости


данных через реrистр DS. Далее дата создания файла сохраняется в с-m­
кс. С nомощью маски 1Fh и команды and в реrистрс АХ выделяется
день месяца. Для rrреобразовани.я: в символьную форму номер дня де­
лиrся на 10, к обоим результатам (часmому и ОСТ8'11СУ) добавл.я:кm:я
коды символа 'О' и результат заноскrся в выводимую на экран строку.
Деление осуществляе-t-ся байтовым вариантом команды div (division, де­
ление). Эrа команда делит содержимое регистра АХ на указанный в JСО­
манде оnеранд (в нашем случае на содержимое DL). Часmое помещаt:l'­
ся в реrистр AL, OO'l1rl'OK- в регистр АН.
В nредложении 40 из стека извлекается сохраненнос там исходнос
значение даты (и сразу же сохраняется в стеке снова), и из него маской
выделяется номер месяца, который с nомощью команды логического
сдвШ'а вnраво сдвШ'аСТСЯ к началу реrистра АХ. Для прсобразования
номера месяца в его символьное "IРСХбуквснное обозначение номер ме­
сяца умно:жаtn::я на 3 (nредложения 45... 47) и из рсзульТIП'а вычитается
3 (так юuс. номера месяцев начинаются ·с 1., а смещения в таблице имен
месяцев - с 6). Вычитание осущСС111JIЯстся командой suЬ (suЬtraction,
вычитание), которая вычитает из левого операнда nравый и записы:ваtr
разность на место левого оnеранда. По ходу умножения на 3 мы
·засорили• perиC'Ip АН. Для его очистки можно было восnользоваться
коwандой mov АН,О однако более эффсiСl'ИВно эrо выполнить с по­
мощью команды cbw (convert bytc to word, прсобразование байта в сло­
во). Эrа команда заполняет реrистр АН знаковым бкrом числа, находя­
щеrося в perиC"IPC AL, что даст возможность выполнять арифметические
операции над исходным операндом-байтом как над словом в pcrиC"IPC
АХ. После настройки индексных реrистров Dl и Sl и установки
130 Статья29

счетчика- числа переносимых байтов командой movsЬ с префиксом rep


(предложение 54) имя месяца переносится в выходную е1р0ку.
Обработка года осуществляется аналоmчно обработке дня - маски­
рованием, сдвигом, делением на 10 и преобразованием в символьную
форму. Перед делением на 10 к значению кода из DTA добавляется 80,
так как в записи каталога и в DTA указывается не сам год, а число лет,
прошедших от 1980 года.
Последняя операция по обработке метки - удаление из нее точки,
которая естественна в имени обычного файла, но вьп-лядит странно в
метке. Удаление точки выполняется сдвигом с помощью команды movsЬ
(предложение 67) трех последних символов на один байт влево и зати­
ранием затем последнего символа символом пробела.
Приведеиная программа замечательна тем, что в отличие от команд
DOS LAВEL, VOL и DIR, она выводкг на экран не только значение
метки тома, но и дату ее создания.

Статья 29
Записи

Записи, как и структуры, представляют собой шаблоны, наклады­


ваемые на реальные данные с целью введения удобных мнемонических
обозначений отдельных элементов данных. В отличие от структур,
дающих имена байтам, словам или массивам, в записях определяются
С1J>ОКИ битов внутри байтов, слов 1mи двойных слов.
Вспомним (см. рис. 28.1), что дата записывается в элементе каталога
в 16-разрядном слове, причем старшие 7 бит этого слова обозначают
год, следующие 4 бита - месяц и последние S б1rr - день. Эn1 данные
удобно описаТh с помощью записи date, опредедяемой в программе сле­
дующим образом:

date record year:7, шonth:4, day:S


Ключевое слово record говорит о том, что имя date относится к за­
писи, а мнемонические обозначения year, month и day являются произ­
вольными именами отдельных битовых полей описываемого с:~ова.
Вкmочение в программу описания шаблона битовых полей позволя­
ет ОIУаЗаl'ЬСЯ от уrомительного определения "вручную" смещений кон-
Записи 131

к:рс1НЫХ полей внуtри слова. а таюкс значений масок, 1рСбусмых для


выделения отдельных полей. Для этого используются операторы mask и
width.
Оператор mask возвращает биrовую маску. в которой биты. соаrвст­
сrеующие данному пото. равны 1. а вес остальные биты равны О. Так,
выражение

IIIA.Sk day

эквивалентно двоичному числу 0000 0000 0001 1111 (=1Fh); выражение

IIIA.Sk month

эквивалентно двоичному числу 0000 0001 1110 0000 (1EOh).


Опсраrор width возвращает ширину (в биrах) указанного поля запи­
си. Так, значение выражения

width day

равно 5; значение выражения

width month + width day

равно сумме ширин полей дня и месяца и составляет 9.


Введение в программу 28.1 описания записисделать datc позВОJIЯст
с1р0ки выделения 'lребуемых полей и сдВигов более наrJIЯДНЬJМи (и.
возможно. избежать ошибок "ручного" определения 1рСбуемых значений
масок и ширин полей). Предлагаемые изменения сведены в табл. 29.1.

Tatiltицa 29.1. Замена 'lисл011wх аргужг,;",о. при испол~а011ании записи

Стара11 pe.RaJЩИII HOIS&II pO,RIUЩИII

and АХ, ll'h and АХ, IIIA.Sk day


and AX,lBOh and АХ, IIIA.Sk 11110nth
IIIIOV CL,S IIIIOV CL, width day
anct АХ, оrвооь and АХ, IIIA.Sk year
IIIIOV CL,9 шоv CL,width 1110nth+width day
132 СmатьяЗО

Статья 30
Способы адресации в оптвмвзацu проrрамм

Изучив приведеиные в эrой книге проq>аМ:мы, вы, вероятно, уже


o6panmи внимание на то, что обращение к данным в них вып01ПU~Сm:я
по-разному. Обрабатывас:мые в проiраММе данные можно помещать не­
посредственно в реrиС1р, записьтать в качестве одного из операндов

прямо в код команды, .либо ~м или Ш1ЫМ способом указывать место в


ПIUoUIТИ, rде Э1Я данные расположены. Рассмотрим, например, проrрам­
му, обеспечивающую поиск максимального элемента в массиве данных.

Оримч 30.1. Поиск. ма~ССШ~ального эна'lенШI


1 Сеzомевож дaJUUIX
аае dЬ 1,2,5,3,7,9,8,3,4;МАссиа с исходиыwи даииыwи
~$-аае 1Чис:.по байтов (эn-итовl а wассиае
;Сеzомевт хоwаид
IIIOV DL,aae llliDL•Пepawй эпемеит массива
1U0V СХ, mua.-1 1 121СХ-чис:.по сравниваемых эпеыеитоа
la8Uiyc один (nервыйl
IIIOV BX,l ;(З)ВХ-иидехс атороzоо алемента
cont: CIIIP DL,aae(ВX] 114)DL>cneдyмщezoo алемеита?
jiJ next 1 (5)Да, на &JIAJ1И:S CПOД}'JIIЦOZ'O
IIIOV DL,aae[ВX] 1 (6)Нет, 11 DL :sаиосим cneдYJCIIQКЙ алеwеит
next: inc вх ; (7)И ка аиа.nи:s спедумщеrо
loop ccnt 1 (8)Цикп СХ pas
В предложении 1 в perиC1J> DL заносится содержимое первого байта
послсдомrельности данных, которая в эrой проrрамме обозначена как
.mas. Здесь мы сразу же ВС'IрСЧаемся с двумя способами адресации дан­
ных - реrиС1рОвым и прямым (прямая адресация к памяти).
При использовании реГИС1J>ОВОЙ адресации данные записываются в
perиC'Ip - однобайтовый или двухбайтовый.
Прямой способ адресации JIВЛЯСТСЯ представкrелем rруппы спосо­
бов обращения к данным, которые хранятся не в perиC'Ipax, а в ячейках
ПIUoUIТИ. В рассмmр1шасмом случае при прямой адресации имя mas фак­
'IWIССКИ JIВЛЯСТСЯ адресом памяти, то есть смещением в cerмe1rre дан­

ных, начиная с которого хранятся данные. При эrом в качестве сеr­


ме~m~ого perиC'Ipll по умолчанию используется регистр DS. Содержимое
указанной ячейки памяти переносится (в данном случае) в регистр DL.
Если рассматриваемая ячейка П8МJ1'IИ располаrастся в сегме~. базовый
Способы адресации и оптимизация программ 133

адрес кaroporo находиn:я в другом сеrм:екrном регистр (ES, CS или SS),


то обяэапслъно уазаi{Ие этоrо регистра: mov DL,ES:mas.
Еще oДIUI способ адресации представлен в предлож:ении 3, где в
качестве одноrо из операндов указано число (конкретно 1). Такой опе­
ранд входиr непосредственно в состав команды процессора. Эrот спо­
соб адресации так и называется - непосредствснный.
В предлож:сниях 4 и S применсна разноВИдНость прямой адресации
к памяти, в которой указывается не только обозначение ячейки памяти
(mas), но и величина сдвша оmоситсльно этой ячейки (в данном случае
в регистре ВХ). ОчеВИдНо, что тако~ сnособ адресации удобен при ра­
боrс с массивами.
Вес имсющисся сnособы адресации мож:но условно разделить на
1ри группы: неnосрсдствснный, регистровый и с указанием адреса na-
wrm. При этом адрес nawrm мо:жно задавать nо-разному: прямым ука­
занием символичсскоrо обозначения ячейки памяти, указанием ре­
гистра, в котором храниrся 1ребуемый адрес, или и roro, и другого. Та­
ким образом, 1pC1'bll групnа включает, в сущности, целый ряд сnособов
адресации. Они обычно носят названия: прямая, базовая, шщсксная:,
базово-шщексная, а также базовая, шщексная или базово-шщексная: со
смещением.

Приведем кргпсий обзор сnособов адресации.


Реmетроваа адресаЦНJJ
Оnеранд (байт И.."IИ слово) находиrся в perиc'lpC. Сnособ применим
ко всем программно-адресуем~ регистрам: nроцессора.

Примеры

puah DS ; Сохраиени е DS 11 стехе


aov BP,SP ;Пересыпха содерхиwоrо SP 11 ВР

НепосреАСТВеввu адресаЦНJJ
Оnеранд ~байт или) мож:ет быrь представлен в вцде числа, адреса,
кода ASCII, а так ж:е иметь символьное обозначение.
Примеры
D:1V .АХ, 4C00h ; Операид - 16-pИ'IJioe 'IИCJIO
aov . DX, off8et -8; С:ме111еиио wассиаа - 8 :sаноситс11 а DX
D:IV DL, ' 1 ' 1 Операид - ·ход ASCII CИNIIona • 1•
nwa-9 ;Чис.по 9 попучает обо:sиачеиие nUIII.
aov СХ, nUIII. ; Чис.по, обо:sиачеииое nUIII.,
;:sarpyzaeтc11 а СХ

Прамu адресаЦВJJ к паМJJ111


В команце указывается символическое обозначение ячейки памяти,
над содержиыым которой 1ребуется вьmОJПiитъ оnерацию.

Пр-рк
DL,IUDil ; СодерХИJ.8)е байта ПАN/IТИ С CИNIIOIIИЧOCJGO&
;иwеием шешl пероскпаетс• 11 DL
134 СтатьяЗО

Если нужно обраТИ'IЪСЯ к ячейке памяти с известным aбcOJIIOnlым


адресом, то этоr адрес можно непосредственно указать в качестве оnе­

ранда. Предвариrельно необходимо настроИ"lЪ какой-либо сегмектный


perиC'Ip на начало того участка памяти, в котором находиrся искомая

ячейка

Пример
IIIOV АХ, О ; Настроны сеrмектинй реrистр ка
IIIIOV BS,AX ;cawoe на~апо памяти (адрес 0)
IIIIOV AX,BS:[O) ;Заберем в АХ содерzиwое спова
;пАNRТИ по адресу OOOOh:OOOOh
Заметим, что в этом случае сегментный perиC'Ip указывать обяза­
'РШЬНО.
Все остальные способы адресации <m~осятся к груnпе косвенной
адресации к памяти.

Еазовu и нвдексвu адресации.


Оrносиrельный адрес ячейки памяти находится в perиC'IpC,
обозначение которого заключается в квадраmые скобки. При использо­
вании реrистров ВХ или ВР адресацию называют базовой, при исполь­
зовании perиC'IpOn Sl ШIИ DI - индексной. При адресации через ре­
ГИС'IрЫ ВХ, Sl юm Dl в качестве сегментного perиc'lpa по.цразумевается
DS; при адресации через ВР - SS. Таким образом, косвенная адресация
через реГИС1р ВР предназначена для работы со стеком. Однако при не­
обходимости можно явно указать 'IJ)Сбуемый сегментный реrиС1р.

Приwерк
JDOV AL, [ВХ] ; Сеrwентннй адрес пре.цполаrается в
;DS, смещение а ВХ
IIIOV DL,BS:[BX] ;Сеrwентинй адрес находится в BS,
; смещение а ВХ
IIIOV DX, [ВР] ;Сеrwеиткнй адрес цредполаrаетсм а
;SS, смещение а ВР
IIIIOV AL,[DI) ;Сеrwеитинй адрес предпоnаrается а
;DS, смещение а DI

Еазовu и ивдексвu aдpeeaЦIIII со смещением.


Оrносиrельный адрес операнда опредсляtrся суммой содержимого
perиcn.pa (ВХ, ВР, Sl ИJШ Dl) и указанного в команде числа, которое
доВО/IЬно неудачно наэЬIВ810Т смещением.


np..p

IIIIOV
llliOV
1,2,5,3,7,9,8,Э,4;Nассиа сиwаоnов
ВХ, 2
DL,-a[ВX) ;В
; ВХ-иидеасс -емеита • ...ссиве
DL sаноситс11 треоrий --Т массива

В этом примере 0111осиrельный адрес адресуемоао элемента массива


mas ВЫЧИСЛJIСТСJI как сумма содержимого ВХ (2) и :шачения символи­
чоекого обозначснин mas, которое совшщает с ОТJI~итслыtым адресом
Способы адресации и оптимизация программ 135

начала массива mas. В резульmrе в регистр DL будет заrружен элемент


массива mas с индексом 2, то есть число 5. Предполагается, что базовый
адрес сегмента, в который входиr массив mas, заrружен в DS. Такой же
результат даст следующая последовательность команд:

JIIOV ВХ, offset DIAS; ВХ-оТИОСИТе.JIЬИЫЙ адрес 11Ч8ЙJсИ DIAS


JDOV DL, 2 [ВХ]
Здесь относкrельный адрес адресуемого элемента массива mas
вычисляется как сумма содержимого регистра ВХ и дополнкrельного
смещения, задаваемого константой 2. Последняя команда мо.жет бьпь
заnисана в следующем виде:

mov DL, [ВХ+2]


mov DL, [ВХ]+2

Адресация с помошью регистров SI и DI осущесm1Яется анало­


гично. При использовании регистра ВР следует помнить, что в качестве
сегментного регистра по умолчанию подРазумевается регистр SS
Баэово-индексиu адресаЦИJI.
Оmосиrельный адрес операнда оnределяется суммой содержимого
базового и индексного реntстров. Допускается использование следую­
щих пар:
(ВХ] (SI]
(ВХ] (DI]
(ВР] (SI]
(ВР] (DI]
Если в качес-mе вазовоrо решстра выступает. ВХ, то в качестве сег­
ментного подРазумевается DS (первые две команды), при испо..'IЬзова­
нии в качес-mе базового реrи~тра ВР cerмetmtым регистром по
умолчанию назначается SS (вторые: две команды). При необходим0С111
мо.жно явно указать ~буе"'ый ceP•ICimtый регистр.

Примеры
JIIOV ВХ, (BP](SI];B ВХ ~а~ыпа~тс11 сnово иs стека
tc~~N~HTHШt адрес ИAXO~TCII 8 SS), А
;смещение вычиcnlleTCII как cywwa
;содерzимоrо ВР и SI
IIIOV ES: (BX+DI], АХ; В IIЧeЙJ<:V ПАW11ТИ 1 cera.&eiiTIWЙ адрес
;которой хранитс11 в BS, а сwещеиие равно
;cywwe содерЖКМDrо ВХ и DI, uересмnаетс11
; содерЖИNОе АХ
&аэово-индекс:наи адресаЦИJI со смещением.
Оnюсите.JIЫIЫЙ адрес операнда оnределяется суммой трех величин:
содержимого базового и индексного регистров, а таюке дОПОIПiкrельно­
rо смешения. Допускается использование -rex же пар регистров, что и в
базово-индексном способе; так .же действуют и правила опрсдмения
сегментных регистров.
136 Статья30

Приwерк
1110v !IIAs [ВХ] [SI], lO;CИNВo.n с кодом 10 (•воsврат
;каретки"l перескпаетс• 11 ••ейку
; ПАМR'l'И, сеrмеитИiоiЙ адрес ко'Ж'ОрОЙ
1 xpAIIИТCII 11 DS, А смеааеиие рА11110
;сумме coдepXИNDro реrис~в 8Х и SI
;и отиоситепьиоrо адреса .чейки !IIAs
IIIOV AX,(BP+2+DI];B АХ перескпаетс11 иs стека спово,
;смещение котороrо равио cywwe ВР,
;bi и добавки, равиой двум

Значительная ЧIIC'l'Ь рассмотренных выше способов адресации слу­


жит для обращения к ячейюw памяти. Таким образом, один и таr же
конечный результат можно получиrь с помощью различных способов
адресации. Например, вес 1РИ приведеиные ниже команды
IIIOV DL, !11As+3
IIIOV DL, !IIAII [ВХ] ; В ВХ sараиее sаиесеио чиспо 3
шоv DL, (SI] [ВХ];В ВХ sараиее sаиесеио чиспо 3, а 11
; SI - сыещение !IIA.S

приведУТ к загрузке в рсГИС1J> DL чстt~ертого элемента массива mas (если


ВЫПОJIНЯЮТСЯ описанные в комменТ3рИЯХ условия). Однако команды с
использованием различных способов адресации занимают различный
объем памяти и выполняются за разное время. Так, первая из приве­
деиных выше команд потребует для выполнения 15 машинных тактов,
вrорая - 18, а 1рс1'ЬЯ - 16. Разница нсвелика, однако при многократно)(
выполнении команд в циу.лах суммарный эффект может быть
значителен. С .цруrой стороны, первые две команды занимают в памяти
по 4 байта, а 1рс1'ЬЯ только 2. Таким образом, 1ЩатсJlЫIЫЙ выбор спосо­
бов адресации позваляет в какой-то с-rепени щrmмизировать программы
по времени выполнения или tребуемой памяти, а иногда и по тому, и
по.цруrому.

Время выполнения команды можно определить, раздс.лив tребусмое


для се выполнения число машинных тaJcrOB на частоту работьi конкрет­
ного процессора. Последняя величина колеблется для используемых в
настоящее время переопальных компьютеров в очень широких пределах

- ar единиц до ста МГц и более. Поэтому время выполнения команд и


всей про!раммы в целом оценивают обычно не в збсолютных ве­
личинах, а именно в числе машинных тактов.

Полное время выполнения команды можно выразюъ в виде суммы


двух составляющих: базового времени вьmолнения команды, которое
зависит ar вида команды и способа адресации, и времени вычисления
исполнительного адреса, если операнд нахоцк;ся в памяти. Вторая со­
ставляющая тоже зависит ar способа адресации. Разброс времен выпол­
нения для разных команд может быть весьма значителен. Так, команда
сложения содержимого двух рсrиеtрОв tребует 3 тактов, прямого внуr­
риссrментного персхода- 15 тактов, а команда деления- около 100 так-
Спосо6ы адресации и оптимизация программ 137

rов. То же, хотя и в меньшей степени, относкrся к времени вычисления


исполииrельноrо адреса. Если смещение ячейки памя:rи указываеrея в
pemC'lpC (базовом или индексном), ro к базовому времени вьшолнения
команды следует прибавкrь 5 таю:ов, при базово-индексной адресации-
8, а в случае базово-индексной адресации со смещением - 12.
Рассмотрим несколько примеров оmимизации проrрамм:ы по памя­
ти и времени выполнения.

1. Обиулеиве реrистра

IDOV .АХ, О ;4 тахта, З байт


.suЬ АХ, АХ ;З тахта, 2 байт
xor .АХ, АХ ;З тахта, 2 байт

Видно, что первая команда, будучи наиболее наглядной, в то же


время уступает двум друmм по своим оmимизационным харакrеристи­

кам.

2. Заrрузка в реrистр отиоскrельноrо адреса ячейки памяти

mov DX,off.set mem;4 тахта, З байт


lea DX,mem ;8 тактов, 4 байт

Первый способ загрузки в регистр смещения ячейки оказываеrея


лучше во всех отношениях. С другой стороны, команда lea имеет боль­
ше возможностей, поскольку в ней можно использовать mобые способы
адресации.

3. Заrрузка в пару реrистров полноrо двухсловиоrо адреса

addr dd array_1 ;Полный адрес массива array 1


;в двухсловной ячейке addr -
mov ВХ, word ptr аddr;Получение сиещения,14 тактов,4 байт
mov ES, word ptr addr+2;Cerмeнт, 14 тактов, 4 байт
lea ВХ, addr ;Получение сеrыента и смещения,
;16 тактов, 4 байт

Результат вьmолнения двух первых команд такой же, как и одной


треТhСЙ. Однако использование команды les (или lds для загрузки сег­
ментного реmстра DS) дает существенную экономmо и времени, и па­
мяти.

4. ~мвwкеиве целоrо числа на степень двух

mov ВХ,З2 ;Соwножитепь в ВХ, 4 такта, З байт


JIIUl вх ;Уwиохение, до 133 тактов, 2 байт
mov CL,S ; Величина сдвиrа, 4 тахта, 3 байт
aal AX,CL ;Сдвиr, 28 тактов, 2 байт

Последний пример несколько <:пецифичен. Если вам необходимо


умнаЖить на степень числа 2 (2, 4, 8, 16, ... ), вьп1олненис этой операции
можно существенно ускоркrь, заменив умножение сдвигом влево на

чисдо позиций, равное ноказателю стенени. Каждый СДJIИГ в.1ево на


138 Статья31

одну nозицию приводит к умножению на два. Таким образом, первая и


втораg пары команд в вЬШJеприведенном примере эквивалентны по ре­
зульта'l}', но замена умножения: сдвиrом позволяет усх:ориrь оnерацию в
несколько раз. Те :же рассу:ждсния: применим:ы к делению на степень
числа 2, которое целесообразно зам:сНЯ'11> сдвш-ом вправо.

Статья 31
Программы с несколькими сеrментами команд

До сих пор рассма1ривались небольшие проrраммы, в которых и


главная процедура, и подпрограммы, если они были, помещались в од­
ном сегменте команд. Данные, используемые в программах, также были
~ебольшого Объема и помещались в одном сегменте данных. В эrом
случае суммарный объем команд во всех процедурах не мог превысиrь
64 Кбайт. Общий объем данных rо:же не мог превысить 64 Кбайт. Про
такие проwаммы говорят, чrо они принадлежат к малой модели памяти
(эrот терМИ'.tl используется при проrраммировании на языках высокого
уровня типа С или С++).
Современные прикладные программы обычно имеют больший объ­
ем. Однако увеличить размер сегмента нельзя; если суммарный объем
команд программы превЫПiает 64 Кбайт, в ней следует организоВ81Ъ
несколько сегменrов команд. Программы с несколькими сегментами
команд и одним ссгмснrом данных относsm:я к средней модели памяти.
Qрограмма, содержащая несколько сегменrов команд, в принципс
может иметь "линейный" хар~р. В эrом случае сначала выполняюrея
вес команды первого сегмента, затем процессор переходит к выполне­

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

сегмента, как эrо было до сих пор, а в другой сегмент команд. Однако
удобнее большую программу составить из процедур-подпрограмм. В
этnм случае надо уметь вызывать подпрограмму из другого сегмента.

Любое обращение к другому сегмеН'l}' команд носит название даль­


него, или межсегментного. Обращение же в пределах одного сегмента
наз~я ближнJ!М, или внуrрисегментяым. В соответствии с Э1Юо(
ра="".ИЧают команды ближних и дальних персходов, а таюкс команды
ближних и дальних вызовов подпрограмм.
flрограммы с несколькими сегментами команд 139

Дли roro, чтобы изучить правила орrаиизации мноrосегмситных


проrрамм, мы воспользуемся программиыи комплексом, описанныы в
СТ1Ш.ЯХ 17.•. 19. Комrшекс состояп из ~ух процедур-подпрограмм: he:xasc
для получения символьною представления четы:рехбиrовоrо числа и
binasc, прсобразующей двоичное CJIOВO в 16-ричную символьную форму.
При этом nроцедура binasc для преобразования каждой 16-ричной циф­
ры вызывала подпрограмму he:xasc.
Вьщелим: обе процедуры-подпрограммы в отдельный сегмекr ко­
манд. Эrо позволит нам при необходимости довести объем главной
процедуры: до 64 Кбайт и мнoroxplmio увеличить суммарный объем всех
используемых в комплексе процедур, посколыс:у для них можно пред­
усмотреть не один, а скал:ько уrодно сегмеН'l'ОВ команд.

Модифицируя программу, преобразуем главную процедуру примера


19.1 так. чтобы она выводила на экран сегмекrные адреса обоих сегмен­
rов команд, а тапсе сегмента данных. Эrа информация позволит нам
ВСПОМНИ'l'Ь, как pacпOJI8I'8IO'roJI в физической пaмsrm сегменты загру­
жаемой программы. Дли удобства чиrателя: в примере 31.1 приводится
ПОJПIЫЙ текст nрограммною комrшекса, хотя процедуры binasc и hexasc
целиком заимствованы из примеров 17.1 и 18.1.
В этом и последующих примерах для упрощения текста программ
мы будем использовать библиотеку макрокоманд, описанную в статье
27. Библиотека представляет собой файл (мы дали ему имя МАС.МАС)
с текстами следующих макроопределений:
write - вывод на экран строки текста с помощью функции DOS 09h;
outprog - завершение програМмы с помощью функции DOS 4Ch;
delay - программная задержка на время, задаваемое парамС'lрОм
макрокоманды;

stop - остановка проrраммы с помощью функции 08h до нажатия


любой клавиши.
Имя файла с макроопределением макрокоманд обьявляется в тексте
программы с помощью дирепивы ассемблера include.
Рассмотрим теперь саму программу. XO'DI в ней будет несколько
сегмеН'l'Ов команд, все они мoryr быть описiшы в единственном файле с
исходныы тексrом программы (xO'DI мoryr быть и разнесены по разным
файлам).

Прuер 31.1. ПJЮ2РDММа с дttyМR сегментами IUШaJIO


textl 8egment 'code' ;Сеrмент дn• rnАаной процедуры
&88\Шiе CS:textl, DS:data
include 11\АС oii\AC ;Объжвпенме wакробибпиотеRИ
proc
IIIIOV АХ, data
JIIQV DS,AX
18ыаед.м адрес сеrwента RO~ textl. Он находите• в CS
IIIIOV AX,CS
140 CmamЬR31

810V SI, o.ffaet aeg1+10


call far ptr Ыnаас
write aeg1 ;Bbllloд ка :.храк
.; Вllаедем адрес сеrмекта кокаид text2.
810V АХ, textZ
шоv SI,offaet aeg2+10
call far ptr binaac
write aeq2 ;Bbllloд ка :.храк
;ВЫ!Iедем адрес сеrмекта даккых. Ок находите• а DS
DIOV AX,DS
DIOV SI, offaet dataseg+10
call far ptr binaac
ШОV АН, 09h
write dataaeg ; Bbllloд на :.храк
outprog ;Завершение nporp&NNЫ
aain endp
textl enda
text2 ae9J11ent 1 code 1 ; Сеrмент дn• nодпроrраыw

aaaUIDe CS:text2, DS:data


hexaac proc
;Подnроrраwма nопучеии• сиwаопьноrо предстаапеии• четнрехбитоаоrо
IЧИCJJa. На аходе: исходное чиспо а иnадшей nопоаике AL., адрес
1строхи, худа надо nоместить реsультат, а DS:SI. На выходе:
;АSСII-предстаапеиие nопучеккоrо чисnа а llablii['X'И по адресу DS:SI,
IИСХодное coдepZИNDe реrистра AL раsрушаетс•
puah ВХ ; Сохраним исnопьsуеыьrй а nодпроrр.-
;реrистр

DIQV ВX,offaet tЫhех;ВХ•ацрес таблицы траисп•ции


xlat ; Команда таб.пичкой траисn.11ции
ШОV [SI] ,AL ;Сохраиим реsупьтат
рор вх ;Восстакоаиы реrистр ВХ
ret ; Воsарат в 8ШIЫIIAJCЩyJO nporpuaq
hexaac endp
binaac proc far
;Подпроrраwма nреобраsоваии• двоичкоrо сnова а 16-ричиу.D
IСИNВОЛЬКУJО фoploCif. АХ•преобраsуеJЮе чисnо, DS: SI•aдpec строхи,
1худа nоыешаетс• реsупьтат nреобраsоваиия
push СХ ; Сохраним исnопьsуеыьrй реrистр
push АХ ; Сохраним каше чисnо в стеке
and АХ, O!'OOOh ; Вwцелv.ы стагШУJО четверку битоа
DIOV CL, 12 ; Счетчик сдвиrа
ahr АХ, CL ; Сдвиr вnраво ка 12 бит
call hexaac ;Преобраsуеы а симаоп и отпр.- 81'0
;по адресу [SI)
рор АХ ;Вернеы в АХ исходное чиспо
puah АХ ;И снова сохраиим в стеке
and AX,O!'OOh ;Вwцелиы аторУJО четверку битов
DIQV CL,8 ; Счетчик сдаиrа
ahr AX,CL ;Сдаиr вnраво на 8 бит
inc SI ; Сдаикемс11 к cneдy11111ewv байту в
;строке реsупьтата

call hexaac ;Цреобраsуем а симаоп и отnравим ero


;по адресу [SI)
рор АХ ; Веркем в АХ исходное чис.по
puah АХ ;И сноаа сохраним а стеке
and AX,OI'Oh ;Вwц~ треть~ четверку битоа
CL,4 ;Счетчик сдаиrа
Программы с нвскопькими сегментами команд 141

•hr AX,CL ;Сдвиr ацраао ка 4 6х~а


inc SI ; СД8ИКем::11
К CJieдyJIIIIelq 6ай'1')' 8
;строке реsуп.тата

call hexa.sc ;Цреобраsу.м • окмаоп х о~цра..w ~


; по адресу [SI)
рор АХ ; Веркем • АХ исходкое -CJio
pu.sh АХ ;И снова сохр~ • стеке
and AX,OI'h ; Выхlе.пиw мnад111)1'8 ••~аерку ~оа
inc SI ; Сд8ИИем:111 К CJieдyJIIIIelq байту 8
;строке реsуп.~ата

call hexa.sc ;Цреобраsуем • cиwaon м о~цравиw 8ro


;по адресу [SI)
рор АХ ;Восс~аковим стек
рор сх ;Восс~аковиw испоп•sу«МNА реrмстр
ret ;Воsврат в выsва8ШУ» цроцедуру
bina.sc елdр
text2 eлd.s
data .seqшent ;Начапо сеrмек~а даккмх
aeql dЬ 'TEXTl• ****h',lO,lЗ, '$'
.seq2 dЬ 'ТЕХТ2• ****h',l0,13, '$'
data.seq dЬ 'DATA• ****h',lO,lЗ,'$'
tЫhex dЬ '0123456789AВCDEF'
data eлd.s ; Конец сеrмекта даккых
.stack .seqшent.stack '.stack';Haчano сеrмента стека
dw 128 dup (0) ;Стех
.stack end.s ;Коиец сеrмеита стека
end main ;Конец пporpawwы с укаsакием точки входа

Обратим внимание на отличия данного примера от проrраммы 19.1.


Сегмент команд с главной процедурой получил название text1. Соответ­
ственно изменено имя сегмента в операторах assume и ends. В главной
процедуре, как и раньше, имеются три схожих участка. Сначала прсоб­
разуется в символьную форму и выводиrся на экран адрес текущего
проrраммного сегмента text 1, который берется из сегментного регистра
CS. На втором участке процедуры выводится сегментный адрес сегмента
text2. Его адрес опрсдедяется, как значение имени сегмента tcxt2. На
третьем участке выводш-ея адрес сегмента данных data, который извле­
кается из pcntcтpa DS, предварительно настроенного на этот сегмент.
В сегменте данных изменены обозначения полей с выводимыми со­
общениями и C<t\fИ сообщения.
ПринципИальные отличия данного примера от его npoтanma за­
ключаются в том, что процедура binasc обыmлсна с описателем far
(дальняя), а се вызовы в главной процедурс сопровождаются описателя­
ми far ptr (far pointcr, дальний указатель). Что изменилось при этом в
проrраммах процедур и чем оператор call far ptr отличается от простого
call?
Рассмотрим фрагменты загрузочного модуля нашей многосегмент­
ной проrраммы с указанием расположения некоторых команд, их ·кодов,
смещений, мнемонических обозначений и описания их действия (рис.
31.1).
142 . Статья 31


0000
0000 88 4455
text:1 aegaent 'code'
aaau.e CS:textl,DS:data
8Ain proo
воv AX,data
0003 8111 D8 воv DS,AX
0005 8С С8 IВOV АХ, f;З
0007 · 8111 ОООА воv SI, offaet aeql+lO
ОООА ~ 0009 4451 call far ptr Ыnаас ~l) CS•444D -> 8 стек
2) IP•OOOF -> 8 стек
3) 4451 -> • cs
4) 0009 -> в IP
0001' 84 09 воv 1\И, 09h; 1-11 строка мucpop&CIIIИpeниll v.rite

003& 8AU endp


003111 textl enda
0000 text2 aegмent 'code'
aaauae CS:text2,DS:data
0000 bexasc proc
0000 53 pueh 8Х

0008 сэ ret иs стека 0015 -> 8 IP


0009 hexaac endp
0009 Ыnаас proc far
0009 51 puah сх

0012 1118 I'ПВ call Ьехаас - + 1) IP•OOlSh -> 8 стек


2) 001Sh+FI'В8•0000 -> 8 IP
0015 58 рор АХ

ООЗА СВ r e t - - - - - + 1) иs стека 0001' -> 8 IP


2) иs стека 444D -> 8 CS
0038 binaac endp
0038 text2 ends
Рис. 31.1. Фраtментw эаzруэочноzо модуля npoгJНIJIIJIIW 31.1 с nDRCНJIIOщeй инфорАiацией.

Команда caU far ptr Ьinasc расположена по относИТСIIЬному а,црссу


OOOAh. В ее код входит код операции Д8Jibllcro вызова caU far ptr (9Ah) и
а,црсс процедуры binasc, на каrорую надо осущссmить переход. Эrот ад­
рес записан в виде двух слов: откасительною а,црсса процедуры binasc в
том ссrмеите, где она расположена (0009Bh) и сеrмеН'Шою адрсса.:пою
соrмента, JtОТОрЫЙ, как выяснилось после заrруэки программы в П8М11'1'Ь,
равен 44Slh. TIUCIIМ обра:юм, процсссор, считав из пawrrи: код команды,
имеет попную информацию о том, куда надо осущсствиrь переход.
При ВЫПОJDiснии команды call far ptr процсссор помещает в стек два
слова: сначала ссrмснтный а,црсс текущею сегмента (tcxtl), ~м - ад­
рес воsвраrа (содср.хснм:ос IP, т.е. адрес следующей команды, в данном
случае ОООFЪ). Следует oбpanm. внимание на порядок записи в памяn.
к.омпонснтов двухсловною а.цреса: всегда в слово памяти с большим ад­
ресом записывается ccn.tcii'Пiый адрес, а в слово пawrrи: с меньшим ад-
Программы с несколькими сегментами команд 143
рссом - относиrельный адрес, ИJШ смещение. После сохранения в стеке
а.црсса возврата проЦессор заноскr в сегментный рсrистр команд CS
сегментный адрес процедуры binasc, а в IP - относиn:.льный а.црсс этой
процедуры, которые он извлекает из кода команды call. В рсзуль'nПС
указатель с-n:ка смещается вверх на два слова, а процессор персходит·на

ВЬПIОJПiение ПОдпрQrрамМЫ ИЗ дРУfОГО сегмеиrа.


Команда ret процедуры binasc, расположенная по адресу ООЗАh в
сегменте text2, вьmолня:ет обратную операцию - снимает со стска два
верхних слова, :wруж.ая первое в IP, а :второе - в CS, в рсзультаrс чего
процессор возвращас-rея к вьmОJШению вызывающей процедуры.
Так осущестмяе-nт дальний, ИJШ межсегментный вызов процедуры,
расположенной в дРУfОМ сегменте команд.
Процедура binasc по ходу своего выпОJШения выз~ вложенную
процедуру hexasc, размещенную нами в том же сегменте text2. Эrar вы­
зов осущестмяеrся ближним оператором call (смещение 0012h в сег­
менте tcxt2). В этом случае, как уже описывалось в cnrrьc 16, в стскс со­
хранятся только относительный адрес возврата и, соаrвсm:твснно, ко­
манда ret процедуры hexasc (смещение 0008 в сегменте text2) снимает со
стека только одно слово.

Почему же команда ret процедуры binasc снимает со С'rека два слова,


в то время как такая же, на первый взгляд, команда процедуры hexasc
снимает только одно? В дейс-mиrельности, однако эти две команды не
эквивалеimiы. Сравнив строки с адресами ООЗАh и 0008h во вrором
сегменте, можно заметить, что машинные коды этих двух команд rct
различаются. Так ПOJIYЧIVIOCЬ паrому, что процедура binasc обьявлена
нами с помощью описателя far дальней. Транслятор воспринимает зто
объявление, как 1ребование прсобразовать мнемо11ическос обозначение
ret, встре'11{Вшееся в этой процс.цурс, в код команды даль11сго возврата
CBh. Процедура hexasc не имеет явного описаrеля 1ИПа, и по
умолчанию рассматривается транслятором, как ближняя. С целью по­
вышения наглядности программы се можно бЬVIо назначиn. ближней
явным образом с помощью описаrеля near. В СООТ'ВСТСТВИИ с 'IИПОМ
процедуры и ко~1анда ret, встретившаяся в этой проце.цурс, транслирует­
ся в код ближНего возврата СЗh.
Из приведеиного рассмтрения д01DСНо бьm. ясно, что бmасние
процедуры следует вызышm. только из того же сегмеиrа командой
ближнеrо вызова call, в то время, как процедуры, обьявленные, как
дальние, слсдуGТ вызыва:rь только с помощью команды дальнегО вызова
call fat ptr. Лшnь в этом случае завершающие эти процедуры коыанды
ret будут работаrъ правильно.
144 СтатьяЗ2

Статья 32
Проrраммы с несколькими сеrмекrами данных

В предыдущей статье бьша рассмотрсна программа с двумя сегмен­


тами команд. Вводя дополшrrельные сегмеНТhl команд, мы можем уве­
личивать общий объем команд, входящих в программу, усложняя се
алrориrм и увеличивая: возможности. Часто, однако, относительно не­
сложная программа обрабатывает значительные по объему массивы
данных. В таких случаях 'l])Сбуется увеличивать число сегментов данных.
Программы с одним сегментом команд и несколькими сегментами дан­
ных относятся к компак:m:ой модели памяти.
При налич:ШI нескольких сегментов данных возникают проблемы их
адресации. Поскольку процессор имеет только два сегмеН'Пiых реrие1ра
данных DS и ES (в процессарах 80386 и 80486 предусмотрены дополни­
тельные сегмеН'Пiы:е рсrис'l'ры FS и GS, что увеличивает возможности
этих процессаров по одновременной адресации данных, однако мы по­
ка рассма'l'риваем процессор 8086), в каждый момент времени програм­
ме МОIУГ бьrrь дОС'IУПНЫ mпnь два сегмента данных общим объемом 128
Кбайт. Если число сегментов данных в программе больше двух, рабо­
тать с ними придется последовательно, предварительно нас'l'раивая сег­

ментные рсrис'l'ры данных на требуемую пару сегментов.


Рассмотрим программу с двумя сегментами данных (пример 32.1).
Программа носиr несколько академический харапер, однако в ней про­
демонС'lрированы некоторые полезные практические приемы. В про­
грамме создается тестовый массив данных объемом 32 Кбайт, который
~м сортируется по признаку четности или нечетности числа устано­
меиных битов в каждом байn: массива. Байтами с четным числом би­
тов заполняется один выходной массив, байтами с нсчетным числом
битов - другой. Поскольку в общем случае количество тех и других бай­
тов заранес неизвестно, под выходные массивы выделяется по 32 Кбайт.
Эm массивы размещВJОТСЯ во втором сегменте данных, адресуемом
через рсrие1р ES.

llpиNcp 31.1. 0}ЮlpaAUtla с ihlyМR сегментами данньо:


&88\.UU CS:text, DS:datal
-in proc
IIIOV .AX,datal ;Настроим реrистр DS
aov DS,AX ;на первый сеrмент datal
Программы с нвскопькиии сегментами данных 145

JIIOV AX,data2 ;Настроим реХ"истр BS


JIIOV BS, АХ ; ка :второй сеХ"меиоr data2
; ЗanOJIIUDI иcxoJIIDIЙ маесна rav иатур&.IIЬИЬD& рцом чисеп
JIIOV СХ, 32 7 68 ; C"'eТ'IИJC цикпа
JIIOV ВХ, О ;ИК.ЦеJСс 11 масси:ве rav
JIIOV DL, О ;Чиc.no-sanOJIИИorenь, на"'Ием с 11yn11
fill: JIIOV rav[ВX] , DL ; Отправим чис.по а иcxoJIIDIЙ маесна
inc DL ; OISpasyeм cneayJIII%ee чиспо
inc ВХ ; CJIIIИИeJCII JC cne.ayJIIIIeм:f байоrу
loop fill ; Цюс.п no :всем:.r массиву
1 Рассор'I'Ируем чиспа иs массива rav no JIB'YМ массивам спмента
;data2: в массив evenЫt о!rправим байты с "'eorИЬD& чиспом
;установпенных биоrо:в, 11 масси:в oddЬit - с ие"'етным
IIIOV СХ, 327 68 ; C"'eТ'IИJC цикпа
IIIOV ВХ, 0 ;Ии.цеJСС В ИCXOJIHOM массиве rav
mov SI,O ;ИК.ЦеJСс в массиве •етных байоrо:в evenЬit
mov DI, О ;ИК.ЦеJСс в массиве не•еоrных байоrо:в oddЬit
pros: mov DL, rav[ВX) ; ПOJI}"DDC байоr иs масси:ва rav
test DL, OFI!'h ;Про:аерим еХ"о "'етность
pushf ;Сохраним в стеJСе реsупьтаты проверJСИ
inc ВХ ;Икlсремеит ИНJieJCca а массивеrav
popf ; Восстановим ф.п:uи процессора
jp parity ;Вспи четко - nepexoJI на parity
воv BS:oddЬit[DI),DL;Heчeтиo, в массив не•еткых байто:в
inc DI ;Икlсремент еХ"о yxasaтen11
:)шр outc ; И на cneдyJCIIФIЙ шu ЦИJСnа
parity: шоv BS:evenЬit(SI),DL;Чeтнo, а массив •еткых бu1тов
inc SI ;Икlсремент еХ"о yxasaтen11
outc: loop pros ; Повтор11ть СХ pas

IIIAin endp
text enda
datal segJD.ent
rav dЬ 32768 dup (0)
datal enda
data2 aegJD.ent
oddЬit dЬ 32768 dup (0) 1 Чис.па с не"'етным чиспом биоrо:в
evenЬit dЬ 32768 dup (0) ; Чиспа с "'етным чиспом биоrо:в
data2 enda
В проrрамме предуемтрены два сегмента данных datal и data2.
Сегментный perиC"lp DS будет использошщ.ся для работы с первым: из
них, поэrом:у в операrоре assume имеется определение DS:datal.
Прохрамма начШiастся с НасiрОЙПI обоих сегментных регистров.
Далее осущСС'ПШJiст:я запОJШение массива исходных данных raw сорrи­
руемым:и числами. Для простоты массив заполняст:я натуральным: ря­
дом байrовых чисел, которые, ссrественно, повторяются с шаrом 256.
Сор111р0вка осуществляется в цикле. Чmtость или нечm~ость числа
установленных в байте бкrов опредсляст:я с помощью пары команд tcst
(mmqювание) и jp (jump if parity, переход, если паритет четен). Двухо­
перандная команда tcst фактически выполняет операцию логического И
(and) над двумя операндами и, в зависимости от результата, устанавли­
вает флаги ZF, SF и PF. Команда удобна для определения целого ряда
146 Статья32

. :харuсrеристшс анализируемого числа в целом или заданной ero части


·(заданных битов). На рис. 32.1. на нескольких nримерах показано дей­
ствие эrой команды.

Пepвlolli операид (анапиsируе~Юе чис.по) 1111 0000 1010 0101 • FOЛSh


Второй операнд (каска) 1111 1111 1111 1111 • FFFFh
Реsупь~ат операции И 1111 0000 1010 0101 • FOЛSh
(11 данкок спучае реsупьтат совпадает с акапиsируе~ чис.пок)
8оsмоzине переходы: jпz (реsупьтат не ну.пь)
:!• (11 pesynь',l!aтe устаноапен sнaкoalolli бит)
jp (11 мпадшек байте реsупьтата четное чис.по
устаноапекккх битоа)

Пepвlolli операнд (акапиsируе~Юе чис.по) 1111 0000 1010 0101 • FOЛSh


Второй операнд (каска) 1000 0000 0000 0011 • 8003h
Реsупьтат операции И 1000 0000 0000 0001 8001h
Воsмоакые переходы: jnz(pesynьтaт не нупь)
ja (11 реsупьтате установпек sнaкoalolli бит)
jnp (11 sадакккх битах мпадшеrо байта реsупьтата
нечеткое чис.по устаноапеииых битов)

Пepalolli операнд (анапиsируемое чис.по) 1111 0000 1010 0101 FOЛSh


Второй оnераид (каска) 0000 0000 0000 1010 OOOAh
Реsупьтат операции И 0000 0000 0000 0000 • OOOOh
Boswoaкwe переходы: jz (реsупьтат иупь)
jp (а sадаииых битах мпадшеrо байта реsупьтата
четное чис.по [иупь) устаиоапеннкх битов)

11

ПераNЙ операнд (аиапиsируемое чис.nо) 1111 0000 1010 0101 • FOA5h


Второй операид (каска) 0000 0000 1101 0000 • OODOh
Реsупьтат операции И оооо оооо 1000 оооо • ооеоь

8oswoинwe nереходы: jnz(pesynьтaт ие нупь)


jnp (а sадаииых битах мпадшеrо байта реsупьтата
нечеткое чис.по устаиоапеннкх битоа)

Pllc. 32.1. НеСIШАЬI(О npuмefi06 действия команды tut.

Croиr nерсчислить нссКОJJЬко типичных применений команды tcst.


EcJm в анализируемом числе устаномен старший, знаковый бит, и
он }'Jal3aИ в маске (возможно, 11 числе прочих битов), то нарядУ со сбро-
Программы с нескопькими сегментами данных 147

сом флаrа ZF ~ флаr SF, что можно обнаружиrь с по­


мощью командь~js (рис. 32.1, а и б).
Если а анализируемом чиСJiе не устаиовлен ни один из биrоа, за­
даUНШ маской, то устанавJIИ18СТСЯ флаr ZF, что можно обнаружиrь с
помощью mманд jz или je (рис. 32.1, в).
Если в анализируемом чиСJiе установлен хам бы один из биrоа, за­
данных маской, то флаr ZF сбрасьmмтся, что можно обнаружить с по­
мощью к.оwанд jnz или jne (рис. 32.1, а. б и r).
Очере.IОiой байr исходного массива чиrастся в регистр DL и коман­
дой tcst провсряМ"Ся все его содер.жимое (поскольку вrорой ооеранд ко­
манды test, число FFh, задаст для проверш все биrы). О резуль'nПС про­
ворки на чеmость можно узнап. по состоянию флаrа PF pel'ИC'lpa фла­
rов, который анализируМ"СЯ командой jp. Однако независимо or
чеmости или нечеmости байrа необходимо вьmОJШИТЬ инхрсмент уu­
затм:я исходного массива ВХ. ·Так как команда inc влияет на состояние
флаrа PF, перед ней содержимое perиc'lpa флагов сохраняМ"Ся в стеке
командой pushf (push flags, занесение в стек флагов), а после нес вос­
станамивается обратной командой popf (рор flags, восстановление из
стека флагов). Эrо весьма распространенный прием, позволmощий
"отсрочшь" условный переход, если между командой анализа и услов­
ным переходом необходимо вьmОJШИТЬ каше-то действия.
Каким бы ни бьш анализируемый байr - четным или нечС'IНЬIМ, его
СJiедует записа'l'Ъ во вrорой сегмент данных, адресуемый через ES. По­
этому в командах записи в память содержимого DL регистр ES указан в
явной форме. Эrо еще один пример замсны сегмента. Если опустm:ъ
прсфикс ES:, адресациg осуществилась бы через регистр DS, и мы по­
пали бы в исходный, а не в рсзуm.тирующий массив. Полезно иметь в
виду, что префикс замены сегмента увеличивает на 1 байr дmп1У коман­
ды. В '1П CJI)"WWX, когда 'lрСбуМ"Ся максимальное сокращение размера
проrраммы, это может иметь значение.

В рассиаrренной проrрамыс не прсдусиО'lрСна нarJUJДIWI дсион­


страции се работы. 3апуС'ППС се • отладчике, остаиовiт' перед cтpoiWIII
завершсНIDI и коиандой отладчика D просмспрiт' содержимое ИЗССJIВОВ
raw, oddЬit и cvenЬit.
148 СтатьяЗЗ

Статья 33
Директива assume, инициализация сеrмеiП'ИЫХ
реmстров и замена сеrмеiП'Ов

Обсудим несколько по.цробнее роль диреmmы ассемблера assume.


Вернемся для этоrо к примеру 32.1 и рассмотрим некоторые предложе­
ния этой проrраммы. В предложении с .диреmmой assume, с котороrо
начинался текст сегмента команд, устанавливалось соответствие сегмен­

та команд text сегментному pernC'rpy CS и сегмента данных datal сег­


ментному pernC'rpy DS:

a.s.swne CS:text, DS:datal

Диреmmы assume, которых в проrрамме может бьrrь любое ко­


личество, в принципс мoryr располагаться в любом месте проrраммы,
однако обязательно до тех проrраммных C'rpOK, в которых выполняется
обращение к описываемым в конкретной диреiСJ'ИВС сегментам. Поэтому
предложение вИда

a.s.swne CS: text

дОJDКНо стоять в проrрамме до любых проrраммных C'rpOK и даже до


обьявления процедур. Что же касается установки соответствия peПIC'rpa
DS и конкретною сегмента данных, то, если это соответствие не описа­
но в первой диреК111ве assume, оно может бьrrь описано и позже, на­
пример (для проrраммы 32.1):
a.sswne DS:datal
fill: IIIOV rav[BX), DL; ОТnравим число в исходинК массив

Лоскольку к момеН'I)' трансляции указанной выше команды mov


транслятор уже знает из диреК111Вы assume, что сегмент datal сопостав­
ляется с penfC'rpOM DS, а имя raw описано именно в сегменте datal, ко­
манда mov транслируется в такой код, что процессор при ero выполне­
нии обратится к ячейке памяти с относительным ацресом raw(BX), взяв
сегментный ацрес из pernC'rpa DS. Транслятор выполняет (не слишком
C'rpOryю) проверку правильносm ссьток на данные, так что если бы
ячейка raw входила в дРуrой сегмент, бьта бы зафиксирована ошибка.
Таким образом, описание в диреК111ве assume соответствия сеrментноrо
peПIC'rpa DS сегменту данных позволяет в какой-то степени контроли-
Директива аssитв, сегментные регистры и сегменты 149

ровать правИJIЬность написания проrраммы и, главное, избавляет нас от


необходимосm указьiвать в каждой С1р0Ке, содержащей ссьшку на имя
данных, в каком сегментом регистре находится сегмеiПНый адрес этих
данных. По умолчанию будет подразумеваться регистр DS.
Однако из сказанного совершенно не следует, что к мoмelflY вы­
полнения С1рОКИ с обращением к данным в регистре DS будет в дей­
ствиrел:ьносm находиться сегмеiПНый адрес соответствующего сегмен­
та. Более того, его там и не будет, если мы об этом специально не поза­
ботимся. Предложения

IIIOV АХ, datal


IIIOV DS,AX
как раз и выполняют заrрузку в сегмен·mый регистр DS сегментного ац­
реса 11ашего сегмента данных. Как мы уже знаем, при заrрузке про­
rраммы в память оба сегментных регистра данных указывают на PSP, а
совсем не на сегменты данных, так что до выполнения указанных выше

C'lpOK наш сегмент данных неадресуем.

Несколько по-иному обстоит дело с дополнкrельными сегментами


данных, к которым мы будем обращаться через сегмеiПНЫЙ регистр ES.
Поскольку в проrрамме 32.1 регистр ES в директиве assume не описан,
его следует в явной форме указывать во всех предложениях проrраммы,
где выполняется адресация к дополюrгельному сегменту данных (data2 в
примере 32.1):
IDOV ES:oddЬit[DI),DL;He~eтиo, в массив иечеткых байтов
inc DI ;Инкремент ero YJC&:saтe.nя
jшр outc ;И ка с.nедуJ<ЦИЙ шаr цих.па
parity: mov ES:evenЬit[SI),DL;Чeткo, в ыассив четных байтов

При выполнении приведеиных выше команд mov процессор обра­


пm;я к ячейкам nамяти с относительНЫ.\(И ацреса.ми oddblt(DI) и
взяв при этом сегме1m1ый ацрес из регистра ES. Однако и в
evenblt(SI),
этом случае занесение в регистр ES требуемого сегментного адреса
должно быть выполнено в проrрамме явным образом, например, nред­
ложениями

IIIOV АХ, dat&2


IIIOV ES,AX
Директива assume nозволяет создать умолчание и для регистра ES.
Однако для этого необходимо, чтобы дополнительный сегмент данных
data2 был оnисан в проrрамме до сегмента команд (см. пример 33.1). В
этом случае включение в текст проrраммы директивы

ASSUIII8 ES :dat&2
избавит нас от необходимосm указывать в явной форме регистр ES во
всех командах с обращением к данным из сегмента data2. Если таких
150 Сmаmья3З

прод~~оиений в проtраММо миоrо, ro эrо можот несколько облеrчить


процосс Н11ПИС811101 проrраммы.

;(l)О&ъяапекие дои~еиъвоrо
;сеrман~а дакннх

oddЬit dЬ 32768 dup (0); (2)чис.па с ••••~- 'IICC.JIOM ~а


eveuit dЬ 32768 dup 101; IЗ)чиспа с "'e'Ж'JDD( -с.пом ~а
clata2 elld• 1 14)
text aef88nt 'code' ;(S)Об~•апекие сеrмен'Ж'а команд
aaaua. CS:text,DS:datal,!S:data2;(6)0DИCaнк асе
;сеrмактиwе р81'Истры (~ома SSI
proc ;(7)
IIIOV JUC,datal ; (8)Настроим pel'J8Cтp DS
.-ov DS,AX ; (9)ка nepiiМЙ сеrмен~ datal
asov AX,data2 ; (101Настроим perиcorp BS
IIOV II,JUC 1 (ll)нa аторой се:l'меН'1' data2
; Заu- исхо....- аассиа r - Ka'l:ypa.JIЬIUIМ р11д0м чис-
.оv СХ,32768 ; (12)Сч.-.нк ~а
180V ах, о 1 (13)Индекс; а аасоиае rav
180V DL,O ; (14)Числ:о-sаuопки~еиъ, качаем с нуm~
fill: JDOV rav[8X},DL; (15)0тnрааим -c.no а иcxoiUDIIЙ массиа.
;По )'М)JIЧIUDIID ИCDOJI•sye~c.tl реrистр DS,
;'!llaJC JCaJC rav находи~с• а с:uменте datal
.inc DL ; (lб)Обраsуем с.педу~~Цее чис.по
iac 8Х ; 117) Сдаинемс• IC С.Jiедр!Щ.Щ бай'!llу
loop fill ; (18)Цккп по асему массиау
; Рассор'l'Ируем числ:а иs массиаа ra.w по да)'~& массиаuс се:rмен~а
;data2: • маесна evenЫt о~прааим байты с "18ТНЫ14 чис.пом
;устакоапеннмх би'!l'оа, а маесна oddЬit - с: веч~иыw
1110v СХ, 32768 ; (19) Сче~чик wocna
aov 8Х,О 1 (20)ИJureкc а исходном массиае rav
IIIOV SI,O ; (2l)ИJureiCC а массиве "18'!1/ВЫХ fS~oa
;evenЬit
IIIIDV DI,O ;(22)Инаехс • массиае нечеткых б~оа
;oddЬit
pros: DL,rav[BX) ; (23)Получим байw иs массива rav. По
;уМОп"'аниа иcnoи•sye'l'C.tl ре:rистр DS,
;~ах как raw а сеrмек"Ж"е datal
n:r.,orrь ; (24)проанапиsируем ero чеwкост•
1 (25)Сохраким 11 с~• pes~wa,_ анапиsа
1 (26)ИКмр.мент ккаекса • массиае r.w
;(27)Восставо.нм tnerи ароцессора
paritr 1(28)8спи •••••- nереход ка parity
~it[DI),DL;(2t)H•••твo, а массиа ••••'вкх
;баhоа. По )l'a8mr&JIIIID кcao.rasyewc• IS,
1 wax как ockUtit 11 с-• dat:al
DI 1 (30)Ивмр8М8Вw ero укаsат-11
outc 1 (31)И ка 011..."_- ка:r IUIIUia
par.itr: ~.it(II),D:LI (321Четмо, а масона •eтiDIX б~а.
1По ~&МК8 ксаои•sуеwс• реrистр BS,
.venЬ.it • се:rw.мте datal
, ,. . . . .
SI 1(331-.кр.м.мт .ro
YJCasaoreoiiii
0\&1:01 р~•• 1 (34tПoawop.,. СХ pas
М, fCOOh ; (35 t Saa•JII8-
Директиеа asвume, сегментные регистры и сегменты 151

int 21h ; (361пporp.-


.U.n еьdр ; (З'f 1
text еьdа ;(381Коиец сеrм.в~а ~оNаад
datal eev-ent ;(3910&ъ~апевие сеrм.вта ааивмх
r- dЬ 32768 dup COI; (401
datal еьdа ; (411

Проl'р8МЬlа, nредложенная в статье 32 и нсскош.к.о модифJЩИрОван­


ная в настоJПЦсй cnm.c, Н81П1сана нсопmм~но с точки зрснu объема
расходусмой пawrm и времени выполисния. Hcкcnoporo yJI)"IШeRИR
программы можно достиrнуrь, замсниа адресацию со смсiЦОНием на

чисrо рсrие1р0вую - базовую, индексную или базово-ЮIДексную. Ниже


npИВOДfl'roJI только измененные С'IрОКИ (нумерация С1рОК сохраняс-rоя).

Прш~ер ЗЗ.2. OnmWiuзuJJfМaiUUlJI nJЮZP~~~t~Мa

aaa\.88CS:text,DS:datal; (61Нет иеоiSкоДJОСсти оаио-ат• BS

lllliOV ВX,offset rav; (131Индекс • wассиае rav

fill: IIIOV [ВХ], DL ; ( 151 Oтnpauoa '!DССЛО а исходккй: маесна.


;По у.мсп.аии» иcuon•syeтc• DS, т~ ~~
;rav а сеrыеите datal
lllliOV ВX,offaet rav; (201Инде~с а исходмом масgиае rav
IIIOV SI,offset evenЬit; (211Ииде~с а wассиае •еткых
; байтов evenЬit
IIIOV DI,offset оddЬit;(221Ииде~с а wассиае •••~кмх
;IS&Йтоа oddЬit
proa: IIIOV DL, [ВХ) ; (231По.пучим байт иs wассиаа rav

IIIOV IS: (DI) 1 DL ; (291Нечетно, а wассиа ке•еткых байтоа.


;Яаио ухаsаи !S, т~ JC~ нет IIIIBoro
; ухаsаии11 имени даивмх
parity: IIIOV BS: [SI],DL; (321Четно, 11 маесна ••ткнх ISaiiтoa.
;Явно ухаsаи !S, т~ ка~ иет 11авоrо
;ухаsани~ имени даикмх

Сравним примеры 33.1 и 33.2. В диреiСIЯВе assume otnlcaны только


pcmCipы CS и DS, так как в этом варианте программы ист пр.RМоrо об­
ращения к памяти по имена.\1 ячеек. В предложении 13 в pcmCip ВХ
заноскrоя J{e смещение относкrсльно начала массква raw
(псрвоначально равное 0), а относкrслъный адрес массива. Эrо oll11DOI-
зиpycт предложение 1S, в каrором теперь нет необходиыОС'nl указывать
адрес массива. В дальнейшем последовательное увеличение содержи­
мого ВХ на 1 позволит нам, как и раньше, смещаться по массиву raw.
Аналоmчные изменения внесены и в предложения 20, 21 и 22. Во всех
'JPCX pcmc'ipax теперь xpawm:я (и наращиваются) не индексы ВRУIРИ
массивов, а смещения байтов массивов относитспьно начап соапsеr­
ствующих сеrментов.

Важно обрапm. внимание на предложения 29 и 32. В процессе оп­


тимизации из этих предложений из'ЫПЪI мнемонические обоэначСНИJI
152 СmаmьяЗЗ

·ячеек. По эrой причине транслятор не имеет никакой возможн:ОС'ГИ


определить, к какому сегменту данных выполняется обращение, и сели
бы в предложениях не был указан регистр ES, на этапе выпОJПiения
процессор извлек бы сегментный адрес из регистра DS, исnользуемою в
таких случаях по умолчанию. Команды с базовой, индексной или базо­
во-индексной адресацией следуст использовап. с особой осторож­
ностью, помня, что при оrсутствин префикса замены сегмента в них
по.цразумевается сегментный регистр DS.
ДиреiСГКВа assume позво.пяст в некоrорых случаях не указыва:п. в ко­
мандах программы сегментные реr.истры, однако она не запрещает эrо

дcmrrь в случае необходимОС'ГИ. Часто по ходу программы приходится к


одному и тому же сегменту данных обращаться то через один, то через
друrой сегментный регистр. Такая сmуация типична при использовании
команд обработки строк (movs, stos и др.). Если некоторое поле пawrm
служит сначала приемником данных, перссылаемых в неrо из дpyroro

участка пawrm, а затем источником при перссылке эmх данных на ка­

кос-то третье место, то сначала это поле должно адресовап.ся через ре­

гистры ES:DI, а затем - через DS:SI. Ясно, что как бы мы не объявили


cOO'l'ВCmmSиe сегментных регистров и сегментов данных, в одном из

эmх случаев придется воспользовап.ся префиксом замены сегмента.


При этом стокr замстип., что хотя использование префикса увеличивает
на один байr размер команды, оно, с друrой стороны, повышает на­
rлядность программы.

ДиреiСrИВа assume может использоваться внутри программы неодно­


кра-mо. Предположим, что на некоrором, достаточно продОJDКИТеJIЬном
участке программы, к определенным полям данных надо обращаться
через сегментный регистр DS, а на друrом участке - через регистр ES.
Тогда между этими участками можно сменить сОО'l"ВСТС'mие сегментных
регистров сегментам данных, как эrо схематически показано ниже.

;Сеrиеит дAИIUIIX
data 8egm.ent
II1IIJIIl dw ?
-1112 dw ?
data elld8
; Проrр-е С'l'роки • . .ите
сеr коwанд
&88WDO DSadata
IIIQV АХ, aeJIIl 1Коwакда будет 8ЫПопияться,
}КАК IIIQV АХ, DS :mellll
IIIQV ВХ,111.01112 ;Команда будет внnопкяться,
;как IIIQV ВХ, DS :111.01112
&88\.1111.8 D$: nothing
aвa\.llll.e J:S:data
8IOV AX,aea.l ;Комаида будет выоопияться,
;как IDOV AX,ES:meml
IIIQV BX,III.OIII2 ; Команда будет ISНDo.nJIRTЬCR 1
;как шоv ВX,ESame1112
nрогргмuы типа .сом 153

Дирспива assume DS:nothing (nothing - ничего) снимаеr :wсрсiШе­


ние за сеrм:ентом data perиC'l)>a DS и nозВОЛJI~ :wcpcmrrь за ним дРугой
pei'ИC'lp,ES. Того же эффспа можно бЬVIо достиrнуть, :wcpcmm реrие1р
DS за l.t.81tИМ-'OO дРУI'ИМ сегментом: (сели, конечно, он имеется). Необхо­
димо 'ЮJIЬКО nеред оnисанием: СОО'l'ВС."/l'СТИЯ perиC'l)>a ES и сегмента data
отисниrь захрсiШение за Э1'Ю( сегментом perиC'l)>a DS.
Очевидно, что нсзависимо ar дирспивы assumc, nеред nервым:
участком необходимо Н8С1р0Иl'Ь на сегмент data pcme1p DS, в nеред
IП'ОрЬIМ - ES.

Статья 34
Проrраммы типа .СОМ

В некаrорых случаях оказывается удобно не дРобmь nрограмму на


отдельные сегмскп.r, а вкmочmь вес комnонекп.r nрограммы в один

сегмент. Эrот единс'l'вснный сегмент должен, таким образом, содержать


nрефикс nрограммы (PSP), коды команд, данные и стек. Такие одно­
сегментные nрограмм:ы, сООТВС'rоТВующие (в терминологии языков вы­
сокого уровня) минимальной, или крошечной модели nамяти, обычно
образуют загрузочные модули тиnа .СОМ (в ОТJIИ'iие от модулей тиnа
.ЕХЕ, каrорые рассма1ривались до сих пор), хотя иногда мoryr иметь и
другие расширения (например, SYS). Программы тиnа .СОМ не имеют
особых nрсимуществ nеред nрограммами тиnа .ЕХЕ, кроме своей ком­
nакn~ости, однако они широко используются, nрежде всего, в качестве

реэидеН'ПIЬIХ nрограмм.

При создании программы тиnа .СОМ необходимо выnолнение двух


условий: во-nервых, исходный текст программы должен быть наnисан в
оnределенном формате, с ограничениями, СОО'l'ВС."/l'СТующими мини­
мальной модели памяти, и, во-вrорых, nосле компоновки объс1С111ого
модутi и nолучения обычного загрузочного файла с расширением .ЕХЕ,
необходимо nрсобразоВIПЬ этот файл в формат .СОМ с nомощью си­
стемной утилиn.1 EXE2BIN:

BXI2BIN P.EXI Р.СОМ

Следу~ иметь в виду, что компоновщик LINK создает 1а1руэочньrй


модуль в формате .ЕХЕ. Если, однако, исходная nрограмма написана в
154 . Статья34

фор~ .СОМ, эror модуль .ЕХЕ не является пОJШоценной програымой


и в большинстве случаев будет нсработоспособсн. У11ШИТ1i EXE2BIN
изменяет формп эаrрузочноrо мoдyJUI, превращая ero в пОJШоценную
nporpuwy 'l1Uia .сом.
Дл& тоrо, чтобы освоиrь написание программ в формпе .СОМ,
воспользуемся самой первой программой из статьи 1 н "псрсоборудуем"
се 'lрСбусмым образом (пример 34.1). Между прочим, поскольку в этой
проrрамме не было ни сегмента стека, ни сегмента данных, она уже в
какой-то степени удовл~яст требованиям формата минимальной
модели памяm.

ЛрШtlер 34.1. Лростеiiшая npoгJIOМAIO типа .СОМ


text seqaent 'code'
assuae CS: text, DS: text
orq 256JРеsервироааиие wec~a дп~ PSP
IIIAin proc
JIIOV АН,О9h
JIIOV DX,offset aeasaqe
int 2lh
JIIOV AX,tCOOh
int 21h
aeasaqe dЬ 'Науха уме е~ JWIIoro rиоrик$ 1
11\Ain endp
text enda
end IIIAin
Программа содержит единственный сегмент text, которому приевоси
класс 'code'. В диРеiСI'ИВС assume указано, что сегментные реrн01ры CS и
DS будут соответствовmъ этому сегмеН'IУ. Как уже подРОбно обсУЖRа­
лось выше, упоминание в дирс:IСI'ИВС assume реrн01ра DS в данном
CJiyЧae не 'lрСбуется, так как в проrрамме нет ссьmок на ПOJIJI данных.
Для более СJiожных программ, однако, сопоставление реrн01ра DS и
сегмента команд (в котором в данном CJiyЧae rолько и MOJYl' распОJiа­
rаться: данные) весьма пОJiезно.
Дирею:ива org 256 резервируст 256 байт для PSP. 3апОJIЮП'Ъ PSP бу­
дет по-прежнему си~ма, но место под неrо в начале сегмента дOJDICeн
отвесm программист. В программе нет необходимости инициализиро­
вать реrн01р DS, поскОJIЬку ero, как и ОС1.'МЬНЫе сегментные реm01ры,
инициализируст си~ма. Данные можно размсстиrь ПOCJie проrраммной
процедуры (как это показано на рисунке), ИJIИ внуrри нес, ИJIИ даже пе­
ред ней. Следуст rолько иметь в виду, что при загрузке проrраммы 'l1Uia
.СОМ реrн01р IP всегда инициализируется ЧИСJIОМ 256 (lOOh), поэтому
сразу за диреiСПIВОЙ org 256 ДOJDICIIO СТОЯП. Первое ВЬIПОJШИМОС предло•
ж:ение програм:мы. Если в начале программы желате.льно распОJiожиn.
данные, перед ними СJiедуст поместить команду перехода на реальную
точку входа, например jmp entry.
Образ ПaмJml программы 'l1Uia .СОМ показан на рис. 34.1.
Ввод с клавиатуры десятичных чисел 155

Пос.лс заrрузки про­


CS, 05, ES, SS -+..----PS~P---, граммы все четыре ссr­

ментных perиctpa указы­


25665П
вают на начало единсmен­
"""---- +-IP·01~
Проrрамма ноrо сегмента, т.е. фах­
и дl!ННые
mчески на начало PSP.
:-----
Стек +- SP • FFFEh Указатель стека авrома­
mчески инициализируется
Рис. 34.1. 06pt13 ntiAUimU nJНМ~НlММw .СОМ. числом FFFEЬ. Таким об-
, разом, независимо от фах­
mческоrо размера проrраммы; ей выделяется 64 Кбайт а,цресноrо npo-
crpaнcma, всю нюкнюю часть кaroporo занимает стек. Поскольку вcpx­
НJIJI rраница стека не определена и зависиr от интенсивности и способа
исп011Ь30вания стека программой, следует опасаться затирания стеком
нюкней части программы. Впрочем, такая опасность сущссmует и в
программах типа .ЕХЕ.
Создайте файл с программой из примера 34.1. Подrотовьте nро­
грамму к выпОJПiению. Вы опять увидиrе сообщение компоновщика об
~ynmsи:и в программе сеrмекrа стека:

LINК : warning L402l: no stack seqment


В данном случае, однако, так и доп:хсно быть.
ВыпОJПiите пробный проrон программы и убедиrссь, 'ПО она рабо­
тает, ках о.жидалось. Запустиrе программу под управлением оттщчиха.
Внимательно рассмотрите содсрхсимос реrиС1рОВ процессора: сегмент­
НЫХ. указаrеля команд, yкaзareJUI стека. Оцените, какоrо объема по­
лучился стек.

Статья 35
Ввод е uавиатурw деСJIТИЧных чисел

Как мы уже видели, все данные, поступающие в компъютср с кла­


ВJ181УРЫ ИIDI вьоюдиыые на экран терминала, рассма'lриваются ках коды
ASCII аrображасмых на экране символов. Для вывода на экран числа из
ячейки памяm ИJtИ perи<npa cro СJIСдует предварИ'МЛЬно прсобразовап. в
1С0ДЬ1 ASCII СОО1'ВСТС'11Sующих цифр той системы счисления, в которой
156 Статья35

'l)>Сбуется аrобраэmъ число на экране. Точно таюкс при вводе числа с


клавиатуры полученные символы надо прсобразовать в число (двоичное,
поскольку любые данные хранятся в компыотсрс исключительно в
двоичной форме). Очевидно, что процсдура прсобразования будет зави­
есть от того, какое число мы хотим набрать на клавиатуре - дссJIТИЧнос,
шсстнадцатсричнос или двоичное. В настоящей стаn.е будет рассмоорсн
ввод с клавиатуры дссJIТИЧных чисел.

Помимо преобразования символьных кодов цифр в двоичные числа


и объединения Э11fХ чисел с учетом весов отдельных дссJIТИЧНЫХ разря­
дов, в проrрамме дОJDКсн быть прсдусмоорсн анализ вводимых симвалов
и исключение из входного потока кодов, не ЯВЛJIЮщихся кодами дсся­
mчны:х цифр (такую операцию часто называют филь1рацией). Кроме
того, следуст прсдусмоореть какос-либо соглашение о способе заверше­
ния ввода. Например, можно всегда вводить S десJIТИЧных цифр (с ли­
дирующими нулями, сели число имеет меньше S десJIТИЧНЫХ разрядов).
Удобнее вводить число без лидирующих нулей, завершая ввод нажатием
клавиши <Enter> (или другой выделенной для этого клавиши). В согла­
шениях о правилах ввода (как говорят, в интерфейсе с проrраммой)
должна быть оговорсна реакция проrраммы на неправильно нажатую
клавишу. Проще всего заставmъ проrрамму игнорировать все нецифро­
вые клавиши, хотя может бьnъ прсдусмоорсна и иная реакция, напри­
мер, вывод сообщения об ошибке или подача звукового сиmала. Далее,
мoryr быть варшunъt аrображения вводимой информации на экране:
аrображать или нет случайно введенные нецифровые символы.
Проrраммный фрагмент, приведенный в примере 35.1, ocyщCCТIIJIJieт
ввод с клавиатуры десЯ1ПЧных чисел с любым числом разрядов от 1 до
S. Ввод каждого числа завершается нажатием клавюuи <Enter>. Вводи­
мыс СИМВОЛЫ проверЯЮТСЯ На ИХ прИНад/lеЖНОСТЬ ДССЯ1ПЧНОму Числу;

нецифровые симВОJIЫ не воспринимаются и не отображаются на экране.


Результат прсобразQвания загружается в pemC'Ip АХ.
Принцип прсобразования вводимой ':троки симвалов в число за­
ключается в следующем. Первая введенная цифра (старший дсскniчный
разряд) прсобраэуется в двоичное число и засыластся в результирующую
ячейку number. После ввода и преобразования следующей цифры со­
держимое ячейки numbcr умножается на 10 и к полученному произве­
дению приба.влястся введеннос число. Далее :пот процесс повторяСТСJI
до нажатия клавиши <Entcr>.

Пример JS.l. в.oiJ с ~t~~aiuamypw дeaunu'UIOlfJ rшСАа


rВIDeдew •• 8JCP&II :s&Dpoa, caидeтen~ocт•)IJII8Cit oCS 08Ид._ ••ода
IIIDV АН, 02h . 1 (1)
IIIDV DL, '>'
1 (2)
int 21h 1 131
IIIDV DI, О 1 ( 4) О.ИсТIОС peJ:'IIcтp о111И peS)'RI>'1'&Ta
Ввод с клавиатуры десятичных чисел 157
; Sya- а:аодить и -&llll:sиpoaaть cю.a~OJDI
inpt 1 IIIOV АН, 08h ; (51 Фукхци.11 880.11& CИWIIOIIA беs 18ХА
int 21h ; (61
CDp AL, 13 1 111 Нажата
IС.llавиша <Znter>?
je done(8 1Да, ввод чиспа :sАJСокчеи
;
CJII) 191 Цифровой CИWIIOII?
AL, ' 9' ;
jа inpt11 О 1Нет 1 На повторИJiiЙ ввод
;
C1llp ( 111 ЦифрОIIОЙ CИNIIOJI?
AL, '0' ;
jb inpt( 12 1Нет 1 На повторИJiiЙ вво.11
;
; Введен очередной цифровой CИWIIOII. Bbllleдeм ero на 31Cp-
IIIOV АН, 02h 1 ( 13 1 Фукхци.11 IIWJIOДA CJOalo.Jia
IIIOV DL,AL ; (141CИNIIOII до.пzеи быть в DL
int 21h ; 1151
аuЬ .AL, '0' ; (16,Преобраsуем CJOalo.n а дBOJS"'JJOe чиспо
xor АН, АН ; ( 17 1 Обиупиw АН
IIIOV СХ, АХ ; ( 18) Сохраниw ПOJIY"'eИИYJO цифру в СХ
IIIOV АХ, DI ; 1191 Ре"упьтат преобра"о:ааки.ll пре.J~~UQ~ЩИх
;введенных цифр
IIIOV ВХ,10 ; 120)Миожитепь 10
IIIL1l вх ; 1211АХ•предьщущнй ре:sупьтат * 10
add АХ,СХ ; (22)Добавиw ноаУJО цифру к старо~ чиспу
IIIOV DI,AX 1 123)Сохранкw 11 реrистре DI
jmp inpt 1 (24)На ааод спедуРЩеЙ цифры
done: IIIOV AX,DI 1 (25)Заrру"иw ре:sупьтат а АХ

Проrрамма nрежде всего выводит на экран заnрос в виде знака ">"


(nредложения 1... 3). Перед началом ввода очищается реrисч> Dl, где бу­
дет накаnливаlЪСя результат ввода nоследовательных цифр исходного
числа. Вызовом функции DOS 08h ставится запрос на ввод с клавиа'l)'­
ры одного символа без отображения его на экране (отображать мы будет
только цифры). Функция 08h возвращает введенный символ в AL Код
ASCII нажатой клавиши сравнивается с кодом ASCII клавиши <Entcr>
(код 13, nредложение 7). ЕслИ нажата эта клавиша, nроцесс ввода цифр
заканчивается переходом на метку done. При любой другой клавише
выполняется анализ введенного кода. Содержимое AL сравнивается с
символьным nредстав.пением цифры 9 (предпожение 9). Если введенный
код больше '9', он не является цифрой и его следует О'Iбросить. Э1у си-
1Уадию отрабатывает команда ja, осуществляя переход на начало блока
ввода очередного символа. Если введенный код nрошел nроверку на
верхнюю rраницу, он сравнивается с нижней rраницей - кодом 'О'
(nредложение 11). Команда jb осущсСТВJIЯет nереход на начало блока
ввода символа, если введен символ с кодом меньше '0'. Следующее
nредложение 13 будет выполняться, только если нажша клавиша с циф­
рой. Функцией DOS 02h введенный символ выводится на экран
(nредложения 13 ... 15) и начинастt:я его nреобразование в число.
' В предло.жеНЮI 17 с помощью команды xor выполняется очистка
старшего байта рсrиС1рЗ АХ. Вообще команда xor (exclusive or, ис·
ключающее ИЛИ) анализирует биты обоих операндов (каrорые в дан­
ном случае совnадают) и устанавливает биты результата по следующему
158 Статья35

правилу: каждый биr результата устанавливается в l, ecm соаrвст­


ствующие битьt операндов различаются, и сбрасывается в О, ecm соот­
_ветствующие бИ'lЪI операндов совпадают (рис. 35.1).

ПерDЫЙ операид 0101 0011 0000 1111 (дDоичиое предстаапение)


Второй операид 1110 0011 1111 0000 (двоичное предстаапение)

Реsультат (sамещает 1011 0000 1111 1111 (двоичное продстаапонио)


первый операнд)

Рис. ЗS.I. Результат действия команды xor.

В предложении 17 в команде xor оба операнда совпадают. В этом


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

вьmолнения команды xor в нем будет О (рис. 35.2).


Первый операид 0101 0011 0000 1111
Второй операид 0101 0011 0000 1111

Реsультат 0000 0000 0000 0000


Рис. 35.2. Результат действия команды XOR над совпадающими операндами.

Команда xor reg,reg занимает в памяти меньше места, чем команда


·mov reg,O, что и объясняет использование этого не очень наrлядноrо
приема.

Обиулив старший байт рсл1стра АХ и имея в его младшем байте


введенную десятичную цифру в виде двоичного числа, мы на время со­
храняем содержимое АХ в pcrncтpe СХ (предложение 18). Далее резущ.­
тат преобразования предыдущих цифр (или О, ecm вводится первая
цифра) извлекается из ячейки number и умножается на 10 (предложения
19 ... 21). Команда mul (multiplication, умножение) предполагает наличие
одного из сомножителей в АХ. В качестве другого сомножителя не мо­
жет выступать число (неnосредствснный операнд), поэтому сомножи­
тель10 мы занесJШ в регистр ВХ. Резулыат умножения процессор зано­
сиr в два регистра: в DX (старшую половину результата) и в АХ
(младшую половину). В нашем случае результат умножения не может
превысить 64К, поэтому содержимым DX мы не mrrepecyeмcя.
Получив в АХ резульmт преобразования предыдущих цифр, умно­
женный на 10, мы прибавлясм к нему текущую цифру из регистра СХ,
отnравляем результат в ячейку nurnЬer и переходим на мсnсу inpt с
целью ввода следующей цифры.
При обнаружении кода клавиши <Entcr> выnОJШЯется персход на
метку donc, полученное число заносится в pernC'J1) АХ и проrрамма на
этом завершается.

Рассмотренная проrрамма нсудачна в том отношении, что результат


се выполнения теряется. Проверить се работоспособность можно только
Ввод с клавиатуры десятичных чисел 159

с помощью отладчшса, поставив точку останова вслед за предложением


25 и анализируя содержимое регистра АХ после ввода всех цифр и перс­
хода на метку donc. Восполъзовавшись программиым материалом, по­
лученным при изучении предыдущих статей, неq>удно усовершенство­
вать -лу проrрамму, допОJШИВ се строками преобразования: числа, обра­
зованноrо в ячейке numЬer, в символьную форму и вывода полученной
строки символов на экран.

Вюпочим в сегмент данных описание строки, выводимой на экран,


наnример, в виде

atrinq dЬ 10,13,'****',10,13,'$'
В конце проrраммы, сразу после предложения: 25, вызовем подпро­
rрамму binasc, настроив предварительно регистр SI на адрес выходноrо
поля данных:

IIIOV SI, string+2


call Ьinasc

После этоrо неq>удно с помощью функции 09h DOS вьmесm строку


string на экран. Естественно, надо побсспокоиrься о том, чтобы подпро­
rрамма binasc и вызьmаемая ею подпроrрамма hexasc были либо
вюпочсны в состав исходноrо текста нашей проrраммы, либо под­
ключены к вьmОJПiимому модуmо на этапе компоновки. Все Э'm вопро­
сы рассма'lривались в статьях 21-22.
Еще один недостаток проrраммы заключается в том, что в ней не
анализируется число введенных символов. Между тем в машиннос сло­
во нельзя записать число, прсвьnuающее 65535, поэтому ввод шсстоrо и
последующих десятичных цифр не имеет смысла. Для тоrо, чтобы оrра­
ничить число вводимых законных десятичных цифр и, в то же время, не
учиrывать случайно нажатые алфавиrные и прочие клавиши, счетчик
проходов проrраммы следуст установить в той точке, где начинается об­
работка законной десятичной цифры, т.с. между предложениями 12 и
13. Счетчик можно организовать следующим образом.
Где-либо до метки inpt надо инициализировать счетчик проходов, в
качестве котороrо удобно исполъзовать какой-либо свободный регистр,
например, SI ·
IIIOV SI, 5

а после предложения: 12 включиrь в проrрамму строки изменения: и


анализа содержимоrо счетчика:

ciec SI
jl inpt

Команда jl (jump if lcss, переход, если меньше) не срабатывает, пока


в Sl положительнос число или О. Однако как только после 5 проходов
160 СтатьяЗВ

(т.е. ввода S захониых дсстичных цифр) число в Sl станет меньше О,


команда jl будет после ввода mобого символа персдаваrь управJiение ка­
зад ка метку inpt, блокируя тем самым вывод символов на экрак и их
преобразовакие в числа. В этой сиrуации проtраМма будет 0Ю1Д8'1'Ь иa­
JUntЯ клавшпи <Enter>,
чтобы персйm на СiрОКИ эавершеКИJI.
Создав и отладив проtраМму в последкем варианте, вы 11011}"11Пе
весьма полезный специализированный калысушrгор: он персводиr вво­
димые с клавиаrуры десятичные числа в ШСС1118ДЦIПСрИЧКЫе.

Статья 36
Знаковые и бе:риаковые числа и операции

Выше уже отмечалось, что в машинное слово или pcrиC'lp можно


записiПЬ 64К разных чисел в днапазоке от OOOOh до FFFFh, или от
00000 до 6SS3S. Эrо справедливо в том случае, если мы все возможные
числа рассматриваем, как положительные (бсззнаковые). Если, однако,
мы ХО'IИМ в какой-то программе работать как с положительными, так и
с оорицатсльными числами, т.е. с числами со знаком, нам придеrоя

часть чисел из их полного диапазона (наиболее сстсствскко - половику)


счиnm. оорицатслькым:и. В вычислитслькой техкике npКIUПO оорJЩа­
тслъкыми счиnm. все числа, у которых установлек старший бит, т.с.
числа в диапазоне 8000h-FFFFh. Положительными же сЧИ1'810'rоя числа
со сброшенным старшим битом, т.с. числа в диапазоне OOOOh-7FFFh.
При этом оорищrrелькыс числа записЬfВIUО'rоя в доп011111mтЪном коде,
который образу~ из прямого nутем замсны всех кулей сдикицами и
наоборот (обре:mый код) и прибавлския к получеккому числу единицы
(рис. 36.1).

JСод -спа 5,
llp.IINOA ~ ••• -спо +51 0000 0000 0000 0101
оера~вмй JСод . .спа 61 1111 1111 1111 1010
+1
Дoa~em.IDIA JСод . .спа 5, ~ ••• . .спо -51 1111 1111 1111 1011
l'tle. 36.1. {)(Jptuнa1111• отричатаuюго 1111см.

Спсдуст подчсрJСНУ'l'Ь, что знак числа условен. Одно и то же число


PfFВh, изобрасиное в нИJСНей строке рис. 36.1, можно в одном кон-
Знаковые и беззнаковые числа и операции 161

~КС'М paoobllnpивa'IЪ, как ПОJIОЖИ'IUЬНое (+65531), а В .цруrом- как ar-


piЩIПCIIЬHoe (-5). Таким: образом, знак числа ЯВЛЯт"СЯ хараперистикой
не самоrо числа, а способа ero обработки.
На рис. 36.2 представлена выборочная таблица 16-биrовых чисел с
указанием их знаковых и беззнаковых значений.

16-ричхое Дес~жичиоо преDстаапоние:


DpODCT&IIJI. бoSSII&ICOIIOO SII&ICOIIOO

ооооь 00000 +00000 Нуп.


0001Ь. 00001 +00001 }Минима.пъ11ое по.по:китеп.кое -с.по·
0002Ь 00002 +00002
ОООЗh. 00003 +00003
ДИапаsок по.по:китеп.JDDС -се.и
71'1'Dh 32765 +32765
71'!'1Ь 32766 +32766
71'1'1!'h 32767 +32767 МАксимапъвое по.по:китеп.11ое -с.по
аоооь 32768 -32768 }МАксимапъкое ооrрицатеп.кое -с.по
800lb 32769 -32767
8002Ь 32770 -32766
ДИапаsок ооrрицатеп.JDDС -се.и
I'I'I'Ch 65532 -00004
I'!'I'Dh. 65533 -00003
rrnь 65534 -00002
l'!'!'l!'h 65535 -00001 МИкима.пъкое отрицатеп.кое -c.no
Рис. З6.2. Предстоt1Аение энокоsш и беззнаковш 'IUCU г 16-раэрядНОII компьютере.

Процсссор может вьmолнять операции не только над словами, но и


над байrам:и. Как и в случ:ас целых слов, число в байте можно раоомаr­
рива'IЪ, как бсззнаковос, и тогда оно может принима'IЪ значения ar 000
до 255, или как число со знаком, и тогда диапазон поло~ных
значений уменьшается в два раза (ar 000 до 127), но возникаст возмож­
НОС'IЪ записать столько же отрицательных чисел (ar -001 до -128).
На рис. 36.3 представлена выборочная таблица байтовых (8-
биrовых) чисел с указанием их знаковых и беззнаковых значений.
При операциях с числами следуст ИМС'IЪ в виду явление обо­
рачивания, каrорос можно кр!ПКО выразиrь такими соаmошениями:

FFFFh+OOOlh~OOOOh
OOOOh-OOOlh•FFFFh
Ес.ли последоваmп.но увсJIИЧива'IЪ содержимое рсrие1ра (кроме ссг­
меН'111оrо) или ячейки памJ1'11{, то, достигнув всрхнеrо возможною пре­
дела FFFFh, число "псрсвалит" через му границу, станет равным нулю и
продолжит нapacmm. в об.ласm малых поло:житсльных чисел ( 1, 2, 3 и
т.д.). Точно также, сели последовательно ум:сньшап. некаrорос поло:ии­
тсльное число, оно достигнув нyJUI, перейдет в обласrь отрицаrrсльных
(или, что то же самое, больших бсззнаковых) чисел, проходR значеКЮI
2, 1, О, FFFFh., FFFEhи т.д.
162 Статьязв

16-ри.иое Дес~~ое цредстаапение:


цредстаап. беssиако•ое sиаковое

.OOh 000 +000


Olh 001 +001 Ми:иимапьиое nопохитепьиое чиспо
02h 002 +002
ОЭh 003 +003
04h 004 +004
05h 005 +005 ДиАПа:!!ОИ ПОJIОХИТеJJЬИЫХ ЧИСеJJ

7Dp 125 +125


7Jft 126 +126
7Fh 127 +127 nолохитепьиое чиспо

80h 128 -128 отрицательное чиспо

81h 129 -127


82h 130 -126
8Зh 131 -125
Диаnа5он отрицательных чисеп
FВh 251 -005
FCh 252 -004
FDh 253 -ооз
FEh 254 -002
FJ!"h 255 -001 Мииимапьиое отрицатепьиое чиспо

Рис. Зб.З. Представление знакоеых и беззнаковых байтовых чисел.

Оrоюда, между прочим, следует, что если nри последовательном на­


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

Среди команд nроцессора, выполняющих ту или иную обработку


чисел, можно въщелить команды, индифферентные к знаку числа
(например, inc, dec, test), команды, предназначенные для обра&mси
беззнаковых чисел (mul, div, ja, jb и дР.), а также команды, специально
рассчитанные на обработку чисел со знаком (iщul, idiv, jg, jl и т.д.).
РассмО"q)ИМ в качестве nримера команды умножения. Их две: mul
multiplication, умножение) для умножения беззнаковых чисел и iщul
(integer multiplication, целочисленное умножение) для работы со знако­
выми числами. Результаты их выполнения nри одних и тех же операн­
даХ MOIYJ' радикально различаться.
Обе команды MOIYJ' работать ках со словами, так и с байтами. Они
ВЫПОJПUПОТ умножение числа. находящеrося в регистре АХ (в случае
умножения на слово) или AL (в случае умножения на байт), на операнд,
который может нахоДIОЪСЯ в каком-либо рсrистрс или в ячейке памяти.
Не допускается умножение на непосрсдствсниос значение, а таюке на
содсрJСИWос cerмemвoro рсrиС1)>8.
Знакоеые и беззнаковые числа и операции 163

Размер произведения, т.е. число байтов в нем, всегда в два раза


больше размера сомножителей. Для однобайтовых оnераций nолученное
произведение заnисывается в регистр АХ. Для двухбайтовых оnераций
результат умножения, который имеет размер 32 биr, заnисывается в
регистры DX:AX (в DX - старшая nоловина, в АХ - WI8ДIIIaя).
Рассмотрим несколько конкретных примеров действия команд зна­
кового и беззнакового умножения.

IIIOV .АL,З ;Пераый сомиожитепь•ООЗ


IIIOV BL,2 ;Второй сомиохитепь•ОО2
IIIUl BL ;АХ•ОООбh•ООООб
IIIOV .АL,З ;Пераый сомиожитепь•ООЗ
IIIOV BL,2 ;Второй сомиожитепь•ОО2
iiDul BL ;АХ•ОООбh•+ООООб

Обе команды, mul и imul, дают в данном случае одинаковый резуль­


тат, nоскольку знаковые nоложительные числа совnадают с беззнаковы­
ми. Обратите внимание на то, что результат умножения, будучи в дан­
ном случае небольшим, занимает тем не менее весь регис1р АХ, затирая
его старший байт.

IIIOV AL, O!'Fh 1Пераый СОNИОZИТепь•255


IIIOV BL, 2 ;Второй соwноzитепь•ОО2
IIIUl BL ;AX•01FEh•00510
:raov AL, O!'Fh ;Пераый соыиоzитепь•-001
:raov BL, 2 ;Второй соwноzитепь•ОО2
iшul BL ;AX•J!'F!'Zh•-00002
Здесь действие команд mul и imul над одними и теми же оnеранда­
ми дают разные результаты. в nервом nримере беззнаковое число FFh,
которое интерпретируется, JW( десятичное 255, умно.жается на 2, давая в
результате беззнаковое 00510, или OlFEh. Во втором nримере то же
число FFh рассматривается, как знаковое. В этом случае оно составляет
-001. Умножение на 2 дает -002, wm FFFEh.
Разная интерnретацiОI одного и того же числа FFh обусловлена ис­
nОJIЬЗОваиием в nервом случае команды для обработки беззнаковых
чисел, а во вrором - знаковых.
Аналогичная сmуация возникас:т и nри умножении целых слов:

IIIOV AX,OI'I'I'I'h ;nерамА соWноzитепь•б5535


IIOV 8L,2 ;Второй сомиоzитепь•О0002
111.11 BL ;DXcAX•0001h:!'l'rah•0000131070
IIIOV AL,OI'I'I'I'h ;ПерамА со.wкоzит.пь--00001
JaQV 8L,2 ;~ороА сомиоzитепь-оооо2
iDIUl 8L ;DX:AX•I'I'I'rhci'I'I'Zh--0000000002
В nервом nримере беззнаковое число FFFFh (дссяrичное 6SS3S)
умножается на 2, давая в результате беззнаковое 0000131070, или
OOOlFFFEh. Эrо 32-биrовое число размещается в двух регистрах. Стар­
шая nмовина числа (OOOlh) записЫМС'n:я в регистр DX, затирая f'ro
164 Статьязв

предыдущее содержимое, младшая половm~а (FFFEh) в реrие1р АХ. Во


вrором примере ro же число FFFFh рассматривается, как знаковое. В
"ЭТОМ случае оно составляет -00001. Умножение на 2 дает -0000000002,
или FFFFFFFEh. По-прежнему старшая половШiа этого числа (FFFFh)
записы:ваеоrея в DX, младшая половm~а (FFFEh) - в АХ.
Другая важная группа команд, в которой различаются команды об­
работки знаковых и беззнаковых чисел - это команды условных перехо­
дов. Эrи команды позволяют осуществлять переходы на различные мет­
ки программы в зависимости от результата выполнения предыдущей
команды или, в некоторых случаях, одной из предшествующих команд.
Команды условных переходов часrо используют после команд сравне­
ния (cmp), Шiкремекrа (inc), декремекrа (dec), сложения (add),
вычиrания (sub), проверки (test) и ряда дРугих.
Приведем перечень команд условных переходов, чувствкrельных к
"знаковости" числа.
Знаковые команды
jg (jump if greater, переход, если больше)
jge (jump if greater or equal, переход, если больше или равно)
jl (jump if less, переход, если меньше)
jle (jump if less or equal, переход, если меньше или равно)
jng (jump if not greater, переход, если не больше)
jnge (jump if переход, если не больше и не равно)
jnl (jump if переход, если не меньше)
j.~Ic (jtJmp if переход, если не меньше и не равно)
Беззнаковые команды
ja (jump if аЬоvе, переход, если выше)
jae (jump if аЬоvе or equal, переход, если выше или равно)
jb (jump ifbelow, переход, если ниже)
jЬе (jump ifbelow or equal, переход, если ниже или равно)
jna (jump if not аЬоvе переход, если не.: выше
jnae (jump if not аЬоvе or equal, переход, если не выше и не равно
jnb (jump if not below, переход, если не ниже
jnbe (jump if not below or equal, переход, если не ниже и не равно
Примеры команд, нечувс:твитеJIЫiых к энаку 'IJICD
je (jump if equal, переход, если равно)
jne (jump if not equal, переход, если не равно)
jc (jump if сапу, переход, если флаг CF установлен)
jcxz (jump ifCX=O, переход, если СХ=О)
Разница между знаковыми и беззнаковыми командами условных
переходов заключается в rом, что знаковые команды рассматриваюmо-
нятия "больше-меньше" применкrельно к числовой оси -32К... О ... +32К,
а беззнаковые команды - применкrельно к числовой оси 0 ... 64К.
Обработка двоично-десятичных чисел 165

Поэтому ДЛJ1 команд.знаковых переходов число 7FFFh (+32767} больше


числа 8000h (-32768), а для команд беззнаковых 7FFFh (32767) меньше,
чем 8000h (32768). Аналогично для знаковых команд О больше, чем
FFFFh (-1), а для беззнаковых - меньше.
Из приведеиного перечия видно, что при сравнении знаковых чисел
используюrея 'Iq>МИНЫ "больше" и "меньше", а при сравнении беззнако­
вых - "ВЫПiе" и "ниже".
Все сказаннос справедливо и а том случае, коrда команды условных
персходов используюrея для анализа содержимого байтовых операндов.
Так, для знаковых команд 7Fh {+127) больше, чем 80h (-128), а О боль­
ше, чем FFh (-1), а для беззнаковых команд- наоборот.
Рассмоорим несколько пmичных примеров использования команд
условных переходов.

CJII) JUC,liDiit ;Сравнение ~ и coдepzиworo ~чейхи liDiit


jb belov ;Переход иа wетку belov, еспи АХ wеиьше
;coдepzиworo ~чейкк liDiit в беssкаковоА
; IIIКAЛe 'IИС е./1

Clllp АХ,liDiit ;Сравнение АХ и coдepZИWDrO ~чейхн limit


jl leaa ;Переход иа метку less, еспи АХ меньше
;coдepzиworo •чейки limit 8 sиАКо8оЙ
;IIIКaлe чисел

Clllp AL, '9' ;Сравнение кода ASCII 8 AL с '9'


ja not n\.UD ;Переход, еспи ие цифра
dec SI - ;Де~емеит счетчика в SI
jl leaa_O ;Переход иа метку leas О, еспи
;содерzиwое SI, уwеиьша•сь, nepeшno
;череs О и c;ano отрицате.nькыw
&dd JUC,ВX ; сnоzеиие АХ и ВХ
je nul ;Переход иа nul, еспи cywwa•O
jqe poaitiv ;Переход иа poaitiv, еспи cywwa >•0

Статья 37
Обработка двоично-десят•IЧных чисел

В ряде прик.ладных областей для прсдстазления чисе.л используется


специальный формаr, называемый двоично-десятичным (Ьinary-coded
decimal, BCD). В таком формате выдают данные некоторые измеритель­
ные приборы; он же используется КМОП-микросхемой компьютеров
IBM РС/АТ д1DI хранения инфорl.(ации о текущем времени. В микро­
процессорах 80х86 предусмоорен ряд команд мя обработхи тах:их чисел.
188 Статья37

Двоично-десятичный формат существует в двух разновидностях:


упакованный и распакованный. В первом случае в байте запис~я
дву,сразрядное десятичное число от 00 до 99. Каждая цифра числа зани­
мает половину байта и храниrся в двоичной форме. Из рис. 37.1 можно
заметить, что для записи в байт десятичного числа в двоично­
десятичном формате достаточно сопроводить записываемое десятичное
число символом h.
1001 0111 Даоичное содерж:ниое байта
"-y-J ~
9 7 Десятичное обозначение числ~
9 7h 1 6--ричное обо!lначеиие числ~
Рис. З7.1. YhaiWIIaNНый д11оично-деСRmичный формат.

В машинном слове или в 16-разрядном реги-стре можно хранить в


двоично-десятичном фор-мате четырехразрядные десятичные числа от
0000 до 9999 (рис.37.2).

000110011001 0010 Двоичное содержимое слоаа


'-у-' ~ '-у-' ~
1 9 9 г Десятичное обо!lиачеиие числа
1 9 9 2h 16-ричиое обоэиачеиие числа

Рис. З7.2. Запись д1СJ1111ичного числа 1992 11 сло11е.

Распакованный формат отличается от упакованного тем, что в каж­


дом байте записывается лишь одна десятичная цифра (по-прежнему в
двоичной форме). В эrом случае в слове можно записать десятичные
числа от 00 до 99 (см. рис. 37.3)

0000 0001 0000 1000 Двоичное содержикоеслова

1 8 Десятичное обо!lначеиие числll


~-.-~.......-
0 1 О Bh 16-ричкое обо!lкачекие '+IСЛо

hc. З7.З. з.nись дiCJUtlu'IНOZO чш:ла 18 • pacnaiWtiiiННOМ 11иiИ.

При хранеНЮI дССSП'И'IНЫХ чисел в аппаратуре обычно используется


бмее эконоюшй )'ПаХОванный формат; умножение и деление выпoл­
lfiiJO'J'CII 'IОЛЬКО с распакованными числами. операции же сложения и
вычитания применииы и к тем, и к .в;руrим.
Раработаем nроцедуры для ВЬПIОJDiения арифметичесJСИХ операций
с информацией о текущем времени. попучаемой из часов реального
времени (КМОП-мИJфОСхема) компь~ В дальнейшем с помощью
:ma nроцедур будет ПOC'IpOCita nроrрамма буДЮIЬника.
Обработка двоично-десятичных чисел 167

В КМОП-микросхеме время хранится в уnакованном десятичном


форма-rе по две десяТичных цифры в одном бай-rе. Таким образом, ДЛJ1
заnиси часов, минуг и секунд требуется три байта. Байты секунд и ми­
нуr могут содержа1Ъ числа от 00 до 59; байт часов - от 00 до 23. Осо­
бенность а}'ифметических операций с временем заключается в том, что
признак переноса в следующий разряд времени (т.е. из разряда секунд в
разряд минуr или из разряда минуr в разряд часов) должен возникать
при иревышении значения 59. Описанная ниже подпрограмма add_unit
позволяет складывать секунды, минуrы или часы в упакованноw
двоично-десятичном формт-е ~ формировать признак переноса, если
результат сложения превышает 59. В этом примере, помимо двоично­
десятичной арифмеnnси, демонстрируются распространенные приемы
передачи в подпрограмму параметров через с-rек и получения однобиrо­
воrо параметра через флаr переноса CF.
Пример 37.1. Подпроzраммо CJIOЖtHUJI одного разряда времени
add unit proc
; Прн :вы:sо:ве: АL•:вре~ :в BCD 1секунды, wииуты ипи часы) • Мпатаий
;байт :верхиеrо спо:ва стека•прибааляеыая :величииа (секуидн, wииутм
;ипи часы). При :воs:врате: АL-реsультат спо~еиия :в BCD, АН paspY8eH
pu.sh ВР ; (1)Сохраниы испольsуеwые
pu.sh ВХ ; (2)реrистры
mov АН, 0 ; ( 3) По.zrrото:вик АН
mov ВР, SP ; (4)Настроиы баsовый реrистр
mov ВХ, [ВР+б] ; (5)Получим nараметр
add AL, BL ; 1б) Спо:а:иы cnaraewыe
daa ; (7)kAK BCD
jnc les.s100 ; (8)С~ меньше 100
mov АН, 1 ; (9)С)')ОСА больше 100, s&ШIIIIeм Olh :в lU!
lesa100: с1:11р .АХ, бОh ; (10)Надо ли корректировать спед)'11111КЙ
;раsряд :вреwеии?
jb done ; (11)Нет, cywwa < 60
аuЬ .АХ, бОh ; (12)Да, cy.uua > 60, :вычтем 60
daa ; (13)как BCD
atc ; С14)Устаиовиы CF, как приsнак
jl:llp done1 ; (15)переиоса и иа внход
done: clc ; 11б)Сбросиы CF (переиоса кет)
done1: рор ВР ; 117)Восстаноикwиспольsуеwые
рор вх ; (18)ре1'истры
ret 2 ; (19)Скорректируем укаsатепь стека
add_unit endp

Всякая подпрограмl.rа общего назначения дОЛJСНа иметь четко опрс·


деленный ин-rерфейс, т.е. правила персдачи в нес парамС1JЮD и по­
лучения резуль'l'm'а. Подпрограмма не дОЛJСНа разрушап. содержимое
!31СИХ-лнбо регистров или ячеек П8МЯ'111, сели хс такое происходит, '00
это таюке дОJDКНо быть оговорено.
Подпрограмма add_unit oфopl\IJieнa в mще щюцедуры и не содержит
(и не использует) каких-либо пмей данных. ПредпQJW'IСТСЯ, что
188