
Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004
.pdf
ГЛАВА 7 Усложненные технологии неуправляемого кода в Visual Studio .NET |
271 |
|
|
Диалоговое окно Exceptions слегка сбивает тем, что неуправляемые исключе ния разделены между двумя узлами верхнего уровня: C++ Exceptions и Win32 Exceptions. Параметры по умолчанию предписывают отладчику при отладке кон сольных приложений останавливаться только по исключениям Control C (0x40010005) и Control Break (0x40010008). Чтобы отладчик останавливался при инициации определенного исключения, выберите исключение в дереве и в груп пе When The Exception Is Thrown (т. е. в первом случае исключения) выберите Break Into The Debugger. Изображение выделенного элемента изменится на большой красный шар с крестом внутри. В диалоговом окне серые шары меньшего разме ра обозначают исключения, наследующие свои параметры от предков. Большой серый шар обозначает продолжение работы при первом случае исключения. На конец, маленький красный шар говорит о том, что родительский узел прерывает работу при первом случае исключения и узел потомок наследует от предка. Па раметры исключений сохраняются для каждого решения отдельно.
Я хочу установить в узлах Win32 Exceptions и C++ Exceptions параметр Break Into The Debugger для обоих вариантов: When The Exception Is Thrown и If The Exception Is Not Handled. Тогда при инициации неуправляемого исключения лю бого типа процесс будет остановлен, позволив мне определить, допустимо ли это исключение. Если все или какой то один тип исключения настроен на останов, вы увидите диалоговое окно (рис. 7 8), показывающее первый случай исключения C++. Щелкнув кнопку Break, вы окажетесь в первой функции из стека, имеющей исходный код, что обычно является именно тем местом в коде, где инициирова но исключение. Если в этой точке щелкнуть Step Over или Step Into, отладчик попросит подтверждения информационным окном, спрашивая, хотите ли вы пе редать исключение отлаживаемой программе. Щелкните Yes, и вы сразу остано витесь в обработчике исключения. Превосходно для определения, где обрабаты ваются ваши исключения. Есть масса ошибок, порожденных обработкой исклю чений неверным обработчиком.
Рис. 7 8. Диалоговое окно первого случая исключения
Щелчок в диалоговом окне первого случая исключения кнопки Continue пе редает исключение отлаживаемой программе и продолжает выполнение. Кнопка Ignore несколько отличается и зависит от типа исключения, а также того, содер жится ли оно в списке диалогового окна Exceptions. Если это серьезное исключе ние, сгенерированное центральным процессором (вроде нарушения доступа), щелчок кнопки Ignore приведет к попытке перезапуска команды нарушителя, ко торая вновь покажет диалоговое окно первого случая исключения. Если исклю чение инициировано вызовом RaiseException (такое как «0xC0000008, Invalid HANDLE was specified»), выполнение продолжится, как если бы исключение не возникало

272 ЧАСТЬ II Производительная отладка
вовсе. Поскольку исключения C++ инициируются через вызов RaiseException, вы полнение продолжится, будто throw не было.
Дополнительные советы по обработке символов
Как я уже говорил, усложненная обработка символов Visual Studio .NET с новым сервером символов и технологией хранения символов совершенно великолепна (см. главу 2). В отладке неуправляемого кода вы можете установить дополнитель ные пути для символов внутри проекта и получить для каждого проекта свое ме стоположение символов за пределами обычного сервера символов.
В диалоговом окне проекта Property Pages\Configurations Properties\ на стра нице свойств Debugging есть поле Symbol Path, где можно указать свой путь для символов в этом проекте. Хорошая новость: он присоединяется к любым парамет рам, указанным в переменной окружения _NT_SYMBOL_PATH, таким образом, не перезаписывая их.
Отключение от процессов Windows 2000
Сейчас вы уже знаете, что вправе отключаться от процессов при отладке в Windows XP/Server 2003. Однако, если вы еще поддерживаете Windows 2000, вы попались: начав отладку, вы будете отлаживать этот процесс до конца, что особенно утом ляет при отладке прикладного серверного ПО. К счастью, в Microsoft поняли, что не все собираются разом переходить на новейшие и лучшие ОС, и выдали хоро шее решение для отключения от процессов Windows 2000.
Как часть Visual Studio .NET и Remote Components Setup, устанавливается служба Win32 с именем DBGPROXY, представляющая прокси отладчика. Она будет запус каться в Windows 2000 как отладчик. А значит, в Windows 2000 вы сможете под ключаться и отключаться от чего угодно! Запустив однажды DBGPROXY коман дой NET START DBGPROXY, вам больше не придется ничего делать. Visual Studio .NET автоматически творит чудо, а вы просто занимаетесь отладкой, и вам доступны функции отключения. Разумеется, если почему либо DBGPROXY останавливает ся, то все отлаживаемые ею процессы завершаются. Настоятельно рекомендую пе ревести службу DBGPROXY на автоматический запуск, чтобы использовать ее пре имущества!
Обработка дамп-файлов
Вернемся в главу 3, где я рассказывал о диалоговом окне SUPERASSERT и его кнопке Create Mini Dump, позволяющей сохранять на диск текущее состояние процесса, чтобы иметь возможность загрузить его в отладчик позже. Visual Studio .NET по зволяет легко читать любые созданные дамп файлы. Открыть дамп файл в Visual Studio .NET так же просто, как открыть обычное решение.
Запустив Visual Studio .NET, выберите Open Solution из меню File. В диалого вом окне Open Solution перейдите в каталог, где хранится ваш дамп файл. Дамп файлы обычно имеют расширение DMP, которое есть в поле со списком Files Of Type, так что можете выбрать его или ввести *.DMP в поле ввода File Name. Выбе рите DMP файл и щелкните кнопку Open. Как всегда, Visual Studio .NET создаст
ГЛАВА 7 Усложненные технологии неуправляемого кода в Visual Studio .NET |
273 |
|
|
вездесущий файл решения, необходимый для любых действий внутри среды. На жав любую из клавиш отладчика — Step Into, Step или Debug, вы получите при глашение для записи решения и загрузки дамп файла.
Если вы работаете на той машине, где был создан дамп файл, и ваши двоич ные файлы скомпилированы, Visual Studio .NET автоматически найдет исходный код и символы, соответствующие дамп файлу. Чтобы присоединить операцион ные символы, установите _NT_SYMBOL_PATH, включив туда место хранения сим волов, или, запустив отладку, откройте окно Modules, щелкните правой кнопкой модули без символов и укажите нужные символы.
Чтобы помочь отладчику определить где найти модули, есть два способа. Проще всего — указать каталоги модулей в переменной окружения MODPATH: добавьте каждый каталог, отделяя его точкой с запятой, к переменной окружения MODPATH, как в пе ременной окружения PATH. Если хотите установить путь поиска модулей глобаль но, укажите его в SZ_REG!параметре GlobalModPath в любом из следующих разделов реестра. Если хотите сделать путь доступным всем пользователям этой машины, используйте раздел HKEY_LOCAL_MACHINE.
HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\NativeDE\Dumps\
HKEY_LOCAL_MACHINE\Software\Microsoft\VisualStudio\7.1\NativeDE\Dumps\
К сожалению, отладчик Visual Studio .NET не считывает двоичные файлы на прямую у сервера символов в отличие от WinDBG. Так что, если вы работаете с дамп файлами с клиентских сайтов, вам, вероятно, лучше использовать WinDBG (см. главу 8).
Кроме открытия дамп файлов, Visual Studio .NET может их создавать. На пер вый взгляд, это не так уж важно, но с точки зрения Bugslayer, мы получаем еще одну прекрасную технологию решения проблем. Создавая дамп файлы на разных этапах напряженного сеанса отладки, вы получаете посмертный след, по которо му можно выйти к проблеме. Это дает прекрасную возможность фиксировать состояния программы для демонстрации другим членам команды и оценки пове дения во времени. Я дошел до того, что в процессе отладки делаю снимки так ча сто, что могу быстро заполнить все жесткие диски. Но жесткие диски — это не большая плата в сравнении с возможной стоимостью неустраненной ошибки.
Записывать дамп файлы в ходе сеанса отладки очень просто. Из нижней час ти меню Debug выберите команду Save Dump As. В появившемся диалоговом окне File Save можно указать точное место создания дамп файла. Visual Studio .NET позволяет записывать два вида дамп файлов. Первый в Visual Studio .NET называ ется минидамп (minidump). Он содержит информацию о версии ОС, о стеке всех потоков и о версии файлов каждого модуля, загруженного в процесс. Обычные минидамп файлы довольно малы. При написании этого материала я подключил отладчик к Word 2002 и размер минидамп файла составил всего 38 Кб, тогда как рабочий набор занимал около 16 Мб.
Второй тип записываемого дамп файла — минидамп с кучей (minidump with heap) — сохраняет ту же информацию, что и минидамп, вместе со всей выделен ной памятью в процессе. С таким форматом дамп файла можно отслеживать зна чения указателей по всему адресному пространству. Разумеется, за эту дополни

274 ЧАСТЬ II Производительная отладка
тельную информацию приходится платить гораздо больше. Минидамп с кучей для Microsoft Word 2002, в который загружена вся эта глава, занимает 96 Мб! Как пра вило, я придерживаюсь обычной версии минидампа, потому что мне не часто приходится прослеживать разные уровни указателей. Но приятно знать, что он есть.
Увы, Visual Studio .NET не позволяет записывать дамп в самом полезном фор мате — минидамп с описателями (minidump with handles). Это можно объяснить тем, что, раз Visual Studio .NET не включает средств просмотра информации опи сателей, нет причин записывать эту информацию. Однако, как вы увидите в гла ве 8, WinDBG позволяет просматривать информацию описателей. В наличии ин формации описателей заключается разница между отслеживанием многопоточ ной взаимной блокировки и неспособностью решить эту проблему. Поскольку эта информация так важна, диалоговое окно SUPERASSERT сохраняет ее.
Не забудьте прочитать о работе с дамп файлами в WinDBG. Хотя WinDBG слож нее в использовании, этот отладчик лучше приспособлен к считыванию дамп файлов, полученных от клиентов, в основном потому, что может загружать дво ичные файлы вне хранилища символов. С помощью его улучшенной обработки символов и более информативных команд вам будет проще определить причину проблем у клиентов.
Стандартный вопрос отладки
Как устанавливать точки прерывания в еще не загруженных DLL?
Большая проблема Visual Studio 6 заключалась в том, что попытка устано вить точку прерывания в DLL, которая была динамически загружена в диа логовом окне Additional DLL, была, мягко говоря, катастрофой. Особенно затруднялась удаленная отладка. Однако вы могли даже не заметить отли чия в Visual Studio .NET, так как Microsoft исправила точки прерывания так, что они автоматически взводятся при входе модуля, содержащего исходный файл, в адресное пространство. В окне Breakpoint невзведенные точки пре рывания обозначаются белым знаком вопроса в красной точке. Диалоговое окно Additional DLL пропало, и скатертью дорога!
Язык ассемблера x86
Когда неуправляемое приложение терпит крах, истинная разница между исправ лением ошибок и причитаниями очень часто определяется тем, насколько хоро шо вы понимаете язык ассемблера. Всем нам хотелось бы, чтобы ошибки имели место только в тех модулях, для которых у нас есть исходный код и полный стек вызовов, но это далеко не всегда так. При возникновении ошибки нам обычно остается только смотреть в окно Disassembly (дизассемблированный код) отлад чика Visual Studio .NET и пытаться хотя бы определить, в каком месте программы мы находимся, не говоря уж о поиске причин проблемы.
Я ни в коем случае не утверждаю, что вам нужно знать ассемблер настолько хорошо, чтобы писать все программы с использованием Microsoft Macro Assembler (MASM) — его нужно знать на таком уровне, чтобы легко его понимать. Цель дан
ГЛАВА 7 Усложненные технологии неуправляемого кода в Visual Studio .NET |
275 |
|
|
ного раздела — предоставить вам всю информацию, необходимую для получения рабочего знания языка ассемблера. По окончании чтения этого раздела и несколь ких часов практики ваши знания ассемблера будут более чем достаточными. По траченное время может оказаться тем самым фактором, который позволит вам на самом деле исправлять ошибки, а не блуждать в отладчике, практикуясь в нецен зурном словоупотреблении. Если вы ранее программировали на ассемблере, по мните, что вся информация, представленная в этом разделе, касается того, что вы будете видеть в окне Disassembly. Возможно, вам известны более эффективные способы выполнения некоторых действий, но это не имеет особого значения. Важно познакомиться с тем, как язык ассемблера выглядит в отладчике Visual Studio .NET.
Программисты иногда относятся к ассемблеру с настороженностью: им кажется, что над ним потрудились темные силы. Однако на самом деле в ассемблере нет ничего мистического; просто нужно помнить, что одна ассемблерная команда выполняет одно и только одно действие. Стоит изучить основы ассемблера и понять, как процесор выполняет команды, и вы осознаете, что на самом деле этот язык довольно элегантен. Если вам захочется увидеть настоящую черную магию, изучите любую программу, интенсивно работающую с STL. Магические встраива емые функции STL могут приводить к вызову 30 40 других функций и невероят но большому числу допущений. Лично мне STL иногда кажется гораздо более за гадочной, чем ассемблер.
Познакомив вас с ассемблером, я вернусь к отладчику Visual Studio .NET и рас скажу, как выжить в окне Disassembly. Например, я опишу способы просмотра параметров в стеке и навигацию в окне Disassembly. Кроме того, я объясню связь между окнами Memory и Disassembly и познакомлю вас с советами и уловками, которые помогут отлаживать программы на уровне ассемблера.
Прежде чем мы рассмотрим ассемблер, я должен вас кое о чем предупредить. Возможно, некоторым из вас ассемблер понравится настолько, что вы захотите писать на нем свои программы. Это прекрасно, но так вы поставите под угрозу свою карьеру. Ваши начальники уже говорили со мной и просили, чтобы вы не начинали разрабатывать на ассемблере все, что можно. Ассемблер не является платформенно независимым языком, что может заметно затруднить сопровожде ние написанных на нем программ.
Основы архитектуры процессоров
Набор команд процессоров Intel берет начало от процессора 8086, представлен ного компанией Intel в 1978 году. Во времена MS DOS и 16 разрядных ОС Microsoft Windows язык ассемблера был несколько странным и сложным в использовании, потому что с памятью можно было работать только посредством 64 килобайтных блоков — сегментов. К счастью, современные ОС Windows предоставляют процес сору прямой доступ ко всему адресному пространству, а значит, использовать ассемблер стало гораздо легче.
В этом разделе я опишу базовый набор 32 разрядных команд, поддерживае мый всеми процессорами Intel и AMD с архитектурой x86; иногда его еще обо значают как IA32. Расширенные возможности процессоров Intel Pentium, напри мер набор команд MMX, применяются в Windows редко, и вам почти не придется сталкиваться с ними. Я не буду рассматривать по настоящему мудреные аспекты

276 ЧАСТЬ II Производительная отладка
ассемблерных команд, такие как байты ModR/M и SIB, определяющие способы доступа к памяти. В этой главе под доступом к памяти я понимаю просто доступ к памяти и ничего больше. Я также не буду описывать команды работы с числами с плавающей точкой. Операции с устройством для выполнения команд с плаваю щей точкой (Floating point unit, FPU) процессоров Intel аналогичны обычным командам. Основные различия между ними в том, что FPU имеет свой набор ре гистров и для выполнения команд с плавающей точкой используется архитекту ра, основанная на регистровом стеке. Если эта глава пробудит в вас интерес к процессорам семейства Intel (а я надеюсь, что так оно и случится), загрузите с сайта www.intel.com три тома документации Intel Architecture Software Developer’s Manual (Руководство по разработке ПО для процессоров с архитектурой Intel), представ ленной в формате PDF. В нашем случае самым важным является том 2, Instruction Set Reference (Описание набора команд). В томах 1 и 3 приводится базовая ин формация об архитектуре процессоров и сведения для разработчиков ОС соот ветственно. Вы даже можете бесплатно получить эти тома в бумажном формате, просто позвонив по телефону. Скорее всего они вам не понадобятся, но, поста вив их на полку, вы, несомненно, станете чувствовать себя гораздо более умным!
Необходимо помнить, что процессоры x86 очень гибки и предоставляют много способов выполнения похожих операций. К нашему счастью, компиляторы Micro soft достаточно успешно выбирают самый быстрый способ и используют соот ветствующую конструкцию во всех возможных случаях, так что понять назначе ние отдельных разделов кода становится гораздо легче. Ниже я опишу команды языка ассемблера, которые чаще всего встречаются в коде программ. Если вас заинтересуют другие ассемблерные команды, обратитесь к руководству Intel.
Регистры
Сначала мне хотелось бы рассказать про регистры процессора. Каждый бит дан ных программы рано или поздно попадает в регистры, поэтому, если вы будете понимать назначение каждого регистра, вам будет легче узнать, когда программа начинает плохо себя вести. У процессоров x86 восемь регистров общего назна чения (EAX, EBX, ECX, EDX, ESI, EDI, ESP и EBP), шесть сегментных (CS, DS, ES, SS, FS и GS), регистр указателя команд (EIP) и флагов (EFLAGS). В процессоре есть и другие ре гистры, например, отладочные и управляющие регистры, но они имеют специ альное назначение, и при отладке в обычном пользовательском режиме вы с ними не столкнетесь. Схема регистра общего назначения показана на рис. 7 9. Помни те: некоторые 32 разрядные регистры позволяют обращаться к отдельным их частям. Описание всех регистров общего назначения приведено в табл. 7 6. Един ственный сегментный регистр, представляющий для нас интерес, — FS — содер жит адрес блока информации о потоке (Thread information block, TIB), выполня ющемся в данный момент. Конечно, ОС использует и другие сегментные регист ры, но она настраивает их так, чтобы они были «прозрачны» для обычных опера ций. Регистр указателя команд содержит адрес выполняемой в данный момент команды.

|
|
ГЛАВА 7 Усложненные технологии неуправляемого кода в Visual Studio .NET |
277 |
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
|
EAX |
|
|
|
|
|
0 |
|
|||||
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
AH |
|
|
AL |
|
|
|
|
|
|
|
15 |
|
|
|
AX |
|
0 |
|
|||||
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Значение |
|
Разряды |
|
|
|
||||
|
|
|
|
|
|
|
|
EAX |
|
|
0–31 |
|
|
|
|
|
|
|
|
|
|
|
|
AX |
|
|
0–15 |
|
|
|
|
|
|
|
|
|
|
|
|
AH |
|
|
8–15 |
|
|
|
|
|
|
|
|
|
|
|
|
AL |
|
|
0–7 |
|
|
|
|
Рис. 7 9. |
|
|
|
|
|
|
|
|
|
|
|
||||
Схема регистра общего назначения |
|
|
|
Регистр флагов EFLAGS содержит флаги статуса и флаги управления. Биты ре гистра EFLAGS характеризуют результат выполнения команд. Так, флаг нуля ZF (Zero Flag) устанавливается в 1, если в результате выполнения команды было получено значение 0. В главе 4 я рассказывал, как перевести процессор в пошаговый ре жим; если помните, это было связано с установкой флага ловушки TF (Trap Flag) в регистре EFLAGS. На рис. 7 10 показано окно Registers (регистры) отладчика Visual Studio .NET. В этом окне регистр EFLAGS называется EFL. Заметьте: я не показываю в окне Registers регистры для работы с числами с плавающей точкой и другие ре гистры специального назначения, такие как MMX или 3DNow! Чтобы выбрать интересующие вас регистры, щелкните в окне Registers правой кнопкой и укажи те соответствующий пункт в появившемся контекстном меню.
Табл. 7-6. Регистры общего назначения
|
|
Доступ |
Доступ |
|
32-раз- |
|
к младшему |
к старшему |
|
рядный |
Доступ |
байту |
байту |
|
регистр |
к 16 битам |
(биты 0-7) |
(биты 8-15) |
Специальные функции |
EAX |
AX |
AL |
AH |
В этом регистре сохраняются воз |
|
|
|
|
вращаемые функциями целочис |
|
|
|
|
ленные значения. |
EBX |
BX |
BL |
BH |
|
ECX |
CX |
CL |
CH |
Команда Loop использует этот ре |
|
|
|
|
гистр для подсчета итераций цикла. |
EDX |
DX |
DL |
DH |
В этом регистре хранятся 32 стар |
|
|
|
|
ших разряда 64 разрядных значе |
|
|
|
|
ний. |
ESI |
SI |
|
|
При выполнении команд переме |
|
|
|
|
щения или сравнения блоков па |
|
|
|
|
мяти в этом регистре хранится ад |
|
|
|
|
рес источника. |
EDI |
DI |
|
|
При выполнении команд переме |
|
|
|
|
щения или сравнения блоков па |
|
|
|
|
мяти в этом регистре хранится ад |
|
|
|
|
рес назначения. |
см. след. стр.

278 |
ЧАСТЬ II |
Производительная отладка |
|
|
|
||
Табл. 7-6. |
Регистры общего назначения (продолжение) |
||
|
|
|
|
|
|
Доступ |
Доступ |
32-раз- |
|
к младшему |
к старшему |
рядный |
Доступ |
байту |
байту |
регистр |
к 16 битам |
(биты 0-7) |
(биты 8-15) Специальные функции |
ESP |
SP |
|
Указатель стека. Этот регистр не |
|
|
|
явно изменяется при вызове функ |
|
|
|
ций, возвращении из функций, вы |
|
|
|
делении в стеке места для локаль |
|
|
|
ных переменных и очистке стека. |
EBP |
BP |
|
Указатель базы/кадра стека. Этот |
|
|
|
регистр содержит адрес кадра сте |
|
|
|
ка процедуры. |
|
|
|
|
Рис. 7 10. Окно Registers среды Visual Studio .NET
Значения флагов, показанных в окне Registers, описаны в табл. 7 7. В докумен тации к Visual Studio .NET названия флагов в окне Registers не обсуждаются, по этому вполне возможно, что их обозначения вам незнакомы. К сожалению, мне монические обозначения этих флагов в Visual Studio .NET не соответствуют обо значениям Intel, поэтому при чтении документации Intel вам придется выполнять некоторые сопоставления. Отмечу также, что окно Registers в Visual Studio .NET стало поддерживать одну очень полезную функцию: измененные в результате вы полнения команды флаги выделяются красным цветом. В предыдущих версиях Visual Studio измененные флаги ничем не отличались от остальных, поэтому сле дить за изменениями было довольно сложно. К нашему всеобщему удовольствию, при отладке машинного кода наблюдать за флагами почти не приходится.
Хотя окно Registers выглядит, как обычное текстовое окно, такое как Output, вы можете редактировать содержащиеся в нем значения. Просто наведите указа тель мыши на значение нужного вам регистра, расположенное справа от знака равенства, и введите измененный вариант. Ввод нового значения начинается с места расположения курсора. Окно Registers также поддерживает функцию Undo.

ГЛАВА 7 Усложненные технологии неуправляемого кода в Visual Studio .NET |
279 |
|||
|
|
|
|
|
Табл. 7-7. |
Значения флагов окна Registers |
|
|
|
|
|
|
|
|
|
|
Обозначение |
|
|
Флаг |
|
флага в |
|
|
в окне |
|
документации |
|
|
Registers |
Значение |
Intel |
Описание |
|
OV |
Флаг переполнения |
OF |
Устанавливается в 1, если команда |
|
|
|
|
привела к целочисленному перепол |
|
|
|
|
нению. |
|
UP |
Флаг направления |
DF |
Имеет значение 1, если команды ра |
|
|
|
|
боты со строками обрабатываются в |
|
|
|
|
порядке от старшего адреса к млад |
|
|
|
|
шему (автодекремент), 0 — если |
|
|
|
|
команды работы со строками выпол |
|
|
|
|
няются в порядке от младшего адреса |
|
|
|
|
к старшему (автоинкремент). При ге |
|
|
|
|
нерировании кода C/C++ всегда реа |
|
|
|
|
лизуется второй вариант. |
|
EI |
Флаг разрешения |
IF |
Значение 1 показывает, что преры |
|
|
прерывания |
|
вания разрешены. При отладке в |
|
|
|
|
пользовательскм режиме этот флаг |
|
|
|
|
всегда равен 1, так как запрещение |
|
|
|
|
прерываний, кроме всего прочего, |
|
|
|
|
блокирует клавиатуру и обновление |
|
|
|
|
экрана. |
|
PL |
Флаг знака |
SF |
Содержит значение старшего бита |
|
|
|
|
результата выполнения команды. Зна |
|
|
|
|
чение 0 показывает, что результат по |
|
|
|
|
ложителен, 1 — отрицателен. |
|
ZR |
Флаг нуля |
ZF |
Имеет значение 1, если в результате |
|
|
|
|
выполнения команды был получен 0. |
|
|
|
|
Этот флаг очень важен для команд |
|
|
|
|
сравнения. |
|
AC |
Вспомогательный |
AF |
Устанавливается в 1 при возникнове |
|
|
флаг переноса |
|
нии переноса или заема в результате |
|
|
|
|
операций в двоично десятичном |
|
|
|
|
формате (binary coded decimal, BCD). |
|
PE |
Флаг четности |
PF |
Устанавливается в 1, если младший |
|
|
|
|
байт результата содержит четное чис |
|
|
|
|
ло единичных битов. |
|
CY |
Флаг переноса |
CF |
Имеет значение 1, если арифметичес |
|
|
|
|
кая операция привела к переносу или |
|
|
|
|
заему старшего бита результата. Так |
|
|
|
|
же устанавливается в 1 при перепол |
нении в случае беззнаковых целочис ленных арфметических операций.
Формат команд и адресация памяти
Все команды процессоров Intel имеют такой базовый формат:
[префикс] команда [операнды]

280 ЧАСТЬ II Производительная отладка
Как правило, вы будете встречать префиксы только перед некоторыми коман дами работы со строками (эти случаи я опишу в разделе «Манипуляции со стро ками»). Представленный формат операндов указывает на направление операции: от источника к приемнику, поэтому читайте операнды в порядке справа налево.
Команда с одним операндом: XXX источник
Команда с двумя операндами: XXX приемник, источник
Чтобы вам было легче привыкнуть к этому формату, укажите пальцем на вто рой операнд (источник) и переместите палец влево, пока он не укажет на опе ранд приемник. Перемещая палец, говорите «от источника к приемнику». Имен но так я делаю, когда читаю ассемблерный код. Источник и приемник путают очень многие люди, начинающие изучать ассемблер Intel, так что трюк с пальцем на самом деле может оказаться полезным. Кое кто говорил мне, что чтение ассемблерного кода облегчается, если вместо запятой между источником и приемником представ лять знак равенства. Однако порядок выполнения операций все равно восприни мается как обратный, если только вы не привыкли читать книги, написанные на арабском языке или иврите.
Операнд источника может быть регистром, ссылкой на память или непосред ственным — т. е. «жестко закодированным» — значением. Операнд приемника может быть регистром или ссылкой на память. Процессоры Intel не позволяют, чтобы и источник, и приемник являлись ссылками на память.
Ссылки на память представляют собой операнды, заключенные в квадратные скобки. Так, ссылка [0040129Ah] говорит «получить значение ячейки памяти, рас положенной по адресу 0x0040129A». Буква «h» в ассемблере свидетельствует о том, что число представлено в шестнадцатеричном виде. Ссылка [0040129Ah] аналогична разыменованию указателя на целое число в языке C. Ссылаться на память можно через регистры: например, операнд [EAX] означает «получить значение памяти по адресу, указанному в регистре EAX». Очень часто адрес обращения к памяти вы числяется иначе: путем сложения значения регистра и некоторого смещения. Так, операнд [EAX+0Ch] означает «добавить 0xC к значению в регистре EAX и получить значение памяти, расположенное по получившемуся адресу». Некоторые ссылки на память могут быть довольно сложными, например [EAX+EBX*2], в формирова нии которой участвуют два регистра.
Чтобы процессору было ясно, к какому объему памяти обратиться, в ряде слу чаев ссылке предшествует спецификатор указателя. Спецификаторы указателя обозначаются как BYTE PTR, WORD PTR и DWORD PTR для байта, слова и двойного слова соответственно. Можете считать их аналогами приведения типов в C++. Если в дизассемблированном коде спецификатор указателя отсутствует, значит, выпол няется обращение к двойному слову.
Иногда ссылка на память проста, и вы можете легко узнать, к какому адресу она обращается. Например, ссылка [EBX] — это просто ссылка на ячейку памяти, адрес которой содержится в регистре EBX, поэтому, чтобы увидеть значение па мяти, можно просто открыть окно Memory и ввести EBX. Однако иногда для вы числения ссылки на память приходится проводить сложное умножение шестнад цатеричных чисел. К счастью, окно Registers покажет, на какую ячейку памяти ссылается команда.