Отладка приложений

         

Полный пример


Представив все важные части языка Intel-ассемблера, обратимся к полному примеру одной из API-функций операционных систем Win32. В листинге 6.2 показан полностью прокомментированный дизассемблерный код функции IstrcpyA из библиотеки KERNEL32.DLL пакета обслуживания Service Pack 4 операционной системы Windows NT 4. Функция IstrcpyA копирует одну строку в другую. Эту функция выбрана потому, что она показывает понемногу все, что обсуждалось до сих пор в этой главе, а также потому, что цель этой функции легко понять. Комментарии, выделенные точками с запятой, делают их настолько подробными, насколько это возможно.

Листинг 6-2. IstrcpyA- полный пример на языке ассемблера

; Прототип функции:

; LPTSTR Istrcpy ( LPTSTR IpStringl , LPCTSTR lpString2 )

IstrcpyA:

; Начать подготовку к установке SEH-кадра.

77F127E6: MOV EAX , ES:[00000000h]

; Установить регулярный кадр стека.

77F127EC: PUSH EBP

77F127ED: MOV EBP , ESP

; Продолжить установку SEH-кадра.

77F127EF: PUSH OFFh

77F127F1: PUSH 77F3CD48h

77F127F6: PUSH _except_handler3

77F127FB: PUSH EAX

77F127FC: MOV DWORD PTR FS:[00000000h] , ESP

; Сохранить 12 байтов для локальных переменных.

77F12803: SUB ESP , 00Ch

; Сохранить значения регистра, которые будут разрушены

; как часть этой функции

77F12806: PUSH EBX

77F12807: PUSH ESI

77F12808: PUSH EDI

Сохранить текущую вершину стека в локальной переменной.

Эта строка - также часть установки SEH. 

7F12809: MOV DWORD PTR [EBP-018h] , ESP

Инициализировать эту локальную переменную к 0. Эта строка указывает,

что функция входит в блок _try. 

77F1280C: MOV DWORD PTR [EBP-004h] , 00000000h

Первый шаг после установки должен получить длину строки

копирования. Строка копирования - второй параметр.

Переместить второй параметр (строку, которая будет скопирована) в EDI.

77F12813: MOV EDI , DWORD PTR [EBP+OOCh]

Istrcpy будет просматривать 4,294,967,295 байтов до NULL-терминатора.

EDX используется позже со значением -1, а здесь он инициализируется.

Помните, что REPNE SCAS использует регистр ЕСХ как счетчик цикла.


 77F12816: MOV EDX , FFFFFFFFh

 77F1281B: MOV ЕСХ , EDX

; Обнуление EAX, так что SCAS будет искать символ NULL. 

77F1281D: SUB EAX , EAX ; Поиск символа NULL.

77F1281F: REPNE SCAS BYTE PTR [EDI]

; Поскольку ЕСХ считает в обратном направлении, переключить все биты так, 

; чтобы длина строки оказалась в ЕСХ. Эта длина включает символ NULL.

 77F12821: NOT ЕСХ

;Поскольку REPNE SCAS инкрементирует также и EDI, вычесть длину строки

;из EDI так, чтобы EDI указывал обратно, на начало строки.

 77F12823: SUB EDI , ЕСХ

Держать длину строки в ЕАХ. 

77F12825: MOV ЕАХ , ЕСХ

;Переместить второй параметр в ESI, т.к. ESI является исходным

;операндом строчных инструкций.

77F12827: MOV ESI , EDI

;Переместить первый параметр (целевую строку) в EDI. 

77F12829: MOV EDI , DWORD PTR [EBP+008h]

;Длина строки была подсчитана в байтах. Делите длину строки на 4,

;чтобы получить число двойных слов (DWORDS). Если число символов

;нечетное, REPE MOVS не будет копировать их всех.

;Любые остающиеся байты

;копируются прямо после REPE MOVS. 

77F1282C: shr ЕСХ , 002h

;Копировать строку второго параметра в строку первого. 

77F1282F: REPE MOVS DWORD PTR [EDI] , DWORD PTR [ESI]

;Переместить сохраненную длину строки в ЕСХ. 

77F12831: MOV ЕСХ , ЕАХ

;Операция AND счетчика с числом 3, чтобы получить

;остающиеся байты для копирования 

77F12833: AND ЕСХ , 00Зh

;Копировать остающиеся байты из строки в строку.

 77F12836: REPE MOVS BYTE PTR [EDI] , BYTE PTR [ESI]

Istrcpy возвращает первый параметр, поэтому переместить

;возвращаемое значение в ЕАХ 

77F12838: MOV ЕАХ , DWORD PTR [EBP+008h]

;Установить локальную переменную в -1, указывая, что функция

;покидает этот блок try/except. 

77F1283B: MOV DWORD PTR [EBP-004h] , EDX

;Функция завершена; выйдите и переместитесь домой. 

77F1283E: JMP 77F12852h

;Если вы просмотрите эту функцию, то заметите, что фактически нет

;инструкции, которая переходит или ветвится по адресу 0x77F12840.


Этот

; адрес является частью фильтра исключений кадра SEH. Фильтр исключений -

;это часть кода, которая сообщает возврату из SEH, что нужно делать.

;Здесь фильтр исключений эквивалентен функции

;_except (EXCEPTION_EXECUTE_HANDLER). Код возврата должен выполнить

;обработчик, который расположен справа от инструкции RET. Подробные

;сведения о фильтрах исключений можно найти в MSDN

;или в книге Джеффри Рихтера

;"Программирование приложений для Microsoft Windows" (Jeffrey Richter,

;"Programming Applications for Microsoft Windows".-

;Microsoft Press, 1999)

77F12840: MOV EAX , 00000001h

77F12845: RET

; Следующие три инструкции — блок исключения для функции.

; Восстановить стек, сохраненный ранее.

77F12846: MOV ESP , DWORD PTR [EBP-018h]

; Установить локальную переменную в -1, указывая, что функция

; покидает этот блок try/except.

77F12849: MOV DWORD PTR [EBP-004h] , FFFFFFFFh

; Установить 0 в качестве неуспешного возвращаемого значения.

77F12850: XOR ЕАХ , ЕАХ

; Получить предыдущий SEH-кадр.

77F12852: MOV ECX , DWORD PTR [EBP-010h]

; Восстановить предварительно сохраненный в стеке EDI.

77F12855: POP EDI

; Отменить SHE-кадр.

"7F12856: MOV DWORD PTR FS: [00000000h] , ECX

; Восстановить предварительно сохраненный в стеке ESI.

77F1285D: POP ESI

; Восстановить EBI, предварительно сохраненный в стеке.

77F1285E: POP EBX

; Отменить установку нормального стекового кадра

77F1285F: MOV ESP , ЕВР

77F12861: POP EBP

; Возврат в вызывающую программу и очистка 8 байтов стека.

; Istrcpy is a __sdtcall function.

77F12862: RET 00008h



Содержание раздела