Что такое xor в ассемблере
Команды ассемблера
Опкод add имеет следующий синтаксис:
Выполняет вычисление: приемник = приемник + источник.
Имеются также другие формы:
приемник | источник | пример |
---|---|---|
регистр | регистр | add ecx, edx |
регистр | память | add ecx, dword ptr [104h] / add ecx, [edx] |
регистр | значение | add eax, 102 |
память | значение | add dword ptr [401231h], 80 |
память | регистр | add dword ptr [401231h], edx |
Эта команда очень проста. Она добавляет значение источника к значение приемника и помещает результат в приемник. Другие математические команды:
Поскольку регистры могут содержать только целочисленные значения (то есть числа, не, с плавающей запятой), результат деления разбит на частное и остаток. Теперь, в зависимости от размера источника, частное сохраняется в eax, а остаток в edx:
размер источника | деление | частное в. | остаток в. |
---|---|---|---|
BYTE (8-bits) | ax / делитель | AL | AH |
WORD (16-bits) | dx:ax* / делитель | AX | DX |
DWORD (32-bits) | edx:eax* / делитель | EAX | EDX |
Источник операции деления может быть:
Источник не может быть непосредственным значением, потому что тогда процессор не сможет определить размер исходного операнда.
команда | AND | OR | XOR | NOT | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Бит источника | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 1 |
Бит приемника | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | X | X |
Бит результата | 0 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 |
AND (логическое И)устанавливает бит результата в 1, если оба бита, бит источника и бит приемника установлены в 1.
OR (логическое ИЛИ)устанавливает бит результата в 1, если один из битов, бит источника или бит приемника установлен в 1.
XOR (НЕ ИЛИ)устанавливает бит результата в 1, если бит источника отличается от бита приемника.
NOTинвертирует бит источника.
Выполнение операции XOR на этими битами:
Если вы выполните инверсию каждого бита, то получите:
Значит после операции NOT, ecx будет содержать 0000FFFFh.
Команда jz выполнит переход, если ecx = 0.
Вот и конец урока. Надеюсь, этот не был скучным. Следующий урок расскажет вам про подпрограммы.
13. Логические операции в ассемблере
Статья основана на материале xrnd с сайта asmworld (из учебного курса по программированию на ассемблер 16-битного процессора 8086 под DOS).
Логические операции выполняются поразрядно, то есть отдельно для каждого бита операндов. В результате выполнения изменяются флаги. В программах эти операции часто используются для сброса, установки или инверсии отдельных битов двоичных чисел.
Логическое И
Если оба бита равны 1, то результат равен 1, иначе результат равен 0.
AND | 0 | 1 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
Ещё одно использование этой команды — быстрое вычисление остатка от деления на степень 2. Например, так можно вычислить остаток от деления на 8:
and ax,111b ;AX = остаток от деления AX на 8
Логическое ИЛИ
Если хотя бы один из битов равен 1, то результат равен 1, иначе результат равен 0.
OR | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 1 | 1 |
Логическое НЕ (инверсия)
Каждый бит операнда меняет своё значение на противоположное (0 → 1, 1 → 0). Операция выполняется с помощью команды NOT. У этой команды только один операнд. Результат помещается на место операнда. Эта команда не изменяет значения флагов. Пример:
not byte[bx] ;Инверсия байта по адресу в BX
Логическое исключающее ИЛИ (сумма по модулю два)
Если биты имеют одинаковое значение, то результат равен 0, иначе результат равен 1.
XOR | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 1 | 0 |
Исключающим ИЛИ эта операция называется потому, что результат равен 1, если один бит равен 1 или другой равен 1, а случай, когда оба равны 1, исключается. Ещё эта операция напоминает сложение, но в пределах одного бита, без переноса. 1+1=10, но перенос в другой разряд игнорируется и получается 0, отсюда название «сумма по модулю 2». Для выполнения этой операции предназначена команда XOR. У команды два операнда, результат помещается на место первого. Команду можно использовать для инверсии определённых битов операнда. Инвертируются те биты, которые в маске равны 1, остальные сохраняют своё значение. Примеры:
Обозначение операции в комментарии к первой строке используется во многих языках высокого уровня (например C, C++, Java и т.д.). Часто XOR используют для обнуления регистров. Если операнды равны, то результат операции всегда равен 0. Такой способ обнуления работает быстрее и, в отличие от команды MOV, не содержит непосредственного операнда, поэтому команда получается короче (и не содержит нулевых байтов, что особенно нравится хакерам):
Пример программы
Допустим, у нас есть массив байтов. Размер массива хранится в байте без знака. Требуется в каждом байте сбросить 1-й и 5-й биты, установить 0-й и 3-й биты, инвертировать 7-й бит. А затем ещё инвертировать целиком последний байт массива.
Упражнение
Объявите переменную x как двойное слово с каким-то значением. Инвертируйте 7-й, 15-й и 31-й бит. Обнулите младший байт переменной. Присвойте единичное значение битам 11-14 и 28-30. Результат сохраните в переменной y (естественно, она тоже должна быть объявлена как двойное слово). Инвертируйте значение x. Результаты можете выкладывать в комментариях.
FasmWorld Программирование на ассемблере FASM для начинающих и не только
Учебный курс. Часть 15. Логические операции
Автор: xrnd | Рубрика: Учебный курс | 23-04-2010 |
Распечатать запись
Логические операции выполняются поразрядно, то есть отдельно для каждого бита операндов. В результате выполнения изменяются флаги. В программах эти операции часто используются для сброса, установки или инверсии отдельных битов двоичных чисел.
Логическое И
Если оба бита равны 1, то результат равен 1, иначе результат равен 0.
AND | 0 | 1 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
Для выполнения операции логического И предназначена команда AND. У этой команды 2 операнда, результат помещается на место первого операнда. Часто эта команда используется для обнуления определённых битов числа. При этом второй операнд называют маской. Обнуляются те биты операнда, которые в маске равны 0, значения остальных битов сохраняются. Примеры:
and ax,bx ;AX = AX & BX and cl,11111110b ;Обнуление младшего бита CL and dl,00001111b ;Обнуление старшей тетрады DL
Ещё одно использование этой команды — быстрое вычисление остатка от деления на степень 2. Например, так можно вычислить остаток от деления на 8:
and ax,111b ;AX = остаток от деления AX на 8
Логическое ИЛИ
Если хотя бы один из битов равен 1, то результат равен 1, иначе результат равен 0.
OR | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 1 | 1 |
Логическое ИЛИ вычисляется с помощью команды OR. У этой команды тоже 2 операнда, и результат помещается на место первого. Часто это команда используется для установки в 1 определённых битов числа. Если бит маски равен 1, то бит результата будет равен 1, остальные биты сохранят свои значения. Примеры:
or al,dl ;AL = AL | DL or bl,10000000b ;Установить знаковый бит BL or cl,00100101b ;Включить биты 0,2,5 CL
Логическое НЕ (инверсия)
Каждый бит операнда меняет своё значение на противоположное (0 → 1, 1 → 0). Операция выполняется с помощью команды NOT. У этой команды только один операнд. Результат помещается на место операнда. Эта команда не изменяет значения флагов. Пример:
not byte[bx] ;Инверсия байта по адресу в BX
Логическое исключающее ИЛИ (сумма по модулю два)
Если биты имеют одинаковое значение, то результат равен 0, иначе результат равен 1.
XOR | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 1 | 0 |
Исключающим ИЛИ эта операция называется потому, что результат равен 1, если один бит равен 1 или другой равен 1, а случай, когда оба равны 1, исключается. Ещё эта операция напоминает сложение, но в пределах одного бита, без переноса. 1+1=10, но перенос в другой разряд игнорируется и получается 0, отсюда название «сумма по модулю 2». Для выполнения этой операции предназначена команда XOR. У команды два операнда, результат помещается на место первого. Команду можно использовать для инверсии определённых битов операнда. Инвертируются те биты, которые в маске равны 1, остальные сохраняют своё значение. Примеры:
xor si,di ;SI = SI ^ DI xor al,11110000b ;Инверсия старшей тетрады AL xor bp,8000h ;Инверсия знакового бита BP
Обозначение операции в комментарии к первой строке используется во многих языках высокого уровня (например C, C++, Java и т.д.). Часто XOR используют для обнуления регистров. Если операнды равны, то результат операции всегда равен 0. Такой способ обнуления работает быстрее и, в отличие от команды MOV, не содержит непосредственного операнда, поэтому команда получается короче (и не содержит нулевых байтов, что особенно нравится хакерам):
Пример программы
Допустим, у нас есть массив байтов. Размер массива хранится в байте без знака. Требуется в каждом байте сбросить 1-й и 5-й биты, установить 0-й и 3-й биты, инвертировать 7-й бит. А затем ещё инвертировать целиком последний байт массива.
Упражнение
Объявите переменную x как двойное слово с каким-то значением. Инвертируйте 7-й, 15-й и 31-й бит. Обнулите младший байт переменной. Присвойте единичное значение битам 11-14 и 28-30. Результат сохраните в переменной y (естественно, она тоже должна быть объявлена как двойное слово). Инвертируйте значение x. Результаты можете выкладывать в комментариях.
Комментарии:
щерт, а как к примеру 30е биты инвертировать или так прописывать:
xor [n], 01000000 00000000 00000000 00000000
Можно и так 🙂 Если добавить b в конце двоичного числа и без пробелов.
Но удобнее в шестнадцатеричном виде записать 40000000h.
ааа, запутался с этими младшими и старшими байтами, но вроде справился
use16
org 100h
xor byte[x],10000000b ;Инвертирую 7-й бит (старший бит младшего байта вроде)
xor byte[x+1],10000000b ;Инвертирую 15-й бит
xor byte[x+3],10000000b ;Инвертирую 31-й бит (старший бит старшего байта)
and byte[x],0 ;Обнуление младшего байта
or byte[x+1],01111000b ;Присваиваю единичное значение битам 11-14
or byte[x+3],01110000b ;Присваиваю единичное значение битам 28-30
mov ax,word[x]
mov word[y],ax
mov ax,word[x+2]
mov word[y+2],ax
Вообще я имел в виду, что значение x надо только инвертировать. А результат всех манипуляций сохранить в y ))) Ну ладно. Задание немного косячное, потому что если младший байт всё равно обнуляем, можно 7-й бит не инвертировать 😀
«and byte[x],0» то же самое, что «mov byte[x],0»
Кстати, ты инвертируешь не переменную x, а младшее слово y. Нужно 2 команды not на двойное слово.
«Кстати, ты инвертируешь не переменную x, а младшее слово y…» Дааа малость перепутал 🙂
xor byte[x],10000000b ;Инвертирую 7-й бит (старший бит младшего байта вроде)
xor byte[x+1],10000000b ;Инвертирую 15-й бит
xor byte[x+3],10000000b ;Инвертирую 31-й бит (старший бит старшего байта)
and byte[x],0 ;Обнуление младшего байта
or byte[x+1],01111000b ;Присваиваю единичное значение битам 11-14
or byte[x+3],01110000b ;Присваиваю единичное значение битам 28-30
mov ax,word[x]
mov word[y],ax
mov ax,word[x+2]
mov word[y+2],ax
not [x] ; не совсем понятно, почему, «Нужно 2 команды not на двойное слово».
аа ясно, значит not [x], только для младшего слова, тогда еще not word[x+2] нужен да.
Я понял в чём дело. FASM эту команду компилирует как для 32-битного операнда 🙂 Там к команде добавляется специальный префикс и она работает как в режиме 32-битного процессора. Это будет работать на 286 процессоре и выше. Но если использовать только 16-битный код, то надо написать в 2 этапа:
not word[x]
not word[x+2]
Так что программу ты правильно написал. Её можно оптимизировать немного, если сначала загрузить переменную целиком в 2 регистра, проделать все манипуляции и затем сохранить результат. Команды будут короче, когда операнд в регистре и работать должно быстрее. Но это так, на заметку.
mov ax,word[x]
mov bx,word[x+2]
xor al, 10000000b
xor ah, 10000000b
xor bh, 10000000b
or ah,01111000b
or bh,01110000b
mov word[y],ax
mov word[y+2],bx
mov ax, 4c00h
int 21h
;——————————
x dd 256
y rd 1
Да, всё правильно. Хороший вариант с загрузкой переменных в регистры 🙂
В твоём коде можно объединить 2 команды XOR в одну:
xor al, 10000000b xor ah, 10000000b
use16 ;gen 16-bit cod
org 100h ;begin 100h
;——————logik——————————
mov ax, word[x]
mov bx, word[x+2] ; x=ax:bx
;————8765432187654321——————
xor ax, 0100000001000000b ; 7, 15 =0
xor bx, 0100000000000000b ; 31
and al, 0 ; al=0
or ax, 0010010000000000b ; 11, 14 =1
or bx, 0010100000000000b ; 28, 30 =1
mov word[y], ax
mov word[y+2], bx
mov ax, word[x]
mov bx, word[x+2] ; x=ax:bx
not ax
not bx
mov word[x], ax
mov word[x+2], bx
Хорошо, но не совсем так, как в описании упражнения.
«Присвойте единичное значение битам 11-14 и 28-30».
Предполагается с 11 по 14 и с 28 по 30.
xor ax, 0100000001000000b ; 7, 15 =0 xor bx, 0100000000000000b ; 31
Биты обычно нумеруются с нуля от младшего к старшему. Поэтому 31-й бит — самый старший.
Можно выполнить второй XOR только для BH, так как младшая часть маски нулевая.
Второй раз загружать x в регистры не нужно. Все действия выполняются с x, потом дополнительно инверсия.
Спасиб, понял косяки, буду стараться оптимизировать лучше
А кстати наборные маски можно делать как в си
Да, можно такое. Синтаксис FASM отличается от Си, но смысл тот же:
xor ax,(1 shl 7) or (1 shl 15)
Я обычно сразу пишу в 16-ричном виде.
хочется как-то более простое решение, чем считать позиции единичек и ноликов
так вон xrnd показал
xor ax, 8080h
7 bit = 0x80, 1^7 степени
15 bit = 0x8000, 1^15 степени
31 bit = 0x80000000, 1^31 степени
bit value (hex)
———————-
1 0x1
2 0x2
3 0x4
4 0x8
5 0x10
6 0x20
7 0x40
8 0x80
а ваще я могу ошибатся так как теорию
сделал с xrnd по примеру «xor ax, 8080h»
Ну только не 1^7, а 2^7=128
Биты нумеруются с нуля. 2 в степени номер бита.
bit value (hex)
———————-
0 0×1
1 0×2
2 0×4
3 0×8
4 0×10
5 0×20
6 0×40
7 0×80
оКэй, спасибо за поправку … я просто в win-калькуляторе коммандой (1 14-01-2011 00:13
Хитрец, использовал 32-битные регистры 🙂
not ebx ; инвертируем 7,15,31
Конечно, нужные биты инвертируются, но и остальные тоже 😀 Здесь надо использовать XOR.
Дальше тоже много ошибок.
mov cl,[eax] ; cl влезает только последней байт x 23-31(байты) and cl, 11110001b or cl, 00001110b
Делает совсем не то, что нужно.
В CL загружается младший байт (биты 0-7).
Команда AND сбрасывает биты 1-3.
Команда OR устанавливает биты 1-3. Получается, AND делать не нужно.
Данные в памяти хранятся байтами. Это значит, что отдельный бит прочитать или записать нельзя, всегда выполняется операция с целым байтом.
В этом случае порядок битов в байте — это только обозначение. Обычно младший бит рисуют справа, а старший — слева. Нумеруют справа налево, начиная с нуля.
То, о чем ты пишешь — это порядок байтов в слове (или двойном слове) при хранении в памяти. В разных архитектурах бывает 2 варианта: little endian и big endian.
little endian — младший байт по младшему адресу — этот способ используется в архитектуре Intel x86.
big endian — старший байт по младшему адресу. Бывает и такое, но в других процессорах.
Двойное слово состоит из четырёх байтов. С регистрами всё понятно — младшая часть будет в AL, CL и т.д. На то она и младшая часть регистра.
А в памяти будет младший байт по младшему адресу, так как little endian:
ой не так
В регистре 0123456789
В памете 8967452301
Если интересно, подробнее о порядке байтов можно почитать в википедии:
http://ru.wikipedia.org/wiki/Little_endian
Привет.
AND..0….1
0……0…..0
1……0…..1
Не как не пойму как ей пользоваться можно.
Пользоваться также, как таблицей умножения 🙂
В первой строке и первом столбце значения операндов. На пересечении строки и столбца записан результат.
Например, 0 AND 0 = 0, 0 AND 1 = 0 и т.д.
А что за вторая таблица — я не понял.
Как с помощью логических команд очистить (обнулить) содержимое регистра B. Возможно использование дополнительного регистра C, не содержащего никакой полезной информации.
Лучше всего использовать XOR, так как эта операция всегда даёт результат 0, если операнды равны.
Ещё можно сделать AND с нулем.
mov ax, word[x+2]
mov bx, word[x]
xor ax, 8000h
xor bx, 8080h
or ax, 7000h
or bx, 7800h
mov word[y+2], ax
mov word[y], bx
;mov ax, word[x+2]
;mov bx, word[x]
mov ax, 4C00h
int 21h
Тут есть одна особенность: «not [x]» FASM сделает 32-битной командой, так как x — двойное слово.
Cейчас врядли можно найти 16-битный 8086 🙂
Но для него пришлось бы писать такой код:
not word[x] not word[x+2]
mov ax,word[x]
mov bx,word[x+2]
xor al,80h
xor ah,128
xor bh,10000000b
xor al,al
or ah,01111000b
or bh,01110000b
mov word[y],ax
mov word[y+2],bx
not word[x]
not word[x+2]
mov ax,4C00h
int 21h
Помогите пожалуйста с программой:
Дан массив из 5 байт. Рассматривая его как массив из 8 пятиразрядных слов, найти “исключающее или” всех 8 слов для выражения “10101”.
Сама-то хоть пыталась написать?
Ладно, помогу. Здесь нужно использовать сдвиги для выделения групп по 5 бит.
Так как массив всего из 5 байт, проще написать линейный алгоритм, без цикла.
use16 org 100h mov si,array mov ax,[si] ; Первые два байта add si,2 mov bl,al ; Первое 5-битное слово shr ax,5 xor bl,al ; 2-е слово shr ax,3 mov ah,[si] ; Чтение 3-го байта inc si shr ax,2 xor bl,al ; 3-е слово shr ax,5 xor bl,al ; 4-е слово shr ax,1 mov ah,[si] ; Чтение 4-го байта inc si shr ax,4 xor bl,al ; 5-е слово shr ax,4 mov ah,[si] ; Чтение 5-го байта shr ax,1 xor bl,al ; 6-е слово shr ax,5 xor bl,al ; 7-е слово shr ax,5 xor bl,al ; 8-е слово and bl,1Fh ; bl = результат mov ax,4C00h ; Выход из программы int 21h array db ‘10101’
не пойму,а где здесь сам массив из 5 байт?
Я вижу ток выражение 10101.
Почему массив заполняется этим выражением,а не допустим 10000b,11000b,10001b… и так 8 слов…(
Это выражение и есть массив 🙂
Я объявил его как строку из 5 символов. Каждый символ — байт. То есть получается массив из 5 байтов.
Восемь 5-битных слов объявить не получится. Так как директива db объявляет байты. Если записать через запятую, получится 8 байтов со значениями 0001000b, 00011000b и т.д.
Напишите пожалуйста,коммент к каждой строке,если вас это не сильно затруднит,просто я не могу уловить алгоритм(((
Я могу сказать что делает каждая команда,а смысл уловить никак не могу(((
Плиз,оч нужна эта прога((
Смысл алгоритма в следующем. Сдвигая по 5-бит вправо, можно выделять 5-битные слова из последовательности битов. Но так как мы работаем с байтами, нужно ещё и «собирать» эту последовательность из отдельных байтов.
То есть после сдвига на 8 бит нужно читать следующий байт из массива.
В первый раз читается сразу 2 байта. Сдвигать надо 16-битный регистр, чтобы младшие биты одного байта попадали в страшие биты другого.
Исключающее ИЛИ считается в регистре BL, при этом старшие 3 бита обнуляются в конце программы.
Теперь не слезу с этого сайта,пока асм не выучу))))
Команда XOR
Команда XOR в Ассемблере выполняет операцию исключающего ИЛИ между всеми битами двух операндов. Результат операции XOR записывается в первый операнд. Синтаксис:
XOR ПРИЁМНИК, ИСТОЧНИК
ПРИЁМНИК может быть одним из следующих:
ИСТОЧНИК может быть одним из следующих:
С учётом ограничений, которые были описаны выше, комбинации ПРИЁМНИК-ИСТОЧНИК могут быть следующими:
Операция исключающего ИЛИ
При выполнении операции исключающего ИЛИ значение результата будет равно 1, если сравниваемые биты отличаются (не равны). Если же сравниваемые биты имеют одинаковое значение, то результат будет равен 0.
Потому эта операция и называется исключающей. Она исключает из сравнения одинаковые биты, а с неодинаковыми выполняет операцию логического ИЛИ.
Но, так как любая пара неодинаковых битов это 0 и 1, то операция логического ИЛИ в результате даст 1.
Таблица истинности исключающего ИЛИ
Таблица истинности XOR приведена ниже:
Особенности операции XOR
Операция XOR обладает свойством реверсивности. Если её выполнить дважды с одним и тем же операндом, то значение результата инвертируется. То есть если два раза выполнить эту операцию между битами X и Y, то в конечном результате мы получим исходное значение бита Х.
Это свойство можно использовать, например, для простейшего шифрования данных (об этом как-нибудь в другой раз).
Проверка флага чётности после операции XOR
Команда XOR работает с 8-, 16- и 32-разрядными операциями.
Иногда есть необходимость после выполнения операции проверить флаг чётности PF, для того, чтобы узнать, какое количество единичных битов (чётное или нечётное) содержится в младшем байте результата (это бывает необходимо не только в случае выполнения операции XOR, но и при выполнении других арифметических и логических операций).
Если флаг чётности установлен, то в результате получилось чётное количество единичных битов. Иначе флаг будет сброшен.
Можно также просто проверить на чётность любое число, не меняя значения результата. Для этого надо выполнить команду XOR с нулевым значением. То есть в ПРИЁМНИКЕ должно быть проверяемое число, а в ИСТОЧНИКЕ должен быть ноль. А затем надо проверить флаг чётности. Пример:
Чётность в 16-разрядных словах
Как уже было сказано, флаг чётности устанавливается в зависимости от количества единиц, содержащихся в младшем байте результата. Чтобы проверить чётность 16-разрядного операнда, надо выполнить команду XOR между старшим и младшим байтом этого числа:
Таким нехитрым способом 16-разрядный операнд разбивается на два байта (2 группы по 8 битов), и при выполнении команды XOR единичные биты, находящиеся в соответствующих разрядах двух 8-разрядных операндов, не будут учитываться. Потому что соответствующий бит результата равен нулю.
Команда XOR удаляет из результата любые пересекающиеся единичные биты двух 8-разрядных операндов и добавляет в результат непересекающиеся единичные биты. То есть чётность полученного нами 8-разрядного числа будет такой же, как и чётность исходного 16-разрядного числа.
В результате 4 единицы, то есть флаг PF будет установлен
Чётность в 32-разрядных двойных словах
Ну а если надо определить чётность в 32-разрядном числе?
Тогда число разбивается на четыре байта, и поочерёдно с этими байтами выполняется операция исключающего ИЛИ.
Тогда для определения чётности числа В нам надо будет использовать следующую формулу:
B0 XOR B1 XOR B2 XOR B3
Но в ассемблере такая запись недопустима. Поэтому придётся немного подумать.