Логические операторы

Последнее обновление: 11.07.2023

Для манипуляции отдельными битами в регистре язык ассемблера ARM предоставляет ряд логических операторов:

AND{S} Xd, Xs, Operand2
EOR{S} Xd, Xs, Operand2
ORR{S} Xd, Xs, Operand2
BIC{S} Xd, Xs, Operand2

AND

Инструкция 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, которое в бинарной форме равно 11002. Затем инструкция AND поразрядно умножает его на число 6, которое в бинарной форме равно 01102.

1100
*
0110
=
0100

То есть в итоге в регистре W0 будет число 0100 или 4 в десятичной системе.

ORR

Оператор 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, которое в бинарной форме равно 11002. Затем инструкция ORR поразрядно складывает на число 6:

1100
+
0110
=
1110

То есть в итоге в регистре W0 будет число 11102 или 1410 в десятичной системе.

EOR

Оператор 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

Оператор 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, которое в бинарной форме равно 11002. Затем инструкция BIC поразрядно поразрядно применяет операцию AND NOT к значению регистра W0 и числу 6:

1100
AND NOT
0110
=
1000

То есть в итоге в регистре W0 будет число 10002 или 810 в десятичной системе.

ORN

Операция 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
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850