x86互換のアセンブリ言語に触れてみた
アセンブリの実行環境は?
Windowsではどうも学習用程度のアセンブリだとdos窓で実行できるらしい。
ファイルを指定して実行ダイアログにcmdと打ち込んでコマンドプロンプトを立ち上げる。
「debug」コマンドを打ちこむと対話モードが始まり、アセンブリの編集、実行ができるようになる。
debugコマンドの使い方
- a [オフセット]
アセンブリの記述
- g =[オフセット1] [オフセット2]
オフセット1からオフセット2までの機械語の実行
- d [オフセット1] [オフセット2]
オフセット1からオフセット2までのダンプ
- u [オフセット1] [オフセット2]
オフセット1からオフセット2までの逆アセンブル
- r (レジスタ)
(指定した)レジスタを表示、及び新しい値の格納
- t =[オフセット1] [オフセット2]
オフセット1からオフセット2までをレジスタをトレースしながら実行
- e [オフセット] (コードリスト)
メモリへ直接マシンコードの記述
- q
debugコマンドの終了
オフセットはメモリのオフセットアドレスの事。
例えば編集の場合だと -a 100と打ち込むことで
-a 100 17DF:0100 mov ax,41 17DF:0103 _
のようにメモリの100番地から書き始める事ができる。
四則演算
- 足し算
-a 100 17DF:0100 mov ax,10 17DF:0103 mov dx,20 17DF:0106 add ax,dx 17DF:0108 ;実行 -g =100 108 AX=0030 BX=0000 CX=0000 DX=0020 SP=FFEE BP=0000 SI=0000 DI=0000 DS=17DF ES=17DF SS=17DF CS=17DF IP=0108 NV UP EI PL NZ NA PE NC 17DF:0108 0000 ADD [BX+SI],AL DS:0000=CD
mov ax,10 でaxレジスタに10をコピー
mov dx,20 でdxレジスタに20をコピー
add ax,dx でaxとdxを足して解をaxにセット
-g =100 108 でメモリの100番地から108番地までを実行するという意味。
最後の3行が実行後のレジスタの状態。AXが10と20を足した後の値になっている。
ちなみに値の10、20は全て16進数。
- 引き算
-a 100 17DF:0100 mov ax,1F 17DF:0103 sub ax,06 17DF:0106 -g =100 106 AX=0019 BX=0000 CX=0000 DX=0020 SP=FFEE BP=0000 SI=0000 DI=0000 DS=17DF ES=17DF SS=17DF CS=17DF IP=0106 NV UP EI PL NZ NA PO NC 17DF:0106 01D0 ADD AX,DX
引き算はsubコマンド。1F - 06 = 19 でAXに19がセットされている。
subの第2オペランドに指定した06のような値はリテラルではなく即値と呼ぶ。
- 掛け算
17DF:0100 mov ax,10 17DF:0103 mov dx,5 17DF:0106 mul ax 17DF:0108 -g =100 108 AX=0050 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=17DF ES=17DF SS=17DF CS=17DF IP=0108 NV UP EI PL NZ NA PO NC 17DF:0108 0000 ADD [BX+SI],AL DS:0000=CD
掛け算、割り算はオペランドを一つしか指定しない。
しかも指定したオペランドが8ビットなのか16ビットなのかで違う。<8ビットの場合>
⇒AL(AXの下位8ビットを指す)と指定値を掛けて結果がAXに入る<16ビットの場合>
⇒AXと指定値を掛けて、結果の上位16ビットがDXに下位16ビットがAXに入る
16ビットを超えるを計算してみる
17DF:0100 mov ax,1FFF 17DF:0103 mov dx,10 17DF:0106 mul dx AX=FFF0 BX=0000 CX=0000 DX=0001 SP=FFEE BP=0000 SI=0000 DI=0000 DS=17DF ES=17DF SS=17DF CS=17DF IP=0108 OV UP EI PL NZ NA PO CY 17DF:0108 0000 ADD [BX+SI],AL DS:0000=CD
ちゃんと1桁繰り上がってDXに0001が入ってる。
このややこしい仕様は一体!?
こんなのがCPU毎にバラバラな上、コマンドセットとかも違うと。。。
機種依存の意味が少しわかった気がする。
メモリへの値の書き込み
17DF:0100 mov ax,4241 17DF:0103 mov [150],ax -d 150 151 17DF:0150 41 42 AB
[]で数値を囲む事によりメモリのアドレス指定となる。
レジスタaxに入れた値を[150]にコピー。(これをストアと呼ぶ)
-d で指定された範囲のダンプをとれる。
正しくセットした41と42が表示されている。ASCIIコードでいうAとB。
42と41が逆になっているのはリトルエンディアンといってx86系のメモリ管理の仕組み。
即値を直接メモリに書き込む場合はPTRコマンドを使う
17DF:0100 mov word ptr [150], 4443 17DF:0106 -d 150 151 17DF:0150 43 44 CD
書き込む値のビット長に応じてwordまたはbyteを指定する必要がある。
4443で16ビットの為、word。44だけならbyteでよい。
アセンブラは思っていたよりずっとシンプル。
コンピュータの仕組みを知るのには良いが、かなり非生産的というのがとりあえずの印象かな。