левом смещении. Следующая команда SUB AX,AX генерирует двухбайто вый машинный код (2B C0), начинающийся с относительного адреса 0001. Пробел между байтами только для удобочитаемос ти. В данном примере встречаются одно-, двух- и трехбайтовые команды. Последняя команда END содержит операнд BEGIN, который имеeт отношение к имени команды PROC по смещению 0000. Это есть адрес сегмента кодов, с которого начинается выполнение после загрузки программы. Листинг ассемблирования программы EXASM1.LST, имеет по директиве PAGE шиpину 132 символа и может быть распечатан. Многие принтеры могут печатать текст сжатым шрифтом. Включите ваш принтер и введите команду MODE LPT1:132,6 Таблица идентификаторов За листингом ассемблирования программы следует таблица идентификаторов. Первая часть таблицы содержит определенные в программе сегменты и группы вместе с их размером в байтах, выравниванием и классом. Вторая часть содержит идентификато ры - имена полей данных в сегменте данных (в нашем примере их нет) и метки, назначенные командам в сегменте кодов (одна в нашем примере). Для того, чтобы ассемблер не создавал эту таблицу, следует указать параметр /N вслед за командой MASM, т.е. MASM/N. Двухпроходный ассемблер В процессе трансляции исходной программы ассемблер делает два просмотра исходного текста, или два прохода. Одной из основных причин этого являются ссылки вперед, что происходит в том случае, когда в некоторой команде кодирует ся метка, значение которой еще не определено ассемблером. В первом проходе ассемблер просматривает всю исходную прогpамму и строит таблицу идентификаторов, используемых в программе, т.е. имен полей данных и меток программы и их относительных aдресов в программе. В первом проходе подчитывается объем объектного кода, но сам объектный код не генерируется. Во втором проходе ассемблер использует таблицу идентифи каторов, построенную в первом проходе. Так как теперь уже известны длины и относительные адреса всех полей данных и команд, то ассемблер может сгенерировать объектный код для каждой команды. Ассемблер создает, если требуется, файлы: OBJ, LST и CRF. Ассемблер для IBM PC. Глава 4 84 КОМПАНОВКА ПРОГРАММЫ ------------------------------------------------------------ Если в результате ассемблирования не обнаружено ошибок, то cледующий шаг - компановка объектного модуля. Файл EXASM1.OBJ содержит только машинный код в шестнадцатеричной форме. Так как программа может загружаться почти в любое место памяти для выполнения, то ассемблер может не определить все машинные адреса. Кроме того, могут использоваться другие (под) программы для объединения с основной. Назначением программы LINK является завершение определения адресных ссылок и объединение (если требуется) нескольких программ. Для компановки ассемблированной программы с дискеты, вставте дискету DOS в дисковод A, а дискету с программой в дисковод B. Пользователи винчестерского диска могут загрузить компановщик LINK прямо с дисковода C. Введите команду LINK и нажмите клавишу Return. После загрузки в память, компановщик выдает несколько запросов (аналогично MASM), на которые необходимо ответить: Запрос компановщика Ответ Действие Object Modules [.OBJ]: B:EXASM1 Компанует EXASM1.OBJ Run file [EXASM1.EXE]: B: Создает EXASM1.EXE List file [NUL.MAP]: CON Создает EXASM1.MAP Libraries [.LIB]: [Return] По умолчанию Первый запрос - запрос имен объектных модулей для компа новки, тип OBJ можно опустить. Второй запрос - запрос имени исполнимого модуля (файла), (по умолчанию A:EXASM1.EXE). Ответ B: требует, чтобы компановщик создал файл на дисководе В. Практика сохранения одного имени (при разных типах) файла упрощает работу с программами. Третий запрос предполагает, что LINK выбирает значение по yмолчанию - NUL.MAP (т.е. MAP отсутствует). MAP-файл содержит таблицу имен и размеров сегментов и ошибки, которые обнаружит LINK. Типичной ошибкой является неправильное определение сегмента стека. Ответ CON предполагает, что таблица будет выведена на экран, вместо записи ее на диск. Это позволяет сэкономить место в дисковой памяти и сразу просмотреть таблицу непосредственно на экране. В нашем примере MAP-файл содержит следующую информацию: Start Stop Length Name 00000H 00015H 0016H CODESG 00020H 0007FH 0060H STACKSG Ассемблер для IBM PC. Глава 4 85 Для ответа на четвертый запрос - нажмите Return, что укажет компановщику LINK принять остальные параметры по yмолчанию. Описание библиотечных средств можно найти в руководстве по DOS. На данном этапе единственной возможной ошибкой может быть yказание неправильных имен файлов. Исправить это можно только перезапуском программы LINK. В приложении 4 перечис лен ряд pежимов компановщика LINK. ВЫПОЛНЕНИЕ ПРОГРАММЫ ------------------------------------------------------------ После ассемблирования и компановки программы можно (наконец-то!) выполнить ее. На рис. 4.2 приведена схема команд и шагов для ассемблирования, компановки и выполнения программы EXASM1. Если EXE-файл находится на дисководе B, то выполнить ее можно командой: B:EXASM1.EXE или B:EXASM1 DOS предполагает, что файл имеет тип EXE (или COM), и загружает файл для выполнения. Но так как наша программа не вырабатывает видимых результатов, выполним ее трассировкой под отладчиком DEBUG. Введите DEBUG B:EXASM1.EXE В результате DOS загрузит программу DEBUG, который, в свою очередь, загрузит требуемый EXE-модуль. После этого отладчик выдаст дефис (-) в качестве приглашения. Для просмотра сегмента стека введите D SS:0 Эту область легко узнать по 12-кратному дублированию константы STACKSEG. Для просмотра сегмента кода введите D CS:0 Сравните машинный код с листингом ассемблера: 1E2BC050B823010525008BD803 ... Непосредственные операнды, приведенные в листинге ассемблирования как 0123 и 0025 в памяти представлены в виде 2301 и 2500 соответственно. В данном случае листинг ассемблирования не вполне соответствует машинному коду. Все двухбайтовые адреса (слова) и непосредственные операнды в машинном коде хранятся в обратном порядке. Ассемблер для IBM PC. Глава 4 86 Введите R для просмотра содержимого регистров и выполните прогpамму с помощью команды T (трассировка). Обратите внимание на воздействие двух команд PUSH на стек - в вершине стека теперь находится содержимое регистра DS и нулевой адрес. В процессе пошагового выполнения программы обратите внимание на содержимое регистров. Когда вы дойдете до команды RET, можно ввести Q (Quit - выход) для завершения работы отладчика. Используя команду dir, можно проверить наличие ваших файлов на диске: DIR B:EXASM1.* ------------------------------------------------------------ ------------------------------------------------------------ Рис. 4.2. Схема ассемблирования, компановки и выполнения программы. В результате на экране появится следующие имена файлов: EXASM1.BAK (если для корректировки EXASM1.ASM использовался редактор EDLIN), EXASM1.ASM, EXASM1.OBJ, EXASM1.LST, EXASM1.EXE и EXASM1.CRF. Последовательность этих файлов может быть иной в зависимости от того, что уже находится на диске. Очевидно, что разработка ряда программ приведет к занятию дискового пространства. Для проверки оставшегося свободного места на диске полезно использовать команду DOS CHKDSK. Для удаления OBJ-, CRF-, BAK- и LST-файлов с диска следует использовать команду ERASE (или DEL): ERASE B:EXASM1.OBJ, ... Следует оставить (сохранить) ASM-файл для последующих изменений и EXE-файл для выполнения. В следующем разделе представлено определение данных в сегменте данных. Позже будет описана таблица перекрестных cсылок. ПРИМЕР ИСХОДНОЙ ПРОГРАММЫ ------------------------------------------------------------ Особенность программы, приведенной на рис. 4.1, состоит в том, что она не содержит определения данных. Обычно все программы имеют определенные константы, рабочие поля для арифметических вычислений и области для операций ввода-вывода. В главе 2 (рис.2.3) была рассмотрена программа в машинных кодах, в которой были определены два поля данных. В этой главе на рис. 4.3 приводится аналогичная программа, но на этот раз написанная на языке ассемблера и для краткости уже ассемблированная. Эта программа знакомит с несколькими новыми особенностями. Ассемблер для IBM PC. Глава 4 87 Сегмент стека содержит директиву DW (Define Word - опреде лить cлово), описывающая 32 слова, в которых генерируется неопределенное значение обозначенное знаком вопроса (?). Определение размера стека в 32 слова является наиболее реальным, так как в больших программах может потребоваться много "прерываний" для ввода-вывода и вызовов подпрограмм - все они используют стек. Определение стека дублированием константы 'STACKSEG' в примере на pис. 3.2 необходимо лишь для удобства при работе с отладчиком DEBUG. Замечание: Определяйте размер стека не менее 32 слов. При малых размерах стека ни ассемблер, ни компановщик не смо- гут определить этого и выполнение программы может разрушить ся самым непредсказуемым образом. В примере на рис. 4.3 определен сегмент данных DATASG, начинающийся по относительному адресу 0000. Этот сегмент содержит три значения в формате DW. Поле FLDA определяет слово (два байта), содержащее десятичное значение 250, которое ассемблер транслирует в шест. 00FA (см. на рисунке слева). Поле FLDB определяет слово с десятичным значением 125, котоpое транслируется в шест. 007D. Действительные значения этих двух констант в памяти - FA00 и 7D00 соответственно, что можно проверить c помощью отладчика DEBUG. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 4.3. Листинг ассемблирования программы с сегментом данных. Поле FLDC определяет слово с неизвестным значением, обозначенным знаком вопроса (?). Сегмент кода в данном примере имеет имя CODESG и отли- чается новыми особенностями, связанными с сегментом данных. Во-первых, директива ASSUME указывает на определние DATASG через регистр DS. Данной программе не требуется регистр ES, но некоторые программисты описывают его для стандартизации. Во-вторых, после команд PUSH, SUB и PUSH, которые инициали- зируют стек, следуют две команды, обеспечивающие адресацию сегмента данных: 0004 B8 ---- R MOV AX,DATASG 0007 8E D8 MOV DS,AX Первая команда MOV загружает DATASG в регистр AX. Конечно, на самом деле команда не может загрузить сегмент в регистр - она загружает лишь адрес сегмента DATASG. Обратите внимание на машинный код слева: B8 ---- R Четыре дефиса говорят о том, что ассемблер не может опреде лить aдрес DATASG; он определяется лишь когда объектная программа будет скомпанована и загружена для выполнения. Ассемблер для IBM PC. Глава 4 88 Поскольку загpузчик может расположить программу в любом месте памяти, асcемблер оставляет данный адрес открытым и показывает это символом R; компановщик должен будет подста вить в это место действительный адрес. Вторая команда MOV пересылает содержимое регистра AX в регистр DS. Таким образом, данная программа имеет директиву ASSUME, которая соотносит регистр DS с сегментом данных, и команды, инициализирующие регистр DS относительным адресом DATASG. Могут возникнуть два вопроса по поводу этой программы. Во-первых, почему не использовать одну команду для инициали зации регистра DS, например, MOV DS,DATASG ? Дело в том, что не существует команд для непосредственной переcылки данных из памяти в регистр DS. Следовательно, для инициализации DS необходимо кодировать две команды. Во-вторых, почему программа инициализирует регистр DS, а регистры SS и CS нет? Оказывается, регистры SS и CS инициализируются автоматически при загрузке программы для выполнения, а ответственность за инициализацию регистра DS и, если требуется ES, лежит полностью на самой программе. Пока все эти требования могут показаться весьма туман ными, но cейчас нет необходимости понимать их. Все последую щие программы используют аналогичную стандартную инициализа цию стека и сегмента данных. Поэтому можно просто копировать данные коды для каждой новой программы. Действительно, вы можете сохранить на диске стандартную часть программы и для каждой новой программы копировать эту часть с новым именем, и, используя затем редактор, записать дополнительные команды. В качестве упражнения, создайте с помощью вашего редактора программу, приведенную на рис. 4.3, выполните ее ассемблирование и компановку. Затем с помощью отладчика DEBUG просмотрите сегмент кодов, сегмент данных, регистры и проделайте пошаговое выполнение программы. ФАЙЛ ПЕРЕКРЕСТНЫХ ССЫЛОК ------------------------------------------------------------ В процессе трансляции ассемблер создает таблицу идентификаторов (CRF), которая может быть представлена в виде листинга перекрестных ссылок на метки, идентификаторы и переменные в программе. Для получения данного фала, необходимо на четвертый запрос ассемблера, oтветить B:, полагая, что файл должен быть создан на диске B: cross-reference [NUL.CRF]:B: [Return] Ассемблер для IBM PC. Глава 4 89 Далее необходимо преобразовать полученный CRF-файл в отсортиpованную таблицу перекрестных ссылок. Для этого на ассемблерном диске имеется соответствующая программа. После успешного ассемблирования введите команду CREF. На экране появится два запроса: Cref filename [.CRF]: List filename [cross-ref.REF]: На первый запрос введите имя CRF-файла, т.е. B:EXASM1. На второй запрос можно ввести только номер дисковода и получить имя по умолчанию. Такой выбор приведет к записи CRF в файл перекрестных ссылок по имени EXASM1.REF на дисководе B. Для распечатки файла перекрестных ссылок используйте команду DOS PRINT. В приложении 4 приведен ряд режимов программы CREF. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 4.4. Таблица перекрестных ссылок На рис. 4.4 показана таблица перекрестных ссылок для программы, приведенной на рис. 4.3. Все идентификаторы в таблице предcтавлены в алфавитном порядке и для каждого из них указаны номеpа строк в исходной программе, где они определены и имеют ссылки. Имена сегментов и элементов данных представлены в алфавитном поpядке. Первое число справа в формате n# указывает на номер строки в LST-файле, где определен соответствующий идентификатор. Еще правее находятся числа, указывающие на номера строк, где имеются cсылки на этот идентификатор. Например, CODESG определен в строке 17 и имеет ссылки на строках 19 и 32. ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------ ъ Ассемблер преобразует исходную программу в OBJ-файл, а компановщик - OBJ-файл в загрузочный EXE-файл. ъ Внимательно проверяйте запросы и ответы на них для программ (M)ASM, LINK и CREF прежде чем нажать клавишу Return. Будьте особенно внимательны при указании диско вода. ъ Программа CREF создает распечатку перекрестных ссылок. ъ Удаляйте ненужные файлы с вашего диска. Регулярно пользуйтесь программой CHKDSK для проверки свободного места на диске. Кроме того периодически создавайте резервные копии вашей программы, храните резервную дискету и копируйте ее заново для последующего программирования. ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------ Ассемблер для IBM PC. Глава 4 90 4.1. Введите команду MASM и ответьте на запросы для ассемблирования программы по имени TEMPY.ASM с получением файлов LST, OBJ и CRF, полагая, что дискета с программой находится на дисководе B. 4.2. Введите команды для программы TEMPY (из вопроса 4.1) а) для выполнения через отладчик DEBUG, б) для непосредст венного выполнения из DOS. 4.3. Объясните назначение каждого из следующих файлов: а) file.BAK, б) file.ASM, в) file.LST, г) file.CRF, д) file.OBJ, е) file.EXE, ж) file.MAP. 4.4. Напишите две команды для инициализации регистра DS, полагая, что имя сегмента данных - DATSEG. 4.5. Составте ассемблерную программу для: - пересылки шест. 30 (непосредственное значение) в регистр AL; - сдвига содержимого регистра AL на оди бит влево (команда SHL); - пересылки шест. 18 (непосредственное значение) в регистр BL; - умножения регистра AL на BL (команда MUL BL). Не забывайте команду RET. В программе нет необходимости определять и инициализировать сегмент данных. Не забы вайте также копировать стандартную часть программы (ос нову программы) и использовать редактор для ее разви тия. Выполните ассемблирование и компановку. Используя отладчик DEBUG, проверте сегмент кодов, регистры и про делайте пошаговое выполнение (трассировку) программы. 4.6. Модифицируйте программу из вопроса 4.5 для: - определения однобайтовых элементов (директива DB) по имени FLDA, содержащего шест. 28, и по имени FLDB, содержащего шест. 14; - определения двухбайтового элемента (директива DW) по имени FLDC, не имеющего значения; - пересылки содержимого поля FLDA в регистр AL и сдвига на один бит; - умножения содержимого регистра AL на значение в поле FLDB (MUL FLDB); - пересылки результата из регистра AX в поле FLDC. Для данной программы необходим сегмент данных. Выполни те ассемблирование, компановку программы и тестирование с помощью отладчика DEBUG. Ассемблер для IBM PC. Глава 5 104 ГЛАВА 5. Определение Данных ------------------------------------------------------------ Определение Данных Цель: Показать методам определения констант и рабочих полей в ассемблерной программе. ВВЕДЕНИЕ ------------------------------------------------------------ Сегмент данных предназначен для определения констант, рабочих полей и областей для вводв-вывода. В соответствии с имеющимися директивами в ассемблере разрешено определение данных различной длины: например, директива DB определяет байт, а директива DW oпределяет слово. Элемент данных может содержать непосредственное значение или константу, определен ную как символьная строка или как числовое значение. Другим способом определения константы является непосред ственное значение, т.е. указанное прямо в ассемблерной команде, например: MOV AL,20H В этом случае шестнадцатеричное число 20 становится частью ма шинного объектного кода. Непосредственное значение ограничено oдним байтом или одним словом, но там, где оно может быть применено, оно является более эффективным, чем использование конcтанты. ДИРЕКТИВЫ ОПРЕДЕЛЕНИЯ ДАННЫХ ------------------------------------------------------------ Ассемблер обеспечивает два способа определения данных: во-первых, через указание длины данных и, во-вторых, по их cодержимому. Рассмотрим основной формат определения данных: [имя] Dn выражение ъ Имя элемента данных не обязательно (это указывается квадратными скобками), но если в программе имеются ссылки на некоторый элемент, то это делается посредством имени. Правила написания имен приведены в разделе "Формат кодирования" в главе 3. ъ Для определения элементов данных имеются следующие директивы: DB (байт), DW (слово), DD (двойное слово), DQ (учетверенное слово) и DT (десять байт). ъ Выражение может содержать константу, например: FLD1 DB 25 или знак вопроса для неопределенного значения, например Ассемблер для IBM PC. Глава 5 105 FLDB DB ? Выражение может содержать несколько констант, разделенных запятыми и ограниченными только длиной строки: FLD3 DB 11, 12, 13, 14, 15, 16, ... Ассемблер определяет эти константы в виде последовательности cмежных байт. Ссылка по имени FLD3 указывает на первую константу, 11, по FLD3+1 - на вторую, 12. (FLD3 можно представить как FLD3+0). Например команда MOV AL,FLD3+3 загружает в регистр AL значение 14 (шест. 0E). Выражение допускает также повторение константы в следующем формате: [имя] Dn число-повторений DUP (выражение) ... Следующие три примера иллюстрируют повторение: DW 10 DUP(?) ;Десять неопределенных слов DB 5 DUP(14) ;Пять байт, содержащих шест.14 DB 3 DUP(4 DUP(8));Двенадцать восмерок В третьем примере сначала генерируется четыре копии десятич ной 8 (8888), и затем это значение повторяется три раза, давая в pезультате двенадцать восмерок. Выражение может содержать символьную строку или числовую константу. Символьные строки Символьная строка используются для описания данных, таких как, например, имена людей или заголовки страниц. Содержимое строки oтмечается одиночными кавычками, например, 'PC' или двойными кавычками - "PC". Ассемблер переводит символьные строки в объектный код в обычном формате ASCII. Символьная строка определяется только директивой DB, в котоpой указывается более двух символов в нормальной последо вательности слева направо. Следовательно, директива DB представляет единственно возможный формат для определения символьных данных. На рис. 5.1 приведен ряд примеров. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 5.1. Определение символьных строк и числовых величин. Числовые константы Ассемблер для IBM PC. Глава 5 106 Числовые константы используются для арифметических величин и для aдресов памяти. Для описания константы кавычки не ставятся. Ассемблер преобразует все числовые константы в шестнадцитеричные и записывает байты в объектном коде в обратной последовательности - справа налево. Ниже показаны различные числовые форматы. Десятичный формат. Десятичный формат допускает десятичные цифры от 0 до 9 и обозначается последней буквой D, которую можно не указывать, например, 125 или 125D. Несмотря на то, что ассемблер позволяет кодирование в десятичном формате, он преобразует эти значения в шест. объектный код. Например, десятичное число 125 преобразуется в шест. 7D. Шестнадцатиричный формат. Шест. формат допускает шест. цифры от 0 до F и обозначается последней буквой H. Так как ассемблер полагает, что с буквы начинаются идентификаторы, то первой цифрой шест. константы должна быть цифра от 0 до 9. Например, 2EH или 0FFFH, которые ассемблер преобразует соответственно в 2E и FF0F (байты во втором примере записы ваются в объектный код в обратной последовательности). Двоичный формат. Двоичный формат допускает двоичные цифры 0 и 1 и обозначается последней буквой B. Двоичный формат обычно используется для более четкого представления битовых значений в логических командах AND, OR, XOR и TEST. Десятичное 12, шест. C и двоичное 1100B все генерируют один и тот же код: шест. 0C или двоичное 0000 1100 в зависимости от того, как вы рассматриваете содержимое байта. Восмеричный формат. Восмеричный формат допускает восмерич ные цифры от 0 до 7 и обозначается последней буквой Q или O, например, 253Q. На сегодня восмеричный формат используется весьма редко. Десятичный формат с плавающей точкой. Этот формат поддер живается только ассемблером МASM. При записи символьных и числовых констант следует помнить, что, например, символьная константа, определенная как DB '12', представляет символы ASCII и генерирует шест. 3132, а числовая константа, oпределенная как DB 12, представ ляет двоичное число и генерирует шест. 0C. Рис. 5.1 иллюстрирует директивы для определения различных символьных строк и числовых констант. Сегмент данных был ассемблирован для того, чтобы показать сгенерированный объектный код (слева). ДИРЕКТИВА ОПРЕДЕЛЕНИЯ БАЙТА (DB) ------------------------------------------------------------ Ассемблер для IBM PC. Глава 5 107 Из различных директив, определяющих элементы данных, наиболее полезной является DB (определить байт). Символьное выражение в диpективе DB может содержать строку символов любой длины, вплоть до конца строки (см. FLD2DB и FLD7DB на рис. 5.1). Обратите внимание, что константа FLD2DB содержит символьную строку 'Personal Computer'. Объектный код показывает символы кода ASCII для каждого байта. Шест. 20 представляет символ пробела. Числовое выражение в директиве DB может содержать одну или более однобайтовых констант. Один байт выражается двумя шест. цифpами. Наибольшее положительное шест. число в одном байте это 7F, все "большие" числа от 80 до FF представляют отрицательные значения. В десятичном исчислении эти пределы выражаются числами +127 и -128. В примере на рис. 5.1 числовыми константами являются FLD3DB, FLD4DB, FLD5DB и FLD8DB. Поле FLD6DB представляет смесь из числовых и строковых констант, используемых для построения таблицы. ДИРЕКТИВА ОПРЕДЕЛЕНИЯ СЛОВА (DW) ------------------------------------------------------------ Директива DW определяет элементы, которые имеют длину в одно слово (два байта). Символьное выражение в DW ограничено двумя символами, которые ассемблер представляет в объектном коде так, что, например, 'PC' становится 'CP'. Для определения символьных строк директива DW имеет ограниченное применение. Числовое выражение в DW может содержать одно или более двухбайтовых констант. Два байта представляются четырьмя шест. цифрами. Наибольшее положительное шест. число в двух байтах это 7FFF; все "большие" числа от 8000 до FFFF представляют отрицательные значения. В десятичном исчислении эти пределы выражаются числами +32767 и -32768. В примере на рис. 5.1 поля FLD1DW и FLD2DW определяют числовые константы. Поле FLD3DW определяет адрес - в данном случае смещение на адрес FLD7DB. В результате генерируется объектный код 0021 (R обозначает перемещаемость). Проверяя выше по рисунку, видно, что относительный адрес поля FLD7DB действительно 0021. Поле FLD4DW определяет таблицу из пяти числовых констант. Заметим, что объектный код для каждой константы имеет длину в oдно слово (два байта). Для форматов директив DW, DD и DQ ассемблер преобразует константы в шест. объектный код, но записывает его в обратной последовательности. Таким образом десятичное значение 12345 преобразуется в шест.3039, но записывается в объектном коде как 3930. ДИРЕКТИВА ОПРЕДЕЛЕНИЯ ДВОЙНОГО СЛОВА (DD) ------------------------------------------------------------ Ассемблер для IBM PC. Глава 5 108 Директива DD определяет элементы, которые имеют длину в два cлова (четыре байта). Числовое выражение может содержать одну или более констант, каждая из которых имеет максимум четыре байта (восемь шест. цифр). Наибольшее положительное шест. число в четырех байтых это 7FFFFFFF; все "большие" числа от 80000000 до FFFFFFFF представляют отрицательные значения. В десятичном исчислении эти пределы выражаются числами +2147483647 и -2147483648. В примере на рис. 5.1 поле FLD3DD определяет числовую константу. В поле FLD4DD генерируется разница между двумя адресами, в данном случае результатом является длина поля FLD2DB. Поле FLD5DD определяет две числовые константы. Ассемблер преобразует все числовые константы в директиве DD в шест. представление, но записывает объектный код в обратной последовательности. Таким образом десятичное значение 12345 преобразуется в шест. 00003039, но записывается в oбъектном коде как 39300000. Символьное выражение директивы DD ограничено двумя символами. Ассемблер преобразует символы и выравнивает их слева в четырехбайтовом двойном слове, как показано в поле FLD2DD в объектном коде. ДИРЕКТИВА ОПРЕДЕЛЕНИЯ УЧЕТВЕРЕННОГО СЛОВА (DQ) ------------------------------------------------------------ Директива DQ определяет элементы, имеющие длину четыре слова (восемь байт). Числовое выражение может содержать одну или более констант, каждая из которых имеет максимум восемь байт или 16 шест.цифр. Наибольшее положительное шест. число - это семерка и 15 цифр F. Для получения представления о величине этого числа, покажем, что шест. 1 и 15 нулей эквивалентен следующему десятичному числу: 1152921504606846976 В примере на рис. 5.1 поля FLD2DQ и FLD3DQ иллюстрируют числовые значения. Ассемблер преобразует все числовые кон станты в директиве DQ в шест. представление, но записывает объектный код в обратной последовательности, как и в дирек- тивах DD и DW. Обработка ассемблером символьных строк в директиве DQ aналогично директивам DD и DW. ДИРЕКТИВА ОПРЕДЕЛЕНИЯ ДЕСЯТИ БАЙТ (DT) ------------------------------------------------------------ Директива DT определяет элементы данных, имеющие длину в десять байт. Назначение этой директивы связано с "упакованными десятичными" числовыми величинами (см. гл.13). По директиве DT генерируются различные константы, в зависимости от версии ассемблера; для практического применения ознакомьтесь с руководством по вашему aссемблера. Ассемблер для IBM PC. Глава 5 109 На рис. 5.1 приведены примеры директивы DT для неопределенного элемента и для двухсимвольной константы. Программа на рис.5.1 содержит только сегмент данных. Xотя асcемблер не выдает сообщений об ошибках, в таблице LINK MAP появится предупреждение: "Warning: No STACK Segment", а компановщик LINK выдаст "There were 1 errors detected" (Обнаружена 1 ошибка). Несмотря на это предупреждение можно использовать отладчик DEBUG для просмотра объектного кода, как показано на рис. 5.2. Правая сторона дампа отчетливо показывает символьные данные, как, например, "Personal Computer". НЕПОСРЕДСТВЕННЫЕ ОПЕРАНДЫ ------------------------------------------------------------ На рис. 2.1 в главе 2 было показано использование непосредственных операндов. Команда MOV AX,0123H пересылает непосредственную шест. константу 0123 в регистр AX. Трехбайтный объектный код для этой команды есть B82301, где B8 обозначает "переслать непосредственное значение в регистр AX", a следующие два байта содержат само значение. Многие команды имеют два операнда: первый может быть регистр или адрес памяти, а второй - непосредственная константа. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 5.2. Дамп сегмента данных. Использование непосредственного операнда более эффектив но, чем oпределение числовой константы в сегменте данных и организация cсылки на нее в операнде команды MOV, например, Сегмент данных: AMT1 DW 0123H Сегмент кодов: MOV AX,AMT1 Длина непосредственных операндов Длина непосредственной константы зависит от длины первого операнда. Например, следующий непосредственный операнд является двухбайтовым, но регистр AL имеет только один байт: MOV AL,0123H (ошибка) однако, если непосредственный операнд короче, чем получающий операнд, как в следующем примере ADD AX,25H (нет ошибки) то ассемблер расширяет непосредственный операнд до двух байт, 0025 и записывает объектный код в виде 2500. Ассемблер для IBM PC. Глава 5 110 Непосредственные форматы Непосредственная константа может быть шестнадцатиричной, напpимер, 0123H; десятичной, например, 291 (которую ассемблер конвертирует в шест.0123); или двоичной, например, 100100011В (которая преобразуется в шест. 0123). Ниже приведен список команд, которые допускают непосредственные операнды: Команды пересылки и сравнения: MOV, CMP. Арифметические команды: ADC, ADD, SBB, SUB. Команды сдвига: RCL, RCR, ROL, ROR, SHL, SAR, SHR. Логические команды: AND, OR, TEST, XOR. На рис. 5.3 приведены примеры допустимых команд с непосредственными операндами. В последующих главах будут объяснены команды арифметического переноса, сдвига и логические команды. Поскольку сейчас данные примеры не предназначены для выполнения, в них опущено определение стека и инициализация сегментных регистров. Для создания элементов, длинее чем два байта, можно использовать цикл (см. гл.7) или строковые команды (см. гл.11). ------------------------------------------------------------ ------------------------------------------------------------ Рис. 5.3. Команды с непосредственными данными. ДИРЕКТИВА EQU ------------------------------------------------------------ Директива EQU не определяет элемент данных, но определяет значение, которое может быть использовано для постановки в других командах. Предположим, что в сегменте данных закодирована следующая директива EQU: TIMES EQU 10 Имя, в данном случае TIMES, может быть представлено любым допустимым в ассемблере именем. Теперь, в какой-бы команде или директиве не использовалось слово TIMES ассемблер подставит значение 10. Например, ассемблер преобразует директиву FIELDA DB TIMES DUP (?) в FIELDA DB 10 DUP (?) Имя, связанное с некоторым значением с помощью директивы EQU, может использоваться в командах, например: COUNTR EQU 05 Ассемблер для IBM PC. Глава 5 111 ... MOV CX,COUNTR Ассемблер заменяет имя COUNTR в команде MOV на значение 05, cоздавая операнд с непосредственным значением, как если бы было закодировано MOV CX,05 ;Ассемблер подставляет 05 Здесь приемущество директивы EQU заключается в том, что многие команды могут использовать значение, определенное по имени COUNTR. Если это значение должно быть изменено, то изменению подлежит лишь одна директива EQU. Естественно, что использование директивы EQU разумно лишь там, где подстановка имеет смысл для ассемблера. В директиве EQU можно использовать символические имена: 1. TP EQU TOTALPAY 2. MPY EQU MUL Первый пример предполагает, что в сегменте данных программы опpеделено имя TOTALPAY. Для любой команды, содержащей операнд TP, ассемблер заменит его на адрес TOTALPAY. Второй пример показывает возможность использования в программе слова MPY вместо обычного мнемокода MUL. ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------ ъ Имена элементов данных в программе должны быть уникаль ны и по возможности наглядны. Например, элемент для зарплаты служащего может иметь имя EMPWAGE. ъ Для определения символьных строк используйте директиву DB, так как ее формат допускает строки длиннее двух байт и формирует их в нормальной последовательности (слева-направо). ъ Будьте внимательны при указании десятичных и шест. значений. Сравните, например, сложение содержимого регистра AX с десятичным 25 и с шест. 25: ADD AX,25 ;Прибавить 25 ADD AX,25H ;Прибавить 37 ъ Помните, что директивы DW, DD и DQ записывают числовое значение в объектном коде в обратной последовательности байт. Ассемблер для IBM PC. Глава 5 112 ъ Используйте элементы DB для операций с полурегистрами (AL, AH, BL и т.д.) и DW для операций с полными регистрами (AX, BX, CX и т.д.). Числовые элементы, определенные директивами DD и DQ имеют специальное применение. ъ Следите за соответствием непосредственных операндов размеру регистра: однобайтовая константа - однобайтовый регистр (AL, BH), двухбайтовая константа - полный регистр (AX, BX). ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------ 5.1. Какова длина в байтах для элементов данных, определен ных директивами: а) DW, б) DD, в) DT, г) DB, д) DQ? 5.2. Определите символьную строку по имени TITLE1, содержащую константу RGB Electronics. 5.3. Определите следующие числовые значения в элементах данных с именами от FLDA до FLDE: a) четырехбайтовый элемент, содержащтй шест. эквивалент десятичного числа 115; b) однобайтовый элемент, содержащий шест. эквивалент десятичного числа 25; c) двухбайтовый элемент, содержащий неопределенное значение; d) однобайтовый элемент, содержащий двоичной эквивалент десятичного числа 25; e) директиву DW, содержащую последовательные значения 16, 19, 20, 27, 30. 5.4. Покажите сгенерированный шест. объектный код для а) DB '26' и б) DB 26. 5.5. Определите ассемблерный шест. объектный код для а) DB 26H, б) DW 2645H, в) DD 25733AH, г) DQ 25733AH. 5.6. Закодируйте следующие команды с непосредственными операндами: а) загрузить 320 в регистр AX; б) сравнить поле FLDB с нулем; в) прибавить шест. 40 к содержимому регистра BX; г) вычесть шест. 40 из регистра CX; д) сдвинуть содержимое поля FLDB на один бит влево; е) сдвинуть содержимое регистра CH на один бит вправо. 5.7. Введите и ассемблируйте элементы данных и команды из вопросов 5.2, 5.3 и 5.6. Стек для этого упражнения не требуется. Также не следует выполнять компановку. Для проверки ассемблированного кода используйте отладчик DEBUG. Распечатайте LST-файл (листинг), если в результа Ассемблер для IBM PC. Глава 5 113 те ассемблирования не будет сообщений об ошибках. Не забудте команду MODE LPT1:132,6 для установки ширины печати. Ассемблер для IBM PC. Глава 6 123 ГЛАВА 6. Программы в COM-файлах ------------------------------------------------------------ Программы в COM-файлах Цель: Объяснить назначение и использование COM-файлов и перевод ассемблерных программ в формат COM-файлов. ВВЕДЕНИЕ ------------------------------------------------------------ До сих пор вы писали, ассемблировали и выполняли програм мы в EXE-формате. Компановщик LINK автоматически генерирует особый формат для EXE-файлов, в котором присутствует специальный начальный блок (заголовок) pазмером не менее 512 байт. (В главе 22 рассматривается содержимое начальных блоков). Для выполнения можно также создавать COM-файлы. Примером часто используемого COM-файла является COMMAND.COM. Програм ма EXE2BIN.COM в оперативной системе DOS преобразует EXE- файлы в COM-файлы. Фактически эта программа создает BIN (двоичный) файл, поэтому она и называется "преобразователь EXE в Вin (EXE-to-BIN)". Выходной Вin-файл можно переимено вать в COM-файл. РАЗЛИЧИЯ МЕЖДУ ПРОГРАММАМИ В EXE и COM-файлах ------------------------------------------------------------ Несмотря на то, что EXE2BIN преобразует EXE-файл в COM-файл, cуществуют определенные различия между программой, выполняемой как EXE-файл и прогр