MyTetra Share
Делитесь знаниями!
Зачем в ассемблере используют операции Xor ax, ax и Test ax, ax
Время создания: 22.07.2024 09:42
Текстовые метки: ассемблер, assembler, asm, XOR, TEST, оптимизация, ускорение, инструкция, архитектура, x86/x64
Раздел: Компьютер - Программирование - Ассемблеры - Устройство процессора и машинный код
Запись: xintrea/mytetra_syncro/master/base/1721630550ann7caonoz/text.html на raw.github.com

Использование XOR AX, AX


В низкоуровневом программировании часто ставится задача быстро установить значение какого-либо регистра в ноль. Для этой цели можно использовать инструкцию MOV со значением 0. Однако, из-за того, что значение 0, по сути, находится в памяти, то такая инструкция будет выполняться медленно: нужно перенести значение из памяти в регистр процессора. А это достаточно длительная процедура.


Поэтому для обнуления регистра используют трюк, основанный на математике инструкции XOR. Если сделать операцию XOR с любыми двумя одинаковыми значениями, то в результате получится 0. Действительно, в таблице истинности на тех строках, где написаны 1 и 1, а так же 0 и 0, в результате имеется 0.



Таблица истинности XOR



a

b

a ⊕ b

0

0

0

0

1

1

1

0

1

1

1

0



Так как для выполнения данной инструкции используется только значение регистра, и никакого переноса значения из памяти в процессор нет, то такая инструкция выполнится максимально быстро. На разных процесорных архитектурах инструкция XOR выполняется обычно не более 3 тактов.


Кстати, в качеств аргументов инструкции XOR не обязательно должен быть регистр AX. Данный прием активно используется для обнуления и других регистров.


Многие компиляторы C/C++, если видят команду присвоения нуля, будут транслировать ее именно через инструкцию XOR (если значение лежит на регистре).



Использование инструкции TEST AX, AX


Инструкция test ax, ax (или test eax, eax) в языке ассемблера выполняет битовый логический оператор AND между регистром и самим собой.


Инструкция test не изменяет значение в регистре, но влияет на флаги процессора, в частности, на флаг нуля (ZF) и флаг четности (PF). Флаг нуля устанавливается, если результат операции AND равен нулю. Это означает, что если ax содержит нуль, то ZF будет установлен (1), а если ax не равен нулю, то ZF будет сброшен (0).



Другими словами, инструкция test ax, ax обычно используется для того, чтобы узнать, содержится ли нуливое значение в регистре.



После этой инструкции, как правило, идет какая-нибудь инструкция условного перехода, типа je (jump if equal) или jne (jump if not equal). Команда je делает переход, если ZF=1. Команда jne - если ZF=0.



Почему команды условного перехода так странно называются? "Если равно" или "Если не равно"? Равенство чего и с чем имеется в виду? Дело в том, что исторически сложилось так, что в древних вычислительных устройствах небыло отдельной специальной инструкции для побитового сравнения значений. Сравнение программисты производили просто через сумматор. Если в сумматор поместить два значения, первое - в явном виде, второе - в "инверсном" (отрицательном) виде, то произойдет вычетание (SUB) одного значения из другого. Если в результате получится ноль, то это значит, что значения равны.


А так как операция SUB меняет значение регистра ax (кстати, в древних процессорах это был просто регистр A), то была придумана инструкция сравнения CMP. По сути, инструкция CMP точно так же вычетает значение одного регистра из другого или значение непосредственного операнда из регистра. Но результат вычетания никуда не записывается, а только меняются флаги процессора.


Так и получилось, что после CMP делается условный переход: если результат нуливой (ZF=1), то проверяемые значения были равны. Ориентирование на результат команды CMP и дало название инструкциям je и jne.



Инструкция TEST очень похожа на инструкцию CMP, только внутри себя она выполняет не SUB, а побитовое AND (не путать с ADD), вот и все различие.


Так же в этом разделе:
 
MyTetra Share v.0.64
Яндекс индекс цитирования