Инструкции переходов и ветвлений
- JMP абсолютный переход
Как указано в названии, JMP передает управление по абсолютному адресу.
- JE переход, если равно
- JL переход, если меньше чем
- JG переход, если больше чем
- JNE переход, если не равно
- JGE переход, если больше или равно
- OLE переход, если меньше или равно
От инструкций СМР и TEST немного пользы, если программист не имеет возможности воздействовать на их результаты. Условные переходы позволяют выполнять соответствующие ветвления программы. Показанные выше инструкции — это наиболее общие условные переходы, с которыми вы встретитесь в окне Disassembly, хотя всего существует более трех десятков (точнее — 31) различных условных переходов, многие из которых выполняют те же самые действия за исключением того, что в мнемонике используется слово "NOT". Например, инструкция JLE (переход, если меньше или равно) имеет тот же код операции, что JNG (переход, если не больше чем). Работая с другим дизассемблером (не из отладчика Visual C++), можно увидеть иные инструкции. Чтобы расшифровывать все инструкции переходов, можно найти jcc-коды в руководствах Intel.
В следующем примере инструкции условных переходов расположены в том же порядке, как в табл. 6.4. Один из условных переходов немедленно следует за инструкциями СМР и TEST. Оптимизированный код может содержать несколько инструкций, разбросанных между проверкой и переходом, но эти инструкции никогда не изменяют флажков.
Просматривая код дизассемблера, можно заметить, что условная проверка вообще-то противоположна той, что была введена в исходный код. Пример показан в первой секции следующего кода.
void JumpExamples ( int i )
{
// Здесь показан оператор С-кода. Заметьте, что условие записано как
// "i > 0", но компилятор генерирует противоположное условие.
Код
// ассемблера, который показан в следующей секции, похож на тот,
// что генерирует компилятор.
// Разные методы оптимизации генерируют различный код.
// if ( i > 0 )
// {
// printf ( "i > 0\n" ) ;
// }
char szGreaterThan[] = "i > 0\n" ;
_asm
{
CMP i , 0 // Сравнить i с 0 вычитанием (i - 0).
JLE JE_LessThanOne // Если i меньше чем или равно 0, перейти
// к метке.
PUSH i // Поместить параметр в стек.
LEA ЕАХ , szGreaterThan // Поместить в стек форматную строку.
PUSH ЕАХ CALL DWORD PTR [printf] // Вызвать printf. Заметьте, что printf,
// вероятно, приходит из DLL, потому что
// вызов выполняется через указатель.
ADD ESP ,8 // для printf действует соглашение _cdecl,
поэтому
// нужно очистить стек в вызывающей
// программе.
JE_LessThanOne: //Во встроенном ассемблере можно
// перейти к любой С-метке.
}
////////////////////////////////////////////////////////////////////
// Взять абсолютное значение параметра и снова проверить.
// С-код:
// int у = abs ( i ) ;
// if. ( у >=5 )
// {
// printf ( "abs(i) >= 5\n" ) ;
// }
// else
// {
// printf ( "abs(i) < 5\n" ) ;
// }
char szAbsGTEFive [] = "abs(i) >= 5\n" ;
char szAbsLTFive[] = "abs(i) < 5\n" ;
_asm
{
MOV EBX , i // Переместить значение i в ЕВХ.
СМР ЕВХ , 0 // Сравнить ЕВХ с 0 (ЕВХ - 0).
JG JE_PosNum // Если результат больше 0, то ЕВХ
// содержит положительное значение.
NEG ЕВХ // Преобразовать отрицательное в положительное.
JE_PosNum:
СМР ЕВХ , 5 // Сравнить ЕВХ с 5 (ЕВХ - 5).
JL JE_LessThan5 // Переход, если меньше 5.
LEA ЕАХ , szAbsGTEFive // Получить в ЕАХ указатель на правильную
// форматную строку.
JMP JE_DoPrintf // Перейти к вызову printf.
JE_LessThan5:
LEA ЕАХ , szAbsLTFive // Получить в ЕАХ указатель на правильную
// форматную строку.
JE_DoPrintf:
PUSH ЕАХ // Поместить строку в стек.
CALL DWORD PTR [printf] // Напечатать ее.
ADD ESP , 4 .. // Восстановить стек.
}
}
Нетрудно видеть, что результат в первом примере правилен. Идея состоит в" том, что выгоднее проверить противоположное условие и затем выполнить переход, чем сначала выполнить переход, проверить условие внутри оператора if и потом перейти обратно.
- JА переход, если выше
- JBE переход, если ниже или равно
- JC переход, если есть перенос
- JNC переход, если нет переноса
- JNZ переход, если не О
- JZ переход, если О