мости с инструкцией BOUND был написан макрос bound, показанный в
листинге 2-14.
Листинг 2-14. Макрос проверки границ массива
-----------------------------------------------------------------
; Сравнение границ массива, содержащихся в общем регистре REG,
; с двумя последовательными значениями, размещенными в памяти
; по адресу MEM32. Это есть сравнение целых со знаком.
bound MACRO reg,mem32
LOCAL out_bound,in_bound
pushf ; сохранение флажков
cmp reg,word ptr mem32 ; проверка нижнего предела
jl out_bound ; превышение индекса
cmp reg,word ptr mem32 + 2 ; проверка верхн. предела
jle in_bound ; индекс хороший
out_bound:
popf ; очистка стека
INT 5 ; принимаемое действие
in_bound:
popf ; восстановление флажков
ENDM
-----------------------------------------------------------------
Макрос bound сравнивает содержимое общего регистра, содержа-
щего индекс массива, с двумя последовательными ячейками памяти.
Первая ячейка памяти содержит нижний предел индекса, а вторая
ячейка - верхний предел индекса. Инструкция BOUND выполняет пре-
рывание 5-го типа (int5), если проверяемый индекс выходит за пре-
делы границы. Пользователи этой версии макроса могут модифициро-
вать макрос bound для выполнения любых своих действий.
Защита целостности данных
Другой областью, восприимчивой к разрушению, является стек. В
связи с тем, что стек смешивает коды и данные, ошибка в стеке
непременно явится результатом ошибки в программе при попытке про-
цессора использовать данные как ссылку на инструкцию.
Два наиболее общих случая разрушения стека вызывают проблемы
ошибочного выравнивания. Первый случай - из-за несоответствия
операций PUSH и POP, а второй - благодаря попытке извлечь данные
- 2-45 -
с помощью инструкции POP, которые были помещены по другую сторону
инструкций CALL или RET. Эти проблемы можно избежать только путем
удаления особого внимания "спариванию" инструкций PUSH и POP, ис-
пользуемых в программе, и обеспечения гарантии в том, что такие
пары не выполняют ссылки за границы подпрограммы.
В случае передачи параметров возникает вопрос, а как подпрог-
рамма выполняет очистку стека? Обычно, правило для такого случая
состоит в том, что программа, передавшая в стек данные по инс-
трукции PUSH, получает данные из стека по инструкции POP. Если
следовать этому правилу, то путем чтения листинга одной, а не
двух подпрограмм программист может проверить, что стек выровнен.
Однако, жесткое следование этому правилу предотвращает использо-
вание для очистки стека инструкций микропроцессора 8086 RET N.
Если интерфейс между двумя программами полностью отлажен и наде-
жен, то приемлемый риск состоит в использовании инструкции RET N.
Всякий раз, когда программа должна быть закодирована для при-
ема переменного количества параметров, не следует использовать
инструкцию RET N. Имеются различные пути ограничения глобальной
возможности очистки стека только для установленного количества
переменных, но все, вызываемые ими трюковые манипуляции со сте-
ком, являются затруднительными для понимания и более трудными в
отладке. Если подпрограмма должна принимать переменное количество
параметров, то очищать эти параметры из стека должна вызывающая
подпрограмма. Кроме того, вызывающая подпрограмма должна ясно
указывать вызываемой программе количество передаваемых для нее
параметров.
Все операции, выполняемые над стеком, за исключением операций
PUSH и POP, должны происходить под флагом указателя стека и для
доступа к стеку использовать регистр BP. Это значит, что указа-
тель стека должен быть установлен в значение ниже манипулируемого
элемента. Если манипулируемые данные остаются неизменными, то
возникает прерывание. По этой же причине нельзя непосредственно
манипулировать указателем стека до тех пор, пока не произойдет
переключение стека, или открытие памяти стека. Если произойдет
прерывание в то время, когда указатель стека не указывает истин-
ную вершину стека, то данные в стеке могут быть потеряны. Все
сказанное выше не является предостережением для умелого использо-
вания манипуляции стеком.
Заключение
В зтой главе было рассмотрено множество тем: от теоретической
природы структурного программирования до подробного изложения
макроассемблера MASM, MS-DOS и функционирования семейства микроп-
роцессоров 8086. Была предпринята попытка получить некоторые аль-
тернативные подходы в структурном программировании для нужд поль-
зователя ПЭВМ. Хотя маловероятно, что все или даже большинство
этих технических приемов появится в Ваших небольших программах на
языке Ассемблер, мы будем благодарны за то, что многие из них
найдут применение в Ваших обширных проектах. И, если вспомнится
только один момент, то все равно: сначала все обдумайте, а коди-
руйте только после обдумывания.
Большинство более практических указаний о MASM и MS-DOS вновь
"всплывут на поверхность" при обсуждении других вопросов в после-
дующих главах данного руководства. Попытайтесь вывести примеры,
приведенные в этой главе, и Вы получите удовольствие от их ис-
пользования. Из приведенного выше Вам понадобится многое. Боль-
- 2-46 -
шая часть отдельных вводных сведений по управлению памятью
MS-DOS, приведенных в этой главе, послужит фундаментом для гла-
вы 3 "Управление программами и памятью".
Глава 3. УПРАВЛЕНИЕ ПРОГРАММАМИ И ПАМЯТЬЮ
Память MS-DOS
Процессы MS-DOS
Резидентные программы
Функция 4Bh - загрузка и выполнение программ
Переключение контекста и переключение стека
Введение в резидентную часть оперативной памяти
REMOVE - пример интегрированной программы
Заключение
В предыдущей главе были изучены средства создания программ
MS-DOS и различные пути их структурирования. Теперь рассмотрим
как программы MS-DOS существуют в среде MS-DOS. При этом мы для
более полного пояснения некоторых тем, ссылающихся на предыдущие
главы, неоднократно будем возвращаться назад: префикс программно-
го сегмента, работа по распределению памяти MS-DOS, и механизм,
используемый для загрузки программ MS-DOS. В заключение мы введем
механизм для установки программ, остающихся резидентными - тема,
развиваемая в главе 4 и обсуждающая завершение и оставление в па-
мяти резидентных программ (TSR - terminate and stay resident
programs).
Память MS-DOS
Самый простой способ понимания среды функционирования MS-DOS
состоит в рассмотрении формата памяти MS-DOS, моделей распределе-
ния своей ограниченной памяти для всех выполняемых ею и конкури-
рующих между собой целей. Несмотря на отсутствие общих предписа-
ний MS-DOS по отдельным форматам памяти, огромная популярность
стандартов фирмы "ИБМ" и их последовательное принятие обеспечива-
ют нас форматом памяти де-факто.
Формат физической памяти MS-DOS
MS-DOS была разработана для устройств центрального процессора
(CPU) 8086/8088, позволяющих адресовать суммарную память объемом
1 Мбайт. Типичное использование и размещение этой памяти показано
на Рис.3-1. Первые 10 сегментов ("кусков" по 64 кбайт) этой памя-
ти относятся к области пользователя. Это область, объемом в 640
Кбайт, в которой расположены сама MS-DOS и прикладные программы
пользователя. Оставшиеся 6 сегментов, составляющие в сумме
384 Кбайт, называются системной областью и резервируются для ис-
пользования ROM-BIOS (Постоянное запоминающее устройство (ПЗУ)-
базовая система ввода-вывода) и для связи с другими платами в
системе. Заметим, что Рис.3-1 значительно упрощает использование
системной области. В действительности, имеется много типов плат,
которые используют эту область для многих целей, однако, будем
рассматривать только общую схему.
Расширяемая и расширенная память
С появлением MS-DOS были разработаны более мощные центральные
процессоры. Центральные процессоры 80286 и 80386, каждый из кото-
рых имеет расширяемые пределы адресуемой памяти,позволяют в одной
системе размещать мегабайты памяти. Какая польза от того, что MS-
DOS получит сколько-нибудь байтов из этой дополнительной памяти?
- 3-2 -
Адрес Использование памяти
FFFFF .------------------------------------------
| Системное ПЗУ | ^ ^
F0000 |-------------------------| | |
| Используется системой | | |
E0000 |-------------------------| 384 кбайт |
| Используется системой |ПЗУ или др. |
D0000 |-------------------------| | |
| Видеопамять (Video RAM) | | |
C0000 |-------------------------| | |
| Графика EGA | V |
A0000 |-------------------------|------- |
| Пользователь | ^ |
90000 |-------------------------| | |
| Пользователь | | |
80000 |-------------------------| | 1 мбайт
| Пользователь | | |
|-------------------------| | |
| Пользователь | | |
60000 |-------------------------| 640 кбайт |
| Пользователь | Область |
50000 |-------------------------|пользователя |
| Пользователь | | |
40000 |-------------------------| | |
| Пользователь | | |
30000 |-------------------------| | |
| Пользователь | | |
20000 |-------------------------| | |