Initial: mov ах, 0 ; обнуления регістра ах
; обнуления регістра ВХ ; обнуления регістра СХ ; обнулекня регістра DX
Команди процесора 8086 можуть мати від 0 до 2 операндів. Ідентифікатори і коментарі незалежні від команд і указуються в міру необхідності. Початок коментаря позначається символом Ідентифікатор, що указується перед командою процесора, закінчується
двокрапкою і є влучною — символьним позначенням адреси команди. За допомогою міток можна здійснювати переходи до відповідних команд.
Окрім процесорних команд в колонці інструкцій можуть записуватися директиви — вказівки асемблеру-транслятору, виконувані їм в процесі асемблювання. До часто використовуваним, зокрема, відносяться директиви визначення даних різних типів. Наприклад, опис байтового осередку CELL і ініціалізація її нульовим значенням виглядатиме так:
cell db 0 ; визначення нульового
байта в пам'яті
В даному випадку директива DB (Define Byte) указує асемблеру на необхідність визначення в об'єктному модулі нульового байтового осередку (змінній). Ім'я CELL відповідає відносній адресі цього осередку. Після запуску виконавчого модуля в пам'яті буде відведений байтовий осередок і заповнена нульовим значенням. Часто також використовується директива визначення словньїх змінних DW, директиви сегментації (див. далі).
Команди, директиви, імена регістрів є зарезервованими словами. Як ідентифікатори можна використовувати будь-які слова, окрім зарезервованих, і що не починаються з цифр.
Ідентифікаторами є мнемонічні позначення деяких констант в програмі. Константи можуть записуватися також у вигляді чисел і код символів (ASCII). Запис числа починається з цифри (від 0 до 9). Числа можуть записуватися в різних системах числення. За умовчанням використовується десяткова система. Після 16-ричньіх чисел указується буква "h", після двійкових — "Ь". Символьні описи полягають в одинарні лапки. Кожен символ в лапках відповідає константі, рівній ASCII-коду цього символу. Нижче приведено декілька прикладів з використанням констант:
my_var db 65, 41h, 'А' однаковим вмістом my_bin db 3 dup(1000001b) байти, але вже за іншою адресою my_address dw my_var значенням адреси змінною my_var my_stringdb 'Мій рядок' значеннями код букв 'М', 'о'... copying: mov al [my_string]
три байти з
такі ж три
слово із
10 Байт із
копіювання в
регістр AL коди букви 'М'
mov ah [my_string+l] ; копіювання в регістр АН коди букви 'о'
jmp copying ; перехід по мітці
copying до команди mov
Операційна система DOS підтримує два види здійснимих файлів: ЕХЕ і СОМ. За умовпанням редактор зв'язків TLTNK генерує ЕХЕ- файл, як більш загальний. ЕХЕ-программа може включати довільну кількість сегментів пам'яті. Зазвичай використовується три сегменти: команд, даних і стека. Кожен з сегментів використовується для доступу до відповідної інформації. Початковий текст повинен містити директиви, що визначають структуру сегментів програми. Є два способи опису даної структури: за допомогою моделей пам'яті і за допомогою директив явної сегментації. Другий спосіб є стандартним і забезпечує бьльшую наочність і гнучкіші можливості при визначенні структури сегментів. Для явної сегментації використовуються директиви SEGMENT (початок сегменту), ENDS (кінець сегменту) і ASSUME. Наприклад, для опису сегменту команд (коди) з ім'ям COMMANDS можуть бути використані наступні директиви:
commands segment ; початок опису сегменту команд
assume cs:commands
[. . . ] ; тіло сегменту
commands ends ; кінець опису сегменту команд
Директива ASSUME указується тільки в сегменті команд і служить для встановлення відповідності між сегментними регістрами і іменами описаних сегментів, в даному випадку між регістром CS і ім'ям COMMANDS. При запуску виконуваного модуля регістр CS буде заповнений відповідним значенням сегментної адреси.
Завершується опис програми директивою END з вказівкою мітки входу, з якою необхідно починати виконання.
Сукупність цих директив описується в програмах практично без змін, тому має сенс один раз створити файл з їх описом, а потім використовувати його як шаблон для створення кінцевих програм.
Структура типової трьохсегментної ЕХЕ-программьі може виглядати так:
; Дані
my_data segment
[. . .] ; тіло сегменту даних
my_data ends ; Стік
my_stack segment stack ; опис сегменту
стека
dw 32 dup(?) ; резервування
місця для стека my_stack ends ; Код
my_commands segment
assume cs:my_commands
start:
[. . ,] ; виконувана частина програми
(команди) my_commands ends
end start ; кінець програми,
мітка входу
У готовій програмі замість символів [. . .] будуть підставлені інструкції, складові тіло кожного сегменту. Послідовність опису сегментів в більшості випадків може бути будь-якій (наприклад, сегмент даних може описуватися після сегменту команд).
Будова виконуваної частини програми повинна підкорятися правилам операційної системи, оскільки остання служить базою для її запуску, виконання і завершення. Відповідно до особливостей DOS в звичайних ЕХЕ-программах для забезпечення їх коректної роботи потрібно проводити наступні дії: настроювання сегментного регістра DS на сегмент даних (автоматично вона не проводиться) і виклик функції DOS завершення програми. Ці дії також можна включити до складу шаблону програми. Нижче приводиться остаточний вигляд один з варіантів шаблону ЕХЕ-программьі, що включає три сегменти, — даних, стека і коди:
; Лістинг 1. Шаблон трьохсегментнсї ЕХЕ-программн на асемблері ; Дані
my_data segment my_title db 1 Приклад строки$' my_data ends ; Стік
my_stack segment stack ; опис сегменту
стека
aw 32 dup(?) ; резервування 32
слів для стека my_stack ends
; код
my_commands segment
assume es:my_coramands, ds:my_data begin: mov ax, my_data ; занесення адреси
сегменту my_data
mov ds, ax ; у сегментний
регістр ds
[. . .] ; (змістовна частина програми) exit: mov ah, 4Ch ; функція
завершення програми
int 21h
my_commands ends
end begin ; кінець програми,
мітка входу
Команди ініціалізації регістра DS (дві команди MOV) дозволяють надалі звертатися до визначених в сегменті MY DATA даним. Дані не обов'язково описувати в окремому сегменті, необхідно лише дотримувати правильне до них звернення. Наприклад, визначення даних в сегменті команд повинне йти до мітки входу або після виклику функції завершення. Настройка регістра DS повинна проводитися на той сегмент, в якому описані потрібні дані.
При резервуванні пам'яті для стека використовувався оператор "?", відповідний неініціалізованим даним. Пам'ять, що відводиться таким чином, резервується при запуску програми, але нічим не заповнюється і містить, як правило, невідомі і непотрібні наший програмі дані (сміття).
Припустимо, лістинг 1 був збережений у файлі під ім'ям FRAMEASM. Для перевірки шаблону на наявність синтаксичних помилок можна виконати його асемблювання і компоновку за допомогою команд
tasm /z /zi frame tlink. /х /v frame
що по черзі набирають в командному рядку (про призначення параметрів /z, /zi, /х і N можна дізнатися, запускаючи асемблер і компонувальник на виконання без параметрів).
Програма лістингу 1 не виконує ніяких корисних дій, зокрема, нічого не виводить на екран після запуску. Проте вже по її коректному завершенню (повернення в середу запуску) можна судити про її правильність і працездатність.
Якщо замість символів [. . .] підставити наступні команди:
mov
виведення рядка lea
зказаною адресою int
ah, S
функція DOS
dx, ray_title ; розташованою за
21h
і виконати асемблювання і компоновку програми, то після її запуску на текстовий екран в поточну позицію курсора буде виведений рядок "Приклад рядка". Ці команди здійснюють звернення до сервісної функції DOS виведення рядка. Команда LEA завантажує в регістр DX відносну адресу рядка, що виводиться, a INT забезпечує виклик функції. Використання сервісних функцій і вивід на екран буде докладніше розглянуті далі; поки лише відзначимо, що для правильної роботи рядок (тут — MYTITLE), що виводиться, повинен закінчуватися значком "$". Такі рядки іноді називаються ASCIIS- строками.
