Объявлять данные очень просто — например, чтобы объявить байт cо значением 5 достаточно написать:
x db 5 |
где x — название нашей переменной или константы, db — директива объявления байта, а 5 — значение. С помощью названия в программе можно будет обращаться к ячейке памяти, содержащей наш байт. Вообще, название не обязательно и можно его не писать, если оно не требуется:
db 5 |
Если запустить программу в отладчике Turbo Debugger, то в окне дампа можно увидеть результат работы директивы db:
Объявление последовательностей (массивов)
Иногда в программе требуется объявить массив, то есть несколько переменных одинакового размера, расположенных в памяти друг за другом. Например, чтобы объявить массив из 5 двухбайтных чисел можно написать:
array1 dw 1,2,3,4,5 |
где array1 — название массива, 1,2,3,4,5 — значения элементов. Вместо array1 компилятор FASM будет подставлять в программу адрес начала массива, то есть адрес первого элемента.
Дамп памяти будет выглядеть следующим образом (обратите внимание, младший байт каждого слова расположен перед старшим):
Для объявления повторяющихся элементов можно использовать такую запись (объявляем массив из 5 байтов, равных 1):
array2 db 5 dup(1) |
А ещё можно вот так объявить массив (догадайтесь сами, что тут получается):
array3 dd 4 dup(3,7,0) |
Объявление строк
Строка представляет собой массив байтов-символов и записывается в одинарных кавычках:
str1 db 'Hello' |
Для обозначения конца строки используется специальный символ. Обычно это нулевой байт, но для функций DOS используется символ ’$’.
str2 db 'Hello',0 ;Обычно так str3 db 'Hello$' ;Для DOS |
Резервирование данных (точнее памяти для них)
Можно объявлять переменные, не имеющие определённого начального значения. Такие переменные называются неинициализированными. Например, их можно использовать в программе для хранения временного или промежуточного значения. Фактически под переменную просто резервируется место в памяти. Объявлять такие переменные можно с помощью директив db, dw, dd, … и знака вопроса вместо значения.
x1 db? x2 dw?,?,? x3 dd 10 dup(?) |
Кроме того, FASM поддерживает специальные директивы резервирования данных. Число после директивы обозначает количество резервируемых элементов. То же самое можно объявить вот так:
x1 rb 1 x2 rw 3 x3 rd 10 |
С неинициализированными переменными следует быть внимательным. Не надо рассчитывать, что по умолчанию значение будет нулевым или ещё каким-то, иначе это может привести к ошибке.
Директива file
file — это особая директива объявления данных, которая позволяет добавить в исполняемый файл последовательность байтов из внешнего файла. Иногда это может быть очень удобно. Например, если вы хотите добавить изображение в исполняемый файл (в виде данных), или большой кусок текста, или даже код из другого файла. Директива используется следующим образом:
data1 file 'data.bin' ;Добавить файл data.bin целиком. data2 file 'data.bin':20 ;Добавить байты из файла data.bin, начиная со смещения 20. data3 file 'data.bin':20,5 ;Добавить 5 байтов из файла data.bin, начиная со смещения 20. |
Порядок выполнения:
Напишем совсем простую программу. Будем писать только COM-программы под DOS. Они проще, чем EXE.
Для того, чтобы написать программу, нам надо запустить fasmw.exe. (находится на диске С). Откроется окошко, в которое можно смело набивать код:
В это окошко надо ввести следующее:
Первая строка «use16» сообщает FASM’у, что нужно генерировать 16-битный код. Нам нужен именно такой для нашей первой программы. Точка с запятой — это символ комментария. Все что идет после «;» до конца строки игнорируется компилятором. Там можно писать все что угодно.
Вторая строка «org 100h» объясняет FASM’у, что следующие команды и данные будут располагаться в памяти, начиная с адреса 100h. Дело в том, что при загрузке нашей программы в память, DOS размещает в первых 256 байтах (с адресов 0000h — 00FFh) свои служебные данные. Нам эти данные изменять нежелательно.
Далее идут непосредственно команды! Программа на ассемблере состоит из команд процессора. Каждая команда обозначается мнемоникой (символическим именем). Например «mov», «inc», «nop» и т.д. После мнемоники могут идти операнды. Они отделяются одним или несколькими пробелами (или табуляцией).
Команды бывают без операндов, с одним или несколькими операндами. Если операндов больше одного, то они отделяются друг от друга запятыми.
Отступы не обязательны, но желательны — с ними код гораздо легче читать. Пустые строки игнорируются. Регистр символов значения не имеет. Можно писать большими буквами, или маленькими, или вперемешку.
Четвертая строка определяет команду «поместить число 255 в регистр AX». «mov» — это мнемоника команды (от английского «MOVe»). AX — первый операнд — приёмник. 255 — второй операнд — источник. Первый операнд является регистром. Второй операнд — константа 255.
Пятая строка. Тут команда «inc» с одним операндом. Она заставит процессор выполнить инкремент, то есть увеличение на единицу. Единственный операнд — это регистр AX, содержимое которого и будет увеличено на 1.
Шестая строка. Команда «nop» — без операндов. Эта команда ничего не делает.
Седьмая строка. Снова команда «mov», но на этот раз оба операнда являются регистрами. Команда скопирует в BX содержимое AX.
Две последние строки — это стандартное завершение процесса в DOS. Так мы будем завершать все наши программы. Команда «mov» должна быть вам понятна.
Чтобы откомпилировать программу надо выбрать меню Run->Compile. FASM предложит сохранить файл, если вы этого ещё не сделали, а затем скомпилирует. То есть переведет текст, набранный нами, в машинный код и сделает его программой. Файл с расширением.asm — это исходный код или исходник, обычный текстовый файл. При желании его можно открыть блокнотом.
12 байт получилось.
В каталоге с asm-файлом появился файл.com — это и есть наша программа.
Если в коде что-то неправильно, то в этом окне вы увидите сообщение об ошибке.
В общем, наша программа ничего не делает. Её необходимо отладить и тогда будет видно как она работает.
Работа с Turbo Debugger
Из папки преподавателя скопируйте папку TASM на диск С. Прежде всего необходимо запустить отладчик. Для этого удобно использовать bat-файл. Создайте в каталоге программы текстовый файл, назовите его, например, «debug.bat». В него надо записать всего одну строку:
C:\TD\td.exe <файл_программы>.com |
После запуска этого bat-файла вы увидите примерно такое окно:
Сообщение означает, что в исполняемом файле нет специальных данных для отладки. Но нам эти данные и не нужны, потому что программа простая и понятная. Нажимаем ОК. Turbo Debugger отображает окно CPU, в котором можно увидеть, как выполняется программа.
В большой области мы видим код нашей программы. Самый левый столбец — адреса, правее отображаются байты машинного кода, а ещё правее — символическое обозначение команд. Программа размещается в памяти, начиная с адреса 0100h в сегменте кода. В нашей программе всего 6 машинных команд, а за ними в памяти находится случайный мусор (точные значения неизвестны).
Обратите внимание, что отладчик показывает адреса и значения в шестнадцатеричном виде.
В правой части окна CPU отображаются регистры процессора и флаги. В нижней части можно увидеть дамп области памяти и стек. Стек — это специальная структура данных, с которой работают некоторые команды процессора.
Адрес текущей машинной команды определяется регистрами CS и IP, эта команда показана выделенной строкой и стрелкой. Теперь нажмите F8, чтобы выполнить первую команду.
Теперь стрелка указывает на вторую команду. Изменившиеся регистры выделены белым цветом. Регистр AX теперь содержит значение 00FFh (то есть 255, чего мы и хотели от команды «mov ax,255»). Также изменилось значение регистра IP — оно увеличилось на размер выполненной машинной команды, а именно на 3. Теперь СS:IP указывает на следующую команду. Снова нажимаем F8.
Значение регистра AX увеличилось на 1 и стало равным 0100h (256). Значение IP тоже увеличилось на 1, потому что длина команды «inc ax» — 1 байт. Процессор выполняет программу последовательно, одну команду за другой. Ещё раз нажимаем F8.
Команда NOP ничего не делает. Меняется только значение IP — снова увеличивается на 1. Снова F8.
Значение BX становится равным AX. После ещё двух нажатий F8 программа завершается. Закрыть отладчик можно с помощью меню File->Quit.