Xor ассемблер как работает
Для манипуляции отдельными битами числа ассемблер NASM предоставляет ряд логических операторов-инструкций:
and source, dest or source, dest xor source, dest neg dest not dest
Первые три инструкции имеют два операнда.
Инструкции and , or и xor также влияют на регистр флагов. Они всегда сбрасывают флаг переноса CF и переполнения OF. Флаг нуля ZF устанавливается, если результат равен нулю. Флаг знака SF всегда получает значение старшего бита результата.
AND
Инструкция AND выполняет поразрядное логическое умножение. Операция логического умножения возвращает 1, если соответствующие разряды обоих операндов равны 1. Пример программы на Linux
global _start section .text _start: mov rdi, 12 ; помещаем в регистр RDI число 12 - 1100 and rdi, 6 ; rdi = rdi AND 6 = 1100 AND 0110 = 0100 = 4 mov rax, 60 syscall
Здесь в 64-битный регистр RDI помещается число 12, которое в бинарной форме равно 1100 2. Затем инструкция AND поразрядно умножает его на число 6, которое в бинарной форме равно 0110 2.
1100 * 0110 = 0100
То есть в итоге в регистре RDI будет число 0100 или 4 в десятичной системе.
Аналогичный пример на Windows:
global _start section .text _start: mov rax, 12 ; помещаем в регистр rax число 12 - 1100 and rax, 6 ; rax = rax AND 6 = 1100 AND 0110 = 0100 = 4 ret
В ассемблере также есть инструкция test — она также умножает поразрядно биты обоих операндов, однако первый операнд не изменяется. Ее цель установить состояние флагов, в частности, флаг нуля:
global _start section .text _start: mov rbx, 12 test rbx, 12 ; проверяем регистр rbx, что он равен 0 je zero mov rdi, 2 ; если rbx НЕ равен 0 jmp exit zero: mov rdi, 8 ; если rbx равен 0 exit: mov rax, 60 syscall
Здесь мы проверяем значение регистра RBX — если оно равно 0, то будет установлен флаг нуля. При этом значение регистра RBX не меняется.
OR
Инструкция OR выполняет поразрядное логическое сложение. Операция логического сложения возвращает 1, если хотя бы один из соответствующих разрядов обоих операндов равен 1. Например,
global _start section .text _start: mov rdi, 12 ; помещаем в регистр rdi число 12 - 1100 or rdi, 6 ; rdi = rdi OR 6 = 1100 OR 0110 = 1110 = 14 mov rax, 60 syscall
Здесь в 64-битный регистр RDI помещается число 12, которое в бинарной форме равно 1100 2. Затем инструкция OR поразрядно складывает на число 6:
1100 + 0110 = 1110
То есть в итоге в регистре W0 будет число 11102 или 1410 в десятичной системе.
XOR
Инструкция XOR выполняет поразрядную операцию исключающего ИЛИ, при которой возвращается 1, если соответствующие разряды обоих операндов не равны друг другу. если соответствующие разряды обоих операндов равны, то возвращается 0. Например,
global _start section .text _start: mov rdi, 12 ; помещаем в регистр rdi число 12 - 1100 xor rdi, 6 ; rdi = rdi XOR 6 = 1100 XOR 0110 = 1010 = 10 mov rax, 60 syscall
В результате в регистре RDI будет число 10102 или 1010 в десятичной системе.
1100 ^ 0110 = 1010
Стоит отметить, что операция xor нередко применяется для обнуления содержимого регистра, например
xor rdi, rdi ; RDI = 0
NOT
Инструкция NOT выполняет поразрядное отрицание и принимает один параметр:
not dest
Суть операции: если разряд операнда dest равен 1, то он меняется на 0. И наоборот — если разряд в dest равен 0, то он меняется на 1. Например,
global _start section .text _start: mov rdi, 12 ; помещаем в регистр rdi число 12 - 00000000 00000000 00000000 00001100 not rdi ; rdi =NOT(rdi)=NOT(12)= 11111111 11111111 11111111 11110011 mov rax, 60 syscall
Здесь в регистр RDI помещается число 12, которое в бинарной форме равно 1100 2. Однако поскольку регистр у нас 64-битный, то все передние разряды будут представлять нули:
00000000 00000000 00000000 00001100
Поразрядное отрицание или инверсия изменяет значения битов на противоположное (изменяются все 64 бита в регистре). В итоге мы получим число
11111111 11111111 11111111 11110011
Что это за число, зависит от контекста. Так в дополнительном коде старший бит рассматривается как знаковый бит — если он равен 1, то число отрицательное. Соответственно инвертированное выше число будет интерпретироваться как -13. Если число рассматривается как число без знака, которое всегда положительное, то результат: 18446744073709551603
NEG
Кроме обычной инверсии в ассемблере есть арифметическое отрицацие, которое выполняет инструкция NEG . Она также принимает один операнд:
neg dest
фактически значение операнда будет умножаться на -1. Таким образом, мы сможем получить из положительного числа отрицательное, а из отрицательного — положительное. Например:
global _start section .text _start: mov rdi, -12 neg rdi ; rdi = -1 * rdi = -1 * -12 = 12 mov rax, 60 syscall
Команды AND, OR, XOR, NOT
Команды AND, OR, XOR, NOT — это набор команд для выполнения побитовых логических операций над числами. Команда AND (логическое «И», логическое умножение или конъюнкция) выполняется следующим образом: если бит первого числа установлен в 1 и бит второго числа установлен в 1, то и бит результата тоже будет установлен в 1, иначе бит результата будет сброшен в 0.
Команда OR (логическое «ИЛИ», логическое сложение или дизъюнкция) устанавливает бит результата в 1, если бит первого или второго числа установлен в 1.
Команда XOR (исключающее «ИЛИ», строгая дизъюнкция) работает как и команда OR, но если биты обоих чисел установлены в 1, то в результате будет бит сброшенный в 0.
Команда NOT (инверсия) просто устанавливает биты результата на на противоположные от битов числа, то есть если в числе был бит установленный в 1, то в результате будет сброшенный в 0 и наоборот.
Команда AND
mov ax,0001h and ax,1000h ;AX=0000h
Команда OR
mov ax,0001h or ax,1000h ;AX=1001h
Команда XOR
mov ax,0001h xor ax,1000h ;AX=1001h xor ax,1000h ;AX=0001h
Команда NOT
mov al,00010110b not al ;AL=11101001b
Команда XOR
Команда XOR в Ассемблере выполняет операцию исключающего ИЛИ между всеми битами двух операндов. Результат операции XOR записывается в первый операнд. Синтаксис:
XOR ПРИЁМНИК, ИСТОЧНИК
Инструкция XOR всегда сбрасывает флаги CF и OF, а также (в зависимости от результата) изменяет флаги SF, ZF и PF. Значение флага AF может быть любым — оно не зависит от результата операции.
ПРИЁМНИК может быть одним из следующих:
- Область памяти (MEM)
- Регистр общего назначения (REG)
ИСТОЧНИК может быть одним из следующих:
- Область памяти (MEM)
- Регистр общего назначения (REG)
- Непосредственное значение — константа (IMM)
С учётом ограничений, которые были описаны выше, комбинации ПРИЁМНИК-ИСТОЧНИК могут быть следующими:
REG, MEM MEM, REG REG, REG MEM, IMM REG, IMM
Операция исключающего ИЛИ
При выполнении операции исключающего ИЛИ значение результата будет равно 1, если сравниваемые биты отличаются (не равны). Если же сравниваемые биты имеют одинаковое значение, то результат будет равен 0.
Потому эта операция и называется исключающей. Она исключает из сравнения одинаковые биты, а с неодинаковыми выполняет операцию логического ИЛИ.
Но, так как любая пара неодинаковых битов это 0 и 1, то операция логического ИЛИ в результате даст 1.
Таблица истинности исключающего ИЛИ
Таблица истинности XOR приведена ниже:
0 XOR 0 = 0 0 XOR 1 = 1 1 XOR 0 = 1 1 XOR 1 = 0
Особенности операции XOR
Операция XOR обладает свойством реверсивности. Если её выполнить дважды с одним и тем же операндом, то значение результата инвертируется. То есть если два раза выполнить эту операцию между битами X и Y, то в конечном результате мы получим исходное значение бита Х.
0 XOR 0 = 0 XOR 0 = 0 0 XOR 1 = 1 XOR 1 = 0 1 XOR 0 = 1 XOR 0 = 1 1 XOR 1 = 0 XOR 1 = 1
Это свойство можно использовать, например, для простейшего шифрования данных (об этом как-нибудь в другой раз).
Проверка флага чётности после операции XOR
Команда XOR работает с 8-, 16- и 32-разрядными операциями.
Иногда есть необходимость после выполнения операции проверить флаг чётности PF, для того, чтобы узнать, какое количество единичных битов (чётное или нечётное) содержится в младшем байте результата (это бывает необходимо не только в случае выполнения операции XOR, но и при выполнении других арифметических и логических операций).
Если флаг чётности установлен, то в результате получилось чётное количество единичных битов. Иначе флаг будет сброшен.
Можно также просто проверить на чётность любое число, не меняя значения результата. Для этого надо выполнить команду XOR с нулевым значением. То есть в ПРИЁМНИКЕ должно быть проверяемое число, а в ИСТОЧНИКЕ должен быть ноль. А затем надо проверить флаг чётности. Пример:
MOV AL, 10110101b ;Поместить в AL число с нечётным ;количеством единичных битов (5) XOR AL, 0 ;При этом флаг чётности PF не ;устанавливается (PO) MOV AL, 10110111b ;Поместить в AL число с чётным ;количеством единичных битов (6) XOR AL, 0 ;При этом флаг чётности PF ;будет установлен (PE)
В отладчиках обычно для обозначения чётного количества единиц в полученном результате используется сокращение PE (Parity Even), а для нечётного — PO (Parity Odd).
Чётность в 16-разрядных словах
Как уже было сказано, флаг чётности устанавливается в зависимости от количества единиц, содержащихся в младшем байте результата. Чтобы проверить чётность 16-разрядного операнда, надо выполнить команду XOR между старшим и младшим байтом этого числа:
MOV AX, 64C1h ;0110 0100 1100 0001 - 6 единичных битов XOR AH, AL ;Флаг чётности будет установлен
Таким нехитрым способом 16-разрядный операнд разбивается на два байта (2 группы по 8 битов), и при выполнении команды XOR единичные биты, находящиеся в соответствующих разрядах двух 8-разрядных операндов, не будут учитываться. Потому что соответствующий бит результата равен нулю.
Команда XOR удаляет из результата любые пересекающиеся единичные биты двух 8-разрядных операндов и добавляет в результат непересекающиеся единичные биты. То есть чётность полученного нами 8-разрядного числа будет такой же, как и чётность исходного 16-разрядного числа.
0110 0100 1100 0001 - исходное 16-разрядное число 0 XOR 1 = 1 1 XOR 1 = 0 1 XOR 0 = 1 0 XOR 0 = 0 0 XOR 0 = 0 1 XOR 0 = 1 0 XOR 0 = 0 0 XOR 1 = 1
В результате 4 единицы, то есть флаг PF будет установлен
Чётность в 32-разрядных двойных словах
Ну а если надо определить чётность в 32-разрядном числе?
Тогда число разбивается на четыре байта, и поочерёдно с этими байтами выполняется операция исключающего ИЛИ.
Например, мы разбили 32-разрядное число B на четыре байта B0, B1, B2, B3, где В0 — это младший байт.
Тогда для определения чётности числа В нам надо будет использовать следующую формулу:
B0 XOR B1 XOR B2 XOR B3
Но в ассемблере такая запись недопустима. Поэтому придётся немного подумать.
Ну и напоследок о происхождении мнемоники XOR. В английском языке есть слово eXception — исключение. Сокращением от этого слова является буква Х (так повелось). Вы наверняка встречали такое в рекламе или в названии продуктов, производители которых претендуют (ну или думают, что претендуют) на исключительность. Например, Лада XRAY, Sony XPeria и т.п. Так что XOR — это аббревиатура, собранная из двух слов — eXception OR — исключающее ИЛИ.
Assembler: Logic
Всем доброго времени суток! Naize в студии, а это значит, что вас сегодня ждёт статья про Ассемблер. Ура, наш самый любимый язык, наконец-то мы продолжаем его учить! Цель сегодняшней статьи — объяснить, что такое логические операторы, и описать, какие они бывают конкретно в АСМЕ. Итак, за дело! Для начала познакомимся со списком этих самых операций, а потом поговорим про каждую подробнее))
What is Logic at Assembler?
Вот список логических побитовых команд:
- AND — Побитовое логическое умножение. Используют для выделения части битов.1100 AND 1010 = 1000
- OR — Побитовое логическое сложение. Используют вместо команд сравнения
- XOR — Побитовое сложение по модулю два. Используют для обнуления.
- TEST — Выполняется логическое умножение, но приемник не меняется. Меняются только флаги.
- NOT — Инвертирует каждый бит
Побитовые они оттого, что сравнивают каждый байт двоичного числа по-отдельности. За исключением NOT, эта команда нечего не с чем не сравнивает.
Хорошо, в общем виде вы теперь знаете, что к чему. Пора поговорить про все логические операции подробнее, и попутно дать несколько примеров для полного понимания темы.
Логическое И (AND)
В Assembler этот оператор сравнивает два регистра по одному биту. Он обозначается как AND, и вот пример работы:
Во всех примерах, что я сегодня буду показывать, постараюсь “отстраниться” от самого синтаксиса асма, и сфокусироваться на самой работе команд. Поэтому так как показывается в примерах, непосредственно в языке сделать не получиться.
01101001 AND 01000111
Очевидно, что результатом этой операции будет 01000001, давайте я напишу в более удобном виде:
Возникает один вопрос: куда же будет помещён результат выполнения оператора? Так вот, результат записывается в регистр, который стоит первым после and. Например:
Результат будет помещён в регистр eax.
Логическая инструкция TEST
Во многих случаях нам бы не хотелось, чтобы число переписывалось и теряло своего первоначального значения. Именно для этого существует логическая инструкция TEST.
Она как и AND производит побитовое умножение, но не записывает результат в какой либо регистр, а всего лишь поднимает флаги для каждого бита, то есть она, как бы так сказать, имитирует выполнение and.
Логическое ИЛИ (OR)
В Assembler логическое побитовое ИЛИ обозначается как OR, и синтаксис идентичен синтаксису команды and, по своей сути представляет побитовое сложение. Давайте посмотрим на простой пример:
01101001 OR 01000111
Результатом этой операции будет 01101111, и, как и в случае с AND, OR поместит это двоичное число в регистр, который стоит первым после самой команды. Вот более удобная запись, кстати:
Логическое исключающее ИЛИ (XOR)
Также помимо логического ИЛИ, существует исключающее ИЛИ. Оно обозначается командой XOR и выделяет различия в регистрах, то есть, если в одном бите содержится 1, а в другом 0, то XOR вернет 1, если же в битах содержатся одинаковые значения, то XOR вернет 0.
Конструкция из 3 xor позволяет поменять местами значения в регистрах.
Вот так вот это выглядит. И, что очень важно, работает быстрее, нежели специальная команда, для обмена значениями.
Также отметим конструкцию XOR eax, eax — она позволяет обнулить регистр (естественно, вместо eax может быть любой другой регистр). По сути это аналог команды MOV eax, 0, но многие из тех, то работает с асмом, любят использовать именно эту конструкцию… Потому что она быстрее и тратит меньше памяти.
Давайте посмотрим на простой пример:
00101110 XOR 10011100
В данном примере, после выполнения XOR получится 10110010, думаю суть всего этого вы уже уловили))
Результат этой команды, как и в случае с предыдущими, помещается в тот регистр, который идёт первым.
Логическое НЕ (NOT)
Данная мнемоника инвертирует все биты числа, она единственная из сегодняшнего списка, не сравнивает что то с чем то. И в качестве “аргументов” она принимает только один регистр, в который и помещается в итоге результат ей выполнения:
Так, давайте ка глянем пример:
NOT 01010011
Понятно, что результатом данной операции будет 10101100. В след за предыдущими, пример в более читаемом виде:
AfterWords
Вот и всё на сегодня. Теперь вы немного лучше разбираетесь в ассемблере, и знаете, какие логические операции в нем используются. В следующем посте мы поговорим про IMUL, IDIV и NEG. Пока не буду рассказывать, что это, если захотите — сами найдёте))
До скорых встреч!)
P.S. Не забывайте, что множество интересных статей можно найти на нашем Telegram канале и в Telegram боте, также все статьи мы публикуем в Twitter и Facebook