Dos fn 23h дать размер файла через fcb


Содержание

Dos fn 23h: дать размер файла через fcb

Assembler для начинающих

Прежде, чем перейти к упомянутому примеру, необходимо рассмотреть
формируемую DOS структуру данных — блок управления файлом FCB (File
Control Block), который является существенным элементом файловой
системы и участвует во всех файловых операциях.

Блок управления файлом обеспечивает связь пользовательской
программы с функциями DOS. При любой файловой операции происходит
обращение к блоку FCB. На Фиг.5.5 показан состав стандартного
блока FCB. Имеется модификация блока FCB, называемая расширенным
блоком FCB, которая применяется в специальных случаях, когда нужно
«скрыть» файл. Скрытый файл защищен от записи. Это значит, что
программа не может модифицировать содержимое этого файла, не
изменив предварительно его блока FCB. Скрытый файл не фигурирует в
листинге справочника. Скрыть файл — один из простейших способов
защиты файла от неумелого пользователя. В приводимых примерах
используются только стандартные блоки FCB.

Поля данных блока FCB охватывают все атрибуты файла. Номер
дисковода, имя и тип файла составляют идентификатор файла. Размер
файла и дата яаляются атрибутами файла, которые приводятся в
листинге справочника. Оставшиеся поля — текущий номер блока, длина
записи и номер записи при произвольном доступе — служат для
определения местоположения внутри файла при операциях чтения и
записи. Длина записи указывает на число байтов в определяемой
пользователем записи. Так как все операции чтения и записи в файл
начинаются с границы записи, то длина записи определяет количество
данных, обрабатываемых во время каждой из этих операций.
Существуют два способа определения текущей записи при обращении
к файлу. При первом, последовательном, способе записи
обрабатываются по порядку. При этом текущий номер блока и
относительный номер записи определяют запись, которая будет
обрабатываться следующей. По мере того, как программа выполняет
операции чтения или записи, DOS увеличивает на 1 относительный
номер записи, чтобы он указывал на следующую запись. Выполнение

Функции прерывания DOS INT 21H

Дата добавления: 2015-06-12 ; просмотров: 1606 ; Нарушение авторских прав

Ниже приведены базовые функции для прерывания DOS INT 21H. Код функции устанавливается в регистре AH:

Завершение программы (аналогично INT 20H).

Ввод символа с клавиатуры с эхом на экран.

Вывод символа на экран.

Ввод символа из асинхронного коммуникационного канала.

Вывод символа на асинхронный коммуникационный канал.

Вывод символа на печать (гл.19).

Прямой ввод с клавиатуры и вывод на экран.

Ввод с клавиатуры без эха и без проверки Ctrl/Break.

Ввод с клавиатуры без эха с проверкой Ctrl/Break.

Вывод строки символов на экран.

Ввод с клавиатуры с буферизацией.

Проверка наличия ввода с клавиатуры.

Очистка буфера ввода с клавиатуры и запрос на ввод.

Установка текущего дисковода.

Открытие файла через FCB.

Закрытие файла через FCB.

Начальный поиск файла по шаблону.

Поиск следующего файла по шаблону.

Удаление файла с диска.

Последовательное чтение файла.

Последовательная запись файла.

Внутренняя операция DOS.

Определение текущего дисковода.

Установка области передачи данных (DTA).

Получение таблицы FAT для текущего дисковода.

Получение FAT для любого дисковода.

Чтение с диска с прямым доступом.

Запись на диск с прямым доступом.

Определение размера файла.

Установка номера записи для прямого доступа.

Установка вектора прерывания.

Создание программного сегмента.

Чтение блока записей с прямым доступом.

Запись блока с прямым доступом.

Преобразование имени файла во внутренние параметры.

Получение даты (CX-год,DН-месяц,DL-день).

Получение времени (CH-час,CL-мин,DН-с,DL-1/100с).

Установка/отмена верификации записи на диск.

Получение адреса DTA в регистровой паре ES:BX.

Получение номера версии DOS в регистре АХ.

Завершение программы, после которого она остается резидентной в памяти.

Получение вектора прерывания (адреса подпрограммы).

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

Получение государственно зависимых форматов.

Создание подкаталога (команда MKDIR).

Удаление подкаталога (команда RMDIR).

Установка текущего каталога (команда CHDIR).

Создание файла без использования FCB.

Открытие файла без использования FCB.

Закрытие файла без использования FCB.

Чтение из файла или ввод с устройства.

Запись в файл или вывод на устройство.

Удаление файла из каталога.

Установка позиции для последовательного доступа.

Изменение атрибутов файла.

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

Дублирование файлового номера.

«Склеивание» дублированных файловых номеров.

Получение текущего каталога.

Выделение памяти из свободного пространства.

Освобождений выделенной памяти.

Изменение длины блока выделенной памяти.

Загрузка/выполнение программы (подпроцесса).

Завершение подпроцесса с возвратом управления.

Получение кода завершения подпроцесса.

Начальный поиск файла по шаблону.

Поиск следующего файла по шаблону.

Получение состояния верификации.

Получение/установка даты и времени изменения файла.

Получение расширенного кода ошибки.

Создание временного файла.

Создание нового файла.

Блокирование/разблокирование доступа к файлу.

Получение адреса префикса программного сегмента (PSP).

Порты

Порт представляет собой устройство, которое соединяет процессор с внешним миром. Через порт процессор получает сигналы с устройств ввода и посылает сигналы на устройство вывода. Теоретически процессор может управлять до 65 536 портами, начиная с нулевого порта. Для управления вводом-выводом непосредственно на уровне порта используются команды IN и OUT:

uКоманда IN передает данные из входного порта в регистр AL (байт) или в регистр АХ (слово). Формат команды:

uКоманда OUT передает данные в порт из регистра AL (байт) или из регистра АХ (слово). Формат команды:

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

1. Статическое указание порта возможно при непосредственном использовании значения от 0 до 255:

Ввод: IN AL.порт# ;Ввод одного байта

Вывод: OUT порт#,АХ ;Вывод одного слова

2. Динамическое указание порта устанавливается в регистре DX от 0 до 65535. Этот метод удобен для последовательной обработки нескольких портов. Значение в регистре DX в этом случае увеличивается в цикле на 1. Пример ввода байта из порта 60Н:

MOV DX,60H ;Порт 60Н (клавиатура)

IN AL,DX ;Ввод байта

Ниже приведен список некоторых портов (номера в шестнадцатеричном представлении):

Регистры маски прерывании.

Ввод с клавиатуры

Звуковой порт (биты 0 и 1)

Монохромный дисплей и параллельный адаптер печати

В случае, если, например, программа запрашивает ввод с клавиатуры, то она выдает команду прерывания INT 16H. В этом случае система устанавливает связь с BIOS, которая с помощью команды IN вводит байт с порта 60Н.

На практике рекомендуется пользоваться прерываниями DOS и BIOS.

Однако можно также успешно обойтись без BIOS при работе с портами 21, 40. 42, 60 и 201.

Вопрос 78. Файловая система MS DOS, функции с использованием FCB и дескриптора

Прежде чем рассмотреть структуру томов в ОС DOS, необходимо пояснить ряд понятий, описывающих структуру диска на физическом уровне.

o Ряд концентрических колец, называемых дорожками;

o Дорожки делятся радиально на сектора;

o Диск состоящий из нескольких пластин и все дорожки расположенные на одинаковом расстоянии от центра называются цилиндром.

Дисковый том в MS DOS

Все типы дисков используют размер сектора 512 байт в MS DOS.

Группы цилиндров могут относиться к различным операционным системам. Программа DOS FDISK может разбивать фиксированный диск на несколько разделов (до четырех) разного размера.

Дисковые сектора определяются магнитной информацией, которую записывает утилита форматизации диска. Информация включает идентификационный номер каждого сектора. BIOS нумерует сектора 1-8, 1-9 или 1-15, в зависимости от емкости диска. Дорожки не маркируются, вместо этого они определяются механически по смещению головки чтения/записи от внешнего края диска. Дорожки нумеруются от 0 до 39 для дискет диаметром 5 1/4 дюйма, а для дисков большей емкости их может быть больше. Дисковые функции BIOS обращаются к определенному сектору, указывая номера дорожки и сектора. Однако функции DOS рассматривают все сектора диска, как одну цепь, которая нумеруется подряд, начиная от 0, поэтому каждый сектор имеет свой логический номер сектора.

Для дискет первый сектор (дорожка 0, сектор 1) содержит запись начальной загрузки, которая является небольшой программой, позволяющей компьютеру считать с дискового накопителя остальные части MS DOS. Затем идут две копии таблицы размещения файлов, которые содержат информацию о распределении дискового пространства (вторая копия хранится из соображений безопасности). Затем идет корневой каталог, который содержит список файлов и ссылок на подкаталоги, а также указывает в каком месте диска они начинаются.

Hаконец, далее идут две небольшие программы DOS IBMBIO.COM и IBMDOS.COM, которые считываются при старте и обеспечивают компьютер возможностями необходимыми для нахождения и загрузки файла COMMAND.COM.

Фиксированные диски имеют главную запись загрузки, которая содержит таблицу разделов, позволяющую разделить диск между несколькими операционными системами. Таблица разделов содержит информацию о том, где на диске начинается раздел DOS, а также первый сектор какого раздела содержит запись начальной загрузки. В остальном, раздел организован так же, как и дискета.

Файловая система

Диск использует таблицу размещения файлов (FAT) для отведения дискового пространства файлам и хранения информации о свободных секторах. Из соображений безопасности на всех дисках хранятся две копии FAT. Они хранятся последовательно, в секторах с самыми младшими доступными логическими номерами, начиная со стороны 0, дорожки 0, сектора 2 (сектор 1 также занят записью начальной загрузки). Число секторов, занимаемых FAT определяется размером и типом диска

Таблица размещения файлов хранит информацию о каждом кластере секторов на диске. Kластер это группа стандартных секторов размером 512 байт (независимо от типа диска MS DOS всегда работает с 512-байтными секторами). Группа секторов используется, чтобы уменьшить размер FAT.

Kаждая позиция в таблице размещения файлов соответствует определенной позиции кластера на диске. Обычно файл занимает несколько кластеров и запись в каталоге файлов содержит номер стартового кластера, в котором записано начало файла. Просмотрев позицию FAT, соответствующую первому кластеру, DOS находит номер кластера, в котором хранится следующая порция этого файла. Этому кластеру соответствует своя запись в FAT, которая в свою очередь содержит номер следующего кластера в цепочке. Для последнего кластера, занятого файлом FAT содержит значения от FF816 до FFF16.

Hеиспользуемым (или освобожденным) кластерам записывается значение 000, а плохим секторам — FF716. Hаконец, значения от FF016 до FF716 приписываются резервным кластерам.

Hомер кластера содержит 3 шестнадцатеричные цифры, для хранения которых требуется 1 1/2 байта. Для уменьшения размеров FAT числа для двух соседних кластеров хранятся в трех последовательных байтах таблицы. MS DOS автоматически производит все необходимые вычисления.

Первые три байта FAT не используются для номеров кластеров.

Первый байт содержит код, определяющий тип диска, а следующие 2 байта оба равны FF16. Поскольку эти позиции таблицы заняты, то кластеры нумеруются, начиная с 2, причем кластеры 2 и 3 занимают вторую тройку байт таблицы.

MS DOS 3.0 может создавать FAT с записями размером 16 бит. Такие записи необходимы для фиксированных дисков размером более 10M, которые имеют больше, чем 4086 кластеров.

Для нахождения следующего кластера файла:


1. Умножить номер кластера на 1.5.

2. Прочитать 2 байта с полученным смещением (округляя вниз).

3. Если номер кластера четный, то взять младшие 12 бит, иначе взять старшие 12 бит.

Для преобразования номера кластера в логический номер сектора:

1. Вычесть 2 из номера кластера.

2. Умножить результат на число секторов в кластере.

Kаждый диск имеет один корневой каталог, с которого начинается поиск всех остальных каталогов. Kорневой каталог может содержать элементы, указывающие на подкаталоги, которые в свою очередь могут содержать ссылки на другие подкаталоги, образуя древовидную структуру каталогов. Kорневой каталог всегда расположен в определенных секторах диска; подкаталоги хранятся как обычные дисковые файлы, поэтому они могут быть расположены в любом месте диска.

Фиксированный диск может содержать до четырех корневых каталогов, если он разбит на разделы, хотя MS DOS «видит» только один корневой каталог. Kаталоги могут иметь различные размеры, в зависимости от размера диска и его разбиения на разделы. В следующей таблице приведены размеры и позиции корневых каталогов для разных типов дисков:

Тип диска Размер каталога Число элементов Hачальный сектор
дискета 160K 4 сектора
дискета 180K 4 сектора
дискета 320K 7 секторов
дискета 1.2M 14 секторов
жесткий 10M переменные
жесткий 20M переменные

В зависимости от разбиения на разделы фиксированный диск может иметь различные размеры каталога и номер начального сектора. Если весь диск отведен для MS DOS, то на XT и AT под корневой каталог отводится 32 сектора, что позволяет иметь в нем 512 элементов.

Kак корневой каталог, так и подкаталоги, используют 32 байта для хранения информации об одном файле, независимо от типа диска.

Таким образом в каждом секторе может храниться информация о 16-ти элементах каталога. Kаждое 32-байтное поле разбито следующим образом:

Биты 0-7 8-10 12-21 22-23 24-25 26-27 28-31
Значение Имя файла Расширение файла Атрибут файла Зарезервировано Время последнего доступа к файлу Дата последнего доступа к файлу Hачальный кластер Размер файла

Точка между именем файла и его 3-байтным расширением не хранится. Все поля выровнены на левую границу, а пустые байты заполняются пробелами (код ASCII 32). Атрибут файла определяет является ли файл скрытым, защищенным от записи и т.д. Он определяет также специальные элементы каталога, такие как подкаталоги или метка тома. Информация о времени и дате упакована, поэтому для чтения этих значений требуются битовые операции.

Начальный кластер указывает на позицию в таблице размещения файлов (FAT). FAT хранит информацию о свободном пространстве на диске, а также отводит сектора при записи файла. FAT отводит дисковое пространство порциями, большими чем 1 сектор, которые называются кластерами. Файл расположен в цепочке кластеров и FAT содержит соответствующую цепочку элементов, указывающих, где эти кластеры расположены на диске.

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

Дескриптор файла – 16 битовое беззнаковое целое, используемое DOS и программами для обращения к файлам.

FCB —структура данных (файловые управляющие блоки), в которой содержится информация о позициях, в которых выполняются последовательно операции чтения или записи, о размерах записей в файле и прочие данные, которые, в основном, использует ОС.

Понятие дескрипторов файлов было введено в DOS версии 2.0.

Метод FCB:

Функция: 1116 прерывания 2116 — ищет первое появление файла.

Порядок вызовов: в DS:DX имя файла или путь на неоткрытый FCB.

При возврате AL будет содержать 0, если файл найден, и FF — если нет. DTA заполняется информацией из каталога. Для обычных FCB первый байт DTA содержит номер накопителя (1 = A и т.д.), а следующие 32 байта содержат элемент каталога. Для расширенного FCB первые 7 байтов файла копируются в первые 7 байтов расширенного FCB, восьмой байт указывает на накопитель, а следующие 32 байта – элемент каталога.

;—в сегменте данных

FCB DB 1,’NEWDATABAK’,25DUP(0)

MOV AH,11H ;функция поиска в каталоге

LEA DX,FCB ;указываем на FCB

CMP AL,0 ;успешно?

JNE NO_FILE ;если нет, то процедура обработки ошибки

LEA BX,DTA ;теперь DS:BX указывает на элемент каталога

После использования функции 1116 можно использовать функцию 1216 для поиска следующих подходящих элементов, когда имя файла содержит джокеры. В данном случае в имени файла допустим только символ «?», но не «*». Эта функция работает в точности так же, как и первая, и если найден второй файл, то информация о первом файле в DTA будет уничтожена повторной записью.

Метод дескриптора файлов:

Функция: 4E16 прерывания 2116 ищет файл с данным именем.

Порядок вызова: DS:DX должны указывать на строку, дающую путь файла. Hапример, B:\EUROPE\FRANCE\PARIS указывает на файл PARIS. Строка может содержать до 63 символов и завершаться символом ASCII 0. Имя файла может содержать джокеры, включая как «?», так и «*». Поместите атрибут файла в CX; если он обычный то 0, следует произвести анализ ошибки.

При возврате устанавливается флаг переноса, если файл не найден. Если файл найден, то функция заполняет DTA информацией о файле. Отметим частный случай использования DTA методом дескриптора файлов — обычно, DTA используется функциями MS DOS для работы через FCB. Первые 21 байт DTA зарезервированы DOS для поиска следующих совпадающих файлов. Двадцать второй байт дает атрибут файла, за ним следуют два байта, содержащие время и еще два байта содержащие дату. Следующие 4 байта содержат размер файла (младшее слово сначала). И, наконец, дается имя файла в виде строки переменной длины, заканчивающейся байтом ASCII 0. Точка (ASCII 46) разделяет имя и расширение и не один из этих элементов не заполнен пробелами.

;—в сегменте данных

PATH DB ‘B:FRANCE\PARIS\4EME’,0

MOV AH,4EH ;номер функции

LEA DX,PATH ;DS:DX указывают на путь

MOV CX,0 ;обычный атрибут файла

INT 21H ;ищем файл

JC NO_FILE ;уход, если не найден

LEA BX,DTA ;DS:BX указывают на DTA

MOV AL,[BX]+21 ;теперь атрибут файла в AL

Следующее появление имени файла (когда используются джокеры) ищется с помощью функции 4FH прерывания 2116. Она готовится в точности так же, как и функция 4EH, при этом указатель DTA не должен меняться. Kогда других совпадений не найдено, то устанавливается флаг переноса, а в AX появляется 18.

Папиллярные узоры пальцев рук — маркер спортивных способностей: дерматоглифические признаки формируются на 3-5 месяце беременности, не изменяются в течение жизни.

Организация стока поверхностных вод: Наибольшее количество влаги на земном шаре испаряется с поверхности морей и океанов (88‰).

Механическое удерживание земляных масс: Механическое удерживание земляных масс на склоне обеспечивают контрфорсными сооружениями различных конструкций.

MS-DOSMS-DOSMS-DOS Microsoft Disk Operating System (дисковая ОС от Microsoft) коммерческая операционная система для персональных компьютеров фирмы Microsoft. — презентация

Презентация была опубликована 6 лет назад пользователемimg0.liveinternet.ru

Похожие презентации

Презентация на тему: » MS-DOSMS-DOSMS-DOS Microsoft Disk Operating System (дисковая ОС от Microsoft) коммерческая операционная система для персональных компьютеров фирмы Microsoft.» — Транскрипт:

2 MS-DOS Microsoft Disk Operating System (дисковая ОС от Microsoft) коммерческая операционная система для персональных компьютеров фирмы Microsoft. MS-DOS самая известная ОС из семейства DOS, установленная на большинстве PC-совместимых компьютеров. Со временем она была заменена различными вариантами операционной системы Windows.

3 История* 1975, январь. Журнал «Popular Electronic» объявляет о выпуске набора для сборки микрокомпьютера Altair компании MITS на чипе i , февраль. Пол Аллен приезжает в MITS и представляет разработанный Биллом Гейтсом BASIC-интерпретатор для Altair. 1975, март. Стив Джобс и Стив Возняк организуют компьютерный клуб в г.Менло-Парк, штат Калифорния. 1975, август. Билл Гейтс и Пол Аллен организуют товарищество Micro- Soft. 1979, декабрь. Годовой объём продаж Microsoft: $. Количество служащих: 25. Продукция: трансляторы языков BASIC, FORTRAN и Cobol. 1980, апрель. Тим Паттерсон (Seattle Computer Products) начинает разрабатывать операционную систему для чипа i8086. __________ * Источник: Дениэл Ичбиа, Сьюзен Кнепер, «Билл Гейтс и сотворение Microsoft», Р-н-Д: Феникс, 1997

4 История 1980, август. Представители IBM приезжают в Microsoft. Гейтс подписывает контракт на разработку BASIC-интерпретатора и даёт рекомендации в отношении спецификаций микрокомпьютера. 1980, сентябрь. IBM предлагает написать трансляторы языков BASIC, FORTRAN, Cobol и Pascal для планируемого компьютера IBM. Тим Паттерсон демонстрирует в Microsoft свою 86-DOS, написанную для чипа i8086. Microsoft принимает решение о разработке на её базе ОС для микрокомпьютера IBM. 1980, октябрь. Microsoft покупает права на 86-DOS. Microsoft представляет IBM предложение о разработке трансляторов и операционной системы. 1980, ноябрь. Micorsoft подписывает контракт с IBM и получает первый опытный образец IBM PC. 1980, декабрь. Годовой объём продаж Microsoft: $. Количество служащих: 40.

5 История 1981, февраль. Первый запуск MS-DOS на опытном образце IBM PC. 1981, апрель. Тим Паттерсон поступает на работу в Microsoft. 1981, август. Объявление о создании IBM PC. Microsoft выпускает MS- DOS версии 1.0. Главой отдела по IBM PC назначается Дон Эстридж. 1981, декабрь. Годовой объём продаж Microsoft: $. Количество служащих: , март. IBM объявляет о создании PC XT с жёстким диском 10 Мбайт. Microsoft публикует MS-DOS 2.0 для PC XT. 1983, ноябрь. Microsoft представляет Windows. Этот графический интерфейс поддержан 23 производителями микрокомпьютеров, но – не IBM. 1984, август. IBM внедряет в производство PC AT с жёстким диском 20 Мбайт. Microsoft выпускает поддерживающую его MS-DOS , ноябрь. Выпуск MS-DOS 3.1 с поддержкой сети. 1991, июнь. Выпуск MS-DOS , апрель. В модернизированной версии Windows 3.1 усовершенствовано управление файлами и улучшен внешний вид.

6 Поздние версии 4.01 – первая полностью и официально русифицированная версия (май 1988г) – последняя (до повсеместного перехода на Windows 95) широко применявшаяся версия DOS (1994г).

7 Подсистемы MS-DOS Файловая система Система управления памятью Система управления программами Система связи с драйверами устройств Система обработки ошибок Служба времени Система ввода/вывода консоли оператора …

8 Состав MS-DOS BIOS (Basic Input-Output System) Блок начальной загрузки Файл io.sys (ibm.com, drbios.sys)– модуль взаимодействия с BIOS Файл msdos.sys (ibmdos.com, drdos.sys) – модуль обработки прерываний Файл command.com – командный процессор Утилиты (внешние команды) Драйверы устройств Файл config.sys – файл конфигурации системы Файл autoexec.bat – файл автозапуска программ при загрузке ОС

9 Файловая система Логические диски: A,B,C,D…Z Файловая структура на дисках: –Boot-сектор (сектор 0) –FAT (секторы 1-18, основная и дублирующая таблицы) –Root Directory (секторы 19, 20) –Io.sys, msdos.sys (секторы 33,…) –Область данных

10 Загрузка MS-DOS BIOS: –POST, Power On Self Testing –Поиск и загрузка Блока начальной загрузки (БНЗ) БНЗ загружает io.sys Io.sys: –Загружает и настраивает msdos.sys –Определяет состояние подключённых устройств –Инициализирует подключённые устройства –Загружает необходимые драйверы устройств –Передаёт управление msdos.sys Msdos.sys: –Настраивает рабочие таблицы –Загружает драйверы, указанные в config.sys –Загружает командный процессор command.com Command.com: –Выполняет команды, содержащиеся в autoexec.bat –Выдаёт на экран системную подсказку (system prompt) –Ожидает команд пользователя

11 Запуск вычислительного процесса — путём ввода спецификаций программного (.EXE,.COM,.BIN) или пакетного (.BAT) файла, расположенного в текущем каталоге текущего устройства

12 Команды работы с каталогом DIR – просмотреть содержимое MKDIR (MD) – создать каталог CHDIR (CD) – перейти в каталог RMDIR (RD) – удалить каталог

13 Команды работы с файлами TYPE – вывести содержимое на экран DELETE — удалить COPY — копировать RENAME — переименовать

14 Команды для работы с дисками FORMAT — форматировать DISKCOPY – дублировать дискету VOL – вывести метку диска LABEL – создать/заменить метку диска CHKDSK – проверить диск SYS – создать загрузочную (системную) дискету

15 Команды конфигурирования системы и управления устройствами CLS – очистить экран DATE – показать/установить дату PATH – указать пути поиска PROMPT – изменить формат приглашения TIME – показать/установить время VER – вывести версию ОС

16 Файловый менеджер Norton Commander

17 Прерывания BIOS 00h: Деление на ноль. 01h: Пошаговое. 02h: Немаскируемое. 03h: Точка прерыв. 04h: Переполнение. 05h: Печать экрана. 06h: (резерв) 07h: (резерв) 08h: Таймер. 09h: Клавиатура. 0Ah-0dh: (hdwr ints) 0Eh: Дискета. 0Fh: (hdwr int) 10h: Видео сервис. 11h: Список оборудования. 12h: Размер исп.памяти. 13h: Дисковый в/в. 14h: В/в через последовательный порт 15h: Расшир.сервис AT. 16h: В/в клавиатуры. 17h: В/в принтера. 18h: ROM-BASIC. 19h: Загрузка. 1Ah: В/в таймера. 1Bh: Прерывание клавиатуры. 1Ch: Пользовательское прерывание по таймеру 1Dh: Видео параметры 1Eh: Параметры дискет 1Fh: Символы графики

18 Прерывания DOS 20h: Завершить программу 21h: Сервис DOS 25h/26h: Абсолютные чтение/запись диска 27h: Завершиться, но остаться резидентным 28h: Квант времени DOS (НЕТ В ДОКУМЕНТАЦИИ)28h: Квант времени DOS (НЕТ В ДОКУМЕНТАЦИИ) 2eh: Выполнить команду DOS (НЕТ В ДОКУМЕНТАЦИИ)2eh: Выполнить команду DOS (НЕТ В ДОКУМЕНТАЦИИ) 2fh: Мультиплексное прерывание (спулинг печати)2fh: Мультиплексное прерывание (спулинг печати)

19 INT 21H: сервис DOS Это прерывание служит главным входом большинства функций DOS. Программа, запрашивающая сервис DOS, должна подготовить всю необходимую информацию в регистрах и управляющих блоках, указать в регистре AH номер желаемой функции DOS и затем вызвать прерывание INT 21H. Функция DOS 00H: завершить программу Функция DOS 01H: ввод с клавиатуры Функция DOS 02H: вывод на дисплей Функция DOS 03H: ввод AUX Функция DOS 04H: вывод AUX Функция DOS 05H: вывод на принтер Функция DOS 06H: Обмен с консолью Функция DOS 07H: Нефильтрующий консольный ввод без эхаФункция DOS 07H: Нефильтрующий консольный ввод без эха Функция DOS 08H: Консольный ввод без эха Функция DOS 09H: Выдать строку Функция DOS 0aH: буферизованный ввод строки Функция DOS 0bH: проверить статус ввода Функция DOS 0cH: ввод с очисткой Функция DOS 0dH: Сбросить диск Функция DOS 0eH: Выбрать умалчиваемый диск DOS Функция DOS 0fH: открыть файл через FCB Функция DOS 10H: Закрыть файл через FCB Функция DOS 11H: Найти 1-й совпадающий файл через FCBФункция DOS 11H: Найти 1-й совпадающий файл через FCB Функция DOS 12H: Найти следующий совпадающий файл через FCBФункция DOS 12H: Найти следующий совпадающий файл через FCB Функция DOS 13H: Удалить файл через FCB Функция DOS 14H: читать последовательный файл через FCBФункция DOS 14H: читать последовательный файл через FCB Функция DOS 15H: писать последовательный файл через FCBФункция DOS 15H: писать последовательный файл через FCB (недокументировано) Функция DOS 16H: создать файл через FCB Функция DOS 17H: Переименовать файл через FCB Функция DOS 19H: дать умалчиваемый диск DOS Функция DOS 1aH: установить адрес DTA Функция DOS 1bH: дать информацию FAT (текущий диск) Функция DOS 1cH: дать информацию FAT (любой диск) Функция DOS 21H: читать запись произвольного файла Функция DOS 22H: писать запись произвольного файла Функция DOS 23H: дать размер файла через FCB Функция DOS 24H: установить адрес блока произвольного файлаФункция DOS 24H: установить адрес блока произвольного файла Функция DOS 25H: установить вектор прерывания Функция DOS 26H: создать префикс программного сегментаФункция DOS 26H: создать префикс программного сегмента Функция DOS 27H: читать блок произвольного файла Функция DOS 28H: писать блок произвольного файла Функция DOS 29H: Разобрать имя файла Функция DOS 2aH: дать дату DOS Функция DOS 2bH: установить дату DOS Функция DOS 2cH: дать время DOS Функция DOS 2dH: установить время DOS Функция DOS 2eH: установить/сбросить переключатель верификацииФункция DOS 2eH: установить/сбросить переключатель верификации Функция DOS 2fH: дать текущий DTA Функция DOS 30H: дать номер версии DOS Функция DOS 31H: завершиться и остаться резидентным — — KEEPФункция DOS 31H: завершиться и остаться резидентным — — KEEP Функция DOS 32H: дать дисковую информацию DOS (недокументировано)Функция DOS 32H: дать дисковую информацию DOS (недокументировано) Функция DOS 33H: установить/опросить уровень контроля прерывания DOSФункция DOS 33H: установить/опросить уровень контроля прерывания DOS Функция DOS 34H: адрес статуса реентерабельности DOS Функция DOS 35H: дать вектор прерывания Функция DOS 36H: дать свободную память диска …

20 Расчёт сложных процентов Дано: капитал Q вкладывается в предприятие с ежегодным приростом D%. Определить: текущую величину капитала в течение первых N лет.

21 Расчёт сложных процентов: BASIC-программа 10 PRINT Расчёт сложных процентов 20 INPUT Введите Q, D, N, Q, D, N 30 D1=1+D/ J=1 50 Q=Q*D1 60 PRINT J,Q 70 J=J+1 80 IF J

22 Расчёт сложных процентов: ASM-программа TITLERASCHET.ASM; Расчёт сложных процентов STACKSGSEGMENTSTACK DW64 DUP (?) STACKSGENDS DATASGSEGMENTDATA ; объявление переменных VVQDBВведите величину начального капитала (до ) VVDDB10,13,Введите процент годового прироста DB10,13,% VVNDB10,13,Введите количество расчётных лет DB10,13,% Q0DW? D ? D1DW? N ? J 1 Q ? BUFDB5,0,0,0,0,0,0,0 VIV1DB год капитал DB10,13,%

23 SRBDB14 DUP(0), $ SRDB6 DUP(0), $ SRKDB10, 13, $ FT10DW1 TENDW10 STODW100 DATASEGENDS CODESGSEGMENTCODE MAINPROCFAR ; главная процедура ASSUMECS:CODESG, DS:DATASG, SS:STACKSG ; назначение ;сегментных регистров в сегменте кодов PUSHDS ; запись адреса SUBAX, AX ; префикса программного PUSHAX ; сегмента в стек MOVAX, DATASG ; инициализация содержимого MOVDS, AX ; регистра сегмента данных. ДАЛЕЕ – ;СОБСТВЕННО ТЕКСТ ПРОГРАММЫ MOVAH, 9 ; запрос на ввод Q MOVDX, offset VVQ INT21H MOVAH, 0Ah ; ввод Q MOVDX, offset BUF INT21H CALLSTR2BIN MOVQ0, D1 MOVAH, 9 ; запрос на ввод D MOVDX, offset VVD

24 INT21H MOVAH, 0AH ; ввод D MOVDX, offset BUF INT21H CALLSTR2BIN MOVD, D1 MOVAH, 9 ; запрос на ввод N MOVDX, offset VVN INT21H MOVAH, 0AH ; ввод N MOVDX, offset BUF INT21H x3850CALLSRT2BIN MOVN, D1 MOVAX, D MOVD1, AH ADDD1, 100 ; расчёт D1 = (1 + D/100) * 100 MOVAX, Q0 MOVQ, AX MOVAH, 9 MOVDX, offset VIV1 INT21H RST:MOVAX, Q ; расчёт Q = Q * D1 MULD1 4235DIVSTO MOVQ, AX MOVAX, J

25 CALLBIN2STR MOVAH, 9 ; вывод года MOVDX, offset SR INT21H MOVAH, 9 ; вывод пробела MOVDX, offset SRB INT21H MOVAX, Q ; вывод прибыли CALLBIN2STR MOVAH, 9 MOVDX, offset SR INT21H MOVAH, 9 ; перевод строки MOVDX, offset SRK INT21H INCJ ; j =j + 1 MOVAX, J CMPAX, N ; сравнение J с N JLERST ; условный переход по I

MS-DOS для программиста

3. Файловая система DOS

Теперь, после того как мы познакомились с логической структурой диска, можно приступить к изучению одной из самых развитых систем MS-DOS — файловой системы .

Сервис файловой системы доступен программе через прерывание INT 21h . Многочисленные функции этого прерывания, относящиеся к файловой системе, можно разбить на группы:

  • получение справочной информации;
  • работа с каталогами;
  • работа с файлами.

Функции первой группы позволяют программе получать разностороннюю информацию, касающуюся текущего состояния дисковой системы — текущий диск и текущий каталог, размер свободного места на диске, параметры логического диска и т. д.

Функции второй группы выполняют все необходимые операции с каталогами — создание, переименование, уничтожение каталогов, изменение текущего каталога.

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

Заметим, что существует два класса функций для работы с файлами. Первый класс использует управляющие блоки файлов FCB . Эти функции использовались в MS-DOS версий 1.х и имеют в настоящее время чисто исторический интерес. Вам они, скорее всего, никогда не будут нужны, за исключением одного случая — если вам надо составить программу, способную работать под управлением MS-DOS версии 1.0 или 1.1. В этой книге мы не будем упоминать функции, предназначенные для работы с файлами через FCB.

Второй класс использует идентификаторы файла (file handle). Этот класс функций впервые появился в MS-DOS версии 2.0.

Смысл идентификатора файла индекса очень прост. Для того чтобы приступить к работе с файлом, программа должна вызывать определенную функцию DOS, «открывающую» этот файл. Процесс открытия файла заключается в присвоении ему определенного числа (идентификатора) и выполнении некоторых других инициализирующих действий. Для выполнения каких-либо операций с файлом программа, вызывая соответствующую функцию MS-DOS, должна указать идентификатор этого файла.

Первые пять идентификаторов зарезервированы операционной системой:

Идентификатор Описание
Стандартное устройство ввода (клавиатура)
1 Стандартное устройство вывода (консоль)
2 Стандартное устройство для вывода сообщений об ошибках (консоль)
3 Стандартное устройство последовательного ввода/вывода, обычно асинхронный адаптер COM1
4 Стандартное печатающее устройство (обычно параллельный порт LPT1)

Зарезервированные идентификаторы всегда доступны программе. Для устройств, соответствующих этим идентификаторам, не требуется выполнять операцию открытия.

Одно из преимуществ файловых функций второго класса (использующих идентификаторы файлов) — возможность одновременной работы с файлами, расположенными в разных каталогах.

Состав функций MS-DOS, предназначенных для работы с файловой системой, достаточно разнообразен. Только в очень редких случаях, связанных в основном с организацией защиты информации от несанкционированного доступа, вам может потребоваться доступ к диску на более низком уровне. Если ваша программа использует для работы с файлами только документированные функции операционной системы, ее работа не будет зависеть от аппаратных средств компьютера, а также от программы, с помощью которой были созданы разделы диска MS-DOS.

3.1. Получение справочной информации

В этом разделе мы опишем наиболее нужные, на наш взгляд, функции MS-DOS, предназначенные для получения справочной информации о состоянии дисковой системы.

Текущий диск и текущий каталог

В любой момент времени программа может определить текущий диск или текущий каталог, а также сменить текущий диск или текущий каталог. Для этого она должна использовать специальные функции прерывания INT 21h .

Для того чтобы узнать номер текущего диска, программа может воспользоваться функцией 19h:

На входе: AH 19h
На выходе: AL Номер текущего устройства НГМД или НМД (0 — А:, 1 — В:, и т. д.).

Для установки текущего диска можно использовать функцию 0Eh, которая имеет следующие параметры вызова:

На входе: AH 0Eh
DL Номер устройства НГМД или НМД (0 — А:, 1 — В:, и т. д.)
На выходе: AL Общее количество дисковых устройств в системе. Эта величина соответствует параметру LASTDRIVE из файла CONFIG.SYS

Для того чтобы узнать текущий каталог, вы можете воспользоваться функцией 47h:

На входе: AH 47h
DL Номер устройства НГМД или НМД (0 — текущий, 1 — А:, 2 — В:, и т. д.)
DS:SI Адрес буфера для записи пути текущего каталога
На выходе: AX Код ошибки, если установлен флаг переноса CF

Буфер должен иметь размер не менее 64 байт. Функция 47h возвращает текущий каталог в формате ASCIIZ (то есть строку, закрытую двоичным нулем, например: «path\dirname»,0) без символа, обозначающего диск. Если текущим является корневой каталог, регистровая пара DS:SI будет указывать на нулевую строку (состоящую из одного двоичного нуля).

Функция 3Bh предназначена для установки текущего каталога:

На входе: AH 3Bh
DL Номер устройства НГМД или НМД (0 — текущий, 1 — А:, 2 — В:, и т. д.)
DS:DX Адрес буфера, содержащего путь к каталогу, который должен стать текущим
На выходе: AX Код ошибки, если установлен флаг переноса CF

Буфер может иметь максимальный размер 64 байт. Он должен содержать путь в формате ASCIIZ. Строка не должна содержать символ, обозначающий диск. Если текущим должен стать корневой каталог, строка должна состоять только из одного двоичного нуля.

Определение размера кластера и сектора

Функции MS-DOS могут помочь вам в получении информации, необходимой для организации доступа к диску на уровне секторов и кластеров. При этом вы будете избавлены от необходимости читать в память и анализировать содержимое загрузочного сектора логического диска.

Информация о таблице размещения файлов FAT для текущего диска может быть получена с помощью функции 1Bh прерывания INT 21h , имеющего следующие параметры вызова:

На входе: AH 1Bh
На выходе: DS:BX Адрес первого байта FAT . Это байт идентификации среды носителя данных, соответствует байту media в блоке параметров BIOS
DX Общее количество кластеров на диске
AL Количество секторов в одном кластере
CX Количество байт в одном секторе

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

Для старых версий MS-DOS регистровая пара DS:BX указывала на FAT , считанный в память. Более поздние версии операционной системы могут содержать по этому адресу только часть таблицы размещения файлов .

Для получения аналогичной информации не о текущем, а о любом диске, используйте функцию 1Ch. Эта функция полностью аналогична предыдущей, за исключением того, что в регистре DL должен быть указан номер НГМД или НМД: 0 — текущий, 1 — А:, 2 — В: и т. д.

Определение размера свободного пространства

Если вас интересует размер свободного места на диске, вы можете его узнать с помощью функции 36h:

На входе: AH 36h
DL Номер устройства НГМД или НМД (0 — текущий, 1 — А:, 2 — В:, и т. д.)
На выходе: AX Количество секторов в кластере или 0FFFFh, если был задан неправильный номер устройства
BX Количество свободных кластеров на диске
CX Количество байт в одном секторе
DX Общее количество кластеров на диске

Эта функция возвращает в регистре AX число 0FFFFh, если вы неправильно указали номер устройства.

Блок управления устройством DDCB

При обсуждении векторной таблицы связи в предыдущем томе «Библиотеки системного программиста» мы рассказывали о блоках управления устройствами DDCB . Поле dev_cb векторной таблицы связи содержит дальний адрес цепочки этих блоков.

Для получения адреса блока DDCB можно воспользоваться недокументированной функцией 32h:

На входе: AH 32h
DL Номер устройства НГМД или НМД (0 — текущий, 1 — А:, 2 — В:, и т. д.)
На выходе: AL 0, если был задан правильный номер устройства;
0FFh, если был задан неправильный номер устройства
DS:BX Адрес блока DDCB


Для получения адреса блока DDCB текущего диска можно также воспользоваться недокументированной функцией 1Fh, которая имеет формат, аналогичный функции 32h, за исключением того, что для нее не надо задавать номер устройства в регистре DL.

Илон Маск рекомендует:  Метод сжатия хаффмана

Флаг прерывания

С помощью функции 33h программа может проверить или установить флаг прерывания при помощи комбинации клавиш и, кроме того, узнать номер диска, с которого выполнялась загрузка операционной системы:

На входе: AH 33h
AL Код операции:
0 — Проверить текущее состояние флага прерывания при помощи комбинации клавиш ;
1 — Установить флаг прерывания при помощи комбинации клавиш ;
5 — Определить номер диска, который был использован для загрузки операционной системы
DL Значение флага прерывания при помощи комбинации клавиш операции с кодом 1:0 — запретить прерывание,1 — разрешить прерывание
На выходе: DL Текущее состояние флага прерывания при помощи комбинации клавиш для операции с кодом 0; Номер диска, использованного для загрузки операционной системы для операции 5 (1 — А:, 2 — В:, и т. д.)

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

Состояние флага прерывания при помощи комбинации клавиш влияет на возможность прервать выполнение программы. Если прерывание запрещено, MS-DOS проверяет эту комбинацию клавиш только при вызове функций стандартного ввода/вывода на консоль, принтер и последовательный порт. Если же прерывание разрешено, указанная комбинация клавиш проверяется и при вызове других функций MS-DOS. Если пользователь нажал комбинацию клавиш , операционная система выполняет прерывание INT 23h , которое завершает работу текущей программы.

Адрес области DTA

Функция 2Fh возвращает в регистровой паре ES:BX адрес текущей области DTA (Disk Transfer Area ), которая используется при поиске файлов в каталогах. Этот адрес необходим резидентным программам, о чем мы говорили в предыдущем томе «Библиотеки системного программиста».

Флаг проверки записи

Функция 54h позволяет программе узнать текущее состояние флага проверки записи информации на диск. В регистре AL эта функция возвращает текущее состояние флага.

Если содержимое регистра равно 1, после записи сектора операционная система считывает его для проверки. Разумеется, такая проверка снижает скорость работы программы. Если после вызова функции регистр AL содержит 0, проверка записи не выполняется.

Для установки флага проверки записи можно использовать функцию 2Eh. Перед вызовом функции в регистр AL необходимо занести новое значение флага проверки: 0 — проверка не нужна; 1 — должна выполняться проверка записанной информации.

Функции библиотеки Borland C++

Стандартная библиотека Borland C++ содержит несколько функций, облегчающих получение справочной информации о состоянии дисковой системы.

_dos_getdiskfree

Функция _dos_getdiskfree использует функцию 36h для получения информации о диске. Файл dos.h содержит такое описание этой функции:

Параметр drive задает номер используемого устройства: 0 — текущий, 1 — А:, и т. д.

Информация возвращается в структуре diskfree_t, которая определена также в файле dos.h:

Поля этой структуры описаны ниже:

Поле Описание
unsigned total_clusters Общее количество кластеров на диске
unsigned avail_clusters Количество свободных кластеров
unsigned sectors_per_cluster Количество секторов, занимаемых одним кластером
unsigned bytes_per_sector Размер сектора в байтах

_dos_getdrive и _dos_setdrive

Для получения номера текущего диска и для установки номера текущего диска можно использовать, соответственно, функции _dos_getdrive и _dos_setdrive .

Функция _dos_getdrive имеет следующий прототип:

Она пользуется функцией 19h для получения номера текущего диска, который записывается по адресу, задаваемому параметром drive. Значение 1 соответствует диску А:, 2 — В:, и т. д.

Функция _dos_setdrive предназначена для установки текущего диска и может быть использована для определения общего числа дисков в системе:

Параметр drive определяет текущий диск (1 — А:, и т. д.). В переменную, адрес которой передается через второй параметр, функция записывает общее количество логических дисков, установленных в системе. Функция _dos_setdrive использует функцию 0Eh прерывания INT 21h .

Программа DISKINF2

Для иллюстрации способов использования функций _dos_getdrive , _dos_setdrive и _dos_getdiskfree мы составили программу DISKINF2 (листинг 3.1).

Листинг 3.1. Файл diskinf2\diskinf2.cpp

3.2. Работа с каталогами

После форматирования логический диск содержит корневой каталог. Если диск форматируется как системный, в этом каталоге могут находится дескрипторы файлов операционной системы io.sys , msdos.sys , command.com .

Операционная система предоставляет программам пользователя удобный сервис для создания, уничтожения и переименования каталогов. Используя сведения, приведенные в этой книге, вы сможете изменять структуру каталогов сами, не прибегая к услугам MS-DOS. Однако это следует делать только тогда, когда операции с каталогами по каким-то причинам нежелательно выполнять с использованием функций операционной системы.

Создание каталога

Для создания каталога используйте функцию 39h прерывания INT 21h :

На входе: AH 39h
DS:DX Адрес строки в формате ASCIIZ, содержащей путь создаваемого каталога
На выходе: AL Код ошибки, если был установлен флаг переноса CF

Строка, адрес которой передается в регистрах DS:DX, может содержать полный путь, состоящий из имени диска и имени каталога, в котором должен быть создан каталог, или она может состоять только из одного имени каталога. В последнем случае каталог создается в текущем каталоге на текущем диске.

Размер строки с именем каталога не должен превышать по длине 64 байта.

Удаление каталога

Удалить существующий каталог можно с помощью функции 3Ah:

На входе: AH 3Ah
DS:DX Адрес строки в формате ASCIIZ, содержащей путь к каталогу
На выходе: AL Код ошибки, если был установлен флаг переноса CF

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

Переименование каталога

Для изменения имени каталогов и файлов предназначена функция 56h:

На входе: AH 56h
DS:DX Адрес строки в формате ASCIIZ, содержащей старое имя каталога или файла
ES:DI Адрес строки в формате ASCIIZ, содержащей новое имя каталога или файла
На выходе: AL Код ошибки, если был установлен флаг переноса CF

Файл или каталог, который будет переименован, должен существовать. Если в имени не указан диск или каталог, то подразумевается, что файл или каталог находится в текущем каталоге на текущем диске. Напротив, каталог или файл с новым именем не должен существовать, иначе функция возвратит признак ошибки.

Эта функция может перемещать файл из одного каталога в другой, если вы укажите разные пути. Каталоги перемещать нельзя, их можно только переименовывать.

Функции библиотеки Borland C++

Стандартная библиотека Borland C++ содержат несколько функций, предназначенных для работы с каталогами.

getcwd

Функция getcwd предназначена для определения текущего каталога. Прототип этой функции описан в файле direct.h:

Первый параметр этой функции — адрес буфера, в который функция запишет строку, содержащую имя текущего каталога. Размер этого буфера определяется вторым параметром.

Если в качестве первого параметра указать NULL, функция динамически закажет буфер длиной n байт из области кучи и вернет его адрес. Эту память впоследствии необходимо будет освободить при помощи функции free.

Функция getcwd всегда возвращает указатель на буфер, содержащий текущий каталог.

mkdir , rmdir , chdir

Для создания и удаления каталогов, изменения текущего каталога имеются функции mkdir , rmdir , chdir .

Все эти функции имеют один параметр — путь каталога, который имеет тип (char *). В случае успешного выполнения операции функции возвращают 0, при ошибке — 1.

rename

Для переименования каталогов (и файлов) предназначена функция rename :

Способ ее использования очевиден: необходимо задать старое и новое имя каталога. Можно задавать как полный путь, так и просто имя каталога либо файла. В последнем случае операция переименования выполняется над каталогами или файлами, находящимися в текущем каталоге.

Функция может возвращать один из приведенных ниже кодов ошибки:

Код ошибки Описание
ENOENT Нет такого файла или каталога
EACCES Нет прав доступа
EXDEV Другой диск

Код ошибки EXDEV возвращается в том случае, когда программа указывает разные диски для старого и нового имен файлов или каталогов.

Важное замечание: если вы задаете полный путь в программе, составленной на С или С++, повторяйте символ ‘\’ два раза в строке пути. Это нужно для того, чтобы избежать конфликта с форматом представления констант в языке С. Например:

Программа DIRCTL

Приведем исходный текст небольшой программы DIRCTL (листинг 3.2), использующий перечисленные выше функции.

Листинг 3.2. Файл dirctl\dirctl.cpp

3.3. Поиск в каталогах

Часто перед программистом стоит задача определения содержимого каталога. При описании логической структуры диска мы приводили текст программы, выводящей на экран содержимого корневого каталога и других каталогов. Эта программа использовала загрузочный сектор логического диска и таблицу размещения файлов . Вы можете использовать такой способ, однако если вам не требуется информация о номерах начальных кластеров файлов и дескрипторы удаленных файлов, лучше применить специальные функции MS-DOS, предназначенные для поиска файлов в каталогах.

Это функции 4Eh и 4Fh.

Указанные выше функции используются вместе следующим образом:

Вначале вызывается функция 4Eh для поиска в каталоге файла, соответствующего образцу. В образце можно использовать символы «?» и «*», которые означают, соответственно, один любой символ и любое количество любых символов. Информация о найденном файле располагается в специальной области, распределенной каждой работающей программе — области DTA .

Затем для поиска остальных файлов, удовлетворяющих заданному ранее образцу, в цикле вызывается функция 4Fh. Условие завершения цикла — отсутствие в каталоге указанных файлов.

Функция 4Eh вызывается следующим образом:

На входе: AH 4Eh
CX Атрибуты файла, которые будут использованы при поиске. Будут найдены файлы, имеющие атрибут, заданный в регистре CX
DS:DX Адрес строки в формате ASCIIZ, содержащей путь каталога или файла
На выходе: AL Код ошибки, если был установлен флаг переноса CF

Функция 4Fh имеет следующие параметры вызова:

На входе: AH 4Fh
На выходе: AL Код ошибки, если был установлен флаг переноса CF

Обе функции устанавливают флаг переноса в том случае, когда каталог не содержит файлов, удовлетворяющих заданному критерию поиска.

Для работы с областью DTA в составе MS-DOS имеются две функции. Это функция 2Fh, позволяющая получить адрес области DTA (она возвращает этот адрес в регистрах ES:BX), и функция 1Ah, предназначенная для установки своей области DTA (адрес новой области DTA должен быть указан в регистрах DS:DX).

Напомним, что по умолчанию область DTA занимает 128 байт в префиксе сегмента программы PSP со смещением 80h.

В случае успешного поиска функции 4Eh и 4Fh помещают в DTA информацию о найденных файлах в следующем формате:

Смещение Размер Содержимое
20 Зарезервировано
21 1 Атрибуты найденного файла
22 2 Поле времени последнего обновления файла
24 2 Поле даты последнего обновления файла
26 4 Длина файла
30 13 Имя файла и расширение в формате ASCIIZ

Номер начального кластера, распределенного файлу или каталогу, невозможно получить с помощью функций 4Eh и 4Fh.

Стандартная библиотека Borland C++ содержат две функции, предназначенные для сканирования каталогов. Это _dos_findfirst и _dos_findnext .

Приведем прототипы этих функций, описанные в файле dos.h:

В этих функциях параметр pattern определяет образец для поиска файлов, параметр attr (атрибуты файла) используется в качестве дополнительного критерия поиска. Параметр found представляет собой указатель на структуру, в которую будет записываться информация о найденных файлах. Эта структура определена в файле dos.h:

Программа DIRLIST

Приведем текст программы просмотра содержимого каталога DIRLIST (листинг 3.3). Программа принимает из командной строки параметр — образец для показа файлов. Если вы укажете параметр *.*, будет выведена информация обо всех файлах. Можно задавать полный путь: c:\*.*.

Листинг 3.3. Файл dirlist\dirlist.cpp

3.4. Работа с файлами

В этом разделе мы рассмотрим функции MS-DOS, предназначенные для создания, открытия, удаления, переименования и перемещения файлов. Операции чтения из файла и записи в файл будут описаны в следующем разделе.

Создание файлов

Для создания файла предназначена функция 3Ch прерывания INT 21h. С помощью этой функции может быть создан файл как в текущем, так и в любом другом каталоге. Если файл с указанным именем уже существует, он обрезается до нулевой длины. Будьте осторожны при использовании этой функции — она может уничтожить файл.

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

Приведем параметры вызова функции создания файла:

На входе: AH 3Ch
CX Атрибуты создаваемого файла:
00h — обычный файл;
01h — только читаемый файл;
02h — скрытый файл;
04h — системный файл
DS:DX Адрес строки, содержащей путь к файлу
На выходе: AX Код ошибки, если был установлен флаг переноса CF;
Идентификатор файла, если флаг переноса CF сброшен

При выполнении этой функции возможно возникновение следующих ошибок:

  • отсутствует какой-либо элемент в пути для создаваемого файла, например, диск или каталог;
  • была сделана попытка создать файл в корневом каталоге, но корневой каталог переполнен;
  • в указанном каталоге уже есть файл с таким именем, и этот файл имеет атрибут «Только читаемый»;
  • пользователь, который работает в сети, не имеет прав доступа для выполнения указанной операции.

Операционная система игнорирует попытки создания с помощью этой функции каталога или метки диска.

Для того чтобы при создании файла случайно не уничтожить содержимое уже существующего файла с таким же именем, программа может использовать функцию 5Bh. Эта функция проверяет заданный путь на предмет наличия указанного файла. Если такой файл уже существует, функция возвращает программе признак ошибки:

На входе: AH 5Bh
CX Атрибуты создаваемого файла:
00h — обычный файл;
01h — только читаемый файл;
02h — скрытый файл;
04h — системный файл
DS:DX Адрес строки, содержащей путь к файлу
На выходе: AX Код ошибки, если был установлен флаг переноса CF;
Идентификатор файла, если флаг переноса CF сброшен

Если вам требуется временный файл, вы можете создать его с помощью функции 5Ah:

На входе: AH 5Ah
CX Атрибуты создаваемого файла:
00h — обычный файл;
01h — только читаемый файл;
02h — скрытый файл;
04h — системный файл
DS:DX Адрес блока памяти, в который функция запишет путь созданного временного файла. Размер этого блока памяти должен быть по крайней мере 13 байт
На выходе: AX Код ошибки, если был установлен флаг переноса CF;
Идентификатор файла, если флаг переноса CF сброшен

Операционная система не будет автоматически удалять созданный временный файл после завершения работы программы или перезагрузки. Программа должна сама удалить этот файл.

Открытие файла

Перед тем, как начать работу с файлом, его нужно открыть. Функции, создающие новые файлы, открывают их автоматически. Для того, чтобы открыть существующий файл, вы можете воспользоваться функцией 3Dh:

На входе: AH 3Dh
AL Требуемый режим доступа:

Бит 7: флаг наследования

0 — идентификатор файла наследуется порожденным процессом
1 — идентификатор файла не наследуется порожденным процессом

Биты 4. 6: режим разделения

000 — режим совместимости
001 — запрещение всех видов доступа
010 — запрещение записи
011 — запрещение чтения
100 — разрешение всех видов доступа

Бит 3:0 — зарезервировано

Биты 0. 2: вид доступа

000 — чтение
001 — запись
010 — чтение и запись

DS:DX Адрес строки, содержащей путь к файлу
На выходе: AX Код ошибки, если установлен флаг переноса CF;
Идентификатор файла, если флаг переноса CF сброшен

С помощью функции 3Dh можно открыть любой файл (но не каталог). Если требуется вид доступа «запись», открываемый файл не должен иметь атрибут «Только читаемый».

Для использования битов 4. 7 (управляющих доступом к файлу другими программами в сети) должна быть запущена программа share.exe .

Если используется бит наследования, то порожденному процессу наследуются вид доступа, запрошенный при открытии файла.

Функция 6Ch обладает расширенными возможностями по созданию и открытию файлов:

На входе: AH 6Ch
AL 00h
BX Байт флагов расширенного режима открытия файла
CX Атрибуты создаваемого файла, используется только при создании файлов
DX Выполняемая функция, если файл существует или не существует:

Биты 0-3 регистра DX задают действие, если файл существует:

0000h — если файл существует, вернуть признак ошибки;
0001h — если файл существует, открыть его;
0002h — если файл существует, заместить и открыть его.

Биты 4-7 регистра DX задают действие, если файл не существует:


0000h — если файл не существует, вернуть признак ошибки;
0001h — если файл не существует, создать и открыть его

DS:SI Адрес строки, содержащей путь к файлу
На выходе: AX Код ошибки, если флаг переноса CF установлен;
Идентификатор файла, если флаг переноса CF сброшен
CX Код выполненных действий:
0 — файл был открыт;
1 — файл был создан и открыт;
2 — файл был замещен и открыт

Регистр BX на входе задает флаги расширенного режима открытия файла в следующем формате:

Биты Назначение
0. 2 Режим доступа при чтении или записи
3 Зарезервировано, должно быть равно 0
4. 6 Режим разделения
7 Флаг наследования
8. 12 Зарезервировано, должно быть равно 0
13 0 — Режим обычного использования обработчика критических ошибок INT 24h (обработчик критических ошибок будет описан позже)
1 — Блокировка обработчика критических ошибок INT 24h. Для того, чтобы узнать причину ошибки, программа должна использовать функцию 59h прерывания INT 21h
14 Управление буферизацией:
0 — Использование стандартной для MS-DOS буферизации;
1 — Отмена буферизации. Использование этого режима замедлит работу с диском, однако вероятность потери информации при аварии в питающей сети уменьшится

Описанная выше функция является как бы комбинацией функций 3Dh и 3Ch (открытие и создание файла). Она удобна, но при ее использовании программа должна убедиться в том, что версия MS-DOS не ниже, чем 4.0.

Удаление файла

Удалить файл можно при помощи функции 41h прерывания INT 21h :

На входе: AH 41h
DS:DX Адрес строки в формате ASCIIZ, содержащей путь удаляемого файла
На выходе: AL Код ошибки, если установлен флаг переноса CF

С помощью этой функции нельзя удалить файл, имеющий атрибут «Только читаемый».

Под удалением файла понимается вычеркивание файла из каталога и освобождение всех принадлежавших ранее этому файлу кластеров. Эти кластеры отмечаются в таблице размещения файлов как свободные. При стирании файлов не происходит уничтожение информации, записанной на диске, поэтому в некоторых случаях можно полностью восстановить случайно удаленные файлы.

Переименование или перемещение файла

Программа может изменить имя файла или переместить его в другой каталог того же самого диска, воспользовавшись функцией 56h прерывания INT 21h :

На входе: AH 56h
DS:DX Адрес строки в формате ASCIIZ, содержащей старое имя
ES:DI Адрес строки в формате ASCIIZ, содержащей новое имя или новый путь к файлу
На выходе: AL Код ошибки, если установлен флаг переноса CF

С помощью этой функции можно переименовать (но не переместить) не только файл, но и каталог.

Функции библиотеки Borland C++

Стандартная библиотека Borland C++ содержит функции для работы с файлами. Эти функции можно разделить на две группы — функции низкого уровня и функции ввода/вывода потоком. Вторая группа функций использует буферизацию и будет рассмотрена в разделе, посвященном буферизованному вводу/выводу.

Функции низкого уровня отображаются на описанные выше функции прерывания INT 21h (а также на функции этого же прерывания, предназначенные для чтения или записи, позиционирования и т. д.).

creat

Для создания файла можно использовать функцию creat :

Эта функция и ее параметры описаны в файлах io.h, sys\types.h, sys\stat.h, errno.h.

Первый параметр определяет путь создаваемого файла и его имя. Если файл с указанным именем существует, и не имеет атрибут «Только читаемый», функция сбрасывает длину файла до нуля. Содержимое файла при этом уничтожается.

Второй параметр позволяет задать атрибуты создаваемого файла. Он может иметь следующие значения:

Параметр Операции, разрешенные для создаваемого файла
S_IWRITE Запись
S_IREAD Чтение
S_IREAD | S_IWRITE Чтение и запись

В операционной системе MS-DOS невозможно создать файл, в который можно было бы писать, но из которого было бы нельзя читать информацию. Поэтому если указать второй параметр как S_IWRITE, будет создан такой файл, для которого разрешены как операция записи, так и операция чтения.

После создания файла функция creat открывает новый файл, возвращая идентификатор файла или код ошибки.

Мощная функция open предназначена как для открытия существующих файлов, так и для создания новых:

Первый и третий параметры этой функции аналогичны параметрам функции creat , причем третий параметр нужен только при создании нового файла. Квадратные скобки указывают на то, что этот параметр можно не указывать.

Параметр oflag может являться результатом логической операции ИЛИ над следующими константами, определенными в файле fcntl.h:

Константа Описание
O_APPEND При записи в файл информация будет добавляться в конец файла
O_BINARY Файл открывается для работы в двоичном режиме (игнорируются управляющие символы, такие как конец строки)
O_CREAT Создается новый файл и открывается для записи. Эта константа игнорируется, если указанный в первом параметре файл уже существует
O_EXCL Используется вместе с O_CREAT . Если указанный в первом параметре файл существует, функция возвратит признак ошибки
O_RDONLY Файл открывается только для чтения, попытка записи в файл приведет к тому, что функция записи вернет признак ошибки
O_RDWR Файл открывается как для чтения, так и для записи
O_TEXT Файл открывается в текстовом режиме
O_TRUNC Существующий файл открывается и обрезается до нулевой длины (если для этого файла разрешена операция записи)
O_WRONLY Файл открывается только для записи (в MS-DOS для файла, открытого с признаком O_WRONLY , разрешено выполнение операции чтения)

close

Для того, чтобы закрыть файл, открытый функциями creat или open , нужно использовать функцию close :

В качестве параметра функции передается идентификатор файла, полученный при открытии или создании файла. Функция возвращает 0 при успешном закрытии файла или -1 при ошибке.

Коды ошибок

Код ошибки для этой и других функций стандартной библиотеки Borland C++ записывается в глобальную переменную errno.

3.5. Чтение и запись файлов

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

Запись данных в файл

Для записи данных в файл предназначена функция 40h прерывания INT 21h . В качестве параметров для этой функции необходимо указать идентификатор файла, полученный при открытии существующего файла или создании нового, адрес блока памяти, содержащего данные для записи и размер этого блока памяти:

На входе: AH 40h
BX Идентификатор открытого файла
CX Количество записываемых байт
DS:DX Адрес блока памяти, содержащего записываемые данные
На выходе: AX Код ошибки, если был установлен флаг переноса CF;
Количество действительно записанных байт, если флаг переноса CF сброшен

При записи данные попадают в то место внутри файла, которое определяется содержимым так называемого файлового указателя позиции. При создании нового файла этот указатель сбрасывается в 0, что соответствует началу файла. При открытии файла с помощью функции 3Dh указатель также устанавливается на начало файла. Операция записи в файл с помощью функции 40h продвигает указатель вперед к концу файла на количество записанных байт.

По мере увеличения размера файла ему будут распределяться все новые и новые кластеры из числа отмеченных как свободные.

Если вам необходимо перезаписать содержимое файла, а не дописывать данные в конец, необходимо воспользоваться функцией позиционирования. Эта функция будет описана в следующем разделе. Она позволяет управлять содержимым файлового указателя позиции.

Следует учитывать, что количество действительно записанных байт может не совпадать с заданным в регистре CX при вызове функции 40h. Такая ситуация возможна, например, при записи в файл, открытый в текстовом режиме, байта 1Ah. Этот байт означает конец текстового файла. Другая возможная причина — отсутствие свободного места на диске.

Если функция вызывается с содержимым регистра CX, равным 0, файл будет обрезан или расширен до текущего положения файлового указателя.

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

Функция 40h может выполнять запись не только в файл, но и в символьное устройство, предварительно открытое функцией 3Dh. Об этом мы говорили в разделах книги, посвященных драйверам.

Чтение данных из файла

Для чтения данных из файла (или символьного устройства) предназначена функция 3Fh прерывания INT 21h :

На входе: AH 3Fh
BX Идентификатор открытого файла
CX Количество читаемых байт
DS:DX Адрес блока памяти, в который будут записаны прочитанные данные
На выходе: AX Код ошибки, если установлен флаг переноса CF;
Количество действительно прочитанных байт, если флаг переноса CF сброшен

Эта функция используется аналогично функции записи. Для нее верны все замечания, касающиеся файлового указателя позиции, количества действительно прочитанных байт и прав доступа.

Функции библиотеки Borland C++

Если ваша программа составлена на языке программирования С или C++, для записи и чтения данных она может воспользоваться функциями write и read :

Эти функции работают аналогично функциям 40h и 3Fh прерывания INT 21h . Параметр handle определяет файл, для которого необходимо выполнить операцию записи или чтения. Параметр buffer — указатель на блок памяти, который содержит данные для записи или в который необходимо поместить прочитанные данные. Количество записываемых или читаемых байт определяется третьим параметром — count.

После выполнения операции функция возвращает количество действительно записанных или прочитанных байт или -1 при ошибке.

Будьте внимательны, если вы записываете или читаете больше 32 Кбайт — вы можете получить признак ошибки, хотя передача данных выполнилась правильно. Большие массивы данных можно записывать по частям.

Программа FCOPY

В качестве примера мы приведем программу копирования файлов FCOPY (листинг 3.4), которая пользуется описанными выше функциями.

Листинг 3.4. Файл fcopy\fcopy.cpp

Для определения момента достижения конца исходного файла в программе использована функция eof:

Для файла с идентификатором handle эта функция возвращает одно из трех значений:

Значение Описание
1 Достигнут конец файла
Конец файла не достигнут
-1 Ошибка, например, неправильно указан идентификатор файла

Программа, которая читает файл с помощью функции 3Fh прерывания INT 21h , может определить момент достижения конца файла анализируя код ошибки, передаваемый в регистре AX.

3.6. Позиционирование

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

Установка файлового указателя

Установить файловый указатель в нужную вам позицию можно с помощью функции 42h прерывания INT 21h :

На входе: AH 42h
AL Метод кодирования смещения:
00h — абсолютное смещение от начала файла;01h — смещение от текущей позиции;02h — смещение от конца файла
BX Идентификатор открытого файла
CX Старший байт смещения
DX Младший байт смещения
На выходе: AX Код ошибки, если установлен флаг переноса CF;Младший байт текущей позиции, если флаг переноса CF сброшен
DX Старший байт текущей позиции

Функция 42h позволяет указывать новое значение указателя либо как абсолютное смещение от начала файла, либо как смещение от текущей позиции, либо как смещение от конца файла. В последних двух случаях используется смещение со знаком. Для указания смещения или абсолютной позиции программа должна задать в регистрах CX, DX соответствующее 32-битное значение.

Что произойдет, если при использовании методов кодирования 01h или 02h попытаться установить указатель позиции до начала файла?

Функция 42h при этом не возвратит признак ошибки, однако если будет сделана попытка прочитать или записать данные, то соответствующая функция чтения/записи завершится с ошибкой.

Определение размера файла

Если использовать метод кодирования 02h и при этом задать нулевое смещение, функция установит указатель на конец файла. Это обстоятельство может быть использовано для определения размера файла в байтах.

Функции библиотеки Borland C++

Стандартная библиотека Borland C++ содержит функции, предназначенные для управления файловым указателем позиции и получения текущего значения этого указателя. Это функции lseek , tell , filelength .

lseek

Функция lseek работает аналогично только что описанной функции 42h. Приведем ее прототип:

Первый параметр определяет файл, для которого выполняется операция позиционирования. Параметр offset определяет смещение. Последний параметр задает метод кодирования смещения. Он может принимать следующие значения, описанные в фале stdio.h:

Значение Описание
SEEK_SET Абсолютное смещение от начала файла
SEEK_CUR Смещение относительно текущей позиции
SEEK_END Смещение относительно конца файла

Функция возвращает величину текущего смещения в байтах относительно начала файла или -1 в случае ошибки. Как и для остальных функций библиотеки, код ошибки находится в глобальной переменной errno.

filelength

Вы, конечно, можете использовать функцию lseek для определения размера файла или текущей файловой позиции. Однако для того чтобы узнать размер файла, лучше воспользоваться специальной функцией filelength :

Эта функция возвращает размер файла в байтах. Файл задается параметром handle. В случае ошибки функция возвращает значение -1.

Для того, чтобы определить текущую файловую позицию, можно использовать функцию tell :

Эта функция возвращает текущую позицию для файла, определенного параметром handle, или -1 в случае ошибки.

Программа SETPOS

Для демонстрации использования функций позиционирования приведем простую программу SETPOS (листинг 3.5), которая для заданного файла и позиции внутри файла отображает содержимое одного байта. Дополнительно программа определяет размер файла и текущую позицию после чтения байта.

Листинг 3.5. Файл setpos\setpos.cpp

3.7. Изменение дескриптора файла

Напомним: атрибуты файла, время и дата его последней модификации, а также размер файла хранятся в дескрипторе файла. Дескриптор файла находится в каталоге.

Операционная система предоставляет вам все необходимые средства для изменения всех полей дескриптора файла, кроме номера начального кластера. Для изменения этого номера вам придется работать с каталогом через таблицу размещения файлов FAT . Для этого нужно сначала считать каталог по кластерам с помощью прерывания INT 25h , модифицировать нужные поля и записать каталог обратно на диск при помощи прерывания INT 26h .

Атрибуты файла

Для работы с полем атрибутов файла предназначена функция 43h прерывания INT 21h :

На входе: AH 43h
AL Выполняемая операция: 00h — чтение атрибутов файла;01h — установка новых атрибутов файла
CX Новые атрибуты файла, если AL = 01h:Биты регистра CX:5 — бит архивации; 4 — каталог;3 — метка диска;2 — системный файл; 1 — скрытый файл; 0 — только читаемый файл
DS:DX Путь к файлу в формате строки ASCIIZ
На выходе: AX Код ошибки, если установлен флаг переноса CF
CX Если не было ошибки, этот регистр содержит атрибуты файла

При изменении атрибутов файла допустимо указывать комбинации битов в регистре CX.

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

Время и дата изменения файла

Для работы с полями времени и даты последней модификации файла предназначена функция 57h прерывания INT 21h :

На входе: AH 57h
AL Выполняемая операция:
00h — чтение даты и времени;01h — установка даты и времени
BX Идентификатор открытого файла
CX Время
DX Дата
На выходе: AX Код ошибки, если установлен флаг переноса CF
CX Если не было ошибки, этот регистр содержит время последнего изменения файла
DX Если не было ошибки, этот регистр содержит дату последнего изменения файла

Для того чтобы изменить время или дату последней модификации файла с помощью этой функции, файл предварительно должен быть открыт. Формат времени и даты для этой функции такой же, как и используемый в дескрипторе каталога (рис. 2.4 и 2.5).

Функции библиотеки Borland C++

Стандартная библиотека Borland C++ содержит функции для чтения и изменения атрибутов файлов, а также времени и даты их последней модификации.

_dos_getfileattr

Для определения атрибутов файла можно использовать функцию _dos_getfileattr :

Эта функция получает атрибуты файла, заданного первым аргументом, и записывает байт атрибутов в младший байт по адресу, указанному вторым параметром.

В случае успешного завершения функция возвращает 0. При ошибке она возвращает код ошибки, полученный от операционной системы и устанавливает глобальную переменную errno в значение ENOENT, что означает отсутствие файла, указанного в параметре path.

_dos_setfileattr

Для изменения атрибутов файла можно использовать функцию _dos_setfileattr :

Параметр attrib может принимать следующие значения:

Значение Описание
_A_ARCH Установка бита архивации
_A_HIDDEN Скрытый файл
_A_NORMAL Обычный файл
_A_RDONLY Только читаемый файл
_A_SUBDIR Каталог
_A_SYSTEM Системный файл
_A_VOLID Метка диска

_dos_getftime

Для определения времени последней модификации файла можно использовать функцию _dos_getftime :

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

_dos_setftime

Если вам надо изменить время или дату последней модификации файла, используйте функцию _dos_setftime :

Параметры этой функции аналогичны используемым в функции _dos_getftime , за исключением того что в качестве второго и третьего параметра применяются не указатели, а непосредственные значения даты и времени.

Программа READONLY

Приведем программу READONLY (листинг 3.6), изменяющую на противоположное значение бита файла атрибутов «Только читаемый» для файла, имя которого передается программе в качестве параметра.

Листинг 3.6. Файл readonly\readonly.cpp

Программа сначала считывает байт атрибутов, затем инвертирует соответствующий бит и устанавливает новое значение байта атрибутов.

3.8. Буферизация

Ввод и вывод для дисков в операционной системе MS-DOS буферизован. Это означает, что данные не сразу записываются на диск, а накапливаются в специальном массиве (буфере). По мере заполнения буфер сбрасывается на диск. При чтении информация заполняет весь входной буфер, независимо от количества байт, которые программа читает из файла. В дальнейшем если программе потребуются данные, которые уже были считаны с диска и записаны во входной буфер, она получит их непосредственно из этого буфера без обращения к диску.

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


Операционная система MS-DOS может создать несколько буферов. Их количество зависит от оператора BUFFERS из файла config.sys . Этот оператор позволяет определить от 2 до 99 буферов. Если файл config.sys не содержит оператора BUFFERS, по умолчанию используются два буфера.

При увеличении количества буферов увеличивается вероятность того, что нужная часть файла уже считана и находится в оперативной памяти. Однако необходимо учитывать, что для хранения буферов расходуется основная оперативная память. Кроме того, с ростом количества буферов увеличивается время, необходимое операционной системе на анализ состояния буферов, что может привести к снижению производительности. Значительное снижение скорости работы наступает при количестве буферов порядка 50.

Еще один способ организовать буферизацию данных для жестких дисков и устройств CD-ROM — использовать драйвер smartdrv.exe . Этот драйвер позволяет создать для диска кеш-память в расширенной памяти.

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

Буферизация данных имеет и свои недостатки. Если в результате аварии в питающей сети или по какой-то другой причине компьютер выключился, то информация, хранящаяся в буферах и не записанная на диск, будет потеряна.

При закрытии файла все буферы, связанные с ним, сбрасываются на диск. Если вам надо сбросить буферы, не закрывая файл, это можно сделать с помощью функции 68h прерывания INT 21h :

На входе: AH 68h
BX Идентификатор открытого файла
На выходе: AX Код ошибки, если установлен флаг переноса CF;
0, если операция выполнена успешно

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

Обратите также внимание на функцию расширенного открытия файлов 6Ch. Эта функция позволяет при открытии файла отменить буферизацию.

3.9. Потоки ввода и вывода

Стандартная библиотека Borland C++ содержит многочисленные функции, использующие собственный механизм буферизации при работе с файлами. Их часто называют функциями потокового ввода/вывода . Такую буферизацию не следует путать с буферизацией, выполняемой операционной системой. Имена всех этих функций начинаются на f — fopen , fclose , fprintf и т. д.

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

Существуют потоки , соответствующие стандартным устройствам ввода, вывода, вывода сообщений об ошибках, стандартному устройству последовательного ввода/вывода и стандартному устройство печати:

Поток Описание
stdin Стандартное устройство ввода
stdout Стандартное устройство вывода
stderr Стандартное устройство для вывода сообщений об ошибках
stdaux Стандартное последовательное устройство ввода/вывода
stdprn Стандартное печатающее устройство

Для использования этих потоков не требуются выполнять процедуру открытия и закрытия.

Для работы со стандартными устройствами ввода/вывода в библиотеках трансляторов языка программирования С имеется соответствующий набор функций, которые должны быть вам хорошо известны — printf, scanf , putchar и т. д. Мы не будем их описывать, так как объем книги ограничен.

Открытие и закрытие потоков

При использовании функций потокового ввода/вывода файлы открываются функцией fopen , а закрываются функцией fclose . Эти функции не только открывают и закрывают файлы (получают и освобождают их идентификаторы), но и, соответственно, создают и уничтожают переменную типа FILE , описанную в файле stdio.h и связанную с данным файлом.

fopen

Для организации потокового ввода/вывода вначале необходимо при помощи функции fopen открыть файл. Функция fopen имеет следующий прототип:

Первый параметр указывает на строку, содержащую путь открываемого файла, второй — на строку режима открытия файла. Возможны следующие режимы:

Режим Операция, для выполнения которой открывается файл
«r» Чтение
«w» Запись
«a» Запись, данные будут добавляться в конец файла

К буквам r, w, a справа могут добавляться буквы t и b.

Буква t означает, что файл будет открыт в текстовом режиме, b — в двоичном. Для двоичного режима не выполняется обработка таких символов, как конец строки, конец файла и т. д.

Строка режима открытия файла может дополнительно содержать символ ‘+’. Этот символ означает, что для файла разрешены операции чтения и записи одновременно.

fclose

Для закрытия файлов, открытых для ввода или вывода потоком, должна использоваться функция fclose :

При закрытии файла освобождаются и сбрасываются на диск все буферы, распределенные этому файлу.

fdopen

Если вы открыли файл с помощью функции open , вы можете создать поток для этого файла, используя функцию fdopen :

В качестве первого параметра используется идентификатор файла, полученный от функции open . Второй параметр аналогичен параметру mode для функции fopen .

Для того чтобы закрыть поток, созданный функцией fdopen , необходимо использовать функцию fclose , а не close .

fileno

Для открытого потока вы можете узнать идентификатор соответствующего файла с помощью функции fileno :

Функция возвращает идентификатор файла, связанного с данным потоком.

fwrite

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

Эта функция записывает в файл stream блоки информации, каждый из которых имеет длину size байт. Количество блоков — count. Данные для записи расположены по адресу buffer.

Если файл открыт в текстовом режиме, каждый символ возврата каретки CR заменяется на два символа — возврата каретки CR и перевода строки LF.

Функция возвращает количество действительно записанных блоков информации без учета замены символа CR в текстовом режиме.

fread

Чтение данных потоком можно выполнить с помощью функции fread :

Эта функция используется аналогично предыдущей. Для распознавания конца файла и обнаружения ошибок после вызова этой функции необходимо использовать функции feof и ferror.

Если при использовании функции fread вы задали значения параметров size или count, равные нулю, функция fread не изменяет содержимое буфера buffer.

fseek

Для позиционирования внутри файла, открытого потоком с помощью функции fopen, предназначена функция fseek :

В этой функции параметр offset задает новое содержимое указателя текущей позиции в файле stream, а параметр origin определяет способ задания новой позиции. Этот оператор может иметь значения, аналогичные используемым в функции lseek :

Значение Описание
SEEK_SET Абсолютное смещение от начала файла
SEEK_CUR Смещение относительно текущей позиции
SEEK_END Смещение относительно конца файла

При открытии файла указатель текущей позиции устанавливается на начало файла. Операции ввода или вывода вызывают увеличение значения этого указателя на количество, соответственно, прочитанных или записанных байт.

Функция fseek позволяет вам установить указатель за конец файла, однако при попытке установит указатель до начала файла функция возвратит признак ошибки — ненулевое значение.

При использовании функции fseek для позиционирования внутри файлов, открытых в текстовом режиме, необходимо учитывать особенность обработки текстовых файлов — автоматическую замену символа возврата каретки CR на пару символов: возврат каретки CR и перевод строки LF. Для текстовых файлов функция fseek будет правильно работать только в следующих двух случаях:

  • если поиск выполняется со смещением offset, равным нулю, при любом значении параметра origin;
  • если поиск выполняется относительно начала файла, причем в качестве смещения offset используется значение, полученное специальной функцией ftell .

ftell

Функция ftell возвращает текущее значение указателя позиции для файла, или -1 при ошибке:

Пара функций ftell и fseek позволит вам правильно организовать позиционирование для файлов, открытых в текстовом режиме.

fgetpos , fsetpos

Есть еще одна возможность организовать позиционирование внутри файлов, открытых потоком — вызов пары функций fgetpos и fsetpos :

Эти две функции используют для запоминания и установки позиции переменную с типом fpos_t, определенным в файле stdio.h. Функция fgetpos записывает в эту переменную текущую позицию в потоке stream. Содержимое переменной затем может быть использовано для установки позиции в потоке с помощью функции fsetpos .

Обе эти функции возвращают нулевое значение в случае успешного завершения работы, или ненулевое — при ошибке.

Форматный ввод и вывод

Среди потоковых функций можно выделить группу функций форматного ввода и вывода. Это такие функции, как fputc , fgetc , fputs , fgets , fprintf , fscanf .

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

fputc

Для записи в поток отдельных байт используется функция fputc :

Байт c записывается в поток stream начиная с текущей позиции. После записи текущая позиция увеличивается на единицу. Функция возвращает записанный байт или значение EOF , которое служит признаком ошибки.

fgetc

Для побайтового чтения содержимого файла, открытого потоком, удобно использовать функцию fgetc :

Эта функция возвращает байт, считанный из потока stream и преобразованный к типу int. После чтения байта текущая позиция в потоке увеличивается на единицу.

При достижении конца файла или в случае ошибок функция fgetc возвращает значение EOF . Однако для проверки на ошибку или конец файла лучше пользоваться специальными функциями ferror и feof. Если вы открыли файл в двоичном режиме, единственный способ определить момент достижения конца файла — использовать функцию feof, так как значение константы EOF может находиться в любом месте двоичного файла.

fputs и fgets

Для работы со строками предназначены функции fputs и fgets .

Функция fputs предназначена для вывода строки в файл, открытый потоком:

Первый параметр — указатель на строку, второй — поток, в который эта строка выводится. Двоичный нуль, закрывающий строку, в выходной файл не копируется. После вывода строки содержимое текущего указателя позиции увеличивается на количество записанных байт.

Для ввода строк из текстового файла удобна функция fgets :

Функция читает байты из потока stream и записывает их в блок памяти, указатель на который задан параметром string, до тех пор, пока не произойдет одно из двух событий — будет прочитан символ новой строки ‘\n’ или количество прочитанных символов не станет равно n-1.

После того, как байты будут прочитаны в блок памяти, в конец строки образованной из этих байт, функция запишет двоичный нуль. Если был прочитан символ новой строки ‘\n’, он тоже будет записан.

Для анализа достижения конца файла или ошибок необходимо использовать функции feof и ferror.

fprintf

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

Эта функция аналогична хорошо известной вам функции форматного вывода на экран printf, с которой обычно начинают изучение языка программирования С. Вспомните такую программу:

Функция fprintf имеет дополнительно один параметр — stream, который определяет выходной поток.

После завершения работы функция возвращает количество записанных байт или отрицательную величину, если при записи произошла ошибка.

fscanf

Для форматного ввода информации из файла можно использовать функцию fscanf , аналогичную известной вам функции scanf :

Эта функция читает данные, начиная с текущей позиции в потоке stream, в переменные, определенные аргументами arg. Каждый аргумент должен являться указателем на переменную, соответствующую типу, определенному в строке формата format.

Функция fscanf возвращает количество успешно считанных и преобразованных в указанный формат полей. Те поля, которые были считаны, но не преобразовывались, в возвращаемом функцией значении не учитываются.

При достижении конца файла функция возвращает значение EOF . Если функция возвратила нулевое значение, это означает, что преобразование полей не производилось.

Буферизация потоков

Рассмотрим теперь функции, управляющие буферизацией для потокового ввода/вывода.

setbuf

Функция setbuf позволяет вам заменить системный буфер на свой собственный:

Параметр buffer должен указывать на подготовленный пользователем массив, имеющий размер BUFSIZ байт. Константа BUFSIZ описана в файле stdio.h.

setvbuf

Функция setvbuf позволяет программе не только указать свой буфер, но и задать его размер:

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

Параметр buffer должен указывать на подготовленный программой буфер размером size байт. Этот буфер будет использоваться для работы с потоком stream.

Параметр mode может принимать значения _IOFBF , _IOLBF , _IONBF . Если mode равен _IOFBF или _IOLBF, параметр size указывает размер буфера. Если параметр mode равен _IONBF, буферизация не используется, а параметры buffer и size игнорируются.

Параметры _IOFBF и _IOLBF эквивалентны друг другу.

Если в качестве адреса буфера buffer задать значение NULL, функция автоматически закажет буфер размером size.

Функция setvbuf возвращает нуль при успешном завершении и ненулевую величину, если указан неправильный параметр mode или неправильный размер буфера size.

Для чего может понадобиться изменение размера буфера?

Главным образом — для сокращения времени, необходимого для позиционирования магнитных головок при выполнении операций одновременно над несколькими файлами, например, при копировании файлов, слиянии нескольких файлов в один и т. д.

fflush

При закрытии потока функцией fclose содержимое буфера записывается на диск. Если программе необходимо выполнить запись содержимого буфера на диск без закрытия файла, она может воспользоваться функцией fflush :

Эта функция возвращает нуль при успешной записи буфера на диск, а так же в тех случаях, когда поток либо совсем не имеет буфера, либо открыт только для чтения. При ошибке возвращается значение EOF .

Если поток открыт только для чтения, функция fflush очищает содержимое буфера, связанного с этим потоком.

Программа BUFCOPY

В качестве примера приведем текст программы BUFCOPY (листинг 3.7), копирующей содержимое текстового файла.

Программа копирует этот файл три раза. В первый раз она использует буфер стандартного размера, затем увеличивает размер буфера в десять раз, и наконец, копирует файл без использования механизма буферизации. Каждый раз программа измеряет продолжительность копирования файла с помощью функции clock, входящей в состав стандартной библиотеки Borland C++.

Листинг 3.7. Файл bufcopy\ bufcopy.cpp

3.10. Другие функции для работы с файлами

В задачу данной книги не входит описание всех функций стандартных библиотек трансляторов Borland C++, Microsoft Quick C или аналогичных, предназначенных для работы с дисками и файловой системой. Но мы приведем еще несколько интересных и полезных на наш взгляд функций.

Как мы уже отметили, программа может использовать два режима ввода/вывода для файлов — текстовый и двоичный. Переключение этого режима для открытого файла можно выполнять с помощью функции setmode :

Первый параметр — идентификатор файла. Второй параметр может принимать два значения:

Значение Описание
O_TEXT Установить текстовый режим
O_BINARY Установить двоичный режим

Функция setmode должна вызываться перед началом операций ввода или вывода в открытый файл.

Мы рассказывали о позиционировании внутри файла. Если вам нужно просто установить указатель позиции на начало файла, открытого для потока, вы можете воспользоваться функцией rewind :

Если вам нужно переназначить ввод или вывод для стандартных потоков (stdin, stdout, stderr), вы можете использовать функцию freopen :

Функция freopen закрывает файл, с которым был связан поток stream, и переназначает этот поток на файл, определенный параметром filename. Параметр mode задается так же, как и для функции fopen .

Можно переназначить идентификатор файла, открытого функцией open . Для этого можно воспользоваться одной из двух функций — dup или dup2 :


Первая функция связывает с открытым файлом еще один идентификатор. Она возвращает этот идентификатор при успешном завершении. В случае ошибки она возвращает значение -1.

Новый идентификатор может быть использован для любых операций над файлом.

Функция dup2 переназначает идентификатор файла handle2, связывая его с тем же файлом, которому соответствует идентификатор handle1. Если во время вызова функции dup2 с идентификатором handle2 связан какой-либо открытый файл, этот файл закрывается. В случае успешного завершения функция dup2 возвращает нулевое значение. Если произошла ошибка, возвращается значение -1.

3.11. Таблица открытых файлов

В предыдущем томе при описании векторной таблицы связи мы говорили о том, что для всех открытых файлов MS-DOS хранит различную информацию в специальной таблице. Ее адрес находится в поле file_tab векторной таблицы связи.

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

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

Вы можете самостоятельно экспериментировать с этой таблицей. Можно, например, попробовать создать несколько идентификаторов для какого-либо файла и посмотреть после этого содержимое поля, в котором находится количество идентификаторов, связанных с данным файлом.

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

Однако не обольщайтесь — все что связано с таблицей файлов, отсутствует в документации по операционной системе MS-DOS. Используя эту таблицу для определения списка кластеров или для каких-либо других целей, вы рискуете потерять совместимость с последующими версиями операционной системы.

3.12. Обработка критических ошибок

Операционная система MS-DOS позволяет программам устанавливать собственный обработчик критических ошибок аппаратуры. Мы уже говорили о том, что вектор 0000h:0090h, соответствующий прерыванию INT 24h , содержит адрес обработчика критических ошибок. Этот обработчик получает управление от операционной системы, когда драйвер какого-либо устройства обнаруживает ошибку аппаратуры.

Обратите внимание на то, что обработчик критических ошибок не вызывается при работе с диском через прерывания INT 25h или INT 26h. Тем более, он не вызывается при работе с диском на уровне прерывания INT 13h .

При запуске программы операционная система MS-DOS копирует адрес обработчика в префикс сегмента программы PSP, а после завершения работы программы — восстанавливает его из PSP.

Стандартный обработчик MS-DOS выводит на экран сообщение:

Если ваша программа должна сама обрабатывать ошибки аппаратуры, она может установить свой собственный обработчик критических ошибок.

Анализ регистров

Когда обработчик получает управление, регистры процессора содержат информацию, необходимую для определения причины и места появления ошибки:

Регистр Содержимое
AH Информация об ошибке.Бит 0: тип операции:
0 — чтение, 1 — запись
Биты 1,2: область диска, где произошла ошибка:
00 — системные файлы;
01 — область FAT ;
10 — область каталога;
11 — область данных.
Бит 3: если равен 1, возможен выход с кодом FAIL
Бит 4: если равен 1, возможен выход с кодом RETRY
Бит 5: если равен 1, возможен выход с кодом IGNORE
Бит 6 зарезервирован, равен 0
Бит 7 тип устройства: 0 — диск; 1 — символьное устройство
AL Номер диска (если бит 7 регистра AH равен 0)
DI Код ошибки (биты 0. 7, остальные биты не определены)
BP:SI Адрес заголовка драйвера устройства, в котором произошла ошибка

Обработчик критических ошибок не должен пользоваться функциями MS-DOS с кодами, большими чем 0Ch (из-за того, что функции MS-DOS не реентерабельны).

Программа обработки критических ошибок может вывести на экран сообщение об ошибке и запросить оператора о необходимых действиях. Ей разрешено также получить дополнительную уточняющую информацию об ошибке с помощью функции 59h прерывания INT 21h или узнать версию MS-DOS с помощью функции 30h этого же прерывания.

Дополнительная информация об устройстве, в котором произошла ошибка, может быть получена с использованием адреса заголовка драйвера устройства, который передается операционной системой при вызове обработчика в регистрах BP:SI.

Анализ стека

Для определения номера функции MS-DOS, в которой произошла критическая ошибка, программа-обработчик может выполнить анализ стека. Когда обработчик получает управление, стек имеет следующую структуру:

Адрес возврата в DOS для команды IRET

FLAGS

Содержимое регистров программы перед вызовом INT 21h

AX, BX, CX, DX, SI, DI, BP, DS, ES

Адрес возврата в программу, вызвавшую функцию DOS

FLAGS

Выполнив анализ регистра AH, можно определить номер функции MS-DOS, при вызове которой произошла ошибка, а зная содержимое остальных регистров — и все параметры этой функции.

Код действия

После выполнения всех необходимых действий программа обработки критических ошибок должна возвратить в регистре AL код действия, которое должна выполнить операционная система для обработки данной ошибки:

Код Описание
Игнорировать ошибку
1 Повторить операцию
2 Завершить задачу аварийно, используя адрес завершения, записанный в векторе прерывания INT 23h
3 Вернуть программе управление с соответствующим кодом ошибки

При открытии файлов с помощью функции 6Ch программа может заблокировать вызов обработчика критических ошибок.

Функции библиотеки Borland C++

Для составления программы обработки критических ошибок вы можете воспользоваться языком ассемблера или функциями стандартной библиотеки Borland C++ с именами _dos_getvect , _dos_setvect , _chain_intr . Однако лучше всего использовать специально предназначенные для этого функции _harderr , _hardresume и _hardretn .

_harderr

Функция _harderr предназначена для установки нового обработчика критических ошибок, она имеет следующий прототип:

Параметр handler — указатель на новую функцию обработки критических ошибок.

_hardresume

Функция _hardresume и описанная ниже функция _hardretn должны быть использованы в обработчике критических ошибок, установленном функцией _harderr .

Функция _hardresume возвращает управление операционной системе, она имеет прототип:

Параметр result может иметь следующие значения (в соответствии с необходимыми действиями):

Значение Описание
_HARDERR_ABORT Завершить программу аварийно
_HARDERR_FAIL Вернуть код ошибки
_HARDERR_IGNORE Игнорировать ошибку
_HARDERR_RETRY Повторить операцию

Эти параметры описаны в файле dos.h.

_hardretn

Функция _hardretn возвращает управление непосредственно программе, передавая ей код ошибки, определяемый параметром функции error:

При этом программа получает код ошибки error после возврата из вызванной ей функции MS-DOS. Если ошибка произошла при выполнении функции с номером, большим чем 38h, дополнительно устанавливается флаг переноса. Если номер функции был меньше указанного значения, в регистр AL записывается величина FFh.

Функция обработки критических ошибок

Функция обработки критических ошибок handler имеет следующие параметры:

Первый параметр — код ошибки устройства. Он равен содержимому регистра AX при вызове обработчика прерывания INT 24h . Аналогично, параметр errcode соответствует содержимому регистра DI — код ошибки. Третий параметр devhdr — это указатель на заголовок драйвера устройства (передаваемый в регистрах BP:SI).

Программа CRITERR

Для демонстрации использования функций установки обработчика критических ошибок приведем программу, которая пытается создать каталог на диске А:. Эта программа сама обрабатывает критические ошибки, запрашивая у оператора информацию о необходимых действиях.

Whatis.Ru

Информация о компьютерах доступным языком
Назад на сайт

Страниц: 1 2

#26 18-01-2011 19:35:39

Re: . Введение в Ассемблер

Программа DEBUG

Программируем под DOS на ассемблере, используя виндовый DEBUG.

Программа DEBUG — мощный отладчик, входящий в состав Windows. Для запуска — жмём [Win+R] и вводим DEBUG. Перед нами мигающий курсор. Введём знак вопроса ? и получим список команд:

— A (assemble) — Создание двоичного кода процессоров 8086 непосредственно в памяти.
— С (compare) — Сравнение двух блоков памяти.
— D (dump) — Просмотр содержимого заданного диапазона адресов памяти.
— E (enter) — Ввод данных в память по заданному адресу.
— F (fill) — Заполнение адресов в области памяти заданными значениями.
— G (go) — Выполнение загруженной программы.
— H (hexadecimal) — Выполнение шестнадцатеричных арифметических операций.
— I (input) — Считывание и вывод на экран одного байта из указанного порта ввода.
— L (load) — Загрузка файла или содержимого сектора диска в память.
— M (move) — Копирование содержимого одного блока памяти в другой.
— N (name) — Задание имени исполняемого файла, L (load) или W (write).
— O (output) — Вывод байта в порт вывода.
— P (proceed) — Выполнение цикла, инструкции, прерывания или процедур.
— Q (quit) — Выход из Debug, без сохранения тестируемого файла.
— R (register) — Редактирование содержимого регистров ЦПУ.
— S (search) — Поиск в области памяти по шаблону.
— T (trace) — Выполнение одной инструкции с выводом содержимого регистров.
— U (unassemble) — Дезассемблирование и просмотр исходного кода программы.
— W (write) — Запись файла на диск.

Подробное описание команд с примерами можно найти в справке винды ([Win+F1]debug).

Теперь, запустим DEBUG и просмотрим, что у нас в регистрах. Вводим команду «R». Как видим, значение всех регистров процессора равняется нулю:

AX, BX, CX, DX = 0000

Мы можем вносить требуемые значения в регистры.

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#27 18-01-2011 19:39:28

Re: . Введение в Ассемблер

Пишем прогу на ассемблере.

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

1) Создадим *.сом в программе DEBUG
2) Дизассемблируем его, при помощи того-же DEBUG
3) Полученные 16-тиричные значения и есть инструкции, которые выполняет процессор

Итак, начнём с создания *.сом, который выведет символ на экран. Запустим DEBUG и введём команду «А». Дальше, «топчем клаву» как на рисунке:

Чтоб вывести символ на экран, в регистр AH помещается 02H, а в DL — код выводимого символа, плюс 30H. Далее вызываем прерывание-DOS INT 21H (вывод на экран), и закрываем программу дёрнув прерывание INT 20H (exit). Всё, что находится после INT 20H игнорируется процессором.

В листинге дизассемблирования указывается сегмент памяти, в который была загружена наша программа (13F2) и смещение внутри сегмента 100H, обязательное для СОМ-файлов. Необходимо помнить, что прикладные программы загружаются в первую-свободную область памяти, поэтому у Вас значение 13F2 может быть другим, в зависимости от свободной памяти.

Следующим столбцом в дизассемблерном листинге идут 16-тиричные значения (выделены серым), которые представляют собой непосредственные инструкции процессору. Ниже — уже ничего нет, ..только ядро. Вообще-то есть ещё интерператор 16-тиричных чисел в двоичные, но он невсчёт. В конечном виде наша программа TEST_PROGA.COM обрабатывается процессором в таком вот виде:

Но вернёмся в реальность. Чтоже дают нам эти опыты. . а то, что программы написанные на ассемблере имеют наименьший размер, по сравнению с другими языками программирования. В качестве примера возьмём программу (окно с одной кнопкой в центре) написанную на языках высокого уровня. После компиляции получим такие размеры файла:

C++ Builder 4 — 22kb
Delphi 5 — 291kb
Delphi 5 + библиотека KOL — 26kb
Ассемблер MASM — около 3kb

Так, что смотрите и делайте выводы, что лучше использовать. Программу таких размеров можно легко внедрить в свободное пространство любого исполняемого файла. э-э-э чтот меня не туда занесло

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#28 19-01-2011 01:37:15

Re: . Введение в Ассемблер

..а вон чё WinHex показывает:

Да такой код можно хоть-куда пихнуть, ..к примеру в заголовок EXE-файла. Там столько свободного пространства, что можно слона разместить. 200-300h байт всегда найдётся. ..а нам больше и не надо, вешеприведённая TEST_PROGA.COM весит всего 17 байт (17 символов в исходнике). 300h — это уже 768 символов, ..целый материк, свобода мысли.

Достаточно перехватить управление в коде, перевести его на себя и замутить чё-нить. Объясню «в двух словах»: как это делается! ..Пишется прога на асме (желаемого характера), которая привычным движением руки вставляется в WinHex — в начало, середину, или «конец» EXE-файла жертвы. Желательно, конечно, в начало. после «PE»-заговка. Самый оптимальный вариант — после перечисления DLL-лок (инклудов). Там как-раз достаточно места, и быстрее примем управление. Фрагмент внедрения в CHKDSK.EXE нашей «Бацилы»:

Если Вы запустите такой инфицированный CHKDSK.EXE, то сначала отработает наш код, а только потом запустится сам chkdsk. . но не всё так просто. Там есть своя «Техника внедрения». Дизассемблируется chkdsk.exe, и в листинге ищется команда JMP (переход на метку). Перехватываем этот JMP и после исполнения основного кода «бацилы» передаём управление обратно на эту метку, командой RET ассемблера в коде нашей программы.

В качестве бонуса, вешаю в скрепке пару примеров программ на ассемблере.

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#29 19-01-2011 12:49:58

Re: . Введение в Ассемблер

Что нужно знать о прерываниях

Как уже отмечалось, прерывания бывают двух типов — DOS и BIOS. Но что они из себя представляют. Попробуем ответить на этот вопрос.

Прерывания — это вовсе не прерывания, а готовые программы (процедуры), которые компьютер вызывает для выполнения определенной задачи. Внутри этих «программ-прерываний» имеются вложенные подпрограммы, каждая из которых выполняет определённую задачу. Эти подпрограммы вызываются векторами прерываний!

Программа-прерывание вызывается по номеру (к примеру INT 13H, дисковый ввод/вывод BIOS), где в качестве «параметра» заносится её вектор, т.е. подпрограмма. Например, для вывода информации на экран, нам нужно воспользоваться сервисом-DOS и запросить прерывание с номером INT 21H. Подпрограмму 02H необходимо указать в регистре AH:

При включении компьютера, BIOS выстраивает таблицу векторов прерывания в первых 1024 байтах памяти. Этот килобайт памяти начинается с адреса 0000:0000 и заканчивается 0000:0400 (1024d = 0400h). Откроем в WinHex память, и взглянем на эту таблицу:

Каждый вектор имеет длину 4 байта. Вектор для прерывания 0 начинается с ячейки 0000:0000, прерывания 1 — с 0000:0004, 2 — с 0000:0008, 3 — с 0000:000C и т.д.

Если посмотреть на четыре байта, начиная с адреса 0000:0020, в которых содержится вектор прерывания 8H (прерывание времени суток), то Вы обнаружите там A5FE00F0. Имея ввиду, что младший байт слова расположен сначала, это 4-байтное значение переводится в F000:FEA5. Это стартовый адрес программы ПЗУ, выполняющей прерывание 8H.

Если размер таблицы 1024 байт, а один вектор имеет длинну 4 байта, то выходит чтобы найти общее кол-во векторов нужно 1024/4. . получаем 256. Таким образом, в общем пространстве имеется место для 256 векторов (подпрограмм), которые «разбиваются» по всем номерам прерываний BIOS и DOS. В каждом прерывании может находиться до 20 подпрограмм.

Прерывания с номерами до INT 20H обслуживает BIOS. Номера прерываний DOS лежат в пределах от 20 до 32H:

Прерывания BIOS (без подфункций) Прерывания DOS (без подфункций)

00h: Деление на ноль. 20h: Завершить программу
01h: Пошаговое. 21h: Сервис DOS
02h: Немаскируемое. 25/26h: Абсолютные чтение/запись диска
03h: Точка прерыв. 27h: Завершиться, но остаться резидентным
04h: Переполнение. 28h: Квант времени DOS (НЕТ В ДОКУМЕНТАЦИИ)
05h: Печать экрана. 2eh: Выполнить команду DOS (НЕТ В ДОКУМЕНТАЦИИ)
06h: (резерв) 2fh: Мультиплексное прерывание (спулинг печати)
07h: (резерв) 22h: Адрес завершения
08h: Таймер. 23h: Адрес Control-Break
09h: Клавиатура. 24h: Адрес обработчика критических ошибок
0Ah-0dh: (hdwr ints)
0Eh: Дискета.
0Fh: (hdwr int)
10h: Видео сервис.
11h: Список оборудования.
12h: Размер исп.памяти.
13h: Дисковый в/в.
14h: В/в последовательный порт
15h: Расшир.сервис AT.
16h: В/в клавиатуры.
17h: В/в принтера.
18h: ROM-BASIC.
19h: Загрузка.
1Ah: В/в таймера.
1Bh: Прерывание клавиатуры.
1Ch: Прерывание по таймеру
1Dh: Видео параметры
1Eh: Параметры дискет
1Fh: Символы графики

Приведу краткое описание прерывания-BIOS INT 13H:

INT 13H: дисковый ввод-вывод
Этот сервис предоставляет прямой доступ к адаптерам дискеты и жёсткого диска. Рекомендуется там, где это возможно, использовать INT 25H и INT 26H, чтобы предоставить драйверам устройств-DOS выполнять всю низкоуровневую обработку. Разумеется, для таких операций, как форматирование диска или установка защиты от копирования, прерывание INT 13H может оказаться единственной альтернативой.

подфункции: 00H сброс контроллера 08H дать парам диска 10H проверить готовность
01H дать статус 09H иниц табл парам 11H рекалибрация
02H читать секторы 0aH длинное чтение 14H диагностика
03H писать секторы 0bH длинная запись 15H дать тип диска
04H верификация 0cH искать цилиндр 16H изменить статус
05H форматир дорожку 0dH альтерн сброс 17H уст тип диска

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#30 20-01-2011 13:39:20

Re: . Введение в Ассемблер

Использование сервисов DOS. Прерывание INT 21H.

После загрузки MS-DOS в память, операционная система предоставляет нам свои услуги, в виде прерывания INT 21H (сервисы DOS). Используя это прерывание в своих программах мы можем выполнять около 80-ти операций. Не буду перечислять все функции этого прерывания, остановлюсь только на наиболее значимых:

00H: завершить программу 27H: читать блок произвольного файла
01H: ввод с клавиатуры 28H: писать блок произвольного файла
02H: вывод на дисплей 2aH: дать дату DOS
05H: вывод на принтер 2cH: дать время DOS
09H: Выдать строку 2fH: дать текущий DTA
0dH: Сбросить диск 30H: дать номер версии DOS
0eH: Выбрать умалчиваемый диск DOS 31H: завершиться и остаться резидентным — KEEP
0fH: открыть файл через FCB 32H: дать дисковую информацию DOS
10H: Закрыть файл через FCB 35H: дать вектор прерывания
13H: Удалить файл через FCB 36H: дать свободную память диска
14H: читать файл через FCB 39H: создать новое оглавление — MKDIR
15H: писать файл через FCB 40H: Писать в файл через описатель
16H: создать файл через FCB 48H: дать размер памяти
17H: Переименовать файл через FCB 56H: Переименовать/переместить файл
25H: установить вектор прерывания 5bH: создать новый файл

Функция 09H прерывания INT 21H (вывод строки символов на экран).

Процедуры, которые выводят целые строки символов на экран — очень полезны, но они могут накладывать ограничения на содержимое выводимой строки. Надо обращать внимание на то, какие управляющие коды (табуляция, пробел и т.п.) интерпретируются, а какие нет.

Как уже говорилось, при вызове прерывания необходимо указать значение функции в регистре AH (в нашем случае — 09H). Далее, вводятся инструкции и вызывается само прерывание. Регистр DX должен указывать на первый символ строки (т.е. расположение текстовой строки). В конце строки обязательно должен присутствовать символ «$». Это означает, что сам символ «$» не может входить в строку. Сама строка может быть любой длины.

Чтоб перевести текст на следующую строку, в конце указываются спец-символы 0AH (перевод строки), и 0DH (возврат каретки). Без них — текст будет располагаться в одну строчку.

. пришло время скачать инструментарий, чтоб проводить эксперементы. Программы, целиком написанные на ассемблере, транслируются в машинный код при помощи ассемблера. Под DOS-ом большой популярностью пользуется пакет TASM, для винды — MASM от Microsoft. С ним конкурирует FASM, поддерживающий более естественный синтаксис. Его и качаем с сайта WASM.RU. Он отличается от предшественников тем, что это и транслятор и компилятор в одном флаконе. Вводиш в окне инструкции, жмёш F9 и на выходе получаеш готовый исполняемый файл! Очень удобно. особенно для начинающих!

. значит скачали FASM 1.67, и в поле набиваем текстовые строки нашей программы. Вот пример:

Программа, приветствующая WHATIS из досовского окна.

use16 ; DOS работает в 16-тиразрядном режиме
org 100h ; Делаем СОМ-файл с начальным смещением 100h

mov AH,09h ; Суём в регистр AH функцию 09h прерывания 21h
mov dx,text ; В регистре DX указываем от куда брать строку
int 21h ; Вызываем прерывание 21h
ret ; Возвращаемся туда, от куда были вызваны

; Текстовая строка (адрес для регистра DX)
text db ‘Hello, WHATIS. $’


. если нужно вывести несколько строк, то можно сделать так:

. на выходе — СОМ-файл размером 63 байт. Таким способом можно выводить текстовые строки из памяти, которые содержат информацию об оборудовании, объёме свободной памяти и т.д. и т.п.

Программа составляется из нескольких-подобных участков кода, которые выполняют определённые задачи. На каждый участок кода ставится индивидуальная метка, к которой можно обратиться с любого места программного кода. Эти участки объединяются в модули, а несколько модулей образуют законченный софт, . в чём мы убедимся позже.

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#31 21-01-2011 12:22:44

Re: . Введение в Ассемблер

Определение Стека

Стек — это такое место хранения данных, которые при надобности можно обратно восстановить. В нём хранятся адреса переходов, различные данные и т.д. Регистр SP указывает на адрес вершины стека. Регистр ВР содержит адрес, начиная с которого в стек вносится или забирается информация.

Представьте, что одна подпрограмма вызывает другую. Вызываемая подпрограмма завершила свое выполнение, теперь ей надо передать управление подпрограмме, которая её вызвала. Как-раз адрес следующей команды (после вызова подпрограммы) находится на верхушке стека, в регистре SP.

Стек — как штанга с блинами: засунули адрес, засунули второй, засунули третий, и достают адреса в порядке обратном засовыванию, ..сначала третий, второй, первый. Следовательно, подпрограмма, может вызвать ещё одну подпрограмму, а она в свою очередь ещё одну и так, сколько хошь, всё ограничивается только размером стека.

Таким образом, программа продолжит выполнение инструкций только после того, как отработают ПОДпрограммы, принявшие управление:

В стек можно заносить не только адреса, но и данные, текстовые строки и т.п. Команда ассемблера PUSH помещает данные в стек, а команда POP снимает их от туда. При использовании стека наша программа «Hello, Whatis. » примет следующий вид:

Здесь, мы закинули в стек вторую строчку текста, вывели на экран первую, а потом извлекли из стека вторую. Дело в том, что регистр не может хранить сразу два разных значения, поэтому перед тем как внести в него, нужно сохранить имеющееся, дабы не потерять всё.

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

#32 24-01-2011 12:34:02

Re: . Введение в Ассемблер

Память 16-тиразрядных систем (DOS).

Самое главное преимущество ассемблера состоит во взаимодействии с памятью. Программировать на ассемблере не зная, как устроена память — бессмысленно.

В DOS — память сегментная. Вся память делится на сегменты по 64К, и адрес задаётся форматом «сегмент:офсет». Сегмент — задаёт порядковый номер сегмента, а офсет — смещение в этом сегменте. Это объяснение для 16-тиразрядных программ (32-хразрядные обсудим позже).

На рис. общая память, разделённая на сегменты по 64kb. Здесь — максимум 65536 сегментов:

;; 16 двоичных разрядов — это 1111 1111 1111 1111, или 65535d (FFFFh).
;; 65535 * 64Кб = 4 194 240Кб (или 4096Мб, или 4Гб памяти).

С помощью 16 бит можно адресовать только 65536 байт памяти и 65536 сегментов. Например, 0000:4012 это означает: сегмент 0, смещение 4012. Чтобы узнать, что находится в том адресе, вы сначала переходите на сегмент 0, а затем в сегменте смещаетесь на 4012.

Память 32-хразрядных систем (WIN-32).

В 32-хразрядном Windows (95 и выше) Вы всё еще имеете сегменты, но вам не нужно заботиться о них, потому, что они уже не 64kb (как в 16-разрядном), а 4 Гб. Это называеся плоской моделью памяти (flat). Здесь есть только смещения и они теперь 32-разрядные (в диапазоне от 0 до 4 294 967 295). Каждая ячейка в памяти указывается смещением.

Но 4ГБ может и не быть на машине, поэтому эта память называется виртуальной. Мало того, каждый процесс выполняется в своём виртуальном адресном пространстве, . а это значит, что никакой другой процесс не сможет получить доступ к вашей памяти. Для этого существуют специальные API функции.

Память 0-0000FFFF не используется и служит для выявления нулевых указателей, значит, если вы укажете адрес 0000С567, то он будет считаться нулевым. Любая попытка обратится к этой памяти приводит к ошибке. Память выше 80000000 одна для всех процессов. В этой памяти находится код нулевого кольца, структуры ядра, код планировщика задач, код драйверов, диспетчер ввода вывода, таблица прерываний и т.д. Любая попытка обратиться к памяти ядра приводит к ошибке и к немедленному завершению приложения.

Память в диапазоне 00001000-7FFFFFFF доступна для 3 кольца (т.е. для вашего приложения). С ней Вы, что хотите то и делаете, в неё также грузятся DLL-ки.

Если Вам даётся 2ГБ памяти, то это не означает, что вы можете обратиться к любому участку памяти. Для того чтобы получить доступ к некоторому участку памяти надо сначала её зарезервировать. Минимальный размер выделяемой памяти — страница, равна 1000h байтам (1000h байт = 4096d байт, или 4КБ). Даже если вы захотите выделить 5 байт, то всё равно выделится 4КБ. Думаю, вы не столкнётесь с тем, что вам надо будет выделять память. Это нужно при работе с файлами для того, что бы в эту память читать файл.

Болтовня ничего не стоит. Покажите мне код.. (Linus Torvalds)

«Assembler IBM PC 7. Лабораторная работа № 2. Системные функции dos ввода-вывода информации. Обработка строковых переменных»

7.1. ЦЕЛЕВЫЕ УСТАНОВКИ

· Освоение стандартных способов ввода-вывода DOS.

· Разработка программ по обработке символьной информации с использованием строковых команд.

7.2. МЕТОДИЧЕСКИЕ РЕКОМЕНДАЦИИ

7.2.1. ВЫЗОВЫ ФУНКЦИЙ MS-DOS ДЛЯ ВВОДА-ВЫВОДА СИМВОЛЬНОЙ ИНФОРМАЦИИ

Для того чтобы написать простую, но законченную программу, необходимо знать три вещи – как вводить данные, как выводить результат и как остановить выполнение программы. В языках высокого уровня имеются специальные операторы ввода/вывода, которые позволяют в удобной форме реализовать эти функции. В системе команд процессора ix86 также имеются команды ввода/вывода, но они реализуют эти операции на самом низком, физическом уровне, т.е. обеспечивают обращение к портам ввода/вывода по конкретным адресам. Для обеспечения ввода/вывода информации на этом уровне программист должен знать номера портов каждого устройства, а также протоколы или алгоритмы обслуживания этих устройств. Операционная система MS DOS реализует ряд сервисных функций ввода/вывода на логическом уровне, которые выступают как пронумерованные функции прерывания Int 21h. При этом прикладная программа пользователя должна сообщить необходимые для данной функции параметры и передать управление DOS, которая и осуществит все необходимые операции по управлению устройством на физическом уровне (где-то, возможно, обратится за помощью к BIOS), а затем вернёт управление прикладной задаче, сообщив, успешно ли завершилась операция или же была допущена ошибка.

Прерывания, в основном, можно разделить на два основных типа: аппаратные (hardware) и программные (software interrupt). Аппаратные прерывания вызываются сигналами от периферийных устройств, требующими обслуживания процессором, а программные, через посредство команды Int, вызывающей какую-либо сервисую функцию (процедуру) DOS или BIOS. Перечень функций, выполняемых операционной системой DOS, подробно изложен в п. 3.

Упрощенная схема обработки прерывания изображена на рис. 2.1. Процессор выполняет команду прерывания, используя таблицу векторов, где содержатся все адресные указатели обработчиков (аппаратных и программных) прерываний. Действия процессора при переходе на выполнение подпрограммы-обработчика (инициируемое командой Int n) и последующем возврате обратно (при встрече команды Iret) в точку выхода из основной программы показаны на рис. 2.1 цифрами в кружках. Одно и то же прерывание может выполнять несколько различных функций, код которых помещается в регистрah, а дополнительные параметры заносятся в другие регистры РОН. Возвращаемая обработчиком информация содержится в регистре al или ax, если флаг cf=0. Флаг cf устанавливается в 1, если произошла какая-либо ошибка, код которой заносится в регистр ax (так называемый код возврата ошибки). Возможные коды ошибок приводятся в руководствах по DOS [4, 10, 12].

Рис. 2.1. Упрощенная схема обработки программного прерывания Int n

Функции информационного обмена MS DOS в своём развитии изменялись от специализированных программ обмена для каждого типа устройства на основе блока управления файлами FCB (File ControlBlock) до унификации обмена на основе файловой системы через дескрипторы. Дескриптор или логический номер файла идентифицирует файл или устройство, с которым должна работать прикладная программа. Это упрощает программирование операций ввода/вывода, т.к. позволяет осуществлять обмен информации независимо от природы файла (устройства). Существует пять стандартных дескрипторов файлов, которые предоставляются прикладной программе:

· – стандартный ввод с консоли (обычно клавиатура);

· 1 – стандартный вывод на консоль (обычно экран дисплея);

· 2 – устройство вывода ошибок (всегда дисплей);

· 3 – внешнее устройство обмена AUX (асинхронный адаптер COM1);

· 4 – стандартный принтер (первый параллельный порт LPT1).

Стандартный ввод (как и стандартный вывод) можно перенаправить средствами DOS на любое устройство или в файл, а стандартная ошибка всегда связана с экраном (обычно дескриптор 2 используют для вывода диагностических сообщений). Перенаправление ввода или вывода программы осуществляет командный процессор Command.com. Если, допустим, в программе prog предусмотрен ввод данных через дескриптор стандартного ввода ²0², а вывод данных через дескриптор вывода ²1², то при обычном запуске программы командой prog.exe программа будет требовать входные данные с клавиатуры и выводить результаты своей работы на экран. Если, однако, при запуске программы использовать символ перенаправления

то система сама создаст файл file.txt, и весь вывод программы будет записан в этот файл. Ввод по-прежнему будет осуществляться с клавиатуры. Запуск программы командой

заставит программу выполняться в режиме ввода информации из файла file.dat и вывода в файл file.txt. Ни экран, ни клавиатура использоваться не будут. Сама программа ничего не знает об этих перенаправлениях – она во всех случаях обращается к стандартному устройству ввода данных и к стандартному устройству вывода данных. Просто DOS как бы подставляет ей на входе и выходе другие устройства.

7.2.2. ВВОД С КЛАВИАТУРЫ СИМВОЛЬНОЙ ИНФОРМАЦИИ

7.2.2.1. Буфер ввода данных с клавиатуры

Нажатие любой клавиши клавиатуры вызывает сигнал аппаратного прерывания (прерывания с типом 09h), заставляющий процессор прервать исполняемую программу и перейти на подпрограмму обработки прерывания от клавиатуры. Обработчик прерывания формирует двухбайтовый код с последующей засылкой его в кольцевой буфер ввода данных с клавиатуры, располагающийся по адресу 0040h:001Eh в системной области оперативной памяти. Для алфавитно-цифровых клавиш старший байт этого кода представляет scan-код клавиши (условный номер клавиши на клавиатуре), а младший – ASCII-код клавиши, т.е. 8-битовый код закреплённого за этой клавишей символа.

Заполнение буфера клавиатуры, рассчитанного на 15 слов или ударов по клавишам, происходит по мере нажатия клавиш и не связано с выполнением текущей программы. Если программе требуется ввести с клавиатуры определённый символ (или строку), она с помощью соответствующей системной функции DOS обращается к буферу ввода и, при наличии в нём данных, передаёт первый из поступивших в этот буфер символов в программу. Дело в том, что запись и считывание кодовых слов в буфер клавиатуры соответствует принципу FIFO (first in – first out, первым вошёл – первым вышел), поэтому считывание символа из буфера освобождает место для ввода последующих. Если к моменту вызова функции DOS буфер ввода оказывается пуст, DOS будет непрерывно опрашивать его состояние, ожидая появления в буфере очередного кода, а исполнение программы приостанавливается до нажатия клавиши.

7.2.2.2. Системные функции DOS ввода данных с клавиатуры

DOS предоставляет несколько способов ввода данных с клавиатуры [4, 5, 7, 11, 12, 13, 14]:

¨ использование группы функций Int 21h (01h, 06h, 07h, 08h, 0Ah¸0Ch), обеспечивающих посимвольный ввод с клавиатуры в разных режимах;

¨ обращение к клавиатуре, как к файлу, с помощью функции 3Fh.

Функции DOS, осуществляющие ввод с клавиатуры, различаются друг от друга некоторыми другими важными характеристиками, которые приведены в табл. 2.1.

Сравнительная характеристика функций DOS ввода с клавиатуры

Номер функции DOS

01h

06h

07h

08h

0Ah

0Bh

Ch

Реакция на Ctrl+C

Ожидание нажатия клавиши

Ввод расширенных кодов ASCII

Ввод кодов с помощью Alt/цифра

Эхо-символы. Отображение вводимого символа на экране.

Реакция на Ctrl+C. Аварийное завершение программы (ASCII-код 03h). Вызывается обработчик прерывания Int 23h, завершающий текущую программу с выходом в DOS.

Ожидание нажатия клавиши. Функция, при отсутствии символа в кольцевом буфере ожидает его ввода. Функции, обладающие этим свойством, являются синхронными, иначе – асинхронными.

Ввод расширенных кодов ASCII. Все функции DOS, считывающие данные с клавиатуры, передают в программу только ASCII-код (младший байт кодового слова клавиши), оставляя scan-код (старший байт) без внимания. Правда, это относится только к алфавитно-цифровым клавишам, т. е. клавишам, за которыми закреплены отображаемые на экране символы (94 символа со значениями ASCII-кода от 32 до 126). Особенности считывания информационных кодов с других, так называемых функциональных и управляющих клавиш, будут рассмотрены дальше в разделе ²Расширенные коды ASCII².

Очистка буфера. Процесс считывания кодов с буфера ввода может дать непредсказуемый эффект, если перед вызовом функции DOS этот буфер не был пуст. Программа, не желающая вводить набранные досрочно коды, должна очистить клавиатурный буфер с помощью специальной функции Ch прерывания 21h (при al = 0).

Ввод кодов с помощью комбинации Alt/цифра. Позволяет вводить в программу коды символов второй половины ASCII-таблицы, с использованием цифровой клавиатуры (правая часть консоли).

¨ Функция 01h. Ввод одиночного символа с эхом.

Вводит символ из стандартного устройства ввода и отображает его на устройстве стандартного вывода. Ввод каждого символа сопровождается перемещением курсора вправо на следующую позицию. При отсутствии символа ждёт ввода. При наборе строки обрабатываются управляющие клавиши: BS (шаг назад без удаления символа, AL = 08h), TAB (табуляция, AL = 09h), ENTER (переход на начало текущей строки, AL = 13h). Допустимо перенаправление ввода. Если ввод не перенаправлен, выполняет обработку . Для чтения расширенного кода ASCII требует повторного выполнения функции.

¨ Функция 06h. Ввод одиночных символов из стандартного устройства ввода и вывод одиночных символов на стандартное устройство вывода.

Режим работы определяется содержанием регистра DL в момент вызова функции: DL = FF – режим ввода, DL = <FFh – 00h > – режим вывода соответствующего этому коду символа. В режиме вывода коды ASCII: 07h – звонок, Dh – возврат каретки, Ah – перевод строки, рассматриваются как управляющие и выполняются соответствующие им действия.

Если вводимый символ в устройстве ввода присутствует, то он помещается в AL (без эха) с установкой флага ZF = 0, иначе ZF = 1. Отличительным качеством функции 06h является то обстоятельство, что она, просматривая устройство ввода, не останавливает программы (является асинхронной), если не обнаруживает в нём символа, а просто устанавливает флаг ZF = 1. Допускает перенаправление ввода-вывода. Для чтения расширенного кода ASCII требуется повторное выполнение функции.

Вызов: AH =06h, Int 21h.

ZF = 1 – устройство ввода пустое.

Вывод: DL = FE¸00. Код в регистре DL является одновременно и кодом выводимого символа.

¨ Функция 07h. Нефильтрованный ввод символа без эха.

Вводит символ из стандартного устройства ввода без его отображения на экране. При отсутствии символа ждёт его ввода. Допустимо перенаправление ввода. Не выполняет отработку . Для чтения расширенного кода ASCII требует повторное выполнение функции. Функция, как правило, используется для ввода пароля с целью защиты программы от несанкционированного запуска

¨ Функция 08h. Ввод символа без эха.

Вводит символ из стандартного устройства ввода. При отсутствии символа ждёт его ввода. Допустимо перенаправление ввода. Для чтения расширенного кода ASCII требует повторное выполнение функции. Если ввод не перенаправлен, чувствительна к (иначе надо предварительно включить режим Break). Как и функция 07h, используется для ввода пароля. Пример использования данной функции будет рассмотрен в одной из программ этой работы.

Вызов: AH = 08h, Int 21h.

Вывод: AL = код символа.

¨ Функция Ah. Буферизованный ввод с клавиатуры.

Вводит строку байт из устройства стандартного ввода в буфер пользователя по адресу DS:DX, с отображением на устройстве стандартного вывода. Допустимо перенаправление ввода. Если ввод не перенаправлен, выполняет отработку (иначе надо предварительно включить режим Break). Функция допускает редактирование данных при их вводе клавишами: Backspace (отмена последнего символа), Exc (отмена всего набранного текста), F5 (запоминает текущую строку как подсказку), F3 (восстанавливает подсказку для ввода). Ввод символов строки заканчивается нажатием клавиши , код которой (0Dh) вводится в качестве последнего символа в отведённый буфер.

Структура буфера (резервируется в сегменте данных): байт 0 – назначаемая пользователем максимальная длина строки (1-254) с учётом символа CR (код Dh), байт 1 – число реально введённых символов без учёта символа CR, байт 2 и далее – строка. В следующем примере приведена процедура In_string ввода строки в буфер, емкостью 50 символов. Она возвращает адрес первого символа строки в регистре DX, а число символов в регистре CX.

Buf DB 50. 50 DUP(?) ;Буфер пользователя

lea dx,[Buf] ;Адрес буфера пользователя

mov ah,0Ah ;Запрос функции 0Ah

int 21h ;Вызов DOS

mov cl,[Buf+1] ;Поместить счётчик символов в cx

add dx,2 ;Сделать dx указателем строки

¨ Функция 0Bh. Проверка состояния ввода.

Проверяет наличие символа в буфере клавиатуры. Допустимо перенаправление ввода. Если ввод не перенаправлен, выполняет отработку . Это даёт возможность организовать с её помощью аварийное завершение программы (нажатием комбинации ) с циклом, состоящим из чисто процессорных команд, включив предварительно в цикл вызов функции Bh.

Возврат: Если символа нет, то AL = 0, если символ ждет, то AL = FFH.

¨ Функция 0Ch. Вызов служебной функции DOS для ввода данных с предварительной очисткой буфера клавиатуры. Допускает переопределение ввода.

Вызов: AH = 0Ch, Int 21h,

AL = номер функции ввода: 01, 07, 08, 0Ah (если AL = 0, то только очистка), DS:DX = адрес буфера, если AL = 0Ah.

Выход: AL = байт входных данных (если при вызове Al = 0Ah, данные помещаются в буфер).

¨ Функция 3Fh. Ввод данных из файла или устройства.

Универсальная функция ввода данных в буфер с указателем DS:DX из источника, определённого дескриптором в регистре BX. Допускает переопределение ввода. В регистре CX указывается число байтов, которое необходимо ввести. Пример использования.

In_Area DB 20 DUP(?)

mov ah,3Fh ;Запрос функции 3Fh

mov bx,00h ;Дескриптор ввода (клавиатуры)

mov cx,20 ;Число пересылаемых байт

lea dx,[In_Area] ;Адрес буфера ввода

int 21h ;Вызов функции DOS

sub cx,2 ;Фактически введено

Команда Int 21h ожидает окончания ввода символов, которое фиксируется нажатием клавиши Enter. После ввода текста и нажатия клавиши Enter в буфер In_Aria автоматически вводятся два управляющих символа: CR (код 0Dh) и LF (код 0Ah). Вследствие данной особенности максимальное число символов и размер буфера ввода должны содержать место для двух дополнительных символов. При успешном завершении операции флаг CF = 0, а в регистре AX устанавливается число байтов, введённых с клавиатуры (плюс два дополнительных символа). Если CF = 1, то в регистре AX содержится возвратный код ошибки. Это либо 5 (отказ в доступе), либо 6 (неверный дескриптор).

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

7.2.3. ФУНКЦИИ DOS ВЫВОДА ДАННЫХ НА ЭКРАН

DOS предоставляет следующие способы вывода данных на экран:

использование функций Int 21h (02h, 06h, 09h), обеспечивающих посимвольный ввод с клавиатуры в разных режимах;

обращение к экрану, как к файлу, с помощью функции 40h.


¨ Функция 02h. Вывод одиночного символа.

Выводит символ, находящийся в регистре DL, на экран, после чего курсор сдвигается на одну позицию вправо. Для вывода строки функцию следует использовать в цикле. Допустимо перенаправление вывода. Выполняет обработку при вводе этой комбинации с клавиатуры перед выводом каждого 64-го символа. Эта функция выводит и управляющие ASCII-символы с кодами 07h, 08h, 09h, 0Ah, 0Dh. Символ с кодом 07h (bell, звонок) вызывает звуковой сигнал, с кодом 08h (backspace, забой) – возвращает курсор на одну позицию влево, с кодом 09h (tab, табуляция) – смещает курсор на одну позицию вправо, кратную 8. Действия управляющих клавиш с кодами Ah и Dh рассматривались ранее.

Вызов: AH = 02h, Int 21h.

Выход: DL = ASCII – код символа,

AL = код последнего записанного символа (кроме случая, когда DL = 09, тогда возвращается значение 20h).

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

mov ah,2 ;Запрос функции 02h

mov dl,13 ;Возврат каретки

int 21h ;Вызов DOS

mov dl,10 ;перевод строки

int 21h ;Второй вызов DOS

¨ Функция 09h. Вывод строки.

Выводит строку символов на устройство стандартного вывода (используется в системных программах для вывода на экран информационных сообщений). Строка должна заканчиваться символом $ (код24h), который служит признаком конца строки, и сам не выводится. Допустимо перенаправление вывода. В сообщение могут быть включены и управляющие коды (07h, 08h, 09h, 0Ah, 0Dh), которые вызывают соответствующие им действия (см. функцию 02h). Допустимо использование Exc-последовательностей. Функция выполняет обработку при вводе этой комбинации с клавиатуры перед выводом каждого 64-го символа.

lea dx,[Promt] ;Адрес строки Promt: DS:DX

mov ah,09h ;Запрос функции 09h

int 21h ;Вызов DOS

¨ Функция 40h. Вывод данных в файл или в устройство.

Универсальная функция вывода данных из буфера пользователя в сегменте данных в файл или на устройство, дескриптор которого указывается в регистре BX. Дескриптор 1, закреплённый за стандартным устройством вывода, обеспечивает перенаправление вывода. Значение регистра CX определяет число байтов, которые должны быть выведены, а пара регистров DS:DX указывает адрес выводимых данных. Управляющие коды 08h, 0Ah, 0Dh и некоторые другие приводят к выполнению соответствующих им действий. После завершения вывода при CF = 0 регистр AX содержит число действительно выведенных байтов, а при CF =1 – возвратный код ошибки. Как и при использовании функции 3Fh, это коды ошибок 5 или 6. Пример использования.

Out_Area DB 20 DUP(?)

mov ah,40h ;Запрос функции 40h

mov bx,01 ;Дескриптор дисплея

mov cx,20 ;Число пересылаемых байт

lea dx,[Out_Area] ;Адрес буфера для выводимого сообщения

int 21h ;Вызов DOS

7.2.4. РАСШИРЕННЫЕ КОДЫ ASCII И УПРАВЛЕНИЕ ПРОГРАММОЙ С КЛАВИАТУРЫ

Как уже отмечалось в п 7.2.2, рассмотренный процесс считывания ASCII-кодов клавиш клавиатуры с помощью системных функций DOS относится к алфавитно-цифровым клавишам, за которыми закреплены ASCII-таблицей отображаемые символы (буквы, цифры, знаки препинания и др.). Кроме них, на клавиатуре персонального компьютера имеется ряд клавиш, которым не назначены какие-либо отображаемые символы. Это, например, функциональные клавиши . , клавиши управления курсором , , . , , , специальные клавиши , , а также использующие на практике различные сочетания клавиш с , и . В этом случае, в качестве scan-кода клавиши или какой-либо комбинации из них выступает также старший байт кодового слова, но уже при нулевом младшем байте (нулевом коде ASCII). Например, при нажатии клавиши в кольцевой буфер ввода клавиатуры поступает код 3B00h, а клавиши – 4700h.

Двухбайтовые коды клавиш, содержащие на месте кода ASCII – ноль, называются расширенными кодами ASCII. Эти коды (и соответствующие им клавиши) широко используются для управления программами. Для доказательства этого утверждения достаточно указать на популярную оболочку DOS – Norton Commander. Широкое использование в компьютерах интерактивных средств требовало расширение возможностей ввода с клавиатуры управляющей информации, которую программа должна отличать от вводимого текста. Поэтому расширенные коды ASCII генерируются и всеми алфавитно-цифровыми клавишами, если они нажимаются совместно с клавишей . В табл. 2.2 приведены значения расширенных ASCII-кодов для одиночных клавиш.

Расширенные коды для функциональных клавиш

Клавиша

Код (hex)

Клавиша

Код (hex)

Клавиша

Код (hex)

Клавиша

Код (hex)

Правая часть клавиатуры.

«Num Lock-выкл»

В составе комбинации Alt+

Рассмотренные выше функции DOS, предназначенные для посимвольного ввода данных с клавиатуры, позволяют работать и с расширенными кодами ASCII. Однако программа при этом должна вызывать функцию DOS дважды. Первый вызов всегда возвращает младший байт и, если он равен нулю, то необходимо повторить вызов этой же функции для вывода старшего байта. Это и будет информационный байт расширенного кода ASCII, который можно использовать для управления программой.

Обратим здесь внимание на важный момент! Расширенный код ASCII можно считать, если программа будет настроена на проверку нулевого значения младшего байта для каждого нажатия клавиши. Пример использования функциональных клавиш для управления программой показан в листинге 2.1.

Листинг 2.1. Фрагмент программы, демонстрирующий выполнение альтернативных действий на основе анализа расширенных кодов ASCII

mes1 DB 13,10,’Сообщение $’

mes2 DB 13,10,’Сообщение $’

mes3 DB 13,10,’Сообщение $’

;Ожидаем нажатия клавиши

again: mov ah,08h ;Функция ввода одиночного символа без эха

int 21h ;Первый вызов DOS

cmp al,0 ;Расширенный ASCII код?

mov ah,08h ;Да, введём старший байт

int 21h ;Повторный вызов DOS

cmp al,3B ;Нажата F1?

cmp al,54h ;Нажата ?

cmp al,1Eh ;Нажата ?

jmp again ;Нажато незапланированное

F1: ;Вывод сообщения mes1

Shift_F1: ;Вывод сообщения mes2

Alt_A: ;Вывод сообщения mes3

Exit: ;Завершение программы

7.2.5. СТРОКОВЫЕ КОМАНДЫ. ОБЩАЯ ХАРАКТЕРИСТИКА

Строкой или литералом в языке ассемблера называется последовательность букв, цифр и других символов, заключённых в кавычки или апострофы (двойные кавычки). Следует отметить, что иногда понятие строки трактуется в расширительном смысле, а именно, как последовательность байтов, которые могут либо представлять, либо не представлять ASCII-символы.

Строковые команды, несмотря на синонимичное название со строковыми переменными, предназначены для обработки не только ASCII-строк, но и вообще блоков байтов, одинарных или двойных слов, каждое из которых хранится в памяти в двоичном коде.

Строковые команды представлены в табл. 3.1 и по своему назначению делятся на две группы:

— команды для поиска и сравнения данных (Scas, Cmps).

Любая строковая команда может оперировать как байтами, так и словами, что отражается в мнемокоде команды (например: movsb, movsw, movsd). Все строковые команды, в отличие от других команд процессора ix86, используют для выполнения своих функций одни и те же регистры:

Команды обработки строк

Название команды и её мнемокод

Действие

Тип исполь-зуемого префикса

Влияние на флаги

Lods src – Загрузка Acc из строки

src=byte ds:si Lodsb

src=word ds:si Lodsw

src=dword ds:si Lodsd

_

Stos dst – Сохранение Acc в строке

dst=byte es:di Stosb

dst=word es:di Stosw

dst=dword es:di Stosd

Movs dst,src Пересылка элемента строки

dst=byte es:di, src=byte ds:si Movsb

dst=word es:di, src=word ds:si Movsw

dst=dword es:di, src=dword ds:si Movsd

Scas dst – Поиск элемента в строке

dst=byte es:di Scasb

dst=word es:di Scasw

dst=dword es:di Scasd

Все флаги операции сравнения

Cmps dst, src Сравнение элементов строк

src=byte ds:si, dst=byte es:di Cmpsb

src=word ds:si, dst=word es:di Cmpsw

src=dword ds:si, dst=dword es:di Cmpsd

srcdst .

Все флаги операции сравнения

При этом индексные регистры si(esi) и di(edi) определяют смещения элементов строк в сегментах данных, определяемых регистрами ds и es соответственно. Установите es = ds, если это не противоречит другим условиям реализации программы, что позволит вам не беспокоиться о корректной адресации сегментов памяти. Необходимо помнить, что в строковых инструкциях приёмник – строка es:di(edi) не допускает переопределение, а источник – строка ds:si(esi), допускает переопределение на es:si(esi).

Каждая из строковых команд выполняет операцию только над парой элементов двух строк (или над одним для команд Lods, Stos, Scas) и автоматически настраивается на обработку соседних элементов, обеспечивая продвижение по строке в нужном направлении, а именно:

Здесь величина d определяется согласно правилу:

Тип операнда Флаг направления

Префикс повторения, помещённый непосредственно перед строковой командой, заставляет её циклически выполняться определённое число раз до реализации заданного условия. Существуют три командных префикса:

rep (repeat) – повторять, пока cx ¹ 0;

Префиксы используют регистр CX как счётчик числа циклов (беззнаковое число), которое должно быть записано в CX до начала выполнения строковой команды. Счётчик CX декрементируется на 1 после выполнения строковой команды, но проверяется перед её выполнением. Если CX = 0, то строковая команда не выполняется ни разу. Префиксы repe и repne дополнительно выставляют флаг нуля ZF после выполнения строковой операции.

В листинге 2.2. рассматривается использование строковой команды сравнения cmpsb на примере программы с паролем. Идея простейшей защиты программы от несанкционированного запуска заключается в том, что где-то в программе записывается ключевое слово-пароль, и программа, начав работать, требует ввода этого слова с клавиатуры. Если пользователь ввёл пароль правильно, программа продолжит свою работу, иначе попросит ввести его заново или завершится. Ввод пароля обычно осуществляется функцией DOS, не отображающей вводимые символы на экране (обычно 07h или 08h) и заканчивается нажатием клавиши .

Листинг 2.2. Фрагмент программы с паролем.

password DB ‘camel’ ;Пароль

string DB 80 DUP(?)

promt DB 13,10,’Введите пароль: $’

OK DB 13,10,’Работаем!$’

start: mov ax,@data

begin: mov ah,09h ;Вывод запроса на ввод пароля

mov dx,offset promt ;Адрес запроса

mov bx,0 ;Инициализация индексирования ввода

pass: mov ah,08h ;Функция ввода символа в AL без эха

je compare ;Да, на сравнение

mov [string+bx],al ;Нет, сохраним символ

mov dl,’*’ ;Запишем на экран *

jmp pass ;Повторять

;Сравнение введённого пароля с действительным (сравнение строк)

compare: push ds ;Установить ES на сегмент данных

mov si,offset string ;DS:SI- начало string

mov di,jffset password ;ES:DI- начало password

cld ;DF=0- просмотр вперёд


mov cx,pass_len ;Установить счётчик сравнения

repe cmpsb ;Сравнивать, пока (или повторять

;пока символы двух строк совпадают, но не более CX раз)

jne err ;Строки не равны

Вывод сообщения ОК, подтверждающего правильность пароля

mov dx,offset OK

exit: mov ax,4C00h ;Ввод функции 4С для завершения программы

err: jmp begin ;Повторить ввод пароля

Логика построения программы поясняется подробными комментариями. В программе ввод пароля выполняется в бесконечном цикле, поэтому пользователь, не знающий пароля и запустивший программу, для выхода из неё вынужден будет нажать комбинацию клавиш .

7.3. ЗАДАНИЯ К РАБОТЕ. ПОДГОТОВКА И ВЫПОЛНЕНИЕ

¨ Задания к работе

1) Ввести строку из произвольных ASCII-символов и произвести её сортировку под управлением функциональных клавиш: – по возрастанию; – по убыванию; – завершение программы. Работу программы отобразить на экране.

2) Ввести строку из произвольного числа символов и произвести в ней поиск подстроки SYMBOL. Если подстрока найдена, то её необходимо удалить. Вновь полученную строку вывести на экран. Если подстрока не найдена, вывести сообщение NOT_FOUND. Программу защитить паролем.

3) Ввести строку из произвольного числа символов. Выполнить преобразование символьной строки в её цифровой аналог на основе ASCII-кодов, после чего произвести поиск максимального кода. Работу программы отобразить на экране и защитить паролем.

4) Ввести строку из произвольных ASCII-символов и произвести её сортировку к виду, включающему четыре части разделённые пробелами: цифры, буквы прописные, буквы строчные, все другие символы. Работу программы отобразить на экране и защитить паролем.

5) Ввести строку из нескольких слов, разделённых пробелами. Слова включают в произвольном порядке цифры, строчные и прописные латинские буквы. Отредактированная строка включает слова, начинающиеся с прописной буквы (остальные строчные). Цифры из слов должны быть удалены. Программу защитить паролем.

6) Ввести строку из произвольных ASCII-символов и выполнить с ней преобразования, задаваемые нажатием функциональных клавиш: изменение порядка следования символов исходной строки на обратный, – замена строчной буквы на прописную и обратно, завершение программы.

7) Ввести строку из произвольного числа символов и произвести в ней поиск подстроки COMPUTER. Если такой подстроки нет, то данную подстроку ввести в начало исходной строки и вывести на экран. В противном случае дать сообщение There is. Программу защитить паролем.

8) Добавление и удаление элементов из неупорядоченного массива. Элементы последовательно один за другим вводятся с клавиатуры. При этом, если такой элемент отсутствует в массиве (первоначально он пуст), то он вводится в конец списка, в противном случае, он удаляется из него, а оставшиеся элементы сдвигаются влево (в сторону младших адресов) на одну позицию. Список элементов постоянно отображается на экране. Выход из программы осуществляется с помощью клавиши .

9) Ввести строку из произвольного числа символов. Выполнить преобразование символьной строки в её цифровой аналог на основе ASCII-кодов, после чего произвести поиск минимального кода. Работу программы отобразить на экране и защитить паролем.

10) Ввод с клавиатуры на экран произвольного текста с одновременной записью в буфер. Реализовать элементы редактирования: стирание последних символов клавишей Backspace, контроль над прописной буквой первого слова нового предложения (ввести признак начала предложения). При ошибке строчная буква заменяется прописной. Переход на новую строку осуществляется клавишей . Управление: – вывод копии отредактированного текста из буфера, – выход из программы.

11) Ввод с клавиатуры на экран произвольного текста с одновременной записью в буфер. Программа демонстрирует переход на новую строку одним из двух способов:

– нажатие клавиши , если последнее введённое слово пересекло границу в 40 символов. В этом случае на новую строку автоматически переносится всё последнее слово. После перехода на новую строку вывод текста может быть продолжен в обычном порядке. Выход из программы с помощью клавиши .

12) Ввести строку из произвольного числа символов и произвести в ней поиск подстроки AUTOMATON. Если такой подстроки нет, то в начало исходной строки поместить символ @, а в её конец дописать подстроку и вывести на экран. В противном случае дать сообщение There is. Программу защитить паролем.

13) Программа проверки работоспособности ОЗУ для заданной области памяти данных с использованием шахматного теста. Тест предусматривает запись в ячейки с чётными адресами числа 0AAh, а в нечётные – 55h. В результате последующего считывания осуществляется проверка записанной информации. При обнаружении сбоя запоминается адрес данной ячейки (для проверки выполнения последнего требования использовать прогон программы в отладчике TD).

14) Программа проверки работоспособности ОЗУ для заданной области памяти с использованием сканирующего теста. Тест предусматривает запись байта 00h с последующим считыванием и проверкой, затем те же действия выполняются с числом 0FFh. По результатам теста формируется массив из адресов ячеек, в которых обнаружен сбой (для проверки выполнения последнего требования использовать прогон программы в отладчике TD). Программу оформить как com-файл.

15) Разработать программу, преобразующую все символы введённой строки (в строке представлены произвольные алфавитно-цифровые символы) из нижнего регистра клавиатуры в верхний.

¨ Подготовка и выполнение:

a) ознакомиться с методическими рекомендациями к лабораторной работе и соответствующими тематическими разделами в рекомендуемой литературе;

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

в) программа, по возможности, должна обеспечивать удобный экранный интерфейс с пользователем при её демонстрации;

г) отчёт о выплненной работе представляет собой:

– индивидуальное задание на разработку программы;

– листинг программы с подробными комментариями и описанием её работы.

7.4. КОНТРОЛЬНЫЕ ВОПРОСЫ

1. Что такое дескриптор? Сколько дескрипторов определено в DOS и как ими пользоваться?

2. Какие функции DOS можно использовать для ввода символов с клавиатуры в регистр AL процессора?

3. Назовите функции DOS, осуществляющие ввод строки символов с клавиатуры в память данных.

4. Какие функции DOS осуществляют операцию вывода на экран:

– одиночных символов из регистра DL процессора;

– строки символов из памяти данных?

5. Напишите процедуру перевода курсора на новую строку с помощью функции 02h DOS.

6. Что такое скан-код клавиши и чем он отличается от расширенного кода ASCII? Как нужно организовать вызовы соответствующей функции DOS для получения расширенного ASCII-кода?

7. Каким сегментным регистрам должен адресоваться сегмент данных, в котором располагается:

8. Какие строковые команды влияют на флаги, а какие нет?

9. Перечислите префиксы повторения строковых команд и их возможные сочетания друг с другом.

10. В какой фазе исполнения команды происходит проверка счётчика на равенство нулю при выполнении:

– строковой команды с префиксом повторения;

– команды управления циклом Loop ?

Что происходит с исполнением этих команд, если счётчик СХ инициализирован нулём?

Dos fn 23h: дать размер файла через fcb

31H и INT 27H Завершиться, но остаться резидентным

00H и INT 20H традиционный TERMINATE: завершение программы

4cH TERMINATE: Завершиться, передав код выхода родительскому процессу
4dH получить код выхода завершившегося процесса

INT 23H завершение через Ctrl-Break
INT 24H завершение через Обработчик критических ошибок

Запуск и завершение программ
Префикс программного сегмента (PSP)
Структура заголовка файла EXE

Запуск и завершение программ

Ввиду сегментации адресного пространства процессора 8088/86/286 и того факта,
что переходы (JMP) и вызовы (CALL) используют относительную адресацию, оба типа
программ могут выполняться в любом месте памяти. Программы НИКОГДА не пишутся
в предположении, что они будут загружаться с определенного адреса (за исключе-
нием некоторых самозагружающихся, защищенных от копирования игровых программ).

• Файл COM-формата — это двоичный образ кода и данных программы. Такой файл
должен занимать менее 64K и не содержит перемещаемых адресов сегментов.

• Файл EXE-формата содержит специальный заголовок, при помощи которого загруз-
чик выполняет настройку ссылок на сегменты в загруженном модуле.

Перед загрузкой COM- или EXE-программы DOS определяет
сегментный адрес, называемый префиксом программного сегмента
(PSP), как базовый для программы. DOS выбирает при этом наименьший доступный
адрес; другая управляющая программа (скажем, Microsoft Windows) может выбрать
любую часть памяти. Затем DOS выполняет следующие шаги:

1. Создает копию текущего Окружения DOS для программы. Функция DOS 4bH (EXEC)
позволяет родительской программе создать другое окружение. Например, про-
грамма может запустить COMMAND.COM, установив в качестве подсказки DOS
текст «Use EXIT to return to UltraProg>».

2. Помещает путь, откуда загружена программа, в конец окружения. DOS 3.0+

3. Заполняет поля PSP информацией, полезной для загружаемой программы

5. Загружает регистр AX значением, отражающим корректность обозначений дисков
(если есть) в параметрах, введенных в командной строке:

• если AL=0ffH, то первое обозначение диска неверно
• если AH=0ffH, то второе обозначение диска неверно

EXE-программы содержат несколько программных сегментов, вклю-
чая сегмент кода, данных и стека. EXE-файл загружается, начи-
ная с адреса PSP:0100. В процессе загрузки считывается информация заголовка EXE
в начале файла и выполняется перемещение адресов сегментов. Это означает, что
ссылки типа

mov ax,data_seg
mov ds,ax
и
call my_far_proc

должны быть приведены (пересчитаны), чтобы учесть тот факт, что программа была
загружена в произвольно выбранный сегмент. См. заголовок EXE о подробностях
структуры заголовка и процесса перемещения.

После перемещения управление передается загрузочному модулю посредством инструк-
ции далекого перехода (FAR JMP) к адресу CS:IP, извлеченному из заголовка EXE.

В момент получения управления программой EXE-формата:

• DS и ES указывают на PSP
• CS, IP, SS и SP инициализированы значениями, указанными в заголовке EXE
• поле PSP MemTop содержит значение, указанное в заголовке EXE. Обычно вся
доступная память распределена программе.

COM-программы содержат единственный сегмент (или, во всяком
случае, не содержат явных ссылок на другие сегменты). Образ
COM-файла считывается с диска и помещается в память, начиная с PSP:0100. Заме-
тим, что COM-программа может использовать множественные сегменты, но она должна
сама вычислять сегментные адреса, используя PSP как базу.

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

После загрузки двоичного образа:

• CS, DS, ES и SS указывают на PSP
• SP указывает на конец сегмента PSP (обычно 0fffeH, но может быть и меньше,
если полный 64K сегмент недоступен). Слово по смещению 06H в PSP указывает,
какая часть программного сегмента доступна.
• Вся память системы за программным сегментом распределена программе.
• Слово 00H помещено (PUSH) в стек.
• IP содержит 100H (первый байт модуля) в результате команды JMP PSP:100

Одно время (в эпоху DOS 1.1), описание схемы выхода из
программы, которую изобрел для DOS Rube Goldberg, зани-
мало несколько страниц. Начиная с DOS 2.0, жить стало легче. Вы можете выйти:

• через функцию 4cH (EXIT) в любой момент, независимо от значений регистров.
• через функцию 00H или прерывание INT 20H , когда ваш CS указывает на PSP.

До версии DOS 2.0, вы должны были сохранять сегмент PSP при запуске. Затем,
чтобы выйти, вам приходилось помещать этот сегмент в стек, далее помещать в
стек слово 00H, и наконец выполнять FAR RET. Это передавало управление на
адрес PSP:0000, содержащий код прерывания INT 20H. Эта процедура гарантировала,
что регистр CS устанавливался таким, каким его ожидала DOS.

Функция DOS 4cH устраняет эти сложности и позволяет вам возвращать родительскому
процессу (обычно COMMAND.COM) код выхода , который может быть проверен вызываю-
щей программой или командой COMMAND.COM «IF ERRORLEVEL».

Вы можете также завершить программу и оставить ее постоянно резидентной (TSR),
используя либо INT 27H , либо функцию DOS 31H (KEEP). Последний способ имеет
те преимущества, что резидентный код может быть длиннее 64K, и что вы можете
сформировать код выхода для родительского процесса.

TSR-программы удобны при установке пользовательских заплат для DOS и BIOS.
Эта концепция используется popup-утилитами, такими как SideKick и ваш покорный
слуга TECH Help! (если называть наиболее важные примеры).

Следующие пункты имеют отношение к рассматриваемой теме:

Функции управления процессами индекс функций запуска и завершения
Префикс программного сегмента детальная структура PSP
DOS Fn 26H . построить PSP
DOS Fn 4bH (EXEC). загрузить и выполнить программу
DOS Fn 62H . получить значение PSP для текущей программы
DOS Fn 2fH . получить текущий DTA
Окружение DOS . определить диск и оглавление, из которых
загружена текущая программа

DOS Fn 4bH: Выполнить или загрузить программу — EXEC
Вход AH 4bH
DS:DX адрес строки ASCIIZ с именем файла, содержащего программу
ES:BX адрес EPB (EXEC Parameter Block — блока параметров EXEC)
AL 0 = Загрузить и выполнить
AL 3 = Загрузить программный оверлей
Выход AX код ошибки если CF установлен

DS:DX указывает на строку ASCIIZ в форме: «d:\путь\имяфайла»,0.
Если диск или путь опущены, они подразумеваются по умолчанию.
ES:BX указывает на блок памяти, подготовленный как EPB, формат
которого зависит от запрошенной подфункции в AL.

1. Вызовите функцию 4aH с ES=сегменту PSP и BX=минимальному объему
памяти, требуемой вашей программе (в параграфах).
2. Подготовьте строку ASCIIZ с именем вызываемого программного фай-
ла и установите DS:DX на первый символ этой строки.
3. Подготовьте Блок Параметров EXEC со всеми необходимыми полями.
4. Сохраните текущие значения SS, SP, DS, ES и DTA в переменных,
адресуемых через регистр CS (CS — это единственная точка для
ссылок после того, как EXEC вернет управление от ребенка).
5. Выдайте вызов EXEC с AL=0.
6. Восстановите локальные значения SS и SP.
7. Проверьте флаг CF, чтобы узнать, не было ли ошибки при EXEC.
8. Восстановите DS, ES и локальную DTA, если необходимо.
9. Проверьте код выхода через функцию 4dH WAIT (если надо).

Все открытые файлы дублируются, так что ребенок может обрабатывать
данные как через описатели файлов, так и через стандартный в/в.
Режимы доступа описателей дублируются, но любые активные блокировки
файлов не будут относиться к ребенку. См. функцию 5cH.

После возврата из ребенка, векторы INT 22H Terminate, INT 23H Ctrl-
Break и INT 24H Critical Error восстанавливаются в их предыдущие
значения.

Вместо разбора собственных FCB (как требуется для EPB), вы можете
найти удобным загрузить и выполнить вторичную копию файла
COMMAND.COM, используя опцию /C. Например, чтобы выполнить
программу FORMAT.COM, установите DS:DX на адрес строки ASCIIZ:
«\command.com»,0
и установите EPB+2 на сегмент и смещение следующей строки команд:
0eH,»/c format a:/s/4″,0dH

Такой вторичный интерпретатор команд использует очень мало памяти
(около 4K). Вы можете поискать в Окружении DOS строку COMSPEC=,
чтобы установить точное местоположение файла COMMAND.COM.

См.также: Функции управления процессами Запуск и завершение Функции DOS

DOS Fn 62H: Дать адрес PSP
Вход AH 62H DOS 3.0+
Выход BX сегментный адрес PSP выполняющейся программы

Описание: Эта функция возвращает в BX адрес PSP текущей программы.

Используется, чтобы получить адрес параметров командной строки,
адрес окружения DOS и другой полезной информации в PSP.

Версии: Доступна, начиная с DOS 3.0

DOS Fn 26H: Построить PSP
Вход AH 26H
DX адрес сегмента (параграфа) для нового PSP
CS сегмент PSP, используемого как шаблон для нового PSP
Выход Нет

См.также: PSP (Program Segment Prefix) Окружение DOS Функции DOS

Структура заголовка файла EXE

Поскольку EXE-файл может быть загружен в любой сегмент, все абсолютные сегмент-
ные ссылки (FAR CALL, далекие указатели, ссылки типа MOV AX,data_seg) должны
быть приведены к адресам памяти, соответствующим загрузке. Ниже приведены шаги,
используемые программой загрузки DOS (функция 4bH ) при загрузке файла EXE:

1. создать PSP посредством функции DOS 26H

2. прочитать 1cH байт файла EXE (форматированную порцию заголовка EXE)
в локальную область памяти

3. определить размер модуля = ( (PageCnt*512)-(HdrSize*16) ) — PartPag

4. определить файловое смещение загружаемого модуля = (HdrSize * 16)

5. выбрать сегментный адрес, START_SEG, для загрузки (обычно PSP + 10H)

6. считать модуль в область памяти, начинающуюся с адреса START_SEG:0000

7. LSEEK (уст. указатель файла) на начало таблицы перемещения (TablOff)

8. для каждого элемента перемещения (ReloCnt):

9. Распределить память для программы согласно MaxMem и MinMem

10. Инициализировать регистры и запустить программу:

Замечание: Последние добавления в формат EXE, особенно версии EXE-файлов
«CodeView» и «Windows», содержат дополнительную информацию, включенную в
выполнимый файл. Эти добавления не отражены в этой версии TECH Help!.

Dos fn 23h: дать размер файла через fcb

Assembler для начинающих

Прежде, чем перейти к упомянутому примеру, необходимо рассмотреть
формируемую DOS структуру данных — блок управления файлом FCB (File
Control Block), который является существенным элементом файловой
системы и участвует во всех файловых операциях.

Блок управления файлом обеспечивает связь пользовательской
программы с функциями DOS. При любой файловой операции происходит
обращение к блоку FCB. На Фиг.5.5 показан состав стандартного
блока FCB. Имеется модификация блока FCB, называемая расширенным
блоком FCB, которая применяется в специальных случаях, когда нужно
«скрыть» файл. Скрытый файл защищен от записи. Это значит, что
программа не может модифицировать содержимое этого файла, не
изменив предварительно его блока FCB. Скрытый файл не фигурирует в
листинге справочника. Скрыть файл — один из простейших способов
защиты файла от неумелого пользователя. В приводимых примерах
используются только стандартные блоки FCB.

Поля данных блока FCB охватывают все атрибуты файла. Номер
дисковода, имя и тип файла составляют идентификатор файла. Размер
файла и дата яаляются атрибутами файла, которые приводятся в
листинге справочника. Оставшиеся поля — текущий номер блока, длина
записи и номер записи при произвольном доступе — служат для
определения местоположения внутри файла при операциях чтения и
записи. Длина записи указывает на число байтов в определяемой
пользователем записи. Так как все операции чтения и записи в файл
начинаются с границы записи, то длина записи определяет количество
данных, обрабатываемых во время каждой из этих операций.
Существуют два способа определения текущей записи при обращении
к файлу. При первом, последовательном, способе записи
обрабатываются по порядку. При этом текущий номер блока и
относительный номер записи определяют запись, которая будет
обрабатываться следующей. По мере того, как программа выполняет
операции чтения или записи, DOS увеличивает на 1 относительный
номер записи, чтобы он указывал на следующую запись. Выполнение

FCB и Int 21h/функция 23h

Мне нужно получить размер файла, используя Int 21h/function 23h. Я не знаю, как работает FCB, и я не знаю, как ее использовать. Описание функции 23h, приведенное в этой документации:

Функция 23h (35) Получить размер файла, используя FCB

Как я могу это использовать?

на той же странице, с которой вы связаны, внизу, есть ссылка на FCB. если вы последуете за ним, вы увидите, что вам нужно инициализировать блок памяти для FCB и заполнить его номером диска (03 для C :), имя файла в формате 8.3 и несколько других полей. точка ds: dx в этот блок памяти, установите ah на 23h и int 21 . если al равно 0, это было успешно, и вы можете получить длину файла из ds: dx + 10h.

см. b2 6a 00 00 со смещением 0x10, который соответствует размеру указанного файла:

Я должен был исправить ошибку в dosbox, чтобы заставить это работать, следовательно, медленное обновление.

Илон Маск рекомендует:  Что такое код ingres_field_precision
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL