Linuxでx86アセンブラ（論理演算編）

# \:large_blue_diamond:この記事について
「Linuxでx86アセンブラ」シリーズの4回目です．
前回は四則演算でした．数学ならば四則演算ができればおおよそのことができます．
しかし、計算機の演算は四則演算だけではありません．andやorなどの論理演算があります．
論理演算は条件分岐に欠かせない演算です．今回はアセンブラでの論理演算について説明していきます．

# 使用するソフトウェア
この連載ではLinux環境でnasmを使用することを想定しています．

# \:large_blue_diamond:論理演算とは？
論理演算はブール演算ともよばれ真と偽の２つの値をもつ集合に対する演算です．
2つの値しか持たいないのでbitで計算を行うコンピュータとの相性がとてもよく、10進数の計算より高速に計算を行えます．
論理演算の主なものにnot、and、or、xorがあります．
notは、論理を反転します．入力Aが真なら偽、偽なら真を返します．

| A | 結果 |
|:---|:---|
|  1 | 0 |
| 0 | 1 |

andに考えられるA,B,2つの入力を与えた結果を表にしたものを下に示します．

| A | B | 結果 |
|:---|:---|:---|
|  1 | 1 | 1 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 0 | 

andはAかつBとも言われ、AとBがともに真（1）の時に結果が真(1)になります．

orも同様に表にすると

| A | B | 結果 |
|:---|:---|:---|
|  1 | 1 | 1 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |

となります．orはAまたはBともいい、AとBのどちらかが真(1)のとき結果が真(1)になります．
xorは排他的論理和と呼ばれています．orとほとんど同じですが、A,Bがともに真(1)の時は偽(0)になります．

| A | B | 結果 |
|:---|:---|:---|
|  1 | 1 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 0 | 0 | 0 |

コンピュータの論理演算はこれらの演算をビット列に適用します．

```math
1010 \; {\rm and} \;0110 = 0010 \\
1010 \;\; {\rm or} \;\;0110 = 1110 \\
1010 \; {\rm xor} \;0110 = 1100 
```
# シフトとローテーション
上の論理演算の他にシフトとローテーションがあります．
シフトはビット列を左右にずらします．
左シフトの場合はこのように

```math
0111 \rightarrow 1110
```
右シフトの場合は右の方にビット列がずれます．

```math
1110 \rightarrow 0111
```

左シフトをするとき一番上の位が1の時に一番上のくらいの1はなくなり一番下のくらいに0がはいります．一番上のくらいのビットを再利用したいときはローテーションを使います．
ローテーションを行うとなくなってしまうはずだった一番上の位のビットが一番下の位のビットになります．


# \:large_blue_diamond:アセンブラの論理和
論理演算がどのようなものかわかっていただけたと思います．
それでは、アセンブラのプログラムでこれらの演算を表現するためのニーモニックを見て行きましょう．論理和andの演算を行うためには```and```ニーモニックを使います．

```
and <レジスタ>, <レジスタまたは規定値>
```
結果は第一オペランドに格納されます．```and```の主な使い道ですが、ビット列のマスキングに使います．例えば下の命令はalレジスタの上位4ビットの値だけをそのまま切り出し、それ以外は0に設定します．
```
and al, 0b11110000
```

# \:large_blue_diamond:アセンブラの論理積
```
or <レジスタ>, <レジスタまたは規定値>
```
論理積には```or```ニーモニックを使います．```and```と同様に第一オペランドに結果が格納されます．
 

# \:large_blue_diamond:アセンブラの排他的論理和
```
xor <レジスタ>, <レジスタまたは規定値>
```
排他的論理和には```xor```ニーモニックを使います．```xor```の主な使い道はレジスタの初期化です．排他的論理和では２つのオペランドが等しい時、結果は必ず0になります．これを利用してレジスタの値を0に設定することができます．
```
xor eax, eax
```
この演算によりeaxレジスタを0に設定することができます．
 
# アセンブラのシフト・ローテーション

```
shl <レジスタ>, <回数>
shr <レジスタ>, <回数>
```
左シフトには```shl```．右シフトには```shr```を使います．第二オペランドにシフトする回数を指定します．
ローテーションには
```
ror <レジスタ>, <回数>
rol <レジスタ>, <回数>
```
を使います．オペランドの意味はシフト命令と同じです．


# サンプルコード
上記の命令のサンプルコードです．

```:logic.asm
section .bss

section .data

section .text

global main

main:
   enter 0,0
   nop

.not:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b00001111
   not ax

.and:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b00001111
   mov bx, 0b00001100
   and ax, bx

.or:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b00001111
   mov bx, 0b10100100
   or ax, bx

.xor:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b00001111
   mov bx, 0b10100100
   xor ax, bx

.shl:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b00001111
   shl ax, 4

.rhl:
   xor rax, rax
   xor rbx, rbx
   mov ax, 0b11110000
   shr ax, 4

.final:
    mov eax, 0
    leave
    ret
```

このコードを、logic.asmと名づけて保存してください．

```
nasm -g -f elf64 -o logic.o logic.asm
```
で、コンパイル．
```
gcc -o logic logic.o
```
で、リンクして実行ファイルlogicを生成してください．
```
gdb -tui logic
```
で、どのように処理されているかを見ることができます．
この時レジスタを2進数として表示するには
```
display/t <レジスタ>
```
というコマンドをgdb内で使用します．

# 参考文献
* NASM development team site:   
http://www.nasm.us/
* GDB: The GNU Project Debugger site:   
https://www.gnu.org/software/gdb/
* Assembly Language Step-by-Step: Programming with Linux:   
http://www.amazon.co.jp/Assembly-Language-Step---Step-Programming/dp/0470497025/ref=sr_1_1?ie=UTF8&qid=1446704607&sr=8-1&keywords=assembly+language+step+by+step
 
↓↓\:bowtie:過去の投稿もよろしくね\:bowtie:↓↓

* Linuxでx86アセンブラ(四則演算編)
http://qiita.com/MoriokaReimen/items/4853587dcb9eb96fab62

* Linuxでx86アセンブラ(Cとの連携編)
http://qiita.com/MoriokaReimen/items/590a4ddb3de15bfacb4b

* Linuxでx86アセンブラ(道具編)
http://qiita.com/MoriokaReimen/items/b316a68d76c1eafa18f8

* tmuxの使い方
http://qiita.com/MoriokaReimen/items/d7d5b158cb412dd65a60



↓↓\:bowtie:コメントをいただけたら励みになります\:bowtie:↓↓