Логические операции

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

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

and dest, source
or dest, source
xor dest, source
neg dest
not dest

Первые три инструкции имеют два операнда. Первый операнд - dest может представлять регистр или переменную. Второй операнд - source может представлять регистр, переменную или константу. Кроме того, операнды должны быть одинакового размера и не могут одновременно быть переменными. Если первый операнд назначения имеет длину 64 бита, а второй операнд является константой, то эта константа должна быть не больше 32 битов (при операции значение автоматически расширяется до 64 бит).

Инструкции and, or и xor также влияют на регистр флагов. Они всегда сбрасывают флаг переноса CF и переполнения OF. Флаг нуля ZF устанавливается, если результат равен нулю. Флаг знака SF всегда получает значение старшего бита результата.

AND

Инструкция AND выполняет поразрядное логическое умножение. Операция логического умножения возвращает 1, если соответствующие разряды обоих операндов равны 1. Например,

.code
main proc
    mov rax, 12         ; помещаем в регистр rax  число 12 - 1100
    and rax, 6          ; помещаем в регистр rax = rax AND 6 = 1100 AND 0110 = 0100 = 4
    ret
main endp
end

Здесь в 64-битный регистр RAX помещается число 12, которое в бинарной форме равно 11002. Затем инструкция AND поразрядно умножает его на число 6, которое в бинарной форме равно 01102.

1100
*
0110
=
0100

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

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

.code
main proc
    mov rbx, 12 
    test rbx, 6     ; проверяем значение регистра rax
    je zero
    mov rax, 1
    jmp exit
zero:
    mov rax, 0
exit:
    ret
main endp
end

Здесь мы проверяем значение регистра RBX - если оно равно 0, то будет установлен флаг нуля. При этом значение регистра RBX не меняется.

OR

Инструкция OR выполняет поразрядное логическое сложение. Операция логического слоожения возвращает 1, если хотя бы один из соответствующих разрядов обоих операндов равен 1. Например,

.code
main proc
    mov rax, 12         ; помещаем в регистр rax  число 12 - 1100
    or rax, 6          ; помещаем в регистр rax = rax OR 6 = 1100 OR 0110 = 1110 = 14
    ret
main endp
end

Здесь в 64-битный регистр RAX помещается число 12, которое в бинарной форме равно 11002. Затем инструкция OR поразрядно складывает на число 6:

1100
+
0110
=
1110

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

XOR

Инструкция XOR выполняет поразрядную операцию исключающего ИЛИ, при которой возвращается 1, если соответствующие разряды обоих операндов не равны друг другу. если соответствующие разряды обоих операндов равны, то возвращается 0. Например,

.code
main proc
    mov rax, 12         ; помещаем в регистр rax  число 12 - 1100
    xor rax, 6          ; в регистре rax = rax XOR 6 = 1100 XOR 0110 = 1010 = 10
    ret
main endp
end

В результате в регистре RAX будет число 10102 или 1010 в десятичной системе.

1100
^
0110
=
1010

Стоит отметить, что операция xor нередко применяется для обнуления содержимого регистра, например

xor rax, rax    ; rax = 0

NOT

Инструкция NOT выполняет поразрядное отрицание и принимает один параметр:

not dest

Суть операции: если разряд операнда dest равен 1, то он меняется на 0. И наоборот - если разряд в dest равен 0, то он меняется на 1. Например,

.code
main proc
    xor rax, rax    ; rax = 0
    mov eax, 12     ; помещаем в регистр eax число 12 - 00000000 00000000 00000000 00001100
    not eax         ; eax =NOT(eax)=NOT(12)= 11111111 11111111 11111111 11110011
    ret
main endp
end

Здесь в 32-битный регистр EAX помещается число 12, которое в бинарной форме равно 11002. Однако поскольку регистр у нас 32-битный, то и число фактически будет 32-разрядное, а все передние биты будут представлять нули:

00000000 00000000 00000000 00001100

Поразрядное отрицание или инверсия изменяет значения битов на противоположное (изменяются все 32 бита в регистре). В итоге мы получим число

11111111 11111111 11111111 11110011

Что это за число, зависит от контекста. Так в дополнительном коде старший бит рассматривается как знаковый бит - если он равен 1, то число отрицательное. Соответственно инвертированное выше число будет интерпретироваться как -13. Если число рассматривается как число без знака, которое всега положительное, то результат - 4294967283

NEG

Кроме обычной инверсии в ассемблере есть арифметическое отрицацие, которое выполняет инструкция NEG. Она также принимает один операнд:

neg dest

фактически значение операнда будет умножаться на -1. Таким образом, мы сможем получить из положительного числа отрицательное, а из отрицательного - положительное. Например:

.code
main proc
    mov rax, -12
    neg rax     ; rax = -1 * rax = -1 * -12 = 12
    ret
main endp
end
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850