На рис.1 приведена общая схема процесса разработки программы на
ассемблере. Название программы соответствует рассмотренному ранее
примеру программы. На схеме выделено четыре этапа этого процесса. На
первом этапе, когда вводится код программы, можно использовать любой
текстовый редактор. В Windows таким редактором может быть Блокнот
(Notepad). При выборе редактора нужно учитывать, что он не должен
вставлять «посторонних» символов (специальных символов форматирования). С
этой точки зрения Microsoft Word в качестве основного редактора
ассемблерных программ не годится. Очень интересный редактор — Asm Editor
for Windows. Созданный с помощью текстового редактора файл должен иметь
расширение .asm.
Рис. 1. Схема процесса разработки программы на ассемблере
Для выполнения остальных этапов разработки требуются
специализированные программные средства из пакета MASM или TASM. В ходе
настоящего обсуждения будут описываться средства обоих пакетов, но в
основном на примере TASM, поскольку процесс разработки ассемблерных
Программ с использованием этого пакета более нагляден. В принципе, все
пакеты ассемблера выполняют практически одну работу, но по-разному,
например, маскируют ее с помощью интегрированный среды или объединяют
некоторые этапы разработки. Поняв суть преобразований исходной
программы, выполняемых пакетом TASM, освоить другие пакеты ассемблера
будет на порядок легче.
Компиляция
Компилятор — Программа, предназначенная для трансляции
высокоуровневого языка в абсолютный код или, иногда, в язык ассемблера.
Входной информацией для компилятора (исходный код) является описание
алгоритма или программа на проблемно-ориентированном языке, а на выходе
компилятора — эквивалентное описание алгоритма на
машинно-ориентированном языке (объектный код).
Компиляция — трансляция программы, составленной
на исходном языке, и последующая её компоновка в программу на некоем
машинонезависимом низкоуровневом интерпретируемом коде (как например в
случае языка Java).
Любой компилятор состоит из транслятора и компоновщика. Часто в
качестве компоновщика компилятор использует внешний компоновщик,
реализованный в виде самостоятельной программы, а сам выполняет лишь
трансляцию исходного текста (по этой причине многие ошибочно считают
компилятором разновидность транслятора). Компилятор может быть
реализован и как своеобразная программа-менеджер, для трансляции
программы вызвающая сооствествующий транслятор (трансляторы - если
разные части программы написаны на разных языках программирования) и
затем - для компоновки программы, - вызывающая компоновщик. Ярким
примером такого компилятора является имеющаяся во всех UNIX-системах (и
Linux-системах в том числе) утилита make (имеются реализации утилиты
make и в других системах, в частности в Windows-системах).
Процесс компиляции состоит из следующих фаз:
- Лексический анализ. На этой фазе последовательность символов исходного файла преобразуется в последовательность лексем.
- Синтаксический (грамматический) анализ. Последовательность лексем преобразуется в древо разбора.
- Семантический анализ. Древо разбора
обрабатывается с целью установления его семантики (смысла) — например,
привязка идентификаторов к их определениям, типам данным, проверка
совместимости типов данных, определение результирующих типов данных
выражений и т. д. Результат обычно называется «промежуточным
представлением/кодом», и может быть дополненным древом разбора, новым
древом, абстрактным набором команд или чем-то ещё, удобным для
дальнейшей обработки.
- Оптимизация. Удаляются избыточные команды и
упрощается (где это возможно) код с сохранением его смысла, т. е.
реализуемого им алгоритма (в том числе предвычисляются (т. е.
вычисляются на фазе трансляции) выражения, результаты которых
практически являются константами). Оптимизация может быть на разных
уровнях и этапах — например, над промежуточным кодом или над конечным
машинным кодом.
- Генерация кода. Из промежуточного представления порождается код на целевом языке (в том числе выполняется компоновка программы).
Трансляция программы
Следующий шаг на пути создания исполняемого модуля — трансляция
программы. Для трансляции нужен подготовленный и записанный на диск
исходный текст программы.
На этапе трансляции решается несколько задач:
- перевод команд ассемблера в соответствующие машинные команды;
- построение таблицы символов;
- расширение макросов;
- формирование файла листинга и объектного модуля.
Программа, которая реализует эти задачи, называется ассемблером.
Итог работы ассемблера — два файла: файл объектного модуля и файл
листинга. Объектный модуль включает в себя представление исходной
программы в машинных кодах и некоторую другую информацию, необходимую
для отладки и компоновки его с другими модулями. При использовании
пакета TASM получение объектного модуля исходного файла производится
программой (ассемблером) tasm.exe. Формат командной строки для запуска
tasm.exe следующий:
TASM [ключи] имя_исходнрго_файла [,имя_объектного_файла] [,имя_файла_листинга] [,имя_файла_перекрестных_ссылок]
Файл листинга содержит код ассемблера исходной программы, а также
расширенную информацию об этом коде. Для каждой команды ассемблера
указываются ее машинный (объектный) код и смещение в кодовом сегменте.
Кроме того, в конце листинга TASM формирует таблицы с информацией о
метках и сегментах, используемых в программе. Если есть ошибки или
сомнительные участки кода, то TASM включает в конец листинга сообщения о
них. Если сравнить их с сообщениями, выводимыми на экран, то видно, что
они совпадают. Кроме того, что очень удобно, эти же сообщения
включаются в текст листинга непосредственно после ошибочной строки.
Строки в файле листинга имеют следующий формат:
глубина_вложенности номер_строки смещение машинный_код исходный_код
Далее описано каждое из этих полей:
глубина_вложенности — уровень вложенности включаемых файлов или макрокоманд в файле.
номер_строки — номер строки в файле
листинга. Номера строк листинга используются для локализации ошибок и
формирования таблицы перекрестных ссылок.
смещение — смещение в байтах текущей
команды относительно начала сегмента кода. Это смещение называют также
счетчиком адреса. Величину смещения вычисляет транслятор для адресации в
сегменте кода.
машинный_код — машинное представление команды ассемблера, представленной далее в этой строке полем исходный_код.
исходный_код — строка кода из исходного файла.
Изучая внимательно файл листинга, следует обратить внимание на то,
что не все строки исходной программы имеют соответствующий машинный код
(строки 9, 16, 17, 19...22, 48...50). Это обстоятельство обусловлено
тем, что исходный файл на ассемблере в общем случае может содержать
конструкции следующих типов:
- команды ассемблера — конструкции, которым соответствуют машинные команды;
- директивы ассемблера — конструкции, которые не генерируют
машинных команд, а являются указаниями транслятору на выполнение
некоторых действий или служат для задания режима его работы;
- макрокоманды — конструкции, которые, будучи представлены одной
строкой в исходном файле программы, после обработки транслятором
генерируют в объектном модуле последовательность команд, директив или
макрокоманд ассемблера.
Компоновка программы
После устранения ошибок и получения объектного модуля можно
приступать к следующему этапу — созданию исполняемого (загрузочного)
модуля, или, как еще называют этот процесс, к компоновке программы.
Главная цель этого этапа — преобразовать код и данные в объектных файлах
в их перемещаемое выполняемое отображение.
Результатом работы компоновщика является создание загрузочного файла
с расширением .ехе. После этого операционная система может загрузить
такой файл в память и выполнить его. Полный формат командной строки для
запуска компоновщика довольно сложен (в этой и в большинстве следующих
глав мы в основном будем использовать упрощенный формат):
TLINK [ключи]
список_объектных_файлов [,имя_загрузочного_модуля] [.имя_файла_карты]
[,имя_файла_библиотеки] [,имя_файла_определений] [,имя_ресурсного_файла]
Параметры командной строки для запуска компоновщика перечислены далее.
- ключи — необязательные параметры, управляющие работой
компоновщика. Каждому ключу должен предшествовать символ - (дефис) или /
(слеш). При задании имен ключей имеет значение регистр символов.
- список_объектных_файлов — обязательный параметр, содержащий
список компонуемых файлов с расширением .obj. Файлы должны быть
разделены пробелами или знаком + (плюс), например:
tlink /v prog + mdf + fdr
При необходимости имена файлов снабжают указанием пути к ним.
- имя_загрузочного_модуля —
необязательный параметр, обозначающий имя формируемого загрузочного
модуля. Если оно не указано, то имя загрузочного модуля будет совпадать с
первым именем в списке имен объектных файлов.
- имя_файла_карты — необязательный
параметр, наличие которого обязывает компоновщик создать специальный
файл с картой загрузки. В ней перечисляются
имена, адреса загрузки и размеры всех сегментов, входящих в
программу.
- имя_файла_библиотеки — необязательный
параметр, который представляет собой путь к файлу библиотеки (.lib).
Этот файл создается и обслуживается специальной утилитой tlib.exe пакета
TASM. Утилита позволяет объединить часто используемые подпрограммы в
виде объектных модулей в один файл. В дальнейшем можно просто указывать в
командной строке tlink.exe имена нужных для компоновки объектных
модулей и файл библиотеки, в котором следует искать эти подпрограммы.
Если компонуется Windows-приложение, то на месте параметра
имя_файла_библиотеки должно указываться имя библиотеки им порта.
- имя_файла_определений — необязательный
параметр, который представляет собой путь к файлу определений (.def).
Этот файл используется при компоновке Windows-приложений.
- имя_ресурсного_файла — необязательный
параметр, который представляет собой путь к файлу с ресурсами
Windows-приложения (.res). Этот файл используется при компоновке
Windows-приложений
Отладка программы
На этапе отладки в соответствие с алгоритмом проверяется
правильность функционирования как отдельных фрагментов кода, так и
программы в целом. Но даже успешное завершение отладки еще не является
гарантией того, что программа будет работать правильно со всеми
возможными исходными данными. Поэтому нужно обязательно провести
тестирование программы, то есть проверить ее работу на «пограничных» и
заведомо некорректных исходных данных. Для этого составляются тесты.
Вполне возможно, что результаты тестирования не удовлетворят
разработчика программы. В этом случае ему придется вносить поправки в
код программы, то есть возвращаться к первому шагу процесса разработки
Специфика программ на ассемблере состоит в том, что они интенсивно
работают с аппаратными ресурсами компьютера. Это обстоятельство
заставляет программиста постоянно отслеживать содержимое определенных
регистров и областей памяти. Естественно, что человеку трудно следить за
этой информацией с большой степенью детализации. Поэтому для
локализации логических ошибок в программах используют специальный тип
программного обеспечения — программные отладчики.
Отладчики бывают двух типов:
- интегрированные отладчики, реализованные в виде интегрированной
среды, напоминающей среду для языков высокого уровня (Turbo Pascal,
Visual C++ и т. д.);
- автономные отладчики, представляющие собой отдельные программы.
|