実行方法
アセンブリの開発環境
さて、まずはアセンブリ言語を記述してコンピュータに実行させるために
アセンブリを書くための環境を整えましょう
あなたが、MASM などのアセンブラを持っているならばそれを使ってもかまいません
いざとなれば、Cコンパイラのインラインアセンブラでも良いです
この場合はコンパイラに依存するので、このサイトの多くのソースは正常に動作しない
また、Cのインラインアセンブラはアセンブラと異なり、Cと共同で使うため
通常のアセンブラでは存在しない、いくつかの制約などもあります(コンパイラのマニュアルをご覧ください)
しかし、一番簡単なのはMS-DOSを使うことです
この講座も、基本的にはMS-DOSか純粋なアセンブラを使っていることを想定します
DOS窓を開くか、あるいは起動ディスクをFDに挿入して再起動してください
MS-DOSにはDEBUGコマンドというコマンドが存在します
このコマンドは、本来デバッグを行うことが目的のコマンドなのですが
ずばりアセンブラを記述することができる開発環境にもなるのです
なんとなく、こんな感じの環境でアセンブリ言語を記述します
エディタなど、とくに必要なものはありません
DEBUGコマンドを入力した後、さらにコマンドの入力を促されます
これが、アセンブリ言語を記述したり実行するための環境になります
DEBUGコマンドは、すでに存在している実行ファイルを読みこむこともできます
DEBUG [ファイル名]
このようにファイルを指定した場合は、そのファイルがメモリに読みこまれます
その後、ファイルの内容などを編集することも可能です
当然、編集するにはアセンブリ言語や機械語の知識が必要です
アセンブリを書く
あなたが、何らかのアセンブラなどの開発環境を用いるのなら
付属のエディタや、メモ帳などの使いなれたエディタでアセンブリ言語を記述し
使用しているアセンブラのマニュアルにしたがってアセンブルすれば良いだけです
MS-DOSでは、アセンブリ言語の記述もDOSでおこないます
エディタとは違い、直接メモリにアセンブリを記述してそれを実行します
アセンブリ言語の場合は、非常に命令が細かいため
それなりの形にまで整えないと、実行できるまでになりません。これは、学習には不向きといえます
しかし、MS-DOSのDEGUBコマンドはメモリのXX番地からXX番地までを実行させることができます
これは、非常に学習にも適し、一つ一つの命令を確実に覚えていくことができます
アセンブリを書くには DEBUG コマンドの A(Assembly) コマンドを指定します
Aコマンドは、メモリの何番地からアセンブリを記述するかを指定します
A [アドレス]
アドレスを指定すると、そのアドレスからアセンブリを記述します
通常は 0100 からプログラムを書き始めます
C:\WINDOWS>DEBUG
-A 100
15F2:0100 _
という状態になりますので、ここからアセンブリを書くことができます
15F2:0100 というのは、メモリアドレスです
最初の 15F2 という部分は実行ごとに異なるので違う数字になるでしょう
メモリアドレスとアセンブリの関係については、後ほど詳しく解説します
なにも書かないでEnterキーを押すと、このモードを終了します
DEBUGコマンドを終了する
このコマンドを終了するには Q (Quit) コマンドを指定します
Aコマンドで記述したアセンブリプログラムは保存されません
Qコマンドで DEBUG を終了した場合、メモリに記録されていたプログラムは消滅します
//実際は、上書きされるまで残っています
ある程度実用的なプログラムを記述できるようになれば
ディスクに実行ファイルとして保存する方法も紹介します
C:\WINDOWS>DEBUG
-Q
C:\WINDOWS>
まずは、これからお世話になるDEGUBコマンドの基本操作を覚えてください
プログラムを実行する
Aコマンドで記述したアセンブリや、メモリの機械語を実行するには
G (Go) コマンドを使用します
アセンブリは高級言語とは違い、単体の命令だけでは非常に不完全なプログラムです
そのため、開発中のデバッグ作業は全体としてプログラムを実行するのではなく
メモリのアドレスA〜B番地までを実行するような方法がとられます
G [=開始アドレス] [終了アドレス]
このコマンドを実行すると、開始アドレスから終了アドレスまでのプログラムを実行します
アセンブリ言語は高級言語のような安全性はありません
誤ったプログラムを実行すると、プログラムがクラッシュするので気をつけてください
まぁ、C言語などを経験している人ならば良くわかっていると思います
アドレスについては、後ほど詳しく説明します
今は、Gコマンドでプログラムを実行することができるということを知ってください
T (Trace) コマンドでプログラムを実行させることもできます
これは、あるアドレスから命令ステップ数で実効範囲を指定します
T [=開始アドレス] [命令数]
T コマンドは G コマンドと異なり、命令を実行するごとにレジスタの内容を出力します
さらに、次に実行する命令を出力します
次の画面は、アセンブリ言語でプログラムを記述し
それを、Gコマンド及びTコマンドで実行しています
Aコマンドで記述しているアセンブリ言語の詳細は次の章から説明していきます
今は命令の意味よりも、プログラムの実行方法を覚えてください
C:\WINDOWS>DEBUG
-A 0100
15F2:0100 MOV AX,0123
15F2:0103 MOV [0200], AX
15F2:0106
-G =100 106
AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=15F2 ES=15F2 SS=15F2 CS=15F2 IP=0106 NV UP EI PL NZ NA PO NC
15F2:0106 E8B1E8 CALL E9BA
-T =100 2
AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=15F2 ES=15F2 SS=15F2 CS=15F2 IP=0103 NV UP EI PL NZ NA PO NC
15F2:0103 A30002 MOV [0200],AX DS:0200=0123
AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
DS=15F2 ES=15F2 SS=15F2 CS=15F2 IP=0106 NV UP EI PL NZ NA PO NC
15F2:0106 E8B1E8 CALL E9BA
Gコマンドは、15F2:0100〜15F2:0106までのアドレスを実行しています
終了アドレスまでの命令を実行し終わると、各種レジスタの内容を出力します
AX= とか、BX= というのがそうです。レジスタについては次の章で説明します
15F2:0106 E8B1E8…、というのは、終了アドレスの次の命令です
この部分は、まだプログラムしていない部分なので保証されていません
Tも同様にレジスタのないようと次の命令をコンソールに出力しますが
Tコマンドは、命令ステップごとにこれらの情報を出力します
逆アセンブル
アセンブリ言語を機械語に変換する行為をアセンブルと呼びましたが
この過程を逆にたどる、機械語からアセンブリ言語への変換を逆アセンブルと呼びます
アセンブリを熟知しているのならば、リバースエンジニアリングに応用できます
DEBUGコマンドは、逆アセンブルもサポートしています
指定したプログラムや、その場で記述したプログラムを逆アセンブルできます
逆アセンブルは U (UnAssemble) コマンドでおこないます
U [開始アドレス] [終了アドレス]
開始アドレスから、終了アドレスまでの機械語を逆アセンブルします
-A 100
15F2:0100 MOV AX, 0123
15F2:0103 ADD AX, 1234
15F2:0106
-U 100 105
15F2:0100 B82301 MOV AX,0123
15F2:0103 053412 ADD AX,1234
このようになります
逆アセンブルしたデータの 15F2:0100 B82301 ですが
15F2:0100 は、命令が格納されているアドレスであるということはわかると思います
その後の、B82301 という16進数の列はなんでしょう?
これが、まさにプログラムの真髄機械言語そのものです
MOV AX,0123 を機械語に訳すと B82301 というコードになっているのです
すなわち、1011 1000 0010 0011 0000 0001 という2進コードに変換されています
メモリダンプ
メモリに格納されているバイナリデータを表示することを「ダンプ」というのはご存知でしょう
DEBUGコマンドは、このダンプ機能も存在します
より低水準なプログラムをおこなうのに、バイナリエディタは欠かせないですね
メモリダンプをおこなうには、D (Dump) コマンドを使用します
このコマンドは、メモリの内容を16進数とキャラクタコードで出力します
D [開始アドレス] [終了アドレス]
開始アドレスから終了アドレスまでのメモリのデータをコンソールに表示します
-A 100
15F2:0100 MOV AX , 41
15F2:0103 MOV DX , 42
15F2:0106
-D 100 105
15F2:0100 B8 41 00 BA 42 00 .A..B.
これがメモリダンプです
左に表示されているアドレスを先頭に、1バイトずつ表示されます
B8 41 00 BA…というのが、メモリのデータを16進数として表示したものです
右の .A..B. というものは、メモリのデータをキャラクタコードで表示したものです
通常のバイナリデータは意味のある文字になりませんが、今回はわざとコードを指定しました
16進数 41 がASCIIコードの 'A' にあたることは、すでにご存知のとおりでしょう
また、バイナリエディタのように16進コードを挿入することができます
バイナリの挿入には E (Enter) コマンドを使用します
E アドレス [コードリスト...]
アドレスを先頭にコードリストで指定した16進数を挿入します
-E 100 B8 FF 00
-U 100 102
15F2:0100 B8FF00 MOV AX,00FF
Eコマンドで機械語を直接入力しています
なぜか、FF と 00 の位置が逆になっていますが、これはIntelプロセッサの特徴のひとつです
C言語を習得している方では、すでにご存知の人も多いでしょうが、後ほど説明します