Файл: О.А.Калашников. Ассемблер Это Просто. Учимся программировать.pdf
Добавлен: 16.02.2019
Просмотров: 29244
Скачиваний: 1689
Глава 21. Работа с блоками основной памяти
219
21.2. Работа с основной памятью DOS
21.2.1. Управление памятью
В этом разделе рассмотрим принципы и методы работы с основной памятью
в режиме эмуляции MS-DOS. Основная память имеет объем до 640 Кбайт. Подроб-
но рассмотреть управление памятью в одной главе невозможно. Мы затронем лишь
ключевые, основополагающие моменты.
Как только программа загрузилась, DOS автоматически отводит для нее всю
свободную основную память. Программист может по своему усмотрению урезать
блоки памяти, отводить другие, а также освобождать отведенные участки (блоки)
памяти.
Зачем это нужно и где это можно применять? Представьте ситуацию: мы напи-
сали некоторую программу, которая, в свою очередь, должна загружать другую. Но
так как вся память изначально выделена только нашей программе, то мы не смо-
жем загрузить ничего более. Ведь загружаемой программе (порождаемому процес-
су) также необходимо некоторое количество памяти не только для работы, но и для
загрузки.
Для того чтобы урезать память, используется функция
4Ah
прерывания
21h
(табл. 21.2).
Таблица 21.2. Функция
4Ah
прерывания
21h
:
изменить объем свободной основной памяти
Вход
Выход
ah = 4Ah
es
= сегмент распределенного блока
bx
= размер блока в 16-байтовых параграфах
jc
— ошибка, при этом:
ax
= код ошибки
Распределенный блок в нашем случае — вся память, отведенная программе, на-
чиная с нулевого смещения сегмента
cs
и заканчивая последним свободным бай-
том. Поэтому перед вызовом функции
4Ah
следует убедиться в том, что
es
указыва-
ет на сегмент, куда мы загрузились. В табл. 21.3 показано состояние памяти после
загрузки программы в память для ее последующего выполнения.
Таблица 21.3. Состояние памяти после загрузки программы
Данные
Описание
Системные файлы
Память занята от 0 до текущего байта
Резидентные программы
Память занята от 0 до текущего байта
Наша программа
Память занята от 0 до текущего байта
Метка Finish
Память занята от 0 до текущего байта
Отведенная память нашей программе
Память занята от 0 до конца
Часть III. Файловая оболочка, вирус, резидент
220
После того как наша программа загрузилась в память, вся основная свободная
память отведена только нашей программе.
Задача: урезать занятую программой память до метки
Finish
. Для чего это нуж-
но — рассмотрим позже. Обратите внимание, каким образом мы ужимаем сущест-
вующий блок памяти (
Prepare_memory
, main.asm) (листинг 21.10).
Листинг 21.10. Освобождение отведенной памяти
...
mov bx,offset Finish ;bx=последний байт нашей программы
;Так как bx должен содержать не количество байтов, а количество блоков
;по 16 байт, то мы должны сдвинуть биты вправо на 4
shr bx,4
inc bx ;Увеличим bx на один (на всякий случай)
mov ah,4Ah ;Функция уменьшения/увеличения существующего блока памяти
;В данном случае урезаем, т. к. наша программа, естественно, меньше
;отведенного блока памяти после загрузки.
int 21h
...
После выполнения функции
4Ah
состояние основной памяти будет следующим
(табл. 21.4).
Таблица 21.4. Состояние памяти после освобождения блока
Данные
Описание
Системные файлы
Память занята от 0 до текущего байта
Резидентные программы
Память занята от 0 до текущего байта
Наша программа
Память занята от 0 до текущего байта
Метка Finish
Память занята от 0 до текущего байта
Память за меткой Finish
Память свободна до конца 640 Кбайт, начиная
с первого байта, следующего за меткой Finish
То есть размер свободной памяти равен 640 Кбайт минус смещение метки
Finish
.
После освобождения памяти можно попробовать отвести отдельный блок памя-
ти размером, скажем, 1000h 16-байтовых блоков (параграфов) или 65 536 байт
(листинг 21.11).
Листинг 21.11. Отведение блока памяти размером 65 536 байт
...
mov ah,48h
mov bx,1000h
Глава 21. Работа с блоками основной памяти
221
int 21h
...
mov Seg_files,ax ;Сохраним сегмент отведенного блока
...
В этом примере мы использовали новую функцию. Она описана в табл. 21.5.
Таблица 21.5. Функция
48h
прерывания
21h
: выделить блок основной памяти
Вход
Выход
ah = 48h
bx
= размер блока в 16-байтовых пара-
графах
jc
— ошибка, при этом:
ax
= код ошибки
Иначе: ax = сегмент выделенного блока
Состояние памяти после отведения блока размером 65 536 байт показано в табл. 21.6.
Таблица 21.6. Состояние памяти после отведения блока памяти
Данные
Описание
Системные файлы
Память занята от 0 до текущего байта
Резидентные программы
Память занята от 0 до текущего байта
Наша программа
Память занята от 0 до текущего байта
Метка Finish
Память занята от 0 до текущего байта
Память за меткой Finish + 65 536 байт
Память занята
Память, начиная с адреса Finish +
65 537
байт
Свободна
На рис. 21.3 показан в отладчике участок кода, который отводит память с помо-
щью функции
4Ah
прерывания
21h
.
Рис. 21.3. Урезание и отведение памяти после загрузки программы
Часть III. Файловая оболочка, вирус, резидент
222
21.2.2. Считываем файлы в отведенную память
Для каких целей мы выделяем блок памяти размером 64 Кбайт?
В эту область памяти будет загружаться информация о найденных файлах в те-
кущем каталоге. Таким же образом поступают и все оболочки: просто считывают
файлы в отведенный блок памяти, а затем с ними работают.
Но, например, внутренняя команда
DIR
не загружает в память найденные файлы.
Да и нет смысла. Она нашла файл, тут же вывела информацию о нем на экран
и ищет следующий. Выделять, копировать и удалять файлы эта команда, естест-
венно, не может.
Каким образом заносим в отведенную память найденные файлы? Алгоритм про-
стейший:
1. Ищем первый файл. Если файлов нет, то переходим к шагу 5.
2. Заносим имя файла в отведенный блок памяти. Дописываем после имени файла
ноль.
3. Ищем следующий файл. Если файлов больше нет, переходим к шагу 5.
4. Заносим следующий файл в память сразу же за найденным предыдущим, про-
должаем поиск файлов (шаг 3).
5. Заносим еще один ноль после последнего найденного файла для того, чтобы
дать понять процедурам нашей оболочки, что это был последний найденный
файл.
6. Выводим указанное количество файлов на экран (сколько находится в перемен-
ной
Number_files
) (
Out_files
, files.asm).
Труда разобраться с тонкостями процедур не составит, тем более что в файле-
приложении вполне достаточно комментариев.
Глава 22
Часто задаваемые вопросы
В процессе изучения нового языка программирования, как и любого другого
предмета, всегда возникает множество вопросов. В этой главе мы рассмотрим наи-
более типичные вопросы, которые задают начинающие программисты экспертам
портала http://RFpro.ru.
1. Что такое дизассемблер и для чего он нужен?
Дизассемблер — это программа, которая переводит машинный код на язык
ассемблера. Дизассемблер может применяться при получении исходного кода
для изучения работы программы или корректировки его кода с последующим
ассемблированием.
Если в программе необходимо изменить два-три байта (например, убрать
ограничение на ее работу в более поздних версиях MS-DOS), то можно
воспользоваться и специальным текстовым редактором Hacker's View, который
и может выступать в роли дизассемблера.
2. Перечислите флаги процессора. Где они расположены и за что отвечают?
Флаг переноса
CF
(Carry Flag). Содержит 1, если произошел перенос единицы
при сложении или заем единицы при вычитании. Используется также в цик-
лических операциях и операциях сравнения.
Флаг четности
PF
. Содержит 1, если в результате операции получено число
с четным количеством значащих разрядов, т. е. дополняет результат до
нечетного числа — используется в операциях обмена для контроля данных.
Флаг внешнего переноса
AF
. Контролирует перенос из 3-го бита данных.
Полезен при операциях над упакованными десятичными цифрами.
Флаг нуля
ZF
(Zero Flag). Равен 1, если в результате операции получен 0,
и равен 0 — в противном случае.
Флаг знака
SF
(Sign Flag). Равен 1, если в результате операции получено
отрицательное число (с единицей в старшем разряде, т. е. последний бит
(биты нумеруются справа налево)).
Флаг трассировки
TF
(Trass Flag). Равен 1, если программа выполняется по
шагам, с передачей управления после каждой выполненной команды
прерыванию с вектором 1.