<<
>>

Отладка программы вывода массива

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

Так как системные вызовы, а значит, и константы, с помощью которых эти вызовы можно различать по номерам, нужны любой программе, мы выделили определения констант с этими номерами в отдельный заголовочный файл, который включается в код в первой строке:

#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. Путем выталкивания этого значения из стека мы восстанавливаем значение регистра ВР, имевшее место перед вызовом, и получаем правильный адрес возврата. Теперь программа завершается корректно. Не секрет, что отладка кода на языке ассемблера — скорее искусство, чем наука, однако не стоит пренебрегать помощью трассера, который значительно упрощает процесс.

<< | >>
Источник: Таненбаум Э.. Архитектура компьютера. 5-е изд. 2007

Еще по теме Отладка программы вывода массива:

  1. 18.5. Права и обязанности держателя (обладателя) по работе с массивами персональных данных
  2. Программа Да и программа Нет
  3. Свободное воспроизведение программ для ЭВМ и баз данных. Декомпилирование программ для ЭВМ
  4. Выводы
  5. Музыкальные концертные программы
  6. Выводы
  7. 2.4.3. Выводы
  8. 3.2.3. Выводы
  9. Выводы
  10. Выводы
  11. Г л а в а 9 О ПРОГРАММАХ
  12. 7. Выводы, основанные на эмоциях
  13. 3.1.4. Выводы
  14. Выводы