- •1. Основы программирования для dos 9
- •1.1.7. Средства bios 21
- •2. Приемы системного программирования 57
- •Введение
- •1.Основы программирования для dos
- •1.1. Структура и выполнение программ в dos
- •Программа типа сом
- •Программа типа ехе
- •1.2.Использование служебных функций dos и bios
- •1.3.Вывод на экран в текстовом режиме
- •Средства dos
- •Средства bios
- •Выбор видеорежима
- •Управление положением курсора
- •Вывод символов на экран
- •Прямая работа с видеопамятью
- •1.4.Ввод с клавиатуры
- •Средства dos
- •Средства bios
- •1.5.Графические видеорежимы
- •Работа со стандартными графическими режимами
- •Работа с svga-режимами
- •(Продолжение таблицы 4)
- •(Окончание таблицы 4)
- •1.6.Работа с мышью
- •1.7.Другие устройства
- •Системный таймер
- •Последовательный порт
- •Параллельный порт
- •1.8.Работа с файлами
- •Создание и открытие файлов
- •Чтение из файла и запись в файл
- •Закрытие и удаление файла
- •Поиск файлов
- •Управление файловой системой
- •1.9.Управление памятью
- •Обычная память
- •Область памяти umв
- •Область памяти нма
- •Интерфейс ems
- •Интерфейс xms
- •1.10.Организация процессов
- •Запуск программ на выполнение
- •Переменные окружения
- •Командные параметры
- •2.Приемы системного программирования
- •2.1.Управляющие структуры
- •Структуры if... Then... Else
- •Структуры case
- •Конечные автоматы
- •2.2.Процедуры и функции
- •Передача параметров
- •Передача параметров по значению
- •Передача параметров по ссылке
- •Передача параметров по возвращаемому значению
- •Передача параметров по результату
- •Передача параметров по имени
- •Передача параметров отложенным вычислением
- •Передача параметров в регистрах
- •Передача параметров в глобальных переменных
- •Передача параметров в стеке
- •Передача параметров в потоке кода
- •Передача параметров в блоке параметров
- •Локальные переменные
- •2.3.Обработка прерываний
- •Обработчики прерываний
- •Прерывания от внешних устройств
- •Взаимодействие прикладных и системных обработчиков прерываний
- •2.4.Резидентные программы
- •Системные средства организации резидентных программ
- •Взаимодействие с резидентной программой
- •2.5.Драйверы устройств в dos
- •Литература
Передача параметров в потоке кода
В этом необычном методе передаваемые процедуре данные размещаются прямо в коде программы, сразу после команды CALL:
call print
db “This ASCIZ-line will be printer”
(следующая команда)
Чтобы прочитать параметр, процедура должна использовать его адрес, который автоматически передается в стеке как адрес возврата из процедуры. При этом функция перед выполнением команды RET должна будет изменить адрес возврата на первый байт после конца передаваемых параметров (с тем, чтобы было возможно продолжение работы программы после возврата из процедуры). Например, процедуру print можно реализовать следующим образом:
print proc near
push bp
mov bp, sp
push ax
push si
mov si, [bp+2] ; прочитать адрес возврата/начала данных
cld ; установить флаг направления для команды lodsb
print_readchar:
lodsb ; прочитать байт из строки,
test al, al ; если это 0 (конец строки),
jz print_done ; вывод строки закончен
int 29h ; вывести символ в AL на экран
jmp short print_readchar
print_done:
mov [bp+2], si ; поместить новый адрес возврата в стек
pop si
pop ax
pop bp
ret
print endp
Передача параметров в потоке кода, так же как и передача параметров в стеке в обратном порядке (справа налево), позволяет передавать различное число параметров, но этот метод — единственный, позволяющий передать по значению параметр различной длины, что и продемонстрировал этот пример. Доступ к параметрам, переданным в потоке кода, несколько медленнее, чем к параметрам, переданным в регистрах, глобальных переменных или стеке, и примерно совпадает со следующим методом.
Передача параметров в блоке параметров
Блок параметров — это участок памяти, содержащий параметры, так же как и в предыдущем примере, но располагающийся обычно в сегменте данных. Процедура получает адрес начала этого блока при помощи любого метода передачи параметров (в регистре, в переменной, в стеке, в коде или даже в другом блоке параметров). В качестве примеров использования этого метода можно назвать многие функции DOS и BIOS, например поиск файла, использующий блок параметров DTA, или загрузка (и исполнение) программы, использующая блок параметров ЕРВ.
Локальные переменные
Часто процедурам требуются локальные переменные, которые не будут нужны после того, как процедура закончится. По аналогии с методами передачи параметров можно говорить о локальных переменных в регистрах — каждый регистр, который сохраняют при входе в процедуру и восстанавливают при выходе, фактически играет роль локальной переменной. Единственный недостаток регистров в роли локальных переменных — их слишком мало. Следующий вариант — хранение локальных данных в переменной в сегменте данных — удобен и быстр для большинства несложных ассемблерных программ, но процедуру, использующую этот метод, нельзя вызывать рекурсивно: такая переменная на самом деле является глобальной и находится в одном и том же месте в памяти для каждого вызова процедуры. Третий и наиболее распространенный способ хранения локальных переменных в процедуре — стек. Принято располагать локальные переменные в стеке сразу после сохраненного значения регистра ВР, так что на них можно ссылаться изнутри процедуры, как [ВР-2], [ВР-4], [ВР-6] и т.д.:
foobar proc near
foobar_x equ [bp+8] ; параметры
foobar_y equ [bp+6]
foobar_z equ [bp+4]
foobar_l equ [bp-2] ; локальные переменные
foobar_m equ [bp-4]
foobar_nl equ [bp-6]
push bp ; сохранить предыдущий ВР
mov bp, sp ; установить ВР для этой процедуры
sub sp, 6 ; зарезервировать 6 байт для
; локальных переменных
(тело процедуры)
mov sp,bp ; восстановить SP, выбросив
; из стека все локальные переменные
pop bp ; восстановить ВР вызвавшей процедуры
ret 6 ; вернуться, удалив параметры из стека
foobar endp
Внутри процедуры foobar стек будет заполнен следующим образом (см. рис. 5).
Последовательности команд, используемые в начале и в конце таких процедур, оказались настолько часто применяемыми, что в процессоре 80186 были введены специальные команды ENTER и LEAVE, выполняющие эти же самые действия:
foobar proc near
foobar_x equ [bp+8] ; параметры
foobar_y equ [bр+6]
foobar_z equ [bp+4]
foobar_l equ [bp-2] ; локальные переменные
foobar_m equ [bp-4]
foobar_n equ [bp-6]
enter 6, 0 ; push bp
; mov bp, sp
; sub sp, 6
(тело процедуры)
leave ; mov sp, bp
; pop bp
ret 6 ; вернуться, удалив параметры из стека
foobar endp
-
Х
Y
Z
IP
BP
BP
L
М
N
SP
Рис. 5. Стек при вызове процедуры foobar
Область в стеке, отводимая для локальных переменных вместе с активационной записью, называется стековым кадром.