Полный пример
Представив все важные части языка 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