Рассмотрим теперь работу ассемблера в целом. Детали будут обсуждены позднее, но сейчас нам нужно ввести новые термины и ознакомиться с реальным результатом работы ассемблера.
Ассемблер берет программу, написанную на языке ассемблера, и превращает ее в машинный язык. Файл, который содержит программу на языке ассемблера, называют исходным файлом. Выход и ассемблера в действительности является не собственно машинным языком, а некоторым промежуточным представлением программы. Этот выходной файл называют объектным файлом. Данные в нем называются объектным кодом. Для получения из него настоящего машинного кода объектный код должен быть несколько изменен. Для IBM PC это делает программа редактор связей LINK. Шаг преобразования объектных кодов в машинные принято называть построением связей или редактированием связей. Как пользоваться редактором связей мы увидим в одной из следующих глав.
Помимо преобразования исходного кода в объектный ассемблер создает несколько других выходных файлов. Один из них - ассемблерный листинг. Он содержит сообщение о действиях ассемблера. Зтот файл содержит исходный код вместе с комментариями, а также объектный код, сформированный ассемблером. Фиг. 2.9 дает пример листинга ассемблера, иногда называемого распечаткой.
Microsoft (R) Macro Assembler Version 5.00 10/28/88 16:35:34Фиг. 2.9 Пример ассемблирования Page 1-11 PAGE,1322 TITLE Фиг. 2.9 Пример ассемблирования3 0000 CODE SEGMENT4 ASSUME CS:CODE5 6 0000 03 C3 PART1: ADD AX,BX; Сложить с длиной буфера7 8 0002 CODE ENDS9 ENDФиг. 2.9 Пример ассемблирования
Взяв пример команды ассемблера, рассмотрим результаты работы ассемблера. В правой части распечатки находятся исходные команды. В левой части - информация, сгенерированная ассемблером. Первая колонка содержит номер каждой строки распечатки. Ассемблер устанавливает эти номера для исходного файла. Они строк не обязательно соотносятся с номерами строк в исходном файле сформированном текстовым редактором.
|
Во второй колонке содержатся адреса инструкций. Программа LINK может их изменить, но они являются лучшим предположением, которое может сделать ассемблер на шаге ассемблирования. Следующая колонка - код команды на машинном языке. Поскольу команды 8088 имеют длину от 8 до 56 бит, это поле будет изменяться в размере. Кроме того, программа LINK может изменить некоторую информацию в поле объектных кодов. Редактор связей может изменить любую группу команд, оперирующих с адресами. Однако, за исключением адресов, листинг ассемблера дает верные машинные коды, которые и будут в дальнейшем исполняться.
В большинстве примеров программ мы будем использовать листинг ассемблера. Это позволит нам сразу видеть вырабатываемый ассемблером код.
Другой создаваемый ассемблером файл - файл перекрестных сыылок. Этот файл описывает все связи между метками и командами, которые их используют. Такая информация незаменима, когда вы пытаетесь изменить программу. Вы можете воспользовваться перекрестными ссылками для того, чтобы выявить все команды, которые обращаются к определенному участку памяти. Это позволяет программисту определить все команды, на которые может повлиять изменение в другой части программы. Использование информации о перекрестных ссылках будет обсуждаться в главе 5.
Биты, байты и слова
|
Мы назвали "битом" двоичную цифру, еденичное значение 0 или 1. Для удобства введем специальные названия для некоторых последовательностей битов. Группу из 8 бит принято называть байтом. Во всей документации IBM и в этой книге о любых 8 битах информации говорится как о байте. Байт заслужил свое собственное имя по нескольким причинам. Элементарная ячейка памяти имеет длину 8 бит. При каждом обращении к паамяти IBM PC для процессора запрашивается ровно 8 бит информации. Как мы увидим позднее, отдельные команды 8088 могут производить арифметические и логические опреации над группами в 8 бит. Байт - наименьшая еденица информации, с которой 8088 может манипулировать непосредственно. 8088 может одной операцией сложить два 8-битовых числа, но не может этого проделать с 4-битовыми. Кроме того IBM PC использует байт для представления одного символа. Используя один байт можно представить 256 (2**8) отдельных элементов, таких, например, как графические символы. В следующем пункте мы рассмотрим набор символов IBM PC.
Поскольку байт является элементом памяти, мы должны иметь средство определения в ней отдельных байтов. Задача ассемблера фактически и будет состоять в определении содержимого памяти для выполнения программы. В основном исходный текст ассемблера состоит из выполняемых инструкций. Но для помещения определенного значения в байт памяти ассемблер располагает специальным механизмом - определением байта (dtfine byte) или псевдокомандой DB. DB не является командой 8088. Это команда ассемблеру поместить в память определенные значения. Псевдокоманда
DB 23
|
дает ассемблеру задание сохранить десятичное значение 23 в текущий байт памяти. А оператор
DB 1,2,3,4
сохраняет значения от 1 до 4 по четырем последовательным адресам в памяти.
В программах на языке ассемблера оператор DB применяют для определения областей памяти. В предыдущих примерах мы размещали в памяти определенные значения. Это может быть поисковая таблица или информация для перекодировки чисел. Мы составим несколько примеров, в которых используется определенная подобным образом информация. Кроме того встречаются ситуации, когда программе требуется место в памяти для сохранения данных в процессе исполнения. Во время ассемблирования программы содержимое этого участка памяти неизвестно: собственно, это содержимое будет переменным во время исполнения программы. Инструкция
DB?
сообщает ассемблеру о необходимости выделить один байт памяти, не изменяя его содержимое. В Этом байте может оказаться любое случайное число, которое будет там оставаться пока какая-либо команда не поместит в него определенное значение.
Нам может потребоваться выделить и большое количество байтов, например, чтобы оставить область памяти для массива. Мы можем это сделать так:
DB 25 DUP(?)
Этой инструкцией выделяется 25 байт памяти. Ключевое слово DUP в этой псевдокоманде означает повторить (duplicate). Число 25 указывает, сколько раз ассемблер повторит определение байта в памяти. Значение или значения в скобках ассемблер использует для инициализации этой области памяти. В данном случае это значение неизвестно. Для инициализации области с одним и тем же значением выражение, например,
DB 17 DUP(31)
создает 17 байт со значением 31 каждый. Наконец,
DB 30 DUP(1,2,3,4,5)
выделяет 30 байт со значениями от 1 до 5 в первых пяти байтах. Следующие пять байт тоже имеют значения от 1 до 5 и т.д. Ассемблер повторяет значения в скобках пока не будут заполнены все 30 байт.
Иногда нам хочется обратиться к набору бит меньшему чем байт. Принят размер 4 бит. В 4 битах мы можем представить все 10 десятичных цифр. Для значений такого размера мы будем пользоваться термином "полубайт". Этот термин (в оригинале "nybble" - прим. перев.), который достиг широкого применения, позволяет нам говорить о данных, меньших, чем "байт".
Термин "Слово" имеет для программиста значение отличное от принятого в языке. В применении к ЭВМ слово - это наибольшее количество бит, с которым машина может обращаться как с единым элементом. Для системы IBM/370 слово составляет 32 бит, а для семейства Intel 8088 - 16. Поэтому термин "слово" имеет неопределенный смысл, пока не известна конкретная машина. Размер слова в 8088 составляет 16 бит. Этот размер определяется каналами передачи данных в процессоре. Над числами до 16 бит 8088 может призводить операции одной командой. Любое более крупное число потребует более одной команды. Существуют команды, которые манипулируют и с меньшими объемами памяти, как, например, команда сложения двух 8-битовых чисел. Несколько инструкций позволяют манипулировать и с отдельными битами. Но для сложения двух 32-битовых чисел потребуется уже две команды, складывающие по 16 бит каждая. Наибольшее число над которым мы можем производить элементарные операции типа сложения имеет размер машинного слова.
Аналогично команде определения байта памяти, существует и инструкция для определения слова памяти. Оператор ассемблера DW означает определение слова (define word). Первое утверждение DW на Фиг. 2.10 определяет 16 бит памяти со значением 1234H. Как и в случае с байтами, мы можем использовать оператор DUP для определения больших областей памяти, разбитых на слова. И точно также, для обозначения неинициируемых областей можно использовать операнд "?".
Microsoft (R) Macro Assembler Version 5.00 10/29/88 16:10:44Фиг. 2.10 Примеры определения слов Page 1-11 PAGE,1322 TITLE Фиг. 2.10 Примеры определения слов3 4 0000 1234 DW 1234H5 0002 0003[ DW 3 DUP(5678H)6 56787 ]89 0008???? DW?1011 ENDФиг. 2.10 Примеры определения слов
Одна из обескураживающих черт 8088 - это его манера хранения слов в памяти. На Фиг. 2.10, хоть мы и определяли значение слова как 1234Н, ассемблер сохранит в памяти значение 3412Н, по крайней мере так это выглядит. Посмотрим, как это получается.
Допустим, слово 1234Н сохранено в ячейках 100 и 101. 8088 требует, чтобы ассемблер поместил значение 34Н в ячейку 100, а 12Н - в 101. Легче всего запомнить это так, что ассемблер сохраняет младший байт слова в ячейку памяти с меньшим адресом, а старший байт - с большим. На Фиг. 2.11 показано, содержимое памяти после того, как ассемблер поместит в нее данные. Пока вы не привыкнете к такому методу, вам
Адрес Значение-------------------------.... 100 34Н 101 12Н....-------------------------Фиг. 2.11 Представление в памяти DW 1234H
будет казаться, что все в памяти наоборот. К счастью, если вы не будете смешивать операции над байтами и над словами одной и той же области в памяти, вам незачем беспокоиться об этом неожиданном "переключении" байтов. Программа может спокойно работать со словами, а 8088 всегда разберется что к чему. Только в том случае, если вы захотите обратиться к конкретному байту какого-либо слова, вам придется иметь дело с фактическим способом хранения слов в памяти семейства 8088. Ассемблер обращает внимание на структуру слов в распечатке программы, то есть изображает слова в объектном коде как слова, а не как байты, которые выглядели бы перевернутыми наоборот. Вы сможете различать слова благодаря тому, что ассемблер записывает их шестнадцатеричными цифрами без пробелов.
Однако остался еще один тип данных, который постоянно используется программах на языке ассемблера для микропроцессора 8088. Это - двойное слово, значение в 32 бита длиной. Программы пользуются двойными словами для хранения адресов и очень больших чисел. Чтобы определить область, содержащую значение двойного слова, оператор ассемблера DD значение генерирует поле размером в 4 байта. DD означает операцию выделения двойнго слова (define doubleword). Так же как в случае с DW - опратором, ассемблер размещает в памяти младший байт ниже, а старший - выше. В таком же порядке сохраняются средние два байта. Аналогично операторам DB и DW вы можете пользоваться функцией DUP и применять операнд "?" для того чтобы оставить область неопределенной.
Ассемблер может генерировать и другие структуры данных. Их обсуждение мы отложим, пока не дойдем до некоторых свойств макроассемблера и сопроцессора 8087. Остальные структуры данных используются в программах прежде всего для очень больших чисел в Числовом сопроцессоре или для определения собственных структур данных.
Нумерация бит
Иногда нам будет требоваться идентифицировать отдельные биты в байте или слове. Для этого мы называем номер бита. Индекс или номер каждого бита - это степень двойки, соответствующая позиции этого бита. Самый младший бит - нулевой, поскольку он представляет два в нулевой степени. Самый старший бит в байте - седьмой - 2**7. Самый старший бит в слове - 15-й. Фиг. 2.12 показывает 16-битовое слово с пронумерованными битами.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Фиг. 2.12 Нумерация бит
Такой способ нумерации бит принят во всей документации IBM PC.
Набор символов
Как мы заметили выше, мы можем рассматривать каждый байт информации не как двоичное число, а как символьное значение. Каждое из двоичных чисел от 0 до 255 может представлять определенный символ. Фиг. 2.13 показывает множество символов IBM PC. Колонки здесь соответствуют старшим 4 битам символьного кода, а ряды - младшим 4 битам этого кода. Так, позиция таблицы 41Н соответствует символу "A", а код 5ЕН представляет символ "^".
... | A | B | C | D | E | F | ||||||||||
! | " | # | $ | % | & | ' | ( | ) | * | + | , | - | . | / | ||
: | ; | < | = | > | ? | |||||||||||
@ | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | |
P | Q | R | S | T | U | V | W | X | Y | Z | [ | \ | ] | ^ | _ | |
` | a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | |
p | q | r | s | t | u | v | w | x | y | z | { | | | } | ~ |
Фиг. 2.13 Набор символов IBM
Набор символов IBM PC является расширением набора символов ASCII (Американский стандартный код для обмена информацией). В наборе ASCII значения символов от 20Н до 7ЕН представляют обычные символы латинского алфавита, числовые символы и знаки препинания. Коды от 0Н до 1FH обычно служат управляюшими символами. На Фиг. 2.14 показаны управляющие символы ASCII из этого диапазона. Эти символы имеют значение при передаче на принтеры IBM или другие ASCII-принтеры. Однако на Фиг. 2.13 видно, что эти управляющие символы могут также появляться на экране в виде графических символов. В IBM PC управляющая часть таблицы ASCII используется для графических изображений, с целью более полно реализовать возможности видеоадапторов. Поскольку видеоадапторы могут изобразить любой из 256 кодов, то нет оснований строго регламентировать применение какого-либо из кодов. Разработчики рассматривали все 32 символа из управляющей части таблицы как предназначенные главным образом для графического изображения и обычно не печатаемые принтером. Короче говоря, первые 32 значения являются управляющими кодами при передаче их на принтер, но изображаются как графические символы при выводе их на дисплей.
Символьные значения от 80Н до 0FFH являются расширением набора символов ASCII для IBM PC. Эти символы подобраны разработчиками IBM так, чтобы расширить изобразительные возможности компьютера. Наборы иностранных, графических и научных символов позволяют использовать IBM PC в самых разнообразных приложениях.
Код | Символ | Значение |
NUL | Пусто | |
BEL | Сигнал | |
HT | Горизонтальная табуляция | |
0A | LF | Перевод строки |
0B | VT | Вертикальная табуляция |
0C | FF | Прогон страницы |
0D | CR | Возврат каретки |
0E | SO | Шаг назад |
0F | SI | Шаг вперед |
DC1 | Управление 1 | |
DC2 | Управление 2 | |
DC3 | Управление 3 | |
DC4 | Управление 4 | |
CAN | Отмена | |
1B | ESC | Выход |
Фиг. 2.14 Управляющие коды IBM
В некоторых случаях вы захотите вводить символьные коды в память для их дальнейшего использования программой. Примером может служить сообщение, которое в определенный момент выполнения программы должно быть выдано оператору. Вместо потска кодов символов в таблице, мы можем сразу ввести строку символов в текст программы. Ассемблер позволяет это сделать с помощю оператора DB.
Microsoft (R) Macro Assembler Version 5.00 10/31/88 22:30:38Фиг. 2.15 Определение байтов для текста ASCII Page 1-11 PAGE,1322 TITLE Фиг. 2.15 Определение байтов для текста ASCII34 0000 9D E2 AE 20 E1 AE AE DB 'Это сообщение',10,135 A1 E9 A5 AD A8 A5 0A6 0D78 ENDФиг. 2.15 Определение байтов для текста ASCII
В поле операндов мы вместо ввода чисел (кодов) помещаем заключенную в кавычки строку символов. Ассемблер подберет соответствующие значения кодов и поместит их в память - каждый символ в отдельный байт. Так ассемблер может работать только с символами в диапазоне от 20Н до 0FFH. в диапазоне от 0Н до 1FH символы должны вводиться в программу в виде чисел, а не ограниченной кавычками строки. Это связано с тем, что в тексте исходного файла некоторые управляющие символы используются для обозначения начала и конца строки.
Пример на Фиг. 2.15 показывает создание 15 байт данных в программе. Первые 13 байтов соответствуют 13-ти символам текстовой строки заключенной в кавычки. Первый байт имеет значение 9DH, второй 0E2H и т.д. Последние два байта в 17-ти байтном сообщении - это коды возврата каретки и переводаа строки. Если мы отправим это 17-байтное собщение на принтер, он напечатает заключенный в кавычки текст. Управляющие символы предписывают принтеру перейти после этого на следующую строку документа.