Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере

; Простая программа на ассемблере

data segment para public "data" ; Сегмент данных

data8 db 7,0dh,0ah,'Привет!',0dh,0ah,'$' ;Код

;консольного писка + сообщение

Data16 dw 65535

Data ends

stk segment para stack "stack" ; Сегмент стека

Db 256 dup (?) ; Буфер для стека

Stk ends

code segment para public "code" ; Сегмент кода

Start:

Mov ax,data ; Адрес сегмента данных в регистр AX

Mov ds,ax ; Запись AX в DS

Mov ax,0 ; Обнуление аккумулятора AX

Inc ax ; Увеличение AX на 1

mov bx,ax ; Пересылка <AX> в BX

Mov ch,data8 ; Пересылка переменной data8 в CH

Mov bp,data16 ; Пересылка переменной data16 в BP

Dec word ptr data16

Call mes

Mov ax,4C00h ; Функция завершения программы

Int 21h ; Функция Dos

Mes proc near ; Процедуры вывода сообщения на экран

Lea dx,data8 ; Загрузка смещения data8 в DX

Mov ah,9 ; Функция вывода строки на экран

Int 21h ; Функция DOS

Ret

Mes endp

Code ends

END Start

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

Для использования турбо дебаггера при отладке программы следует оттранслировать программу с включением отладочной информации. Для этого компиляцию программы следует производить с ключом /zi (tasm /zi example.asm), а затем скомпоновать программу с ключом /v (tlink /v example.obj). Следует отметить, что ключи должны задаваться строчными символами.

Запуск программы под турбо дебаггером

Для запуска программы в турбо дебаггере следует набрать td.exe example.exe. Окно запущенного турбо дебаггера с отлаживаемой программой показано на рисунке 4.31.

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

На рисунке 4.31 видны оперативные клавиши (нижняя строка экрана): F1=Help – cправка; F2=Bkpt – точка останова; F3=Close – закрыть; F4=Here – здесь; F5=Zoom – переключение окон; F6=Next – дальше; F7=Trace – трассировка; F8=Step – шаг; F9=Run – выполнить; F10=Menu – меню.

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.31 – Начальный экран при работе с отлаживаемой программой

На рисунке видно также основное меню турбо дебаггера (верхняя строка экрана): Ё – системное меню; File – файл; Edit – редактирование View – обзор; Run – выполнение; Breakpoints – точки останова; Data – данные; Options – параметры; Window – окно; Help – справка.

Данный экран состоит из основной строки меню, окон Module (Модуль) и Watches (Просмотр) и справочной строки.

Завершение работы

Чтобы выйти из отладчика в любой момент и вернуться в операционную среду DOS, нажмите клавиши Alt-X. Если необходимо вернуться в начальное состояние программы, нажатие клавиш Ctrl-F2 в любой момент позволит вам перезагрузить программу и начать выполнение сначала.

Однако при нажатии данных клавиш не сбрасываются точки останова или просматриваемые величины. Чтобы сделать это, нужно воспользоваться клавишами Alt-F O (клавиши Alt-B D также позволяют удалить все точки останова, но иногда быстрее перезагрузиться с помощью Alt-F O).

Получение подсказки

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

Отладка примера программы на языке Ассемблера

Закрашенная стрелка (?) в левом столбце окна Module показывает, где турбо дебаггер остановил выполнение вашей программы.

Если программа еще не была запущена, стрелка находится на первой выполняемой ее строке (на рисунке 4.31 – это 16-я строка).

Для трассировки одной исходной строки программы следует нажать клавишу F7. Стрелка и курсор переместятся при этом на следующую выполняемую строку.

Если посмотреть на правую границу заголовка окна Module (Модуль) на рисунке 4.31, можно увидеть, что там указан номер строки, в которой находится курсор. Если переместить курсор с помощью клавиш управления курсором (стрелки) вверх и вниз, номера строки в заголовке будет меняться.

Для позиционирования курсора на строку в окне Module, можно нажать клавиши Ctrl-L, ввести номер строки и нажать Enter.

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

Чтобы запустить программу на выполнение, пока она не достигнет строки 24, переместите курсор на эту строку, а затем нажмите клавишу F4. Теперь, когда курсор находится на строке 24, нажмите клавишу F7 для выполнения еще одной строки исходного кода. Поскольку выполняемая вами строка представляет собой вызов другой функции, то стрелка теперь позиционируется на первой строке функции mes(строка 28 исходного текста). Курсор немедленно переходит к строке 28, где находится начало функции mes.

Продолжайте нажимать клавишу F7, пока не будет выполнена процедура mes и не произойдет возврат на строку, следующую за вызовом (строка 25).

Если на строке 24 вместо клавиши F7 нажать клавишу F8, то вместо перехода в функцию произойдет переход сразу к строке 25.

Клавиша F8 аналогична клавише F7, которая выполняет процедуру, но она не выполняет по шагам код процедуры.

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.32 Программа остановилась после возврата из процедурыmes

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

Задание точек останова

Другой способ управлять остановкой программы состоит в использовании точек останова. Простейший способ задать точки останова заключается в использовании клавиши F2. Переместите курсор на строку 25 и нажмите клавишу F2. турбо дебаггер подсвечивает строку, показывая, что на ней установлена точка останова (рисунок 4.33).

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.33 – Подсвеченная точка остановка на строке 25

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

Оперативные клавиши: F1=Help – cправка; F2=Bkpt – точка останова; F3=Close – закрыть; F4=Here – здесь; F5=Zoom – переключение окон; F6=Next – дальше; F7=Trace – трассировка; F8=Step – шаг; F9=Run – выполнить; F10=Menu – меню.

Для иллюстрации процесса отладки программы следует сбросить программу в исходное состояние. Для этого надо (Главное меню®Run®Programm reset) или клавиши нажать Ctrl-F2.

Теперь надо запустить программу. Для этого следует выбрать (Главное меню®Run®Run) или нажать клавишу F9 для выполнения программы без прерывания (до первой точки останова, которая у нас установлена на строке 25). При выполнении процедуры mes на экран выводится «Привет!», однако это сообщение не видно, так как экран занят окном турбо дебаггера. Для того, чтобы посмотреть, что же получилось на экране пользовательской программы, необходимо переключиться в режим экрана пользователя (Главное меню®Windows®User Screen) (рисунок 4.34). Того же эффекта можно достичь, нажав клавиши Alt-F5. В окне турбо дебаггера появится окно программы пользователя с сообщением «Привет!». Для выхода из окна программы пользователя следует нажать Esc. На дисплее вновь появится экран турбо дебаггера, а стрелка будет позиционирована на строке 25 (рисунок 4.35), где установлена точка останова, и прекратила свое выполнение программа.

Если теперь опять нажать клавишу F9, программа будет выполнена до конца, так как больше точек останова нет. По завершении программы турбо дебаггер выводит сообщение о завершении программы и о том, что код возврата – (это означает, что программа завершилась без ошибок). Экран турбо дебаггера с сообщением о завершении программы пользователя показан на рисунке 4.36. Это сообщение следует квитировать нажатием клавиши Enter.

Использование окна Watches

В окне Watches (Просмотр) в нижней части экрана показываются значения выбранных переменных. Например, чтобы увидеть значение переменной data8, следует переместить курсор на имя переменной на строке 6 и выбрать команду Watch (Просмотр) из локального меню окна Module. Можно использовать также сокращение этой команды.

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.34 – Результат выполнения процедуры mes на экране пользовательской программы

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.35 – Возврат в окно турбо дебаггера после просмотра окна пользовательской программы

Для этого надо нажать клавиши Alt-F10 для выбора локального меню, затем нажать клавишу W. Для выбора второй переменной – data16, следует выполнить те же манипуляции, поместив предварительно курсор на строку 7.

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.36 – Сообщение турбо дебаггера о завершении программы

Теперь переменные data8 и data16 в окне Watches (Просмотр) в нижней части экрана, где указаны также их тип (byte для data8 и word для data16) и значение (рисунок 4.37). По мере выполнения программы турбо дебаггер изменяет эти значения и отражает их текущие значения.

На рисунке 4.37 видно, что значение переменной data16 – 65535 (0FFFFh). Для того, чтобы посмотреть, как работает окно Watches, поставим точку останова на строке 23 (поместит курсор на строку 23 и нажать клавишу F2). После этого запустим программу (клавиша F9), при этом программа выполнится до точки останова (строки 23). Для того, чтобы выполнить команду на строке 23 (декремент переменной data16), нажмем клавишу F7. При этом будет выполнена команда на строке 23 (значение переменной data16 уменьшится на 1) и управление перейдет на следующую строку (рисунок 4.38).

На рисунке 4.38 видно, что значение переменной data16 в окне Watches уменьшилось на единицу – стало 65534 (0FFFEh).

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.37 – Переменные в окне Watches

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.38 – Индикация выполнения команды dec data16

Анализ переменных можно осуществлять также при помощи окна Inspect (Проверка). Когда программа остановлена (как в нашем случае), существует много способов просмотра данных с помощью команды Inspect (Проверка). Это очень мощное средство позволяет вам анализировать данные таким же образом, как если бы вы визуально наблюдали их при разработке программы.

Команды Inspect (в различных локальных меню и в меню Data) позволяют вам наблюдать за любой заданной переменной. Предположим, вы хотите взглянуть на значение переменной data16 после того, как программа была выполнена до команды в строке 16 включительно (то есть, был выполнен декремент этой переменной). Для этого следует поставить точку останова на строку 17 и выполнить программу (выбрать подпункт Run из основного меню Run, или просто нажать клавишу F9). При этом будут выполнены все команды до строки 16 включительно, и выполнение программы остановится на строке 17. Для того, чтобы посмотреть интересующую нас переменную data16, следует поместить курсор под этой переменной, вызвать локальное меню (Alt-F10) и выбрать такм первый пункт (Inspect). После этого на экране появится окно Inspector (Проверка) (рисунок 4.39).

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.39 – Окно Inspector (Проверка)

В первой строке (заголовке) этого окна вам сообщается адрес данной переменной в памяти. Третья строка показывает, какой тип данных хранится в переменной data16 (это тип word). Справа указано текущее значение переменной. Теперь, проверив значение этой переменной, нажмите клавишу Esc для того, чтобы закрыть окно Inspector. Для этого (как и во всех других окнах) можно также воспользоваться клавишами Alt-F3, либо закрыть окно с помощью "мыши".

Просмотреть переменную можно и более простым способом. Для этого надо нажать Ctrl-I. При этом откроется окно для ввода имени просматриваемой переменной. В имеющееся поле ввода следует ввести имя переменной – data16, и нажать кнопку ОК (рисунок 4.40).

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.40 – Окно для ввода имени просматриваемой переменной

После нажатия кнопки ОК, на экране появится окно, изображенное на рисунке 4.39.

Таким образом можно просматривать значения любых переменных на любом этапе выполнения программы.

Изменение значений переменных в программе

Теперь попробуем изменить значение переменной. С помощью клавиш со стрелками перейдите на строку 22 исходного файла. Поместите курсор на переменную data16, и для проверки ее значения нажмите клавиши Ctrl-I. После того, как будет открыто окно Inspector, нажмите для вывода локального меню окна Inspector клавиши Alt-F10 и выберите команду Change (Изменить) (рисунок 4.41). (Это можно сделать также непосредственно, нажав клавиши Ctrl-C.) Появляется подсказка (диалоговое окно), запрашивающая новое значение (рисунок 4.42).

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.41 – Локальное меню окна Inspector (Проверка) для выбора команды Change (Изменить)

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.42 – Диалоговое окно для ввода нового значения переменной

В заголовке диалогового окна сообщается: Enter new value for word data16 (введите новое значение для переменной data16 типа word).

В это поле можно ввести любое вычисляемое выражение языка Ассемблер, при вычислении которого получается число. Если, например, набрать data8+5 и нажмите клавишу Enter, в окне проверки теперь будет показано новое значение – 65528 (FFF8h), как это показано на рисунке 4.43.

Assume CS:code, DS:data, SS:stk. ; Простая программа на ассемблере - student2.ru

Рисунок 4.43 – Индикация нового значения переменной в окне Inspector (Проверка)

Для изменения элемента данных, который не виден в текущем окне Module (Модуль), следует выбрать команду Data/Evaluate/Modify (Данные/Вычисление/Модификация). При этом будет выведено окно подсказки, в которой вы можете ввести имя изменяемой переменной, как это было показано на рисунке 4.40.

4.5 Процессорные средства тестирования программ

Программные средства отладки

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

Внутренние средства отладки предназначены для облегчения выполнения отладочных процедур. Они подразделяются на 3 типа:

- однобайтная команда прерывания INT3 (код 0CCh);

- пошаговый режим работы (управляемый флагом ловушки TF);

- остановы по командам и данным, задаваемые с помощью регистров отладки процессора.

Команда прерывания

Команда INT3 используется программными отладчиками (в том числе и турбо дебаггером, описанным выше). Выполнение этой команды вызывает исключение 3 (прерывание отладки).

В отличие от других команд прерывания, имеющих двухбайтный формат, команда INT3 однобайтная. Это делает ее удобной для использования в программных отладчиках при установке точек прерывания (например, путем подмены первого байта любой команды). Процессор, встречая в программе команду с кодом 0ССh, вызывает программу обработки прерывания с вектором 3, которая и используется для связи с отладчиком.

Кроме того, данная команда нечувствительна к значению привилегии IOPL как в защищенном режиме, так и в режиме виртуального процессора V86.

Пошаговый режим

В пошаговом режиме выполнение программы осуществляется по одной команде. После выполнения каждой команды вызывается исключение 1 (исключение отладки).

Пошаговый режим задается установкой в единицу флага TF (Trap Flag – флаг ловушки).

Регистры отладки

Отладочные регистры появились в архитектуре микропроцессоров семейства х86, начиная с процессора Intel386. Эти регистры позволяют выставлять точки останова и перехватывать обращения процессора к памяти. В процессорах Pentium и выше можно останавливаться и по обращениям ввода-вывода.

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

Отладочных регистров у процессора восемь: DR0...DR7.

Первые четыре регистра: DR0...DR3 используются для задания до четырех 32-разрядных адресов точек останова. Заданный адрес указывает байт, слово или двойное слово, попадание в который(ое) вызывает срабатывание ловушки останова. Что именно указывает адрес определяется полем LENi (i = 0...3) в регистре DB7. В этом же регистре, но только в поле RWi, задается тип перехватываемого обращения к памяти:

00 – выборка команды из памяти

01 – запись данных в память

10 – обращение к портам ввода-вывода (только для Pentium и выше при включении расширения отладки: бит DE регистра CR4)

11 – чтение или запись данных памяти.

Генерируемые при этом исключения различаются по типу. При выборке команды исключение классифицируется как отказ (fault) и обрабатывается до выполнения (этой выбираемой из памяти) команды. В случае обращения к данным исключение рассматривается как ловушка (trap) и обрабатывается после передачи (читаемых или записываемых) данных.

 
Линейный адрес точки останова 0 DR0
Линейный адрес точки останова 1 DR1
Линейный адрес точки останова 2 DR2
Линейный адрес точки останова 3 DR3
Зарезервировано DR4
Зарезервировано DR5
0/1 BT BS BD 0/1 0/1 0/1 0/1 0/1 0/1 0/1 0/1 B3 B2 B1 B0 DR6
LEN3 R3 W3 LEN2 R2 W2 LEN1 R1 W1 LEN0 R0 W0 GD 0/1 GE LE G3 L3 G2 L2 G1 L1 G0 L0 DR7
                                                         
    0/1   0 – для i386, i486 1 – для Pentium                        
                                                                   

Рисунок 4.44 – Регистры отладки

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

- бит GD (Global Debug Register Access Detect – обнаружение доступа к регистрам отладки), доступный только в реальном режиме или в защищенном режиме на уровне привилегии CPL = 0, позволяет отслеживать любые обращения к отладочным регистрам. При GD = 1 любая попытка обращения вызовет исключение 1 (отказ);

- биты GE и LE (Global и Local Exact data breakpoint match – глобальная и локальная точка немедленного останова по совпадению данных) определяют, будет ли исключение генерироваться сразу после завершения операции обмена при включенной ловушке на обращение к данным или оно произойдет несколько позже (возможно, никогда). Ловушка на обращения за командами всегда срабатывает немедленно. Бит LE автоматически сбрасывается при переключении задач, бит GE не изменяет своего состояния при таких переключениях;

- биты Gi и Li (Global и Local breakpoint enable – разрешение глобальной и локальной точек прерывания) разрешают срабатывание ловушек по отладочным точкам. Биты Li автоматически сбрасываются при переключении задач, биты Gi не изменяют своего состояния при таких переключениях. Автоматический сброс битов Li блокирует лишние срабатывания отладочных точек при переключениях задач.

Для упрощения определения отладчиком причины, вызвавшей срабатывание отладочной точки (исключение 1), могут использоваться биты регистра состояния отладки DR6 (Debug Status Register), идентифицирующие эти причины:

- биты Bi – срабатывание точки останова по регистру DRi,

- бит BS – ловушка пошагового режима,

- бит BT – ловушка переключения задач (по биту T в TSS),

- бит BD – отказ при попытке доступа к регистрам отладки при GD = 1.

Значения флагов Bi действительны только для контрольных точек с установленными битами Li и/или Gi.

Генерация исключений по контрольным точкам может быть отключена флагом RF регистра флагов процессора.

Наши рекомендации