Классификация ввода-вывода
1.9. Приложение V. Описание шаблонов для программирования на языке Ассемблера в MS-DOS.
Человеку, занимающимся программированием на языке Ассемблера в операционной системе MS-DOS часто приходится использовать одни и те же конструкции для инициализации программы, использовать однотипные операции и функции. При этом код повторяется "один в один", и при его наборе можно сделать досадную ошибку. Чтобы это не делать, автор разработал несколько простых шаблонов для осуществления часто встречающихся однотипных операций, и предлагает к его использованию согласно лицензии GPL. Ниже приводится описание этих шаблонов.
1.9.1. Введение
Данные шаблоны предназначены для создания исходного кода на языке Ассемблер для операционной системе MS-DOS и совместимых с нею операционных системах, в том числе и для Microsoft Windows 95-7. В этих шаблонах есть повторяющиеся элементы, смысл которых будет объяснён ниже.
- Директива: page - указывает, сколько строк и позиций будет содержать листинг программы, генерируемый транслятором Ассемблера. Лучше оставить его значение, указанное в шаблоне: 60 строк и 132 позиции в строке, page 60,132;
- Директива: TITLE - указывает, как будет озаглавлен листинг программы, и какие колонтитулы будут печататься при выводе листинга. После этой директивы может идти любой текст, общий длиной до 60 символов. Автор рекомендует в качестве текста использовать имя и назначение программы;
- Директива: ASSUME - указывает, какой сегмент поставлен в соответствие определённому сегментному регистру. По-умолчанию сегменту кода соответствует регистр CS, сегментам данных - DS и ES, сегменту стека - SS. Эти сегменты должны быть определены оператором: SEGMENT перед вызовом этой директивы. Сам вызов этой директивы осуществляется в сегменте кода, обязательно перед вызовом других операторов программы. Если по каким-то причинам часть сегментных регистров не используется, вместо указания имени регистра используется слово: "NOTHING", например: ES:NOTHING ;
- Оператор: SEGMENT - определяет имя и параметры сегмента, используемого в программе на языке Ассемблер. В качестве параметров используются:
- Имя сегмента - располагается перед именем оператора. Оно обозначает метку, под которой данный сегмент идентифицируется в программе на языке Ассемблер. Это имя фигурирует при объявлении сегмента директивой: ASSUME. Это имя используется также в операторах загрузки адреса сегмента;
- Параметр выравнивания сегмента по границе сегмента PARA. Автор рекомендует этот параметр к обязательному использованию;
- Параметр: STACK - используется только для сегментов стека. Указывает, что данный сегмент является сегментом стека;
- Параметр, заключённый в апострофы - указывает компилятору, как будут компоноваться сегменты и их содержимое при выводе листинга ассемблерного файла. Иными словами, он определяет необязательный "класс сегмента". Рекомендуется для сегментов с кодом указывать класс: 'Code', для сегментов с данными - класс 'Data', для сегментов стека - класс 'Stack' ;
Примечание. Несколько сегментов можно указывать только для программ с форматом файла: "EXE". Для файлов в формате "COM" возможен только один сегмент, и этот сегмент - кодовый.
- Оператор: PROC - используется для указания начала любой процедуры на языке Ассемблера. Перед названием этой процедуры стоит её метка, определяющая имя процедуры в программе. Физический конец процедуры указан при помощи оператора: "метка" ENDP, где "метка" имеет то же имя, что и у оператора: PROC. Перед оператором конца процедуры должен находиться оператор выхода из процедуры: RET.
Примечание: После оператора PROC следуют два параметра, определяющие, как будет производиться адресация памяти внутри процедуры. Параметр "FAR" указывает, что будут использоваться только "длинные указатели" - пара адресов: "Сегмент:Смещение". Параметр "NEAR" указывает, что будут при адресации использоваться только "короткие указатели" - "Смещение" адреса внутри текущего сегмента. В программе формата: "COM" допускаются только "короткие" указатели адресов.
Во избежание путаницы не желательно переопределять имена сегментов и процедур, приведённые в шаблонах.
Более подробное описание этих директив и операторов языка ассемблер смотри в книге Питера Абеля.
1.9.2. Формат "EXE". Шаблон для создания файла в формате "EXE" Simple001
Исполняемый MS-DOS файл формата EXE обязательно должен содержать в себе следующие сегменты:
- Сегмент кода (с кодом программы). Таких сегментов может быть несколько, если выполняемая программа содержит множество процедур;
- Сегмент стека. Этот сегмент нужен как для инициализации программы, так и для работы операторов PUSH и POP. В программе на языке Ассемблер указывается максимальный размер стека (это значение Вы должны поставить при объявлении этого сегмента).
- Сегменты данных. В-принципе, это не обязательный сегмент, тем не менее, часто используемый. В этом сегменте объявляются пользовательские переменные и константы языка Ассемблер, которые нужны для вычислений. Если в описании конструкций языка Ассемблер используется комментарий "в сегменте данных", то эти константы и переменные должны быть записаны в одном из сегментов данных.
При инициализации программы на языке Ассемблер для исполняемых файлов в формате "EXE" должны присутствовать следующие операторы:
- PUSH DS - сохранение в стеке содержимого регистра DS. Первоначально в этом регистре находился адрес загрузчика программ в командной оболочке MS-DOS;
- Далее в стек необходимо записать значение "0". Это значение используется для инициализации загрузчика MS-DOS после выполнения программы;
- Затем в регистр DS заносится адрес сегмента с данными выполняемой программы;
- Только после этого пишется код программы на языке Ассемблер.
- Основная процедура программы (как и любая процедура на языке Ассемблер) заканчивается оператором "RET". Этот оператор приводит сегментные регистры в первоначальное состояние и возвращает управление вызывающей программе или загрузчику командной оболочки.
Таким образом, зарезервированными словами шаблона программы на языке Ассемблер являются следующие слова:
- ASSUME
- AX
- BEGIN
- 'Code'
- CODESG
- CS
- 'Data'
- DATASG
- DS
- END
- ENDP
- ENDS
- ES
- FAR
- MOV
- page
- PARA
- PROC
- PUSH
- RET
- SEGMENT
- SS
- STACK
- 'Stack'
- STACKSG
- SUB
- TITLE
Пример шаблона смотри ниже
page 60,132 TITTLE SIMPLE001 (EXE) Пример шаблона на языке Ассемблер ; --------------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' ; --- <ОБЪЯВЛЕНИЕ РАЗМЕРА СТЕКА> STACKSG ENDS ; --------------------------------------------------------- DATASG SEGMENT PARA 'Data' ; --- <ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ В СЕГМЕНТЕ ДАННЫХ> DATASG ENDS ; -------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG, DS:DATASG, SS:STACKSG, ES:DATASG ; --- ИНИЦИАЛИЗАЦИЯ exe ФАЙЛА --- PUSH DS ; Записать DS в стек SUB AX, AX ; Установить ноль в AX PUSH AX ; Записать ноль в стек MOV AX, DATASG ; Занести адрес MOV DS, AX ; DATASG в DS ; --- <КОД ПРОГРАММЫ> RET ; Возврат в DOS BEGIN ENDP CODESG ENDS END BEGIN ; --- Конец программы
1.9.3. Формат "COM". Шаблон для создания файла в формате "COM" Simple002
Исполняемый файл в формате "COM", написанный на языке Ассемблер, содержит только один сегмент - сегмент кода. Поэтому в директиве ASSUME все регистры инициализируются только одним значением: CODESG.
Для инициализации "COM" файла необходимо вначале вызвать оператор "ORG", с помощью которого производится пропуск части кода системного загрузчика программы. Затем идёт определение переменных и констант, используемых в программе. Поскольку в файлах формата "COM" нет сегмента данных, то объявление переменных происходит в начале программы, сразу за адресом загрузчика оболочки. Поскольку, по логике MS-DOS, в первом адресе исполняемой программы в сегменте кода должен быть исполняемый оператор, а не директива определения констант, то первым оператором "COM" программы будет оператор безусловного перехода на метку JMP. В качестве метки выступает имя основной процедуры исполняемого файла "MAIN". Между этими операторами будут располагаться описание констант и переменных программы, которое в файлах формата "EXE" располагались в сегменте данных.
Имена процедур в файле формата "COM" должны обязательно иметь параметр "NEAR", поскольку в файлах этого формата допустимы лишь "короткие" адреса памяти (то есть только смещение относительно сегмента кода текущей программы). Заканчиваться процедура должна оператором: "RET" (последний выполняемый оператор) и, затем, оператором: "метка программы" ENDP". Собственно же программа должна заканчиваться директивой: "END "метка оператора JMP".
Таким образом, зарезервированными словами шаблона программы на языке Ассемблер являются следующие слова:
- ASSUME
- BEGIN
- 'Code'
- CODESG
- CS
- DS
- END
- ENDP
- ENDS
- ES
- JMP
- MAIN
- NEAR
- ORG
- page
- PARA
- PROC
- RET
- SEGMENT
- SS
- TITLE
Примечание. Рекомендуется писать небольшие программы для операционной системы MS-DOS именно в "COM" формате, где это возможно, поскольку двоичный код в формате "COM" в 3 - 10 раз более компактный, чем в формате "EXE". Соответственно выше и скорость загрузки, меньше время выполнения программы. Однако на размер программ в этом формате накладывается ограничение - не более 64 Кбайт.
Пример шаблона смотри ниже.
page 60,132 TITLE SIMPLE002 (COM) Пример шаблона на языке Ассемблер ; --------------------------------------------------------- CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG, DS:CODESG, SS:CODESG, ES:CODESG ; --- ИНИЦИАЛИЗАЦИЯ COM ФАЙЛА --- ORG 100H BEGIN: JMP MAIN ; --------------------------------------------------------- ; --- <ОБЪЯВЛЕНИЕ ПЕРЕМЕННЫХ В ОБЛАСТИ ДАННЫХ> ; -------------------------------------------------------- MAIN PROC NEAR ; --- <КОД ПРОГРАММЫ> ; --- Возврат в DOS и завершение программы RET ; Возврат в DOS MAIN ENDP CODESG ENDS END BEGIN ; --- Конец программы
1.9.4. "Учебный" шаблон файла на языке "Ассемблер"
page 60,132 TITLE PRENT (COM) Пример шаблона на языке Ассемблер ; --------------------------------------------------------- CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG, DS:CODESG, SS:CODESG, ES:CODESG ; --- ИНИЦИАЛИЗАЦИЯ COM ФАЙЛА --- ORG 100H BEGIN: JMP MAIN ; --------------------------------------------------------- ; --- В сегменте данных --- PRESS_MSG DB 0DH, 0AH, 'Press key Enter to Exit...', 0DH, 0Ah,'$' ; --- Приглашение PRESS_ENTER LABEL BYTE ; Ссылка на набор полей MAX_ENTER_LEN DB 02H ; Максимальная длина поля -- 2 байта CUR_ENTER_LEN DB ? PRESS_BUFFER DB 2 DUP (0) ; Буфер для ввода данных ; -------------------------------------------------------- MAIN PROC NEAR ; --- <КОД ПРОГРАММЫ> CALL PRENTER ; --- Возврат в DOS и завершение программы RET ; Возврат в DOS MAIN ENDP ; --- ОБЪЯВЛЕНИЕ ПРОЦЕДУРЫ PRENTER PROC NEAR ; --- Вывод сообщения MOV AH, 09H LEA DX, PRESS_MSG INT 21H ; --- Ввод клавиши 'Enter' MOV AH, 0AH LEA DX, PRESS_ENTER INT 21H ; --- ВЕРНУТЬСЯ В ВЫЗЫВАЮЩУЮ ПРОГРАММУ RET PRENTER ENDP ; --- КОНЕЦ ПРОЦЕДУРЫ CODESG ENDS END BEGIN ; --- Конец программыЛистинг .