Для манипуляции отдельными битами в регистре язык ассемблера ARM предоставляет ряд логических операторов:
AND{S} Xd, Xs, Operand2 EOR{S} Xd, Xs, Operand2 ORR{S} Xd, Xs, Operand2 BIC{S} Xd, Xs, Operand2
Инструкция AND выполняет поразрядное логическое умножение. Операция логического умножения возвращает 1, если соответствующие разряды обоих операндов равны 1. Инструкция AND имеет следующую форму:
AND{S} Xd, Xs, Operand2
AND выполняет поразрядное логическое умножение между разрядами из регистра Xs и значения Operand2 и помещает результат в регистр Xd. Например,
// METANIT.COM. Логическое умножение. .global _start _start: MOV W0, #12 // помещаем в регистр W0 число 12 - 1100 AND W0, W0, #6 // помещаем в регистр W0 = W0 AND 6 = 1100 AND 0110 = 0100 = 4 MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // вызываем функцию и выходим из программы
Здесь в 32-битный регистр W0 помещается число 12, которое в бинарной форме равно 1100
2. Затем инструкция AND
поразрядно умножает его на число 6, которое в бинарной форме равно 0110
2.
1100 * 0110 = 0100
То есть в итоге в регистре W0 будет число 0100 или 4 в десятичной системе.
Оператор ORR выполняет поразрядное логическое сложение. Операция логического слоожения возвращает 1, если хотя бы один из соответствующих разрядов обоих операндов равен 1. Инструкция ORR имеет следующую форму:
ORR{S} Xd, Xs, Operand2
ORR выполняет поразрядное логическое сложение между разрядами из регистра Xs и значения Operand2 и помещает результат в регистр Xd. Например,
.global _start _start: MOV W0, #12 // помещаем в регистр W0 число 12 - 1100 ORR W0, W0, #6 // помещаем в регистр W0 = W0 OR 6 = 1100 OR 0110 = 1110 = 14 MOV X8, #93 SVC 0
Здесь в 32-битный регистр W0 помещается число 12, которое в бинарной форме равно 1100
2. Затем инструкция ORR
поразрядно складывает на число 6:
1100 + 0110 = 1110
То есть в итоге в регистре W0 будет число 11102 или 1410 в десятичной системе.
Оператор EOR выполняет поразрядную операцию исключающего ИЛИ (операция XOR), при которой возвращается 1, если соответствующие разряды обоих операндов не равны друг другу. если соответствующие разряды обоих операндов равны, то возвращается 0. Инструкция EOR имеет следующую форму:
EOR{S} Xd, Xs, Operand2
EOR выполняет поразрядную операцию исключающего ИЛИ между разрядами из регистра Xs и значения Operand2 и помещает результат в регистр Xd. Например,
.global _start _start: MOV W0, #12 // помещаем в регистр W0 число 12 - 1100 EOR W0, W0, #6 // помещаем в регистр W0 = W0 XOR 6 = 1100 XOR 0110 = 1010 = 10 MOV X8, #93 SVC 0
В результате в регистре W0 будет число 10102 или 1010 в десятичной системе.
1100 ^ 0110 = 1010
Оператор BIC (bit clear) выполняет операцию, которую еще называют AND NOT
. Он имеет следующую форму:
BIC{S} Xd, Xs, Operand2
Суть операции: если разряд в Operand2 равен 1, тогда результат равен 0. Если разряд в Operand2 равен 0, тогда результатом будет соответствующий разряд из регистра Xs. Например,
.global _start _start: MOV W0, #12 // помещаем в регистр W0 число 12 - 1100 BIC W0, W0, #6 // помещаем в регистр W0 = W0 AND NOT 6 = 1100 AND NOT 0110 = 1000 = 8 MOV X8, #93 SVC 0
Здесь в 32-битный регистр W0 помещается число 12, которое в бинарной форме равно 1100
2. Затем инструкция BIC
поразрядно поразрядно применяет операцию AND NOT
к значению регистра W0 и числу 6:
1100 AND NOT 0110 = 1000
То есть в итоге в регистре W0 будет число 10002 или 810 в десятичной системе.
Операция ORN выполняет операцию, которую еще называют OR NOT
. Он имеет следующую форму:
ORN Xd, Xs, Operand2
Эта инструкция сначала инвертирует биты в Operand2 (то есть если бит равен 1, то он получает значение 0 и наоборот). Затем выполняем между вторым и третим операндами операцию поразрядного ИЛИ и сохраняет результат в первый операнд. Например,
// METANIT.COM. Логическое умножение. .global _start _start: MOV W0, #0b1100 // помещаем в регистр W0 число 12 - 1100 MOV W1, #0b0110 // помещаем в регистр W1 число 6 - 0110 ORN W0, W0, W1 // W0 = W0 ORN W1 = 1100 OR NOT 0110 = 1100 OR 1001 = 1101 = 1101 = -3 MOV X8, #93 // номер функции Linux для выхода из программы - 93 SVC 0 // вызываем функцию и выходим из программы
Инструкция ORN
поразрядно инвертирует значение регистра W1, а затем к инвертированному значению и регистру W0 применяет операцию OR:
1100 OR NOT 0110 = 1100 OR 1001 = 1101
То есть в итоге в регистре W0 будет число 11012. Причем все старшие биты у него будут равны 1, так как значение W1 - 32-битное число 6 было инвертировано.
То есть полностью число будет 0b11111111_11111111_ 11111111_11111101
. В зависимости от того, как это число интерпретируется - как число со знаком или без знаком, оно может иметь разные значения. Например, если рассматривать его как число со знаком, то
оно будет равно или -310 в десятичной системе.
Компиляторы часто используют эту инструкцию при выполнении побитового ИЛИ с непосредственным значением, которое не может быть эффективно закодировано в инструкцию ORR напрямую, но вместо этого может быть закодировано в инструкцию ORN.
В ассемблере ARM64 нет инструкции, которая инвертирует разряды числа, однако для этой цели можно использовать выше рассмотренную инструкцию ORN:
MOV X0, #0b1100 // помещаем в регистр X0 число 12 - 1100 ORN X0, XZR, X0 // инвертируем число в X0
Фактически здесь к инвертированному значению из X0 и нулевому регистру XZR применяется операция ИЛИ. Фактически же это равноценно обычной инверсии X0. В итоге в
X0 будет число -1310 или 0b11110011
Поскольку инверсия представляет довольно частую задачу, то выше рассмотренная инструкция имеет псевдоним MVN:
MVN Xd, Xs MVN Wd, Ws
Например:
MOV X1, #0b1100 // помещаем в регистр X1 число 12 - 1100 MVN X0, X1 // инвертируем число в X1 и помещаем его в X0