Отладка программы вывода массива
Так как системные вызовы, а значит, и константы, с помощью которых эти вызовы можно различать по номерам, нужны любой программе, мы выделили определения констант с этими номерами в отдельный заголовочный файл, который включается в код в первой строке:
#1пс1ис]е "../БузсаТпг.Ь"
Помимо прочего, в этом файле определены константы для следующих дескрипторов файлов:
БТО™ = О
Бтаоит = 1
8ТОЕ1^ = 2
Они открываются в начале процесса, а в заголовке содержатся метки, указывающие на секции текста и данных. Этот файл имеет смысл включать в заголовок всех исходных ассемблерных файлов, поскольку имеющиеся в нем определения весьма востребованы.
Если исходный код рассредоточен по нескольким файлам, ассемблер включает в него только одну версию заголовочного файла, за счет чего ситуации многократного определения констант удается избежать.Программа аггаурН приведена в листинге В.4. Код не прокомментирован, так как мы предполагаем, что к настоящему моменту читатель уже в достаточной степени знаком с набором команд. В строке 4 адрес пустого стека помещается в регистр указателя базы — так предусматривается возможность очистки стека путем копирования указателя базы в указатель стека, что и выполняется в строке 10. В предыдущем примере (в строках 5-9) мы уже рассматривали ситуацию вычисления и введения в стек аргументов перед вызовом. В строках 22-25 регистры загружаются в подпрограмму.
В строках 27-30 кода показано, как вывести символьную строку, а в строках 31-34 системный вызов рпггЬТ выполняется применительно уже к целочисленному значению. Адрес символьной строки вводится в стек в строке 27, а в строке 33 в стек вводится целочисленное значение. В обоих случаях адресом форматной строки выступает первый аргумент команды Р1ШТР. В строках 37-39 отдельный символ выводится при помощи системного вызова рцгЬсИаг.
Теперь попробуем ассемблировать и запустить программу. Для этого введем команду а$88 аггаур^.э
В результате появляется сообщение об ошибке операнда в строке 28 файла arrayprt.$. Этот файл генерируется ассемблером путем объединения включаемых файлов с исходным файлом; именно результирующий файл обрабатывается ассемблером. В сообщении об ошибке имеется в виду строка 28 именно этого объединенного файла. Изучение строки 28 файла arrayprt.s ничего не даст — нумерация строк в двух файлах не совпадает из-за включения в файл arrayprt.$ строк заголовочного файла. Строка 28 файла arrayprt.$ соответствует строке 7 arrayprt.s, так как включаемый заголовочный файл syscalnr.h содержит 21 строку.
В UNIX для поиска строки 28 в файле arrayprt.$ достаточно ввести команду
head -28 arrayprt.s
Эта команда выводит первые 28 строк объединенного файла. Соответственно, ошибку нужно искать в нижней строке листинга. Аналогичного эффекта можно добиться, просмотрев объединенный файл в текстовом редакторе. Таким образом, мы локализуем ошибку в строке 7 исходной программы, которая содержит команду SHR. Путем изучения табл. В.2 проблема легко обнаруживается: мы забыли указать величину смещения. Строка 7 после исправления должна выглядеть следующим образом:
SHR СХД
Важно отметить, что ошибку нужно исправлять в файле arrayprt.s, а не в объединенном файле arrayprt.$, так как последний автоматически обновляется при каждом запуске ассемблера.
Следующая попытка ассемблировать исходный код, по идее, должна пройти успешно.
Затем запускаем трассер командойt88 arrayprt
В ходе трассировки замечаем, что выходные данные не согласуются с вектором, находящимся в сегменте данных. Вектор содержит значения 3, 4, 7, 11 и 3, в то время как на выходе последовательность начинается с 3, 1024,... Очевидно, что-то не так.
Чтобы найти ошибку, трассер можно запустить заново и шаг за шагом отслеживать состояние машины вплоть до появления неверного значения. Значения, которые требуется вывести, хранятся в памяти в строках 32 и 33. Строка вывода неверного значения — весьма удачное место для начала поисков. При втором проходе цикла становится заметно, что численное значение SI является нечетным, чего не должно быть по определению, так как индексирование производится по словам, а не по байтам. Таким образом, проблема локализуется в строке 35. Значение SI в ней приращивается на единицу, в то время как правильный шаг приращения — 2. Чтобы исправить ошибку, строку нужно изменить следующим образом:
ADD SI.2
После исправления выводимый список чисел не вызывает нареканий.
Тем не менее нас поджидает еще одна ошибка. После завершения вызова vecprint и возврата значения трассер отмечает ошибку в указателе стека. Очевидное решение — проверить, совпадает ли значение, вводимое в стек при вызове vecprint, со значением, находящимся на вершине стека при выполнении команды RET в строке 41. Как выясняется, они не совпадают. Таким образом, строку 40 следует заменить двумя новыми строками:
ADD SP.10 POP BP
Первая команда удаляет 5 слов, помещенных в стек в ходе вызова vecprint; таким образом открывается доступ к значению ВР, сохраненному в строке 22. Путем выталкивания этого значения из стека мы восстанавливаем значение регистра ВР, имевшее место перед вызовом, и получаем правильный адрес возврата. Теперь программа завершается корректно. Не секрет, что отладка кода на языке ассемблера — скорее искусство, чем наука, однако не стоит пренебрегать помощью трассера, который значительно упрощает процесс.
Еще по теме Отладка программы вывода массива:
- 18.5. Права и обязанности держателя (обладателя) по работе с массивами персональных данных
- Программа Да и программа Нет
- Свободное воспроизведение программ для ЭВМ и баз данных. Декомпилирование программ для ЭВМ
- Выводы
- Музыкальные концертные программы
- Выводы
- 2.4.3. Выводы
- 3.2.3. Выводы
- Выводы
- Выводы
- Г л а в а 9 О ПРОГРАММАХ
- 7. Выводы, основанные на эмоциях
- 3.1.4. Выводы
- Выводы