takya.ru страница 1
скачать файл
Лабораторная работа №9

Работа с программой Turbo Debugger.


Данная работа предназначена для знакомства с общепринятыми приемами отладки программных приложений, а также для закрепления пройденного практического материала по курсу «Архитектура ЭВМ» и более углубленного понимания архитектуры и программной модели процессоров семейства Intel x8086. В качестве средства отладки предлагается изучить утилиту Turbo Debugger из пакета программ Borland Pascal.

Программа Turbo Debugger является мощным средством для отладки приложений DOS Real Mode, DOS Protected Mode, Windows. Turbo Debugger позволяет работать с программами типа COM и EXE. Для примера рассмотрим программу COM.

Главным отличием исполняемых модулей COM от EXE о операционной системе DOS является ограничение размера исполняемого файла. В связи с тем, что формат COM появился гораздо раньше EXE (в самой первой версии DOS), исторически сложилось так, что размер COM файла не может превышать размера одного сегмента памяти, т. е. 64 Кб. Это означает, что загружая такой исполняемый модуль в память операционная система настраивает все сегментные регистры, необходимые для корректного выполнения программы, на один и тот же сегмент. То есть, если программа была загружена по адресу 4600:0000, то прежде чем передать управление по этому адресу (например командой JMP 4600:0000), операционная система присваивает сегментным регистрам DS=ES=SS=CS=4600. Это означает, что в такой программе и данные и стек и коды команд находятся в одном сегменте.

Теперь перейдем к Turbo Debugger. Первый пункт меню File содержит стандартные элементы для выбора файла, смены текущего каталога и т. д.

Откройте файл debugger.com. В другом окне откройте файл debugger.asm.txt - это исходный файл откомпилированного debugger.com. Так вам будет удобно сравнивать исходный текст и программу, представленную в виде машинных кодов.

Итак, перед вами открылось основное окно Turbo Debugger. Оно разбито на 5 частей. Первая - сегмент кода. Он расположен в левой верхней части (Рис. 1.)





Рис. 1. Сегмент кода.
В свою очередь окно кодового сегмента разделено на столбцы. Самый левый столбец - адрес текущей команды. Например, на Рис. 1. текущая команда (помечена синей полосой) mov ah, 0F, расположен по адресу cs:0100. Это означает, что в памяти, самая первая команда располагается в сегменте CS со смещением 100h.

Второй столбец - код команды. Например, первая команда - mov ah, 0F для процессора представляется парой байт B4 0F. Если внимательно посмотреть на это число, то можно заметить, что младший байт 0F идентичен второму операнду команды mov ah, 0F. Это объясняется тем, что для процессора старший байт команды является кодом операции. Получив такой код операции, процессор берет из следующей ячейки памяти непосредственный операнд (в нашем случае это 0Fh) и пересылает его в регистр AH.

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

Обратите внимание, что следующая команда mov dx, B800, располагается по адресу cs:0102. Это объясняется тем, что предыдущая команда (mov ah, 0F) занимает в памяти 2 байта. Следовательно, процессор, выполнив первую команду, вычислит расположение следующей сместившись по сегменту кода на 2 байта. А по смещению cs:0102 располагается число BAh - это код операции mov dx, XXXX. Поскольку DX - 16-ти разрядный регистр, то процессор возьмет непосредственный операнд из двух последующих байт. Это 00h и B8h. Соответственно в DX процессор перешлет число B800h. Почему в памяти это число записано в обратном порядке? Об этом речь велась в лекции по форматам данных. Напомним, для шестнадцатиразрядного слова в памяти сначала записывается младший байт, а затем старший.


В левой нижней части окна Turbo Debugger отображен сегмент данных.

Рис. 2. Сегмент данных.

Окно сегмента данных также разделено на три части. Сегмент данных, отображает участок памяти, начинающимся с адреса ds:0000. Участок памяти еще иначе называют дампом памяти.

Первый столбец - адрес строки байт.

Второй столбец - строка из 8 байт. Turbo Debugger в окне сегмента данных представляет дамп памяти в виде строк по 8 байт. Во втором столбце данные отображаются в виде шестнадцатеричных чисел. Первые четыре байта - CDh, 20h, 00h, A0h находятся соответственно по адресам ds:0000, ds:0001, ds:0002 и ds:0003. Следующая строка начинается с адреса ds:0008.

В третьем столбце те же данные отображаются в виде ASCII символов.

Как было сказано ранее, программы COM не может занимать больше одного сегмента памяти и CS=DS=SS=ES. Поэтому вы можете переместиться по сегменту данных до адреса ds:0100 и убедится в том, что по этому адресу начинается наша программа (B4 0F BA 00 B8).


В средней верхней части расположено окно регистров (Рис. 3.).

Рис. 3. Окно регистров
В правой части отображается состояние соответствующих регистров. Также следует отметить, что если в результате выполнения операции значения каких-либо регистров были изменены, то соответствующие регистры подсвечиваются белым цветом.
В правой верхней части расположено окно флагов (Рис. 4.).



Рис. 4. Окно флагов

Комментарии излишни.


В правой нижней части расположено окно стека (Рис. 5.).



Рис. 5. Окно стека
Окно стека поделено на две части. Слева - адрес, справа - значения, хранящиеся в соответствующих ячейках стека.
Теперь можно приступать к выполнению программы. Для выполнения загруженных программ в меню Run существуют несколько пунктов. Перечислим наиболее важные.

Первый пункт - Run F9. Эффект такой же, если бы вы в командной строке DOS ввели debugger.com.

Trace into F7. Эта команда трассировки позволяет выполнять программу в пошаговом режиме. Это означает, что процессор, выполнив очередную команду программы, возвращается в Turbo Debugger, что позволяет пользователю следить за выполнением программы и даже вмешиваться в ход ее выполнения, например, изменяя значения регистров или данных.

Trace over F8. Эта команда трассировки аналогична предыдущей. Разница между ними заключается в следующем: если выполнить команду CALL addr с помощью Trace into, то Turbo Debugger перейдет по адресу addr. Если же выполнить ту же самую команду с помощью Trace over, то подпрограмма выполнится как одна команда до соответствующей команды возврата из подпрограммы RET и Turbo Debugger перейдет к следующей за CALL команде.

Итак, программа debugger.com выводит на экран строку “Institute of IT”. Можете попробовать запустить программу на выполнение (F9).

Просмотреть результаты выполнения можно, нажав Alt-F5.

Теперь проследим за выполнением программы в пошаговом режиме, одновременно сравнивая ее с исходным текстом.

mov ah, 0Fh

mov dx, 0B800h

Выполняя эти команды, можно наблюдать в окне регистров за изменением AX и DX.

push dx

Перед выполнением команды push dx (помещение в стек значения из DX), обратите внимание на значение регистра SP. Это указатель стека. Он указывает на ячейку стека с адресом SS:FFFEh (кстати, значение SS также можно узнать в окне регистров). Перед тем, как выполнить команду процессор уменьшает SP на два (поскольку стек выровнен по длине слова) и затем записывает значение операнда команды push. Значит после выполнения команды в ячейке адресом SS:FFFСh будет храниться значение из DX, а именно B800h.

pop es

Команда pop (извлечение данных из стека) выполняет действия в обратном порядке. Сначала берет данные из ячейки по адресу SS:SP и помещает в операнд (в нашем случае это регистр ES). Затем увеличивает значение SP на 2.



mov di, 0

В DI пересылается значение 0.

До сих пор исходный код программы не отличался от того, что можно видеть в Turbo Debugger. Но сравните

mov bx, Offset MyString


и
mov bx, 015C
Почему такая разница? Это объясняется тем, что язык Turbo Assembler, в котором была написана программа debugger.asm обладает большими макро средствами. В начале файла debugger.asm.txt вы видете строки:
DATASEG

MyString DB 'Institute of IT', 0


Это сообщает компилятору языка Turbo Assembler, что в сегменте данных необходимо разместить строку MyString, которая содержит символы 'Institute of IT', 0. Примерно также в Паскале можно определить строковую константу:

const

MyString: string = 'Institute of IT' + #0;

Компилятор Turbo Assembler, располагает эту строку в памяти по какому-то смещению, а в команду mov bx, Offset MyString подставляет как раз это смещение. Это смещение и есть 015Ch. В этом можно убедиться, посмотрев в сегменте данных по смещению 015Ch. По этому адресу (ds:015Ch) начинается строка 'Institute of IT'. Таким образом, команда mov bx, 015C перешлет в BX смещение первого символа строки в сегменте данных.
call GetStrLen

Перед выполнением этой команды следует учесть несколько моментов. Во-первых, опять можно заметить разницу между исходным текстом программы и откомпилированной программой. Вместо метки GetStrLen в Turbo Debugger стоит значение 0148h. Этот факт объясняется также, как и в предыдущем случае. Компилятор вместо метки GetStrLen подставляет адрес команды, которой соответствует эта метка. В данном случае, этой метке соответствует команда push ax. В памяти эта команда располагается как раз по смещению 0148h. Во-вторых, следует учесть, что команда CALL (вызов подпрограммы), работает со стеком. Чтобы знать, по какому адресу нужно вернуться после завершения подпрограммы, команда CALL сохраняет в стеке адрес следующей за ней команды. Следующая команда mov al, [bx], расположена по смещению 0110h. Перед тем, как передать управление по адресу 0148h (в исходном тексте - метка GetStrLen), процессор сохранит в стеке значение 0110h.

Теперь перейдем к подпрограмме GetStrLen. Ее назначение - вычисление длины строки MyString. Если вы заметили, строка MyString завершается символом 0. Поэтому алгоритм вычисления длины строки можно реализовать в виде цикла, внутри которого поочередно сравниваются все символы строки с нулем, при этом увеличивая какой-нибудь счетчик. В роли этого счетчика у нас выступает регистр CX.

Перед началом цикла (метка cycle), в стеке сохраняются регистры AX, ES, BX, a CX устанавливается в ноль. Затем, в регистр AL заносится очередной байт из строки. Это происходит благодаря косвенной адресации команды mov al, [bx]. Как уже упоминалось, в регистре BX содержится смещение строки MyString. Значит, увеличивая значение BX на единицу, можно по очереди получить доступ ко всем символам строки. Затем с помощью команды cmp al, 0, производится сравнение содержимого AL с нулем. При этом, если AL равен нулю, то флаг нуля Z устанавливается в единицу. Это условие является решающим фактором для команды условного перехода je (осуществить переход если равно). Обратите внимание, что пока в AL значение не равно нулю, и флаг Z не равен единице, команда je 0158h передает управление следующей за ней команде inc bx. Если же флаг Z=1, то управление передается по адресу 0158h.

После выполнения этого цикла, в CX содержится длина строки - 000Fh (пятнадцать символов). Теперь обратим внимание на процесс выхода из подпрограммы. Вначале из стека извлекаются сохраненные вначале подпрограммы регистры AX, ES, BX. Но заметьте, что извлекаются они в обратном порядке. Это обусловлено устройством стека, который функционирует по принципу Последний Пришел - Первый Вышел (LIFO - Last In - First Out). Затем следует команда ret, которая извлекает из стека адрес точки возврата в главную программу- 0110h.

Далее следует уже знакомая вам процедура вывода на экран, путем записи данных в видео-памать. Все необходимые данные подготовлены. В ES:DI содержится адрес первого байта видеопамяти. В BX и в CX - соответственно адрес первого байта и длина строки MyString.

Обратите внимание, на команду mov al, [bx]. В ней данные, косвенно адресуемые регистром BX, пересылаются в регистр AL. Почему в качестве адреса указывается только смещение, заданное в BX? Потому, что по умолчанию (если в качестве сегментного регистра ничего не указано) для косвенной адресации процессор использует сегментный регистр DS, который адресует сегмент данных, где и располагается наша строка. То есть команда mov al, [bx] равносильна mov al, ds:[bx]. Зато в следующей команде mov es:[di], ax пересылки AX в видео-память, сегментный регистр указывается в явном виде. Регистры ES, GS и FS были внедрены в архитектуру процессоров Intel, как дополнительные сегментные регистры данных.

Еще один немаловажный момент. Регистр IP - Instruction Pointer. Указатель инструкции. Этот регистр в паре с сегментным регистром CS (Code Segment - сегмент кода) адресует следующую команду для выполнения. После выполнения очередной команды процессор автоматически изменяет значения регистров CS и IP. Следует заметить, что, собственно, ни одна команда не может изменить значение этих регистров (например, нельзя записать mov cs, ax или mov ip, 0158). Это позволено только процессору. Каким же образом изменяются эти регистры? Все зависит от назначения команды. В этом плане команды делятся на команды передачи управления (условные и безусловные переходы, вызов и возврат из подпрограммы, вызов и возврат из прерывания), которые могут менять значения регистров CS и IP скачкообразно, и на все другие. Давайте проследим за изменением IP.

Первая команда

cycle:


mov al, [bx]

не относится к командам передачи управления. В этом случае вычисление IP состоит в увеличении этого регистра на величину команды mov al, [bx]. Эта команда в памяти занимает 2 байта. Следовательно, чтобы вычислить адрес следующей команды процессор увеличивает IP на 2. Как мы помним mov al, [bx] располагается по смещению 0110h. Значит, после выполнения этой команды IP станет равен 0112h.

mov es:[di], ax

add di, 2

inc bx

Эти команды также не относятся к командам передачи управления, поэтому IP будет увеличиваться на длину соответствующих команд.



loop 0110h

Эту команду по праву можно отнести к командам передачи данных (обратите внимание, что вместо метки cycle, как в исходном тексте, в команде loop в качестве операнда стоит реальное смещение команды mov al, [bx], на которую, собственно, и указывает метка cycle). В это случае регистру IP будет присвоено значение операнда команды loop, а именно 0110h. И в следующем такте процессор опять будет выполнять команду mov al, [bx]. Таким образом организован цикл loop.



После того, как цикл loop выполнится (CX = 0), и строка ‘Institute of IT’ выведена на экран (в этом можно убедиться нажав Alt F5), следуют несколько арифметических команд и команд пересылки данных.

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



Смотрите также:
Лабораторная работа №9 Работа с программой
93kb.
Лабораторная работа № Конструирование таблиц 3 лабораторная работа № Конструирование запросов на выборку 18
904.24kb.
Лабораторная работа №1 линейный вычислительный процесс арифметические выражения
542.66kb.
6. Пояснительная записка по основным направлениям деятельности палаты в отчётный период с указанием достижений и проблемных вопросов, замечаний и предложений в адрес тпп РФ. Работа с членами Палаты
393.9kb.
Лабораторная работа №3 (это пример выполнения лаб работы, индивидуальное задание находится в пункте 4) Тема лабораторной работы: Исследование алгоритма нечеткой кластеризации
95.48kb.
Учебная работа мбоу дод «Дом детского творчества» Учебная работа в мбоу дод «Дом детского творчества»
32.63kb.
Конспект урока питание. Почвенное питание растений. Фио (полностью) Осадчая Нина Анатольевна Место работы
112.07kb.
Лабораторная работа №4 По дисциплине «Информатика» На тему «Текстовый редактор ms word»
17.75kb.
Лабораторная работа №3 Тема: «Определение коэффициента гидравлических сопротивлений в учебном воздухопроводе»
70.09kb.
Лабораторная работа №1. Создание таблиц локальных бд. Субд paradox. Типы данных Paradox. Работа с утилитами bde administrator, Database Desktop
128.63kb.
Лабораторная работа №3 по дисциплине системный анализ на тему «Игра жизнь» 5 семестр 3 курс пиявский С. А
24.52kb.
Лабораторная работа по экологии №1. Анализ эколого-геохимического состояния водных объектов поймы реки Ройка
46.07kb.