Манипуляции со строками
Intel CPU обладают большими возможностями для манипуляций со строками, т. е. поддерживают обработку больших участков памяти в отдельной инструкции. Все рассмотренные здесь строчные инструкции имеют несколько мнемоник, которые можно найти в справочных руководствах Intel. Однако окно Disassembly в Visual C++ всегда дизассемблирует строчные инструкции только в те формы, которые показаны ниже. Все эти инструкции могут работать на областях памяти размером в байт, слово и двойное слово.
- MOVS перемещают данные из строки в строку
Инструкция MOVS перемещает адрес памяти из регистра ESI в регистр EDI. Эта инструкция работает только на значениях, на которые указывают ESI и EDI. Инструкцию MOVS можно представить себе как реализацию С-функции memcpy. Окно Disassembly из Visual C++ всегда показывает размер операции со спецификатором размера, так сразу видно, сколько памяти было перемещено. После того как перемещение заканчивается, регистры ESI и EDI инкрементируются или декрементируются, в зависимости от флажка направления (DF) в регистре EFLAGS (отображаемого как поле UP в окне Registers Visual C++). Если поле UP равно 0, то регистры инкрементируются, а если равно 1, регистры декрементируются. Величина инкремента и декремента зависит от размера памяти, с которой работает операция: 1 — для байт, 2 — для слов и 4 — для двойных слов.
- SCAS сканировать строку
Инструкция SCAS сравнивает значение по адресу памяти, указанному в регистре EDI, со значением в регистрах AL, АХ или ЕАХ (в зависимости от требуемого размера). Результаты сравнения устанавливают значения различных флажков в регистре EFLAGS. Установки флажков — те же, что показаны в табл. 6.4. Если вы сканируете строку в поисках NULL-терминатора (пустого указателя), то инструкцию SCAS можно использовать, чтобы дублировать возможности С-функции strien. Подобно инструкции MOVS, SCAS выполняет автоинкремент или автодекремент регистра EDI.
- STOS сохранить строку
Инструкция STOS сохраняет значение регистров AL, АХ или ЕАХ (в зависимости от требуемого размера) по адресу, указанному регистром EDI.
Инструкция STOS похожа на С- функцию memset. Подобно инструкциям MOVS и SCAS, инструкция STOS автоинкрементирует или автодекрементирует регистр EDI.
- CMPS сравнить строки
- ВЕР повторять по счетчику в EСХ
- REPE повторять, пока равно или счетчик ЕСХ не станет равен 0
- REPNE повторять, пока не равно или счетчик ЕСХ не станет равен 0
При рассмотрении строчных инструкций я упоминал, на какую функцию из исполнительных библиотек языка С была похожа каждая из них. Следующий код показывает (без очевидной проверки ошибок), как выглядят ассемблерные эквиваленты этих функций:
void MemCPY ( char * szSrc , char * szDest , int iLen )
{
_asm
{
MOV ESI , szSrc // Установить исходную строку.
MOV EDI , szDest // Установить целевую строку ng.
MOV ЕСХ , iLen // Установить длину копирования.
// Копировать немедленно!
REP MOVS BYTE PTR [EDI] , BYTE PTR [ESI]
}
}
int StrLEN (char * szSrc )
{
int iReturn ; _asm
{
XOR EAX , EAX // Обнулить ЕАХ.
MOV EDI , szSrc // Поместить проверяемую строку в EDI.
MOV ECX , 0FFFFFFFFh // Максимальное число проверяемых
// символов.
REPNE SCAS BYTE PTR [EDI] // Сравнивать, пока ЕСХ не станет
// равным 0 или не будет найден конец
// строки .
СМР ЕСХ ,0 // Если ЕСХ равен 0, то
JE StrLEN_NoNull // в строке не был найден NULL.
NOT ECX // Преобразовать ЕСХ в положительное число,
// поскольку он был просчитан.
DEC ЕСХ ' // Подсчет для Попадания на NULL.
MOV EAX , ЕСХ // Возврат счета.
JMP StrLen_Done .// Возврат. StrLENJNoNull:
MOV EAX , OFFFFFFFFh // Поскольку NULL не был найден,
И возвратить -1.
StrLEN_Done:
}
_asm MOV iReturn , EAX ;
return ( iReturn ) ;
}
void MemSET ( char * szDest , irit iVal , int iLen )
{ _asm
{
MOV EAX , iVal // EAX содержит полное значение.
MOV EDI , szDest // Переместить строку в EDI.
MOV ECX , iLen // Переместить счет в ЕСХ.
REP STOS BYTE PTR [EDI] // Заполнить память.
}
}
int MemCMP ( char * szMeml , char * szMem2 , int iLen )
{
int iReturn ;
_asm
{
MOV ESI , szMeml // ESI содержит первый блок памяти.
MOV EDI , szMem2 // EDI содержит второй блок памяти.
MOV ECX , iLen // Максимальное число байт для сравнения
// Сравнить блоки памяти.
REPE CMPS BYTE PTR.
[ESI], BYTE PTR [EDI]
JL MemCMP_LessThan // Если szSrc < szDest
JG MemCMP_GreaterThan // Если szSrc > szDest
// Блоки памяти равны.
XOR EAX', EAX // Возвратить 0.
JMP MemCMP_Done
MemCMP_Les sThan:
MOV EAX , 0FFFFFFFFh // Возвратить -1.
JMP MemCMP_Done
MemCMP_GreaterThan:
MOV EAX , 1 // Возвратить 1.
JMP MemCMP_Done
XemCMP_Done:
}
_asm MOV iReturn ,
EAX return ( iReturn ) ;
}