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

       

Инструкции переходов и ветвлений


  •  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 и потом перейти обратно.

  •       переход, если выше
  •  JBE   переход, если ниже или равно
  •  JC     переход, если есть перенос
  •  JNC   переход, если нет переноса
  •  JNZ   переход, если не О
  •  JZ     переход, если О
Эти инструкции условных переходов не столь обычны как те, что были перечислены выше, но их можно увидеть в окне Disassembly. Необходимо разбираться в их условиях интуитивно, по имени перехода.



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