機械語入門メモ
- 11/3(月)
- 機械語入門に行ってきたメモ
- 公開し忘れ気づけば週末(ごめんなさい
先にまとめ
- 相変わらず濃厚な時間で勉強になった
- 命令の意味どうこうより、アセンブリ言語の表現力を知る、というスタンスはデータシート見ながらすごく納得。
- 勉強会の間に実装した分まで。時間が取れ次第続きを実装
- 勉強会同席してた@ryiwoさんがGoで再実装してるみたいで面白そう
- 自分もGo勉強中だし、Haskell番が終わったら後追いで再実装してみようかな。。。
- 同じノリでいろんな言語でやってみるの面白そう。
- @7shiさん今回もありがとうございました。
- 頑張って都合つけて、顔出せるようにしたいな。
HUnit入門
HUnitの使いかた
"ラベル" ~: 式 ~?= 期待値
の演算子でテストする- リストを書いて、テストを並べて書く
- 失敗とエラーは区別されるよ
機械語入門
- 8086
- 16bitのintel CPU
- 今のCPUのベースになっている
- 32bit / 64bitへの拡張の基礎に為っている
- 昔の特有の事情などもあるので、いきなり64bitとかやるとなぜ???となりやすい
- なので16bitからやるほうが、下地の知識として知っておきましょう
2進数
- 0と1の2つの数字で構成される
- 10進数で位がひとつ上がると10倍、2進数で位がひとつ上がると2倍
- 何倍か = 何進数か
- 2進数 11 = 3
- 一桁増える = 2倍なので、
110
-> 11 の2倍なので、110 = 3 x 2 = 6
と出せる
- 一桁増える = 2倍なので、
練習
- サンプルの逆をやってみる
- 数値を渡して2進数文字列
- 下の桁から剰余を求め、どんどん上へ反復。商が0になったら打ち止め
桁揃え
- 16進数に変換する際に、決まった桁数に揃える処理
- 上にはみ出したらそれは落とす
- あとでよく使うので関数を用意
メモリをリストで表現
- 16進数の文字列を2m文字ずつ区切ってリスト化
- 逆にリストを16進数文字列に直す
- リストにしておくと、メモリをシミュレートできる
- 人間が扱うときは面倒なので文字列に
バイトオーダー
- メモリの中には16進数の2桁までしか入らない。
- 1バイト
- あふれる分はどうするか?
2桁ずつバイトごと分割して入れる
並べ方の方式(バイトオーダー)は2種類
- 今回はリトルエンディアンを扱う
数値 -> リトルエンディアン
- 2バイト -> 4桁(4ニブル)
1
を2バイトのリトルエンディアンに0001
->01
,00
- 5桁以上にあふれたものは落とす
桁数を制限されてるものは、上の方を落とす
リトルエンディアンを数値にする、のも2進数を数値にすると同じような仕組み
練習
逆アセンブラ
- アセンブリ言語 = 人間が見やすいように機械語を直したもの
- アセンブリ言語(命令)の意味を説明してると無理があるので、今回はやらない
-
- 学習効率のため
機械語は、数字の塊に意味・命令をつけたもの
今回やることは、逆アセンブラを作る
8086の命令は、配ったシートですべて。
- 64bitの命令になるとこれの5倍ぐらいになる
mov ax, imm16
B83412 mov ax,0x1234
- ぱっと見、3412の部分が0x1234っぽい
- ということは、
B8 = mov ax
っぽい - わかりやすい部分はこう見ちゃえばいい
文字列渡し
- バイナリを16進数文字列で渡せるように
disasm'
って便利関数作っとく- テスト書くの辛いし。。。
mov r16, imm16
mov r8, imm8
8bitと16bitの統合
- オペコードが1バイトか2バイトか、の違いしか無い
- P.1 3行目 immediate to Register に対応
ならばまとめられるはず
- リファクタ
命令表の見方は、命令を一旦2進数になおしてみて、どれが対応するのかを探す
- 今回のものは4bitで分かったが、7bit見ないとわからないものもあったりする
w = 8bitか16bitかを表してる
- 略語は一応最後のP5にある
- w = 0 だとbyte命令 byte = 1バイト
- w = 1 だとword命令 word = 2バイト
- wordが2バイト、というのは不変な話ではなく、CPU依存。x86の場合の話。
- ARMの場合はwordは4バイト
レジスタが8bitなら1バイト、16bitなら2バイトのデータを受け取る
- 表の
data if w = 1
はそれを表してる
- 表の
この表を元にコードをリファクタする
- 割り算でもとれるが、遅い処理なのでビット演算する
- シフト
- 左シフト
- ひとけた増えて、一番下が0になる
- 右シフト
- 一番下の位を押しつぶす
- 割り算の代わりに、桁をつぶす事ができる
- 左シフト
- マスク
- 特定の桁だけを残して、他全部0にする処理
- 論理積(
.&.
)を使う- 両方成り立ってる時だけ1になる
- 残したいところだけ
1
にしてマスクすることで、お目当てのbitだけが取れる
- オペランドに直接数字が書いてるもの(ハードコードされたもの)を
即値(immediate)
という imm
の値を何バイト取ってくればいいかは、w
に1を足したバイト数だとわかるので、そうやって取ってくればいいか
ビットパターン
- せっかくHaskellつかってるので、どの命令かをパターンマッチしよう
- 2進数のままパターンマッチできるようにする
ビット分解
- 1byte = 8bitなのは不変(8086に限って言えば)なので、タプル8bitぶんに直す
- 8回shiftとmaskを繰り返せば得られる
レジスタを再構成
ビットでパターンマッチ
disasmB
という別の関数作って、パターンマッチでbit書けるようにする- wもそのままとれて便利
- なるべく仕様書をそのまま読めるように実装してる
mov(続き)
今までは、一番簡単な行をやったので、あとは順次やっていく
ちなみに、データのパターンから機械語を手動で作ってく作業を
ハンドアセンブル
と呼ぶ- ソラですらすらできなくていいけど、いざとなったらできるぐらいにはなっとくといい
アセンブルとは
ふつう、こういうのはソフトにやらせる
やってみよう
バイナリエディタで保存
- 88 00
- 89 00
- 8A 00
- 8B 00
結果
- 最初の行は、機械語のはいってる位置
$ ndisasm test.bin 00000000 8800 mov [bx+si],al 00000002 8900 mov [bx+si],ax 00000004 8A00 mov al,[bx+si] 00000006 8B00 mov ax,[bx+si]
- これからやってくことは。。。
- バイナリ作ってみて、ndisasmして
- そこから命令とバイナリの対比をみて
- テストケース作って
- 実装していく
データシートだけ見て、アセンブリ言語との対比はわからない
ndisasmがもうあるなら、やらなくていいんじゃ?
- もちろんその通り
- 今やっているのは、これらの命令の構造を理解するための勉強として。
普通は命令1個1個の説明を聞いて。。。なんてやるけど、それだと表現力がわかんない
- なので逆アセンブラを作ってそれを学ぶのを最初にやってみよう!というのがこの会の趣旨なので。
さっき見た命令の内容から、
w
が何を表しているかは知っている- データシートの最後のページを見ると、
d
の説明がある- from reg / to reg
- 代入の方向を表している
- regから代入か、regへ代入か
- 残りの
mod r/m
は、[bi+si]
の内容に関係するのでは?という推測はできる
r/m
- r/mを増やしてやってみる
00000008 8901 mov [bx+di],ax 0000000A 8902 mov [bp+si],ax 0000000C 8903 mov [bp+di],ax 0000000E 8904 mov [si],ax 00000010 8905 mov [di],ax 00000012 89068907 mov [0x789],ax
- なんだか、
8906
の時はちょっと様子が違う- mod = 00 r/m = 110
- この場合に即値を取るっぽい
- 条件に対応させて実装
- mod = 00 r/m = 110
00000012 89068907 mov [0x789],ax 00000016 88063412 mov [0x1234],al 0000001A 89063412 mov [0x1234],ax 0000001E 8A063412 mov al,[0x1234] 00000022 8B063412 mov ax,[0x1234]
レジスタによるアドレス指定
メモリのアドレスは、上位2byteをhigh, 下位2byteをlow
指定できるアドレス指定の組み合わせは、全てのレジスタが使えるわけじゃなくて、決まっている
- データシートに全て書いてある
- これしか使わせない、という取り決めがある
- このようにして、表現力が制限されている
- 32bitはもっと複雑になって、全てのレジスタが使えるようになってたりする
今度はアセンブラ使ってみよう
- 仕様書から組み合わせが全部でた
mov [bx+si],ax mov [bx+di],cx mov [bp+si],dx mov [bp+di],bx mov [si],sp mov [di],bp mov [bp],si mov [bx],di
$ ndisasm test 00000000 8900 mov [bx+si],ax 00000002 8909 mov [bx+di],cx 00000004 8912 mov [bp+si],dx 00000006 891B mov [bp+di],bx 00000008 8924 mov [si],sp 0000000A 892D mov [di],bp 0000000C 897600 mov [bp+0x0],si 0000000F 893F mov [bx],di
これで
89xx
の組み合わせがわかった- mod = 00の部分がわかった
[bp]
はアドレス指定に使っててパターンが異なるので除外
mod = 01 の出し方を説明していく
符号の考え方
ちょっとした暗算の工夫
- 12 + 99 を簡単にするには?
- 12 + 100 - 1にすると簡単
2桁に制限された世界
- 12 + 99 = 12 + 100 - 1 = 111 = 11
- そもそも100を足してるけど、100自体がキャンセルされてる
- 12 + 99 = 12 + 100 - 1 = 12 - 1 = 11
- つまり、2桁に制限された世界では、99を足すことと、1を引くことが同一視できる
- このように0~99で制限された数の集合を
有限体
と呼ぶ
- このように0~99で制限された数の集合を
- 12 + 99 = 12 + 100 - 1 = 111 = 11
補数
- 100 - 1 = 99 -> 100 - 99 = 1
- このように、100から引くことで、お互いを変換できる
- このような関係を
補数
という
符号の線引き
- 足し算と引き算の計算を逆転させるときに補数が出てくる
- 対比表を見ると、絶対値が一定のところで反転している
- 補数の代表値は、絶対値の小さい方の数を代表値として、符号反転して考えることで解釈できる
- 中央値はどうするか?
- 0を含めて考えるといい
- 0をプラスに含めると、中央値をマイナスに含めれば均等になる
問題としているのは16進数
-0x80~0x7F
なぜこれをやる?
- 桁が制限されている
- 巨大な数の足し算は、引き算に相当する
- それをうまいことやるため
ディスプレースメント
- modを01にしてみて適当な値で逆アセンブルしてみる
00000026 894001 mov [bx+si+0x1],ax 00000029 8949FF mov [bx+di-0x1],cx 0000002C 895202 mov [bp+si+0x2],dx 0000002F 895BFE mov [bp+di-0x2],bx 00000032 896464 mov [si+0x64],sp 00000035 896D9C mov [di-0x64],bp 00000038 897600 mov [bp+0x0],si 0000003B 897601 mov [bp+0x1],si 0000003E 897F01 mov [bx+0x1],di
- アドレスに対する差分のことをディスプレースメントと呼ぶ
[bp+0x1]
みたいなやつ
- 符号付きの表現
- 符号をうまく吸収するようにmodrmを拡張
- 符号化のための
disp8
の関数をつくる
ファイルを分ける
- ちょっとでかくなってきたので分割する
- Hex
- DisAsm
- をそれぞれ作って別に読み込む
練習
- 順次シートの実装を進める
問5
- mod = 10, 11に適当に当たりをつける
- mod = 10の範囲は 8980 ~ 89BF になるはず
- mod = 11の範囲は 89C0 ~ 89FF になるはず
mod = 10
00000000 89800001 mov [bx+si+0x100],ax 00000004 89840F00 mov [si+0xf],ax 00000008 8990FF00 mov [bx+si+0xff],dx 0000000C 89920E02 mov [bp+si+0x20e],dx 00000010 89A00000 mov [bx+si+0x0],sp 00000014 89A6DD00 mov [bp+0xdd],sp 00000018 89AFBC0F mov [bx+0xfbc],bp 00000000 89BFFFFF mov [bx-0x1],di
- mod = 10の場合は、ディスプレースメントの部分が拡張しているようにみえる
- mode でビットシフトして取ってくる数が16進数じゃなくて10進数になってる
- disp16作って何とかする
mod = 11
00000000 88C0 mov al,al 00000002 88C1 mov cl,al 00000004 89C0 mov ax,ax 00000006 89C1 mov cx,ax 00000008 89C2 mov dx,ax 0000000A 89C3 mov bx,ax 0000000C 89D0 mov ax,dx 0000000E 89F0 mov ax,si 00000010 89FF mov di,di 00000012 8AC0 mov al,al 00000014 8AC1 mov al,cl 00000016 8BC0 mov ax,ax
- mod = 11 の場合は、r/mのところにregの内容が入ってくる
88C0 - 88FF, 89C0 - 89FFでそれぞれ8bit, 16bitの役割になってる
- wの影響もregと同様に受けている
TODO...
実装
- めっちゃ途中
- 一応、当日出来たとこまで載せる
Hex.hs
module Hex where import Test.HUnit import Data.Char binToInt '0' = 0 binToInt '1' = 1 binStrToInt bin = f (reverse bin) where f "" = 0 f (x:xs) = (binToInt x) + 2 * (f xs) intToBin 0 = '0' intToBin 1 = '1' bin n | n' == 0 = s | otherwise = bin n' ++ s where s = [intToBin (n `mod` 2)] n' = n `div` 2 hexStrToInt bin = f (reverse bin) where f "" = 0 f (x:xs) = (digitToInt x) + 16 * (f xs) hex n | n' == 0 = s | otherwise = hex n' ++ s where s = [intToDigit (n `mod` 16)] n' = n `div` 16 hexn n x | r < 0 = drop (-r) x' | otherwise = replicate r '0' ++ x' where x' = hex x r = n - length x' hexStrToList "" = [] hexStrToList (h:l:xs) = hexStrToInt [h, l] : hexStrToList xs listToHexStr [] = "" listToHexStr (x:xs) = hexn 2 x ++ listToHexStr xs toLE 0 _ = [] toLE n x = x `mod` 0x100 : toLE (n - 1) (x `div` 0x100) fromLE 0 _ = 0 fromLE n (x:xs) = x + 0x100 * fromLE (n - 1) xs toBE 0 _ = [] toBE n x = toBE (n - 1) (x `div` 0x100) ++ [x `mod` 0x100] -- toBE n x = (x `div` 0x100^(n - 1)) `mod` 0x100 : toBE (n - 1) x fromBE 0 _ = 0 fromBE n (x:xs) = x * 0x100^(n - 1) + fromBE (n - 1) xs testHex = TestList [ "1 reverse" ~: reverse "11001" ~?= "10011" , "2 binStrToInt 1" ~: binStrToInt "101" ~?= 5 , "3 binStrToInt 2" ~: binStrToInt "11001" ~?= 25 , "4 bin 1" ~: bin 5 ~?= "101" , "5 bin 2" ~: bin 25 ~?= "11001" , "6 hexStrToInt 1" ~: hexStrToInt "F" ~?= 15 , "7 hexStrToInt 2" ~: hexStrToInt "FF" ~?= 255 , "8 hex 1" ~: hex 15 ~?= "f" , "9 hex 2" ~: hex 256 ~?= "100" , "10 replicate" ~: replicate 5 'a' ~?= "aaaaa" , "11 hexn 1" ~: hexn 2 1 ~?= "01" , "12 hexn 2" ~: hexn 2 255 ~?= "ff" , "13 hexn 3" ~: hexn 8 65535 ~?= "0000ffff" , "14 hexn 4" ~: hexn 2 256 ~?= "00" , "15 hexStrToList 1" ~: hexStrToList "123456" ~?= [0x12, 0x34, 0x56] , "16 hexStrToList 2" ~: hexStrToList "010203" ~?= [1, 2, 3] , "17 listToHexStr 1" ~: listToHexStr [0x12, 0x34, 0x56] ~?= "123456" , "18 listToHexStr 2" ~: listToHexStr [1 ,2 ,3] ~?= "010203" , "19 toLE 1" ~: toLE 2 1 ~?= [1, 0] , "20 toLE 2" ~: toLE 2 0x10000 ~?= [0, 0] , "21 toLE 3" ~: toLE 4 0x12345678 ~?= [0x78, 0x56, 0x34, 0x12] , "22 fromLE 1" ~: fromLE 2 [0, 1] ~?= 0x100 , "23 fromLE 2" ~: fromLE 2 [0x78, 0x56, 0x34, 0x12] ~?= 0x5678 , "24 fromLE 3" ~: fromLE 4 [0x78, 0x56, 0x34, 0x12] ~?= 0x12345678 , "25 toBE 1" ~: toBE 2 1 ~?= [0, 1] , "26 toBE 2" ~: toBE 2 0x10000 ~?= [0, 0] , "27 toBE 3" ~: toBE 4 0x12345678 ~?= [0x12, 0x34, 0x56, 0x78] , "28 fromBE 1" ~: fromBE 2 [0, 1] ~?= 0x001 , "29 fromBE 2" ~: fromBE 2 [0x78, 0x56, 0x34, 0x12] ~?= 0x7856 , "30 fromBE 3" ~: fromBE 4 [0x78, 0x56, 0x34, 0x12] ~?= 0x78563412 ]
- Disasm.hs
module Disasm where import Test.HUnit import Data.Bits import Hex reg8 = ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"] reg16 = ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"] regs = [reg8, reg16] regad = ["bx+si", "bx+di", "bp+si", "bp+di", "si", "di", "bp", "bx"] getBits :: Int -> (Int, Int, Int, Int, Int, Int, Int, Int) getBits x = (b 7, b 6, b 5, b 4, b 3, b 2, b 1, b 0) where b n = (x `shiftR` n) .&. 1 getReg :: Int -> Int -> Int -> Int getReg r e g = (r `shiftL` 2) .|. (e `shiftL` 1) .|. g modrm (x:xs) = (f mode rm, reg) where mode = x `shiftR` 6 reg = (x `shiftR` 3) .&. 7 rm = x .&. 7 f 0 6 = "[0x" ++ hex(fromLE 2 xs) ++ "]" f 0 rm = "[" ++ regad !! rm ++ "]" f 1 rm = "[" ++ regad !! rm ++ disp ++ "]" where disp = disp8 (xs !! 0) f 2 rm = "[" ++ regad !! rm ++ disp ++ "]" where disp = disp16 (fromLE 2 xs) disp8 x | x < 0x80 = "+0x" ++ hex x | otherwise = "-0x" ++ hex (0x100 - x) disp16 x | x < 0x8000 = "+0x" ++ hex x | otherwise = "-0x" ++ hex (0x10000 - x) -- DATA TRANSFER -- MOVE = Move: -- Immediate to Register [1011wreg][data][data if w = 1] disasmB (1,0,1,1,w,r,e,g) xs = "mov " ++ reg ++ "," ++ imm where reg = regs !! w !! getReg r e g imm = "0x" ++ hex (fromLE (w + 1) xs) -- Register/Memory to/from Register [100010dw][mod reg r/m] disasmB(1,0,0,0,1,0,d,w) xs | d == 0 = "mov " ++ rm ++ "," ++ reg | otherwise = "mov " ++ reg ++ "," ++ rm where (rm, r) = modrm xs reg = regs !! w !! r disasm (x:xs) = disasmB (getBits x) xs disasm' hex = disasm $ hexStrToList hex
- Main.hs
module Main where import Test.HUnit import System.IO import Hex import Disasm testDisAsm = TestList [ "1 b8 1" ~: disasm [0xb8, 0, 0] ~?= "mov ax,0x0" , "2 b8 2" ~: disasm [0xb8, 0x34, 0x12] ~?= "mov ax,0x1234" , "3 b8 3" ~: disasm' "b80000" ~?= "mov ax,0x0" , "4 b8 4" ~: disasm' "b83412" ~?= "mov ax,0x1234" , "5 b8-bf 0" ~: disasm' "b90100" ~?= "mov cx,0x1" , "6 b8-bf 1" ~: disasm' "ba1000" ~?= "mov dx,0x10" , "7 b8-bf 2" ~: disasm' "bb0001" ~?= "mov bx,0x100" , "8 b8-bf 3" ~: disasm' "bc0010" ~?= "mov sp,0x1000" , "9 b8-bf 4" ~: disasm' "bdff00" ~?= "mov bp,0xff" , "10 b8-bf 5" ~: disasm' "be00ff" ~?= "mov si,0xff00" , "11 b8-bf 6" ~: disasm' "bffeca" ~?= "mov di,0xcafe" , "12 b0-b7 1" ~: disasm' "b000" ~?= "mov al,0x0" , "13 b0-b7 2" ~: disasm' "b101" ~?= "mov cl,0x1" , "14 b0-b7 3" ~: disasm' "b210" ~?= "mov dl,0x10" , "15 b0-b7 4" ~: disasm' "b311" ~?= "mov bl,0x11" , "16 b0-b7 5" ~: disasm' "b412" ~?= "mov ah,0x12" , "17 b0-b7 6" ~: disasm' "b5ff" ~?= "mov ch,0xff" , "18 b0-b7 7" ~: disasm' "b6ee" ~?= "mov dh,0xee" , "19 b0-b7 8" ~: disasm' "b7ca" ~?= "mov bh,0xca" , "20 getBits" ~: getBits 0xbd ~?= (1,0,1,1,1,1,0,1) , "21 getReg" ~: getReg 1 0 1 ~?= 5 , "22 88-8b mod=00,r/m=000 1" ~: disasm' "8800" ~?= "mov [bx+si],al" , "23 88-8b mod=00,r/m=000 2" ~: disasm' "8900" ~?= "mov [bx+si],ax" , "24 88-8b mod=00,r/m=000 3" ~: disasm' "8A00" ~?= "mov al,[bx+si]" , "25 88-8b mod=00,r/m=000 4" ~: disasm' "8B00" ~?= "mov ax,[bx+si]" , "26 88-8b mod=00,r/m=110 1" ~: disasm' "88063412" ~?= "mov [0x1234],al" , "27 88-8b mod=00,r/m=110 2" ~: disasm' "89063412" ~?= "mov [0x1234],ax" , "28 88-8b mod=00,r/m=110 3" ~: disasm' "8A063412" ~?= "mov al,[0x1234]" , "29 88-8b mod=00,r/m=110 4" ~: disasm' "8B063412" ~?= "mov ax,[0x1234]" , "30 88-8b mod=00 1" ~: disasm' "8900" ~?= "mov [bx+si],ax" , "31 88-8b mod=00 2" ~: disasm' "8909" ~?= "mov [bx+di],cx" , "32 88-8b mod=00 3" ~: disasm' "8912" ~?= "mov [bp+si],dx" , "33 88-8b mod=00 4" ~: disasm' "891b" ~?= "mov [bp+di],bx" , "34 88-8b mod=00 5" ~: disasm' "8924" ~?= "mov [si],sp" , "35 88-8b mod=00 6" ~: disasm' "892d" ~?= "mov [di],bp" , "36 88-8b mod=00 7" ~: disasm' "893f" ~?= "mov [bx],di" , "37 disp8 1" ~: disp8 0 ~?= "+0x0" , "38 disp8 2" ~: disp8 0x7f ~?= "+0x7f" , "39 disp8 3" ~: disp8 0x80 ~?= "-0x80" , "40 disp8 4" ~: disp8 0xff ~?= "-0x1" , "41 88-8b mod=01 1" ~: disasm' "894001" ~?= "mov [bx+si+0x1],ax" , "42 88-8b mod=01 2" ~: disasm' "8949FF" ~?= "mov [bx+di-0x1],cx" , "43 88-8b mod=01 3" ~: disasm' "895202" ~?= "mov [bp+si+0x2],dx" , "44 88-8b mod=01 4" ~: disasm' "895BFE" ~?= "mov [bp+di-0x2],bx" , "45 88-8b mod=01 5" ~: disasm' "896464" ~?= "mov [si+0x64],sp" , "46 88-8b mod=01 6" ~: disasm' "896D9C" ~?= "mov [di-0x64],bp" , "47 88-8b mod=01 7" ~: disasm' "897600" ~?= "mov [bp+0x0],si" , "48 88-8b mod=01 8" ~: disasm' "897601" ~?= "mov [bp+0x1],si" , "49 88-8b mod=01 9" ~: disasm' "897F01" ~?= "mov [bx+0x1],di" , "50 disp16 1" ~: disp16 0 ~?= "+0x0" , "51 disp16 2" ~: disp16 0xff ~?= "+0xff" , "52 disp16 3" ~: disp16 0x8000 ~?= "-0x8000" , "53 disp16 4" ~: disp16 0xffff ~?= "-0x1" , "54 88-8b mod=10 1" ~: disasm' "89800001" ~?= "mov [bx+si+0x100],ax" , "55 88-8b mod=10 2" ~: disasm' "89840F00" ~?= "mov [si+0xf],ax" , "56 88-8b mod=10 3" ~: disasm' "8990FF00" ~?= "mov [bx+si+0xff],dx" , "57 88-8b mod=10 4" ~: disasm' "89920E02" ~?= "mov [bp+si+0x20e],dx" , "58 88-8b mod=10 5" ~: disasm' "89A00000" ~?= "mov [bx+si+0x0],sp" , "59 88-8b mod=10 6" ~: disasm' "89A6DD00" ~?= "mov [bp+0xdd],sp" , "60 88-8b mod=10 7" ~: disasm' "89AFBC0F" ~?= "mov [bx+0xfbc],bp" , "61 88-8b mod=10 8" ~: disasm' "89BFFFFF" ~?= "mov [bx-0x1],di" , "88-8b mod=11 1" ~: disasm' "88C0" ~?= "mov al,al" , "88-8b mod=11 2" ~: disasm' "88C1" ~?= "mov cl,al" , "88-8b mod=11 3" ~: disasm' "89C0" ~?= "mov ax,ax" , "88-8b mod=11 4" ~: disasm' "89C1" ~?= "mov cx,ax" , "88-8b mod=11 5" ~: disasm' "89C2" ~?= "mov dx,ax" , "88-8b mod=11 6" ~: disasm' "89C3" ~?= "mov bx,ax" , "88-8b mod=11 7" ~: disasm' "89D0" ~?= "mov ax,dx" , "88-8b mod=11 8" ~: disasm' "89F0" ~?= "mov ax,si" , "88-8b mod=11 9" ~: disasm' "89FF" ~?= "mov di,di" , "88-8b mod=11 10" ~: disasm' "8AC0" ~?= "mov al,al" , "88-8b mod=11 11" ~: disasm' "8AC1" ~?= "mov al,cl" , "88-8b mod=11 12" ~: disasm' "8BC0" ~?= "mov ax,ax" ] main = do runTestText (putTextToHandle stderr False) (TestList [testHex, testDisAsm]) print $ bin 0xb0 print $ bin 0xb4