Принципиальная разница между test и cmp

версия для печати

В результате выполнения инструкций ассемблера cmp и test меняется состояние флага нуля (ZF). Это все, что у них общего! Опасно считать эти инструкции похожими и тем более заявлять, что они обе выполняют сравнение. Под катом - основание столь дерзкого заявления :)

Почему вообще появилась эта статья. Постигаю азы ассемблера, читаю всякие источники. Когда первый раз узнал про команду cmp - это был разрыв шаблона! Утверждение, что при равенстве сравниваемых значений команда поднимает флаг нуля (ZF=1) для меня звучало, как парадокс. Позже разобрался, почему так. Потом читаю про якобы аналогичную команду test, и сказано в писании: в случае равенства сравниваемых значений сбрасывается флаг нуля! ЧОйРт побери, WTF?! Разобрался таки..

Важный момент: логика флага нуля (ZF). Он поднимается (равен единице), когда результат операции равен нулю, т.е. все биты результата - нулевые.

Инструкция cmp (сокр. от compare - сравнить) сравнивает два значения - регистр, память, непосредственное значение, - и устанавливает/сбрасывает флаг ZF. При этом процессор, получив инструкцию cmp, вычисляет разность указанных значений. Теперь должно быть понятно: если значения равны, то результат вычитания будет 0, следовательно поднимается флаг нуля (ZF=1). Пример:

xor ax,ax    ;обнуляем регистр
mov ax,13d
add ax,7
cmp ax,20d   ;значения равны => их разность=0 => флаг ZF=1
jz someLabel ;переход будет выполнен

Примечание: инструкция cmp отличается от аналогичной sub (substraction - вычитание) тем, что влияет только на регистр флагов.

Инструкция test. Получив такую команду, процессор выполняет операцию AND (логическое И) с двумя операндами. Т.е. выполняется побитовое логическое умножение. Если логическое И выдаст только нули, тогда поднимается флаг ZF. Инструкция test так же влияет только на регистр флагов, в этом ее отличие от инструкции AND. Пример:

xor ax,ax
mov ax,0011b
test ax,0010b ;результат будет не нулевой (второй бит будет равен 1) => ZF=0
jnz someLabel ;флаг нуля сброшен, будет переход 

Выводы: во-первых, cmp и test влияют на флаг нуля противоположным образом. Во-вторых, команду test нельзя использовать для проверки равенства значений! Пример:

mov eax,5

test eax,5    ;установит флаг ZF=0
jnz someLabel ;переход выполнится
...
test eax,4    ;так же установит флаг ZF=0
jnz someLabel ;переход опять выполнится

Сравниваем одинаковые/разные числа, а переход выполняется в любом случае! Если вместо test поставить cmp, то первый переход не выполнится. Почему такие странности с test? Смотрим запись чисел в двоичной СИ:
5(10)=0101(2)
4(10)=0100(2)

Результат инструкции test:
test 5,5: 0101 AND 0101=0101
test 5,4: 0101 AND 0100=0100

В результатах обоих операций есть биты равные единице, поэтому флаг нуля не понимается. Вот поэтому нельзя полагаться на такое сравнение значений.

Итак, команда test применяется для битовой проверки состояния флагов и т.п. Есть еще одно применение - проверка нулевого значения регистра:

test eax,eax
jz someLabel ;переход выполнится только если eax=0

Объяснил, как смог :) Сам долго не мог постичь логику, особенно считая, что test и cmp - похожие по назначению команды. Надеюсь, разница понятно изложена.

[1oo%, EoF]

Понравилась статья? Расскажите о ней друзьям:

Метки: asm, ликбез

Комментарии
Для работы модуля комментариев включите javaScript


Показать/скрыть правила
Имя
[i] [b] [u] [s] [url]
:-) ;-) :D *lol* 8-) :-* :-| :-( *cry* :o :-? *unsure* *oops* :-x *shocked* *zzz* :P *evil*

Осталось 1000 символов.
Код защиты от спама Обновить код
Каждый комментарий проходит ручную модерацию. 100% фильтрация спама.
Продвижение
Время
Метки