Главная -> Книги

(0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30) (31) (32) (33) (34) (35) (36) (37) (38) (39) (40) (41) (42) (43) (44) (45) (46) (47) (48) (49) (50) (51) (52) (53) (54) (55) (56) (57) (58) (59) (60) (61) (62) (63) (64) (65) (66) (67) (68) (69) (70) (71) (72) (73) (74) (75) (76) (77) (78) (79) (80) (81) (82) (83) (84) (85) (86) (87) (88) (89) (90) (91) (92) ( 93 ) (94) (95) (96) (97) (98) (99) (100) (101) (102) (103) (104) (105) (106) (107) (108) (109) (110) (111) (112) (113) (114) (115) (116) (117) (118) (119) (120) (121) (122) (123) (124) (93)

первый раз для построения таблицы имен, второй -для фактической трансляции программы и печати листинга. Большинство ассемблеров современных ЭВМ являются двухпроходовыми.

Для хранения исходной программы необходима память значительной емкости. В мини-ЭВМ, а также в микро-ЭВМ с устройством внешней памяти исходная программа оформляется как файл в накопителе на диске или ленте, а для ассемблирования считывается в основную память. Объектная программа помещается во внешнюю память. Если основной памяти для ассемблера, исходной программы и объектной программы недостаточно или внешняя память отсутствует, исходная программа на обоих проходах считывается построчно с перфоленты. Объектная программа на втором проходе выводится на перфоленту.

Целесообразно построить на первом проходе всю таблицу имен, включив в нее метки и определенные пользователем имена. В этом случае перед вторым проходом для производства эффективного поиска ее можно рассортировать, например расположив имена в алфавитном порядке.

Чтобы построить таблицу имен, ассемблер при обработке каждой строки должен правильно модифицировать свою важнейшую внутреннюю переменную - счетчик адреса. Когда строка содержит машинную команду, необходимо учесть ее длину, даже если значения операндов пока неизвестны. Длина команды обычно определяется ее мнемоникой, но иногда приходится проверять режимы адресации. Например, в микропроцессоре КР580 все команды MOV имеют длину один байт, все команды передачи управления (кроме рестарта и возвратов) трехбайтные и т.д.

При обработке директив на первом проходе счетчик адреса может модифицироваться. Например, при обработке директивы DB необходимо произвести инкремент счетчика адреса на число ее операндов. Оно определяется числом запятых в списке поля операнда, причем поля значений операндов могут быть еще неизвестны. С другой стороны, значение операнда директив ORG и DS должно быть определено на первом проходе, так как оно прямо влияет на счетчик адреса.

Некоторые сложности возникают при обработке макрокоманд. Когда на первом проходе встречается директива MACRO, ассемблер переходит в режим макроопределения и помещает имя макрокоманды в таблицу макроопределений. В нее вводится также тело макрокоманды, в котором формальные параметры заменяются специальными иденти-



фикаторами, например <п> для п-го параметра. В последующем сканировании программы при обработке поля кода вначале просматривается таблица макроопределений, а затем таблица мнемоник машинных команд и директив. Такой порядок дает возможность пользователю переопределять некоторые машинные команды как макрокоманды. Однако чаще поиск производится в другом порядке: .мнемоники команд, директив и имен макрокоманд. Объясняется такой порядок тем, что в программе мнемоники машинных команд встречаются наиболее часто.

Если мнемоника находится в таблице макроопределений, ассемблер переходит в режим макрорасширения. Тело макрокоманды копируется в программу с соответствующей заменой формальных параметров фактическими параметрами макровызова. Когда исходная программа считывается с перфоленты; расширение осуществляется на обоих проходах. Когда же исходная программа хранится во внешней памяти, расширение выполняется только на первом проходе, а второй проход выполняется обычным образом.

После построения полной таблицы имен второй проход не представляет особых трудностей. При сканировании каждой строки содержимое полей кода и операнда с помощью таблицы имен преобразуется в двоичные эквиваленты и формируется объектная программа, представляющая собой цепочки из единиц и нулей. Отметим, что на втором проходе также необходим счетчик адреса. Двоичное значение директивы END загружается в программный счетчик, и процессор готов к выполнению программы.

На обоих проходах большинство действий ассемблера связано с манипуляциями таблицей имен. Ассемблирование начинается с таблицы имен, содержащей ключевые имена: мнемоники команд и идентификаторы внутренних регистров (иногда последние определяются директивами SET). Когда на первом проходе встречается любое имя, необходимо просмотреть таблицу имен и, если имя в таблице отсутствует, сформировать в ней новую запись. Поиск необходим при определении имени и считывании из таблицы его значения. При определении нового имени приходится просматривать всю таблицу, чтобы зафиксировать многократные определения. Для печати определенных пользователем имен в алфавитном порядке необходимо упорядочивать таблицу имен. Таким образом, важными операциями становятся поиск, введение новых записей и сортировка таблицы имен. Время выполнения этих операций непосредственно влияет на скорость ассемблирования. Одним из эффек-



тивных средств обработки таблиц имен является хеширование. Оно заключается в сравнительно простом преобразовании имени посредством хеш-функции в однозначный индекс таблицы имен.

Ассемблеры классифицируются как абсолютные или перемещающие в зависимости от того, формируют они информацию, позволяющую загружать программу в любую область памяти, или нет. Первый адрес, который занимает программа в памяти, называется адресом загрузки. В абсолютном ассемблере адрес загрузки определяется директивой ORG и известен во время ассемблирования. Поэтому при построении адресных констант и команд передачи управления ассемблер использует абсолютные адреса памяти. Следовательно, программа допускает загрузку в одну область памяти или в несколько фиксированных областей.

Сформированная абсолютным ассемблером программа (абсолютный загрузочный модуль) состоит из последовательности записей (блоков), показанной иа рис. 7-4. Ей предшествует специальный код (маркер) начала. Поле ADDR содержит адрес памяти, по которому загружается первый программный байт блока. Содержимое поля ВС счетчика байт идентифицирует число программных байт в блоке. Далее находятся собственно программные байты, загружаемые в смежные ячейки памяти. Байт CKSM конт-оольной суммы представляет собой циклическую сумму или дополнение до нуля циклической суммы всех байт блока, включая ADDR и ВС. Последний блок имеет ВС -О, а содержимое поля ADDR интерпретируется как пусковой адрес программы.

Жесткая фиксация адреса загрузки имеет ряд недостатков и ограничений. При разработке прикладной программы, состоящей из нескольких модулей, нужно знать абсолютные адреса загрузки каждого модуля, а они зависят от размеров модулей, которые неизвестны до окончания разработки. Кроме того, модификация одного модуля приводит к изменениям адресов загрузки других мо-. дулей. Перемещающий (относительный) ассемблер и тесно связанная с ним про-

Маркер

Блок 1

Блок 2

- ADDR

Блок i

Программные байты

CKSM

ADDR -

Влок п - ВС = О -

CKSM

Рис. 7-4. формат выхода абсолютного ассемблера



(0) (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30) (31) (32) (33) (34) (35) (36) (37) (38) (39) (40) (41) (42) (43) (44) (45) (46) (47) (48) (49) (50) (51) (52) (53) (54) (55) (56) (57) (58) (59) (60) (61) (62) (63) (64) (65) (66) (67) (68) (69) (70) (71) (72) (73) (74) (75) (76) (77) (78) (79) (80) (81) (82) (83) (84) (85) (86) (87) (88) (89) (90) (91) (92) ( 93 ) (94) (95) (96) (97) (98) (99) (100) (101) (102) (103) (104) (105) (106) (107) (108) (109) (110) (111) (112) (113) (114) (115) (116) (117) (118) (119) (120) (121) (122) (123) (124)