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

(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) (95)

Длина таблицы глобальных имен

Длина таблицы входных имен

Таблица глобальных имен!

Таблица входных имен

Длина таблицы перемещения

Таблица внешних имен

Таблица

Программные байты (слова)

Рис. 7-6. Форматы объектного модуля и таблицы глобальных имен

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

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



Обычно глобальные имена в исходной программе необ-.ходимо специально объявлять, чтобы редактор связей выявил ошибки в случае неопределенных имен. Директива EXTERNAL как операнд содержит список внешних имей, а директива ENTRY - список входных имен. В ассемблере процессоров СМ единственная директива. GLOBL объявляет имена обоих типов. Имена, определенные в модуле, считаются входными, а остальные - внешними.

Организация таблицы глобальных имен также показана на рис. 7-6. Таблица входных имен содержит все входные имена и их относительные адреса внутри модуля, а таблица внешних имен содержит все внешние имена, с каждым из которых ассоциирован список ячеек, в которых эти имена используются как операнды. Структура таблицы глобальных имей аналогична структуре таблицы перемещения.

Отметим, что внешние имена могут фигурировать в выражениях. Если обозначить ЕХТ -внешнее имя, а ABS - абсолютную константу, имя или выражение, то допускаются следующие формы выражений: ЕХТ, EXT+ABS, ABS-f Н-ЕХТ, ЕХТ-ABS.

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

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

СРЕДСТВА ОТЛАДКИ

Большинство прикладных программ по окончании их разработки содержит логические ошибки, которые выявляются только при выполнении программы. Для их локализации и исправления необходимы специальные отладочные средства. Приходится учитывать, что дать исчерпывающую



проверку сложной программы почти невозможно и даже при обнаружении неправильной работы программы для локализации ошибок потребуется несколько приемов.

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

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

Еще один достаточно надежный, но времяемкий способ заключается в выполнении программы по командам и анализе содержимого регистров процессора и ячеек памяти. В большинстве ЭВМ предусматривается режим покоманд-иого (или пошагового) выполнения программы. Чтобы сократить время отладки, в программу вводятся остановы после выполнения сравнительно крупных сегментов с последующим анализом важных данных. В режиме прослеживания (трассировки) программы, который задается специальным битом Т в слове состояния процессора, машина автоматически печатает команды и данные по мере выполнения программы. Когда бит Т установлен, процессор инициирует программное прерывание после выполнения каждой команды.

Наиболее удобным и мощным средством является диалоговая (интерактивная) программа-отладчик, рассчитанная на взаимодействие ЭВМ с пользователем через коисоль или терминал посредством содержательных приказов. Ниже приведены типичные приказы диалогового отладчика;

% п - обратиться к регистру п для просмотра или изменения его содержимого; как реакция на этот приказ, печатается содержимое регистра, после чего пользователь может ввести новые данные;

п/ - обратиться к ячейке памяти с адресом п (этот приказ аналогичен предыдущему);

addr; В - установить контрольную точку по адресу addr; допускается задание до 8 контрольных точек;

; В - сбросить все установленные ранее контрольные точки;



(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)