Linuxでx86アセンブラ（BCD編）

# この記事について
Linuxでｘ86第9回．今回はBCDです．
多くの高級言語プログラマにとってBCDは馴染がないかかもしれません．アセンブラの機能はCで反映されるていたり名残があったりするのですが、BCDは全く残っていません．intやlong型で事足りることが多いからです．どうしても、CでBCDを使いたい場合は[decNumber](http://speleotrove.com/decimal/decnumber.html)などのライブラリを持ってくる必要があります．

# BCDとは？
Binary Coded Decimalの略で、日本語では二進化十進数と呼ばれます．
コンピュータは基本的には数字を二進数に変換して処理します．
しかし、私達が普段扱っている数字は十進数です．この違いにより時々、不都合が生じることがあります．
例えば0.1+0.9を二進数で足し算すると二進数の正解では0.9999999999999999999999999999999999999....となり、極小さな誤差がでます．これを何万回も繰り返したらどうなるでしょうか．はじめは小さな誤差でも無視できない誤差になっていきます．BCDでは二進化が原因で起きる誤差をなくすことができます．会計など極端な正確さを求められる演算で採用されることがあります．
BCDにはUnpacked BCDとPacked BCDのに種類があります．Unpacked BCDは一バイトにひと桁のデータを保存します．
たとえば1234をUnpacked BCDで表すと、

```
01 02 03 04H
```

で表されます．
Packed BCDは1ニブル（4bit）にひと桁を保存します．
1234をPacked BCDで表すと、

```
1234H
```

で表せます．

# BCDの足し算
Unpacked BCDの足し算の例です

```
xor ah, ah
mov al, '6' ; '6' = 36H
add al, '7' ; '7' = 37H
aaa
or al, 30H
or ah, 30H
```

```mov al, '6'``` によりalは36Hにセットされます．次の行の```add al, '7'``` によりalは6DHにセットされます．これはまずい答えですね．
BCD的には13を意味する3133Hとなって欲しいところ．
そこで```aaa``` ニーモニックを使います．
```aaa``` は次の2つのことをします．

1. alの最下位4bitが9Hより大きい、またはAFがセットされていたら、alに6をたし、ahに1を足します．この際、CFとAFがセットされます．

2. alの上位4ビットは0にセットされます．

つまり、```aaa``` ニーモニックによりalは03Hになりahは01Hになります．このあと```or al, 30H``` と、```or ah, 30H``` によりalとahの上位4ビットは3hにセットされ、alはasciiコードの'3'、ahはaciiコードの'1'になります．

Packed BCDの例を示します．

```
mov al, 71H
add al, 43H
daa
```

この計算はPacked BCDの足し算、71+43を実行します．
```daa``` ニーモニックは、Packed BCDのaaaと同様に足し算によって崩れてしまったBCDを整形します．
```daa``` は下の2つのことを行います．

1. alの最下位4ビットが9より大きい、またはAFがセットされているとき、alに6を足しAFをセットします．
2. alの上位4ビットが9より大きい、またはCFがセットされているとき、60HをALに足しCFをセットします．

```daa``` によりahは01H、alは14Hになります．

# BCDの引き算
Unpacked BCDの引き算は足し算の時と同様にsubしたあとで、```aas``` を用いて整形します．

```
xor ah, ah
mov al, '3'
sub al, '9'
aas
or al, 30H
```

```aas``` は以下の2つのことをします．

1. alの最下位4ビットが9より大きいまたはAFがセットしている場合、alから6、ahから1を引いてCFとAFをセットします．
2. alの上位4ビットをクリアします．

上の例では最終的にalが34hになります．

Packed BCDの引き算の整形には```das``` を使います．

```
mov al, 71h
sub al, 43h
das
```

```das``` は2つのことを行います．

1. alの最下位4ビットが9より大きい、またはAFがセットされていたらalから6を引いてAFをセットします．
2. alの上位4ビットが9より大きいまたはCFがセットされている場合は、alから60Hを引いてCFをセットします．

上の例ではalは最終的に28Hとなります．

# 掛け算・割り算
Unpacked BCDの掛け算の結果の整形には```aam``` を使います．

```
mov al, 3
mov bl, 9
mul bl
aam
or ax, 3030h
```

Unpacked BCDの割り算の結果の整形には```aad``` を使います．

```
mov ax, 0207h
mov bl, 05h
aad
div bl
```
```aad``` はaxレジスタの```div``` が使える二進数の形に変換します．演算の前に呼び出す必要があります．

# デモコード
今回出てきたニーモニックの使い方を説明するデモコードです．

``` BCD.asm
section .bss

section .data

section .text

global main

main:
   enter 0,0
   nop

.bcd_add:
    xor ax, ax
    mov al, '7'
    add al, '8'
    AAA
    or al, 30H
    nop

.bcd_sub:
    xor ax, ax
    mov al, '7'
    sub al, '9'
    aas
    or al, 30H
    nop

.bcd_muldiv:
    mov al, '3'
    mov bl, '9'
    and al, 0FH
    and bl, 0FH
    mul bl
    aam
    or al, 30H
    nop

    mov ax, '45'
    and ax, 0F0FH
    mov bl, '5'
    and bl, 0FH
    aad
    div bl
    or ax, 3030H
    nop

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

64bitはBCDをサポートしていません．32bitのみで使用可能です．
レジスタの本数、長さが大幅に上がったため先述したような問題は無視できるものになってきています．
将来的にはBCDは失われたテクノロジーになっていくでしょう．

# 参考文献
* 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
* Stack Analysis with GDB:    
http://resources.infosecinstitute.com/stack-analysis-with-gdb/

↓↓\:bowtie:過去の投稿もよろしくね\:bowtie:↓↓

* Linuxでx86アセンブラ（条件分岐編） 
http://qiita.com/MoriokaReimen/items/66b8c0e3b2ef1d2993bb

* Linuxでx86アセンブラ（マクロ編） 
http://qiita.com/MoriokaReimen/items/45abbb6c2938abd505ff

* Linuxでx86アセンブラ（スタック編）
http://qiita.com/MoriokaReimen/items/31a8f8ce4a46ba0f3590

* Linuxでx86アセンブラ（基本的なコードの構造編）
http://qiita.com/MoriokaReimen/items/b320e6cc82c8873a602f

* Linuxでx86アセンブラ（論理演算編） 
http://qiita.com/MoriokaReimen/items/bf863585616ad0a0a969

* 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:↓↓