Э. Таненбаум - Архитектура компьютера (1127755), страница 204
Текст из файла (страница 204)
Программирование на языке ассемблера В результате появляется сообщение об ошибке операнда в строке 28 файла аггаург1.$. Этот файл генерируется ассемблером путем объединения включаемых файлов с исходным файлом; именно результирующий файл обрабатывается ассемблером. В сообщении об ошибке имеется в виду строка 28 именно этого объединенного файла. Изучение строки 28 файла аггаург1.5 ничего не даст — нумерация строк в двух файлах не совпадает из-за включения в файл аггаург1.$ строк заголовочного файла.
Строка 28 файла аггаург15 соответствует строке 7 аггаург1.5, так как включаемый заголовочный файл зузса!пг.й содержит 21 строку. В 171ч1Х для поиска строки 28 в файле аггаург1.5 достаточно ввести команду Веаа -2В аггаург1.а Эта команда выводит первые 28 строк объединенного файла. Соответственно, ошибку нужно искать в нижней строке листинга. Аналогичного эффекта можно добиться, просмотрев обьединенный файл в текстовом редакторе. Таким образом, мы локализуем ошибку в строке 7 исходной программы, которая содержит команду 5Нк. Путем изучения табл.
В.2 проблема легко обнаруживается: мы забыли указать величину смещения. Строка 7 после исправления должна выглядеть следующим образом: 5НЙ СХ.1 Важно отметить, что ошибку нужно исправлять в файле аггаург1.5, а не в обьединенном файле аггаург1.5, так как последний автоматически обновляется при каждом запуске ассемблера. Следующая попытка ассемблировать исходный код, по идее, должна пройти успешно. Затем запускаем трассер командой 1ВВ аггаургг В ходе трассировки замечаем, что выходные данные не согласуются с вектором, находящимся в сегменте данных. Вектор содержит значения 3, 4, 7, 11 и 3, в то время как на выходе последовательность начинается с 3, 1024,... Очевидно, что-то не так. Чтобы найти ошибку, трассер можно запустить заново и шаг за шагом отслеживать состояние машины вплоть до появления неверного значения.
Значения, которые требуется вывести, хранятся в памяти в строках 32 и ЗЗ. Строка вывода неверного значения — весьма удачное место для начала поисков. При втором проходе цикла становится заметно, что численное значение 51 является нечетным, чего не должно быть по определению, так как индексирование производится по словам, а не по байтам. Таким образом, проблема локализуется в строке 35.
Значение 51 в ней приращивается на единицу, в то время как правильный шаг приращения — 2. Чтобы исправить ошибку, строку нужно изменить следующим образом: АВВ 51,2 После исправления выводимый список чисел не вызывает нареканий. Тем не менее нас поджидает еще одна ошибка. После завершения вызова чесрг1п1 и возврата значения трассер отмечает ошибку в указателе стека. Очевидное решение — проверить, совпадает ли значение, вводимое в стек при вызове чесрг1пт, со значением, находящимся на вершине стека при выполнении ко- Примеры 803 манды НЕТ в строке 41. Как выясняется, они не совпадают. Таким образом, строку 40 следует заменить двумя новыми строками: Аоо 5Р,10 РОР ВР Первая команда удаляет 5 слов, помещенных в стек в ходе вызова чесрг1пт; таким образом открывается доступ к значению ВР, сохраненному в строке 22.
Путем выталкивания этого значения из стека мы восстанавливаем значение регистра ВР, имевшее место перед вызовом, и получаем правильный адрес возврата. Теперь программа завершается корректно. Не секрет, что отладка кода на языке ассемблера — скорее искусство, чем наука, однако не стоит пренебрегать помощью трассера, который значительно упрощает процесс. Обработка символьных строк и строковые команды Основное назначение этого подраздела — показать механизм обработки повто- ряющихся строковых команд.
В листингах В.б и В.6 представлены простые про- граммы для обработки символьных строк, 51гпдсру.з и гечетзрпз, расположенные в папке ехаар1ек ие строки (зггпясру з) Листинг В.5. Копироваи .5ЕСТ .ТЕХТ 41441агг. Р05Н ееа91 Р05Н иеа92 САСС атгпосрУ АОО 5Р,4 Р05Н О РО5Н 1 5Ч5 аггпосру: Р05Н СХ РАН 51 Р05Н О1 Р05Н ВР ИОЧ ВР.5Р МОЧ АХ.О МОЧ 01.101ВР1 МОЧ СХ.- 1 ВЕРНЕ 5СА58 ИЕВ СХ ОЕС СХ МОЧ 51,101821 МОЧ 01,121ВР1 Р05Н 01 ИЕР МОЧ58 САЕС аггщ9РГ МОЧ 5Р,ВР РОР ВР РОР 01 РОР 51 РОР СХ НЕТ ! 2 ! 3 1 ! 5 ! б ! 8 ' 9 ' 10 ! 11 ! 12 ! 13 ! 14 15 ! 16 ! 17 ! 18 ! 19 ! 20 ! 21 ! 22 ! 23 ! 24 ! 25 ! 26 ! 27 ! 28 ! 29 ! 3О ! 31 804 Приложение В.
Программирование на языке ассемблера .5ЕСТ .ОАТЯ ! 32 ле591: .А5С17 "Наче а 1ооКТп" ! 33 ве592: Я5С!7 лгзсТп ! 34 .5ЕСТ .855 Листинг В.6. Вывод символьных строк задом наперед (гечегзрггз! 91пс1осе "..74уаса1пг.ь" агагг МОЧ 01.абг ' 2 Р05Н АХ ! 3 ИОЧ ВР.5Р ! 4 Р05Н РОТСМАН ! 5 ИОНВ ЯС. Хп ! б ИОЧ СХ. -1 ВЕРИ! 5СЯ58 8 ИЕО СХ ! 9 5ТО ! 10 ОЕС СХ ! П 508 01,2 ! 12 ИОЧ 51.0! 13 1. С0058 14 ИОЧ !ВР1,АХ 15 575 ! 15 ЕООР 1Ь ! 17 МОЧВ ХВРП цп' ! 18 5У5 ! 19 Р05Н О ! 20 Р05Н ЕХ1Т ! 21 5У5 ! 22 .5ЕСТ .ОАТА ! 23 агг .А5С17 "гечег".еХп" ! 24 В листинге В.5 представлена программа копирования строки. Она вызывает подпрограмму зсг! пдрг, которую также можно найти в отдельном файле зтппд рггз (листинга с этим файлом в нашем приложении нет).
Чтобы ассемблировать программу, содержащую подпрограммы в отдельных файлах, в команде аз88 все исходные файлы следует указать, начиная с основной программы, которая определяет имена исполняемого и вспомогательных файлов. К примеру, чтобы ассемблировать программу, представленную в листинге В.5, нужно ввести команду аа88 аггпдсру.з агг1пдрг а Программа из листинга В.6 выводит символьные строки с обратным порядком следования символов. Мы рассмотрим обе программы по очереди.
В листинге В.5 строки кода пронумерованы, начиная с первой метки. Основная программа (строки 2 — 8) начинается с вызова подпрограммы зсгпдсру с двумя аргументами: исходной строкой аезд2 и целевой строкой везд1; подпрограмма копирует содержимое первой во вторую. Теперь рассмотрим непосредственно подпрограмму 81гпдсру, которая начинается в строке д кода. Она рассчитана на то, что адреса целевого буфера и исходной строки вводятся в стек непосредственно перед ее вызовом. В строках 10-13 задействованные регистры сохраняются путем передачи нх значений в стек; впоследствии, в строках 27 — 30, их предполагается восстановить.
В строке 14 значения 5Р и ВР копируются стандартным методом. После этого в 8Р можно загружать аргументы. В строке 26 стек очищается уже знакомым нам способом— значение ВР копируется в 5Р. Примеры 805 Центральным местом подпрограммы является команда ВЕР МОЧ5В, расположенная в строке 24 кода.
Команда МОЧ5В перемещает байт, на который указывает регистр 51, по адресу памяти, определяемому регистром 01. После этого содержимое обоих регистров увеличивается на единицу. Команда МЕР формирует цикл, в котором выполняется команда МОН5В; после перемещения каждого байта она уменьшает значение СХ на 1. Цикл завершается при достижении СХ нулевого значения. Перед выполнением ИЕР ИОЧ5В необходимо подготовить регистры, что и делается в строках 15 — 22. Индекс источника, 51, копируется из аргумента в стек в строке 21; индекс приемника, 01, определяется в строке 22.
Получить значение СХ несколько сложнее. Следует иметь в виду, что конец символьной строки обозначается нулевым байтом. Команда ИОЧ5В не влияет на состояние нулевого флага, в отличие от команды 5СА5В (просмотр байтовой строки). Последняя сравнивает значение, на которое указывает 01, со значением АЕ, и выполняет приращение 01 кна лету».
Подобно ИОЧ5В, она относится к числу повторяющихся команд. В строке 15 очищаются регистры АХ и АЕ, в строке 16 из стека выбирается указатель на 01, а в строке 17 регистр 0( инициализируется значением -1. В строке 18 находится команда ВЕРИЛ 5СА5В, выполняющая операцию сравнения в контексте цикла и в случае равенства устанавливающая нулевой флаг. При каждом проходе цикла выполняется отрицательное приращение СХ, а при установлении нулевого флага цикл останавливается — команда ВЕРИЕ проверяет и нулевой флаг, и СХ. Количество проходов цикла с командой МОЧ5В, таким образом, определяется как разность текущего значения СХ и предыдущего значения — 1 (строки 19 — 20).