ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП |
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы. |
Часть 13 Глава 11 Отладка на уровне ассемблера ----------------------------------------------------------------- Эта глава предназначена для программистов, которые знакомы с программированием на языке ассемблера для процессора семейства 80 х86. Возможности отладчика, описанные в этой главе, могут и не понадобиться при отладке программ, однако, иногда встречаются ошибки, которые легче обнаружить теми способами, которые описаны в этой главе. В следующем разделе объясняется, в каких случаях может возникнуть необходимость в отладке на уровне ассемблера. Затем описываются возможности проверки состояния процессора с использованием встроенного дизассемблера и ассемблера. Затем вы изучите, как проверять и модифицировать необработанные шестнадцатиричные байты данных, как просматривать содержимое стека вызовов функций, как проверять и модифицировать содержимое регистров процессора и, наконец, как проверять и изменять состояния флагов процессора. Когда не достаточно отладки на уровне исходного текста ----------------------------------------------------------------- В большинстве случаев при отладке программ обращение к данным и коду программы производится на уровне исходного текста. Вы обращаетесь к идентификаторам программы, записывая их в том же виде, в котором они записаны в исходном тексте, и отлаживаете программу, выполняя фрагменты ее исходного текста. Однако иногда может потребоваться глубже исследовать проблему, просматривая машинные команды, сформированные компилятором, содержимое регистров процессора и стека. Чтобы делать это, вы должны быть знакомы с семейством процессоров 80х86 и с тем, как компилятор преобразует исходный текст программы в машинные команды. Поскольку имеется достаточно много хороших книг, посвященных внутренней работе процессора, мы не будем здесь рассматривать ее детально. Просматривая машинные команды, сформированные для каждой строки исходного текста программы, можно быстро изучить, как компилятор генерирует машинный код из исходного текста. Компиляторы Си и Паскаля, например, позволяют записывать строки исходного текста программы, в которых выполняется более одного действия. Поскольку отладчик выполняет за один шаг всю строку исходного текста, иногда может возникнуть необходимость узнать результат выполнения некоторой части строки. Выполняя программу по одной машинной команде, можно проверять промежуточные результаты, хотя прежде придется затратить некоторое время на то, чтобы изучить, как компилятор транслирует операторы исходного текста в машинный код. Окно процессора ----------------------------------------------------------------- В этом окне отображается полная информация о состоянии процессора. Можно проверять и изменять биты и байты, составляющие код и данные программы. С помощью встроенного ассемблера в подокне кода можно поставить временную "заплату" в программу, вводя команды точно в таком же виде, как они записываются в исходном тексте на языке ассемблера. Кроме того можно обращаться к внутренним байтам любой структуры данных, отображать их в нескольких различных форматах и модифицировать их. Рис. 11.1 Окно процессора Для того чтобы открыть окно процессора, надо выбрать из главного меню команду View/CPU. В зависимости от того, что вы просматривали в текущем окне, после открытия окна процессора выделяющий курсор будет установлен в нем на соответствующей позиции кода, данных или стека. Это дает возможность быстро просматривать внутреннюю структуру кода, данных или стека в текущей точке программы. Приведенная ниже таблица показывает, где будет установлен выделяющий курсор после выполнения команды CPU. ------------------------------------------------------------ Текущее окно Подокно окна процессора Положение в окне ------------------------------------------------------------ Стека Стека Текущее состояние SS:SP Модуля Кода Текущее состояние CS:IP Действия Кода Адрес действия Переменных Данных* Адрес элемента Проверки Данных Адрес элемента Точек останова Кода Адрес точки останова *Подокно кода, если элемент в окне - не подпрограмма. ------------------------------------------------------------ В верхней строке окна процессора указан тип используемого процессора (8086, 80186, 80286 или 80386). Окно процессора разделено на пять подокон. Для перехода из одного подокна в другое используются клавиши Tab и Shift-Tab. В верхнем левом подокне (подокне кода) отображается дизассемблированный код программы вперемешку со строками исходного текста. Во втором верхнем подокне (подокне регистров) показано содержимое регистров процессора. В правом подокне (подокне флагов) отображается состояние восьми флагов процессора. В нижнем левом подокне (подокне данных) отображается в шестнадцатиричном формате построчный дамп любой выбранной области памяти. В нижнем правом подокне (подокне стека) показано содержимое стека. В подокне кода указатель в виде стрелки показывает текущую точку программы (CS:IP). В подокне стека указатель в виде стрелки показывает текущую позицию в стеке (SS:SP). Если выделенная команда в окне кода обращается к области памяти, в верхней строке окна указывается адрес этой области и ее текущее содержимое. Это позволяет одновременно видеть, какую область памяти занимает операнд команды и значение, которое должно быть записано в память или считано из памяти. В подокне флагов отображается состояние каждого флага процессора. Так же как и для других окон нажатие клавиш Alt-F10 вызывает локальное меню подокна кода. Если для команды меню определена активная клавиша, нажатие клавиши Ctrl в сочетании с первой буквой нужной команды вызывает эту команду. В подокнах кода, данных и стека нажатие клавиш Ctrl-"Стрелка влево" и Ctrl-"Стрелка вправо" сдвигают начальный адрес отображения данных в окне соответственно на единициу вверх и вниз. Этот способ проще, чем использование команды Goto, если требуется лишь немного сместить отображение в окне. Подокно кода ----------------------------------------------------------------- В этом подокне отображаются дизассемблированные команды, начиная с выбранного адреса. В левой части каждой дизассемблированной строки указан адрес данной команды. Адрес либо отображается в виде шестнадцатиричных значений сегмента и смещения, либо значение сегмента заменяется названием регистра CS, если это значение совпадает с текущим содержимым регистра CS. Если окно достаточно широкое (то есть его размеры были увеличены соответствующей командой), отображаются байты, составляющие данную команду. Справа отображается дизассемблированная команда. Дизассемблер -------------------------------------------------- В окне кода автоматически дизассемблируются и отображаются команды программы. Если адрес соответствует либо глобальному идентификатору, либо локальному идентификатору, либо номеру строки, в строке перед дизассемблированной командой отображается данный идентификатор (если командой Mixed установлен режим отображения строк исходного текста перед дизассемблированными командами). Кроме того, если имеется строка исходного текста, которая соответствует адресу данного идентификатора, она отображается после этого идентификатора. Глобальные идентификаторы отображаются в виде обычных имен. Для локальных идентификаторов указывается имя модуля, который отделяется от самого идентификатора знаком # или точкой. Номера строк отображаются в виде имени модуля, за которым стоит знак # или точка, а затем десятичный номер строки. Если отображается некоторый промежуточный операнд, его размер можно вычислить, исходя из количества цифр: байтовое значение имеет две цифры, значение длиной в слово имеет четыре цифры. Turbo Debugger может обнаруживать числовой сопроцессор 8087/ 80287/80387 и дизассемблировать его команды, если в машине установлена соответствующая микросхема или имеется ее эмулятор. Команда дальнего возврата имеет мнемоническое обозначение RETF. Команда ближнего возврата обозначается RET. Там, где это возможно, назначение команд JMP и CALL обозначается символически. Если текущая команда является командой перехода или условного перехода стрелка, указывающая направление перехода будет отображаться только в том случае, если выполняемая команда действительно вызовет переход. Кроме того, адреса памяти в командах MOV, ADD и других отображаются в символическом виде. Локальное меню подокна кода ----------------------------------- -------------- Goto Origin Follow Caller Previous Search View source Mixed Yes -------------- New cs:ip Assemble... I/O -------------- Если вы еще не перешли в подокно кода, сделайте это сейчас с помощью клавиши Tab или Shift-Tab. Затем вызовите локальное меню, нажав клавиши Alt-F10. Команда Goto ------------ После выбора этой команды отладчик запрашивает у пользователя новый адрес, к которому надо перейти. Можно вводить адреса, находящиеся за пределами программы. Это дает возможность проверять код BIOS, DOS и резедентных утилит. Подробная информация, касающаяся ввода адресов, приведена в главе 9. Для возврата в позицию, которая являлась текущей перед выполнением команды Goto, можно использовать команду Previous. Команда Origin -------------- Позиционирует курсор в текущую точку программы, на которую указывает пара регистров CS:IP. Этой командой удобно пользоваться, когда необходимо вернуться к исходной позиции в программе. С помощью команды Previos можно вернуть выделяющий курсор в подокне кода в позицию, где он был установлен до выполнения команыды Origin. Команда Follow -------------- Позиционирует курсор в адрес назначения выделенной в данный момент команды. Курсор в подокне кода позиционируется на команду с адресом, по которому выделенная команда передает управление. Для команд условного перехода адрес указывается так, как если бы данный переход был выполнен. Эту команду можно использовать с командами CALL, JMP, командами условного перехода (JZ, JNE, LOOP, JCXZ и т.д.) и командой INT. С помощью команды Previos можно вернуть выделяющий курсор в подокне кода в позицию, где он был установлен до выполнения команыды Follow. Команда Caller -------------- Позиционирует выделяющий курсор на команду, которая вызвала текущее прерывание или подпрограмму. Эта команда работает не всегда. Если подпрограмма обработки прерывания или другая подпрограмма занесла данные в стек, в некоторых случаях Turbo Debugger не может определить, откуда была вызвана данная подпрограмма. С помощью команды Previos можно вернуть выделяющий курсор в подокне кода в позицию, где он был установлен до выполнения команыды Caller. Команда Previos --------------- Возвращает выделяющий курсор в подокне кода в позицию, где он был установлен до выполнения последней команды, которая изменила его позицию на экране. Позиция курсора, измененная с помощью клавиш управления курсором и клавиш PgUp и PgDw не может быть восстановлена с помощью команды Previos. При выборе команды Previos позиция выделяющего курсора в подокне кода запоминается, и при повторных выполнениях этой команды содержимое подокна будет переключаться между двумя запомненными позициями. Команда Search -------------- Предположим, требуется найти введенную команду или последовательность байтов. Для этого надо ввести команду точно в таком же виде, в каком она вводилась бы с помощью команды Assemble. Обращайте внимание на то, какие команды вы пытаетесь найти. Можно искать только те команды, которые не изменяют байты, в которые они были ассемблированы в зависимости от того, в какой области памяти они ассемблируются. Например, поиск следующих команд не вызывает никаких проблем: PUSH DX POP (DI+1) ADD AX,100 Однако попытка найти следующие команды приведет к непредсказуемым результатам: JE 123 CALL MYfUNC LOOP $-10 Вместо команды можно вводить последовательность байтов. Более подробно ввод последовательности байтов описан в главе 9. Команда Mixed ------------- Включает один из трех режимов отображения дизассемблированных команд и исходного кода: No Исходный код не отображается совсем; отображаются (нет) только дизассемблированные команды. Yes Строки исходного текста отображаются перед первой (да) дизассемблированной командой для данной строки исходного текста. Подокно переключается в этот режим отображения, если текущий модуль является исходным модулем на языке высокого уровня. Both Если для дизассемблированных команд имеется (оба) соответствующая им строка исходного текста, эта строка отображается вместо этих команд, в противном случае отображаются дизассемблированные команды. Этот режим удобно использовать при отладке ассемблерного модуля, когда вместо дизассемблированных команд требуется просматривать соответствующие им строки исходного текста. Этот режим устанавливается в том случае, если текущий модуль является исходным модулем на языке ассемблера. Команда New CS:IP ----------------- Устанавливает указатель текущей позиции программы (содержимое регистров CS:IP) на выделенный в данный момент адрес. При следующем запуске программы выполнение начнется с данного адреса. Эту команду удобно применять в тех случаях, когда требуется пройти без выполнения некоторый фрагмент кода. Этой командой следует пользоваться с особой осторожностью. Если сместить указатель в точку программы с другим состоянием стека, чем в текущей точке, это вероятнее всего приведет к фатальному сбою программы. Эту команду не следует использовать для установки указателя текущей позиции программы в точку, находящуюся за пределами текущей подпрограммы. Команда Assemble ---------------- Ассемблирует команду, заменяя ту, которая находится в выделенной строке. После выбора этой команды отладчик запрашивает команду, которую требуется сассемблировать. Для получения более подробной информации обратитесь к разделу "Ассемблер" данной главы. Эту команду можно также вызвать, просто начав вводить команду, которую необходимо сассемблировать. При этом на экране появляется поле запроса, в точности такое же, как если бы команда Assemble была выбрана из меню. Команда I/O ----------- ------------- In byte Out byte read word Write word ------------- Выполняет ввод или вывод значения в область ввода/вывода процессора, позволяет проверять содержимое регистров ввода/вывода, находящихся на платах и записывать в них данные. При выборе этой команде на экране появляется показанное выше меню. Команда In Byte Считывает байт из порта ввода/вывода. Отладчик запрашивает номер порта, содержимое которого требуется проверить. Для того чтобы считать значение из порта длиной в одно слово, используйте команду Read Word. Команда Out Byte Записывает байт в порт ввода/вывода. Отладчик запрашивает номер порта и значение, которое требуется записать в него. Для того чтобы записать значение в порт длиной в одно слово, используйте команду Write Word. Команда Read Word Считывает слово из порта ввода/вывода. Отладчик запрашивает номер порта, содержимое которого требуется проверить. Для того чтобы считать значение из порта длиной в один байт, используйте команду In Byte. Команда Write Word Записывает слово в порт ввода/вывода. Отладчик запрашивает номер порта и значение, которое требуется в него записать. Для записи значения в порт ввода/вывода длиной в один байт используйте команду Out Byte. С помощью команд IN и OUT можно получить доступ к области ввода/вывода, которую используют контроллеры периферийных устройств, такие как платы последовательного интерфейса, контроллеры диска и видеоадаптеры. Будьте внимательны при использовании этой команды: в некоторых устройствах ввода/вывода чтение из портов считается важным событием, по которому устройство должно выполнить какое-либо действие, как например, установка битов состояния или загрузка нового байта данных в порт. При неосторожном использовании этой команды может нарушиться нормальная работа отлаживаемой программы или устройства. Подокна Register и Flags ----------------------------------------------------------------- Подокно Register, находящееся вверху справа от подокна Code, показывает содержимое регистров роцессора. Верхнее правое подокно - это подокно Flags, в котором паказаны состояния восьми флагов процессора. В приведенной ниже таблице перечислены все флаги и их обозначения в подокне флагов. ------------------------------------------ Буква в подокне Название флага ------------------------------------------ c Флаг переноса z Флаг нуля s Флаг знака o Флаг переполнения p Флаг четности a Флаг дополнительного переноса i Флаг разрешения прерывания d Флаг направления ------------------------------------------ Локальное меню подокна регистров -------------------------------- Для вызова локального меню подокна регистров надо нажать клавиши Alt-F10. Если разрешено использование активных клавиш в комбинации с клавишей Ctrl, команду меню можно вызвать, нажав клавишу Ctrl в сочетании с первой буквой ее названия. -------------------- Increment Decrement Zero Change... Registers 32-bit No -------------------- Команда Increment ----------------- Увеличивает на единицу значение выделенного регистра. С помощью этой команды можно легко выполнить небольшую "настройку" значения регистра, чтобы исправить допущенную в программе ошибку. Команда Decrement ----------------- Уменьшает на единицу значение выделенного регистра. Команда Zero ------------ Устанавливает значение выделенного регистра равным нулю. Команда Change... ----------------- Изменяет значение выделенного регистра. Отладчик запрашивает новое значение. При вводе нового значения можно использовать все имеющиеся возможности вычисления выражения. Эту команду можно также вызвать, просто начав вводить новое значение для данного регистра. При этом на экране появляется поле запроса, точно такое же, как если бы команда Change была выбрана из меню. Команда Registers 32-bit ------------------------ Выполняет переключение между режимами отображения значений 16- или 32-битовых регистров процессора. При работе с процессором 80386 обычно используется режим отображения 32-битовых регистров, если с помощью данной команды не был установлен режим отображения 16- битовых регистров. В действительности необходимость просматривать значения 32-битовых регистров имеется только в том случае, если отлаживаемая программа использует возможности 32-битовой адресации процессора 80386. При отладке программы, в которой используется только обычная 16-битовая адресация можно использовать режим отображения 16-битовых регистров. Локальное меню подокна флагов --------------------------------- ------- Toggle ------- Для вызова локального меню подокна флагов надо нажать клавиши Alt-F10. Если разрешено использование активных клавиш в комбинации с клавишей Ctrl, команду меню можно вызвать, нажав клавишу Ctrl в сочетании с первой буквой ее названия. Команда Toggle -------------- Устанавливает значение флага равным 1, если оно было равно 0, и 0, если оно было равно 1. Значение 0 соответствует сбросу флага, а значение 1 - его установке. Для изменения выбранного флага можно также нажать клавишу Enter. Подокно данных ----------------------------------------------------------------- В этом подокне отображается построчное содержимое выбранной области памяти. В левой части каждой строки указывается адрес данных, отображаемых в данной строке. Адрес либо отображается в виде шестнадцатиричных значений сегмента и смещения, либо значение сегмента заменяется названием регистра DS, если оно совпадает с содержимым этого регистра. Далее в строке отображается один или несколько элементов данных. Формат представления данных зависит от того, какой режим отображения был выбран с помощью команды Display As локального меню. Если выбран один из форматов отображения чисел с плавающей точкой (Comp, Float, Real, Double, Extended), в каждой строке отображается только одно число с плавающей точкой. В формате Byte в каждой строке отображается 8 байтов, в формате Word - 4 слова, в формате Long - 2 двойных слова. В правой части каждой строки приводятся символьные значения, соответствующие отображаемым байтам данных. Turbo Debugger отображает для всех байтовых значений их символьные эквиваленты, поэтому не удивляйтесь, если справа от шестнадцатиричных значений байтов данных вы увидите какие-то непонятные символы; это символьные эквиваленты шестнадцатиричных значений. Примечание: Если подокно данных используется для проверки содержимого видеопамяти, области данных ПЗУ, содержащего BIOS, или векторов с меньшими адресами памяти, в подокне будут отображаться значения, которые содержатся в памяти при выполнении отлаживаемой программы, а не фактические значения, которые там содержатся при работе отладчика Turbo Debugger. То есть это не те значения, которые содержатся в памяти в момент их просмотра. Если программа обращается к областям памяти, которые используются отладчиком, он обнаруживает это и берет правильные значения данных из того места, где он хранит копию областей данных, используемых программой пользователя. Локальное меню подокна данных --------------------------------- Для вызова локального меню подокна данных надо нажать клавиши Alt-F10. Если разрешено использование активных клавиш в комбинации с клавишей Ctrl, команду меню можно вызвать, нажав клавишу Ctrl в сочетании с первой буквой ее названия. ---------------- Goto Search Next Change Follow > Previous ---------------- Display as > Block > ---------------- Команда Goto ------------ Позиционирует курсор на элемент данных с указанным адресом. После выбора этой команды нада ввести новый адрес, к которому требуется перейти. Вводимые адреса могут относиться к областям памяти, занимаемым DOS, резидентными программами и выходить за пределы отлаживаемой программы, что позволит проверять данные, находящиеся в области данных BIOS. Ввод адресов подробно рассмотрен в главе 9. Команда Search -------------- Выполняет поиск строки символов, начиная с текущего адреса памяти, указанного выделяющим курсором. В ответ на запрос отладчика надо ввести последовательность байтов. При поиске не происходит автоматического перехода с конца сегмента на его начало. Ввод последовательностей байтов подробно рассмотрен в главе 9. Команда Next ------------ Выполняет поиск следующего экземпляра последовательности байтов, заданной для предыдущей команды Search. Команда Change... ----------------- Позволяет изменять байты, находящиеся в текущей позиции курсора. Если курсор установлен на ASCII-символе или выбран байтовый формат, в ответ на запрос отладчика необходимо ввести последовательность байтов. В противном случае надо ввести элемент, соответствующий текущему формату отображения. Последовательности байтов рассмотрены в главе 9. Эту команду можно также вызвать, просто начав вводить с клавиатуры новое значение или значения. При этом на экране появляется поле запроса, точно такое же, как и при выборе команды Change из меню. Команда Follow -------------- Данная команда открывает меню, которое позволяет организацию цепочек ближних или дальних указателей. ----------------------- Near code Far code ----------------------- Offset to data Segment:offset to data Base segment:0 to data ----------------------- Команда Near Code Интерпретирует слово под курсором в подокне Data как смещение в текущем кодовом сегменте, заданном в регистре CS. Подокно Code становится текущим подокном и позиционируется на этот адрес. Команда Far Code Интерпретирует двойное слово под курсором в подокне Data как дальний адрес (сегмент и смещение). Подокно Code становится текущим подокном и позиционируется на этот адрес. Команда Offset to Data Позволяет организовывать цепочки указателей размером в слово (ближних, т.е. задаваемых только смещением). Подокно Data позиционируется на смещение, заданное словом в памяти, определяемом текущей позицией курсора. Команда Segment: Offset to Data Позволяет организовывать цепочки дальних указателей (т.е. задаваемых сегментом и смещением). Подокно Data позиционируется на смещение, заданное двумя словами в памяти, определяемом текущей позицией курсора. Команда Base Segment:0 to Data Данная команда интерпретирует слово под курсором как адрес сегмента и позиционирует подокно Data на начало этого сегмента. Команда Previos --------------- Возвращает курсор в подокне данных в положение, которое являлось текущим до выполнения последней команды, изменившей содержимое окна. Позиция курсора, измененная с помощью клавиш управления курсором или клавиш PgUp и PgDw, не запоминается и не может быть восстановлена. Последние пять адресов данных заносятся отладчиком в стек, благодаря чему можно проследить в обратном порядке выполнение нескольких последних команд меню Follow или Goto. Команда Display As ------------------ ----------- Byte Word Long Comp Float Real Double Extended ----------- Позволяет выбрать формат отображения данных в подокне данных. С помощью этой команды можно выбрать любой формат представления данных, используемой с языках Си, Паскаль и ассемблер. Выбор формата производится с помощью меню, показанного выше. Формат Byte ----------- Информация в подокне данных отображается в виде шестнадцатиричных байтов. Этот формат соответствует типу char языка Си и типу byte языка Паскаль. Формат Word ----------- Информация в подокне данных отображается в виде шестнадцатиричных чисел длиной в одно слово. Отображаются 2-байтовые шестнадцатиричные значения. Этот формат соответствует типу int языка Си и типу word языка Паскаль. Формат Long ----------- Информация в подокне данных отображается в виде шестнадцатиричных целых чисел длиной в два слова. Отображаются 4- байтовые шестнадцатиричные числа. Этот формат соответствует типу long языка Си и типу longint языка Паскаль. Формат Comp ----------- Информация в подокне данных отображается в виде 8-байтовых целых чисел. Отображаются десятичные целочисленные значения. Этот формат соответствует типу comp (страндарт IEEE) языка Паскаль. Формат Float ------------ Информация в подокне данных отображается в виде коротких чисел с плавающей точкой. Числа с плавающей точкой отображаются в экспоненциальной форме. Этот формат соответствует типу float языка Си и типу single (стандарт IEEE) языка Паскаль. Формат Real ----------- Информация в подокне данных отображается в виде 6-байтовых чисел с плавающей точкой, используемых в языке Паскаль. Числа с плавающей точкой отображаются в экспоненциальной форме. Этот формат соответствует типу real языка Паскаль. Формат Double ------------- Информация в подокне данных отображается в виде 8-байтовых чисел с плавающей точкой. Числа с плавающей точкой отображаются в экспоненциальной форме. Этот формат соответствует типу double языка Си и типу TBYTE языка ассемблера. Формат Extended --------------- Информация в подокне данных отображаеются в виде 10-байтовых чисел с плавающей точкой. Числа с плавающей точкой отображаются в экспоненциальной форме. Этот формат соответствует внутреннему формату представления данных в сопроцессоре 80х87. Он также соответствует типу long double языка Си и типу extended (стандарт IEEE) языка Паскаль. Команда Block ------------- ------------ Clear Move Set Read Write ------------ Позволяет манипулировать содержимым блоков памяти. Можно перемещать, очищать и устанавливать значения блоков памяти, считывать содержимое дисковых файлов в блоки памяти и записывать блоки памяти в дисковые файлы. При выборе этой команды на экране появляется меню, выше. Команда Clear ------------- Сбрасывает в ноль (0) содержимое непрерывного блока памяти. Отладчик запрашивает начальный адрес и количество байтов, которые необходимо очистить. Команда Move ------------ Копирует один блок памяти в другой. Отладчик запрашивает адрес исходного блока, адрес результирующего блока и количество байтов, которое должно быть скопировано. Команда Set ----------- Устанавливает непрерывный блок памяти в заданное байтовое значение. Отладчик запрашивает адрес блока, количество байтов, которое необходимо установить, и значение, в которое они должны быть установлены. Команда Read ------------ Считывает содержимое файла или его фрагмента в блок памяти. Отладчик сначала запрашивает имя файла, из которого требуется прочитать информацию, а затем адрес блока, в который будет производится считывание, и количество байтов в этом блоке. Команда Write ------------- Записывает содержимое блока памяти в файл. Отладчик сначала запрашивает имя файла, в который требуется записать данные, а затем адрес блока памяти, из которого должны быть взяты данные, и количество байтов в этом блоке. Подокно Stack ----------------------------------------------------------------- Подокно Stack, находящееся в нижнем правом углу окна CPU, показывает содержимое стека. Локальное меню подокна стека ---------------------------- ------------ Goto Origin Follow Previous Change... ------------ Для вызова локального меню подокна стека надо нажать клавиши Alt-F10. Если разрешено использование активных клавиш в комбинации с клавишей Ctrl, для вызова команды меню можно нажать клавишу Ctrl в сочетании с первой буквой ее названия. Команда Goto ------------ Позиционирует курсор на определенный адрес в стеке. В ответ на запрос отладчика надо ввести новый адрес. Если необходимо, можно вводить адреса, находящиеся за пределами стека отлаживаемой программы, хотя обычно для проверки произвольных данных, находящихся за пределами программы, используется подокно данных. Ввод адресов подробно описан в главе 9. Команда Previos возвращает выделяющий курсор в подокне стека в позицию, где он был установлен до выполнения команды Goto. Команда Origin -------------- Устанавливает выделяющий курсор в текущую позицию стека, на которую указывает пара регистров SS:SP. Эту команду удобно использвать для возврата в исходное положение. Команда Previos возвращает выделяющий курсор в подокне стека в позицию, где он был установлен до выполнения команды Origin. Команда Follow -------------- Позиционирует выделяющий курсор на слово в стеке, на которое указывает выделенное слово. Эту команду удобно использовать в тех случаях, когда требуется пройти несколько последовательных элементов стека для возврата в вызывающую функцию. Команда Previos возвращает выделяющий курсор в подокне стека в позицию, где он был установлен до выполнения команды Follow. Команда Previos --------------- Возвращает выделяющий курсор в подокне стека в позицию, где он был установлен до выполнения команды, изменяющей его текущее положение. Положение выделяющего курсора, измененное с помощью клавиш управления курсором или клавиш PgUp и PgDw, не может быть восстановлено. Повторные выполнения команды Previos переключают содержимое подокна стека с одного запомненного адреса на другой. Команда Change -------------- Позволяет заменять выделенное значение элемента стека новым значением, длина которого равна одному слову. Эту команду можно также вызвать, просто начав вводить с клавиатуры новое значение для выделенного элемента стека. При этом на экране появляется поле запроса, точно такое же, как и при выборе команды Change из меню. Ассемблер ----------------------------------------------------------------- Отладчик Turbo Debugger позволяет ассемблировать команды для процессоров 8086, 80186, 80286, 80386, а также команды для числовых сопроцессоров 8087, 80287 и 80387. Если для модификации отлаживаемой программы используется встроенный ассемблер отладчика Turbo Debugger, то изменения, вносимые в прогрмму, не являются постоянными. Если перезагрузить программу с помощью команды Run/Program Reset или загрузить другую программу с помощью команды File/Open, все внесенные изменения будут утеряны. Встроенным ассемблером обычно удобно пользоваться для проверки идей по исправлению ошибок в программе. Если после внесения изменения программа начинает работать правильно, следует перейти в текстовый редактор, внести соответствующие изменения в исходный текст, а затем заново скомпилировать и скомпоновать программу. В следующем разделе описаны различия в синтаксисе встроенного ассемблера и языка Turbo Assembler. Изменение размера адреса операнда ----------------------------- Для команд вызова (CALL), перехода (JMP) и условного перехода (JNE, JL и т.д.) ассемблер автоматически генерирует команды минимального размера, которые достигают адреса назначения. Для того чтобы получить команды нужного размера, можно использовать префиксы NEAR и FAR, записанные перед адресом назначения, например, CALL FAR XYZ jmp NEAR Al Операнды в памяти и промежуточные операнды ------------------------------------------ Когда некоторый идентификатор программы используется в качестве операнда команды, необходимо указать встроенному ассемблеру, как он должен его обрабатывать: как значение или как адрес. Если в качестве операнда записано только сам идентификатор, ассемблер обрабатывает его как адрес, точно так же, как если бы перед ним стоял оператор OFFSET языка ассемблера. Если идентификатор заключен в квадратные скобки ([]), он обрабатывается как содержимое области памяти. Допустим, в программе имеется следующее описание данных: A DW 4 Когда ассемблируется некоторая команда или для обращения к содержимому переменной вычисляется значение выражения языка ассемблера, следует использовать либо одно имя переменной, либо имя переменной, заключенное в квадратные скобки. mov dx,a mov ax,[a] Для того чтобы обратиться к адресу переменной, следует использовать оператор OFFSET: mov ax, offset a Изменение размера операнда ------------------------------------ Для некоторых команд необходимо указывать размер операнда с помощью одного из следующих выражений, записанных перед операндом: BYTE PTR WORD PTR Ниже приведено два примера изменения размера операнда с помощью указанных выражений. add BYTE PTR[si],10 mov WORD PTR[bp+10],99 При ассемблировании команд числового сопроцессора 8087/80287 для изменения размера операндов кроме указанного способа можно использовать следующие выражения: DWORD PTR QWORD PTR TBYTE PTR Ниже приведено два примера использования этих выражений. fild QWORD PTR[bx] stp TBYTE PTR[bp+4] Команды обработки строк --------------------------------------- При ассемблировании команд обработки строк в мнемоническое обозначение команды необходимо включать размер (байт или слово). Ассемблер не воспринимает форму строковых команд, в которой используется безразмерное мнемоническое обозначение для операнда, в котором указан размер. Например, вместо команды STOS WORD PTR[DI], следует использовать команду STOSW. Окно дампа ----------------------------------------------------------------- В этом окне отображается построчный дамп любой выбранной области памяти. Это окно работает точно так же, как подокно данных окна процессора. Рис.11.2 Окно Dump Для получения информации о работе с этим окном и о командах его локального меню обратитесь к разделу "Локальное меню подокна данных" данной главы. Это окно удобно использовать при отладке ассемблерной программы на уровне исходного текста, если требуется просматривать содержимое областей данных. Для того чтобы открыть окно дампа, можно использовать команду View/Dump. Окно дампа также можно использовать при работе в окне проверки, когда требуется просмотреть последовательность байтов, составляющих проверяемый элемент данных. Выбор команды View/Dump открывает окно дампа, в котором отображаются данные, просматриваемые в окне проверки. Окно регистров ----------------------------------------------------------------- В этом окно отображается содержимое регистров процессора и состояние его флагов. Оно работает аналогично комбинации подокон регистров и флагов окна процессора. Рис.11.3 Окно Registers Для получения информации о работе с этим окном и о командах его локальных меню обратитесь к разделам "Локальное меню подокна регистров" и "Локальное меню подокна флагов" данной главы. Это окно удобно использовать при отладке ассемблерной программы на уровне исходного текста, когда требуется проверять состояние регистров процессора. Для удобства работы можно уменьшить размер окна модуля и поместить окно регистров рядом с ним. Генерация кода для программ на языке Turbo C -------------------------------------------- При генерации машинного кода компилятор Turbo C выполняет ряд специальных действий, которые необходимо учитывать при отладке сипрограмм. Ознакомившись с компилятором Turbo C, можно быстро изучить, каким образом строки исходного текста преобразуются в машинные команды. Значения, возвращаемые функцией, помещаются в следующие регистры: ------------------------------------ Тип возвращаемого Регистр(ы) значения ------------------------------------ int AX long DX:AX float ST(0) double ST(0) long double ST(0) near* AX far* DX:AX ------------------------------------ Часто используемые указатели типа int и near компилятор помещает в регистры, используя сначала регистр SI, а затем регистр DI. Доступ к предопределенным переменным и параметрам функций осуществляется через регистры SS:BP. Регистры AX, BX, CX и DX не обязательно сохраняют свои значения при вызовах функций. Всегда используются регистры, размер которых равен одному машинному слову, даже при работе с символьными типами данных. Операторы перехода могут быть скомпилированы в одной из трех форм, в зависимости от того, какая из них обеспечивает более эффективный код: - условные переходы, соответствующие оператору if...else; - таблица переходов по адресам кода; - таблица переходов по значениям ключей и адресам кода. Более подробная информация о генерации кода Turbo С находится в соответствующих руководствах по Turbo С. |