Assyのリベラル文学研究所もご覧ください。

x86アセンブラ

レジスタ

メモリはバスを介してCPUにつながれているが、このメモリとは別にCPU内部にもメモリがあり、「レジスタ」と呼ばれている。
レジスタの基本的な操作は、具体的には次の3つである。
1.メモリやI/Oからレジスタにデータを転送する
2.レジスタに記憶されているデータに対して演算を行う
3.レジスタからメモリやI/Oにデータを転送する
マシン語のプログラムは、これだけのことの組合せにすぎない。どんなに複雑な処理でも、この3つの操作を組み合わせることで実現している。

ポインタ

レジスタはデータを記憶したり演算を行なったりすることができるが、その応用としても1つ大事な機能がある。それはレジスタに記憶されているデータによってメモリのアドレスを指定することだ。
これはCPUの動作のメカニズムにとって重要なことで、この機能によってCPUの動作が実現されるといっても過言ではない。CPUがマシン語命令をメモリから読み込む際に指定するアドレスも、実はあるレジスタに記憶されているデータなのだ。
アドレスを指定するためにレジスタに記憶された値を使うことを、「ポインタとして使う」と言う。

レジスタ

AX, BX, CX, DXの4つのレジスタは、16ビットのレジスタとして使用するだけでなく、その上位・下位をそれぞれ8ビットのレジスタとして単独で使用することもできる。AXレジスタの上位8ビットには「AH」、下位8ビットには「AL」の略号がつけられている。
これらのレジスタはデータを記憶しておいたり、種々の演算に使用することのできる汎用レジスタであるが、各レジスタとも特有の機能を持っており、それらのレジスタと組み合わせて使う命令が決まっている。

  • AX
    • アキュムレータ
    • 各種の演算(他のレジスタより高速)
    • 乗除算
  • BX
    • ベースレジスタ
    • 特定のメモリを指し示すポインタ
  • CX
    • カウントレジスタ
    • 転送や繰り返しの回数を数えるカウンタ
  • DX
    • データレジスタ
    • データの一時記憶用
    • AXと組み合わせて、32ビットの乗除算

そのほか、インデックスレジスタ群(特殊レジスタ群)、セグメントレジスタ群、フラグレジスタなどが存在する。

スタックとポップ

スタックは上へと積んでいき、上から取り出していく、本を積んでいくような考え方で、データを格納する際にそのメモリ領域のアドレスをまったく意識する必要がない。単純な仕組みであるにも関わらず、さまざまな使い道がある。

セグメント

16ビットCPUでは、アドレスの指定を「セグメント方式」で行う。アドレス部は「32AE:0100」といったように、セグメントアドレスとオフセットアドレスに分割される。セグメントベースを固定して考えるならば、オフセットアドレスだけでアドレスを指定することができる。物理アドレスは、セグメントアドレスによって決まるセグメントベースにオフセットアドレスを加えた値になる。
セグメントの例:

-A 0100 (オフセットアドレス0100Hからアセンブルする)
3A9F:0100 MOV AH,1
3A9F:0102 INT 21
3A9F:0104 CMP AL,0D
3A9F:0106 JZ 0111
3A9F:0108 MOV AH,9
3A9F:010A MOV DX,0180
3A9F:010D INT 21
3A9F:010F JMP 0118
3A9F:0111 MOV AH,9
3A9F:0113 MOV DX,01C0
3A9F:0116 INT 21
3A9F:0118 INT 20
3A9F:011A

ここではセグメントアドレスは3A9Fであり、オフセットアドレスは0100から始まる。
注意:ジャンプ先のアドレスは本来分からないはずだが、ここではあらかじめ調べてある。このようなプログラムでは、ラベルを使用できるMASMを使うのが普通である。

MOV命令

MOV 受け取る側, 送り出す側

データの転送(UNIXDOSのコマンドとは方向が逆になる)

MOV AL, 0FFH

1バイトのデータFFHをALレジスタにロードする

MOV [0201H], AL

ALレジスタの内容をオフセットアドレス「201H」にストアする

MOV AL, [0201H]

オフセットアドレス「201H」のメモリの内容をALレジスタにロードする

MOV [0401H], AL

ALレジスタの内容をオフセットアドレス「401H」のメモリにストアする
特定の場所にデータを記憶しておきたい場合などは、MOV XXやMOV [XX]が大活躍します。メモリのことをなぜメモリ(記憶)というのかが良く分かります。

演算・比較命令

ADD AL, 40H

ALレジスタの内容に1バイトデータ「40H」を加える

SUB AL, 20H

ALレジスタの内容から1バイトデータ「20H」を引く

INC AL

ALレジスタをインクリメントする(+1)

DEC AL

ALレジスタをデクリメントする(-1)

CMP AX, XX

AXレジスタの内容と1ワイドデータ「XX」を比較し、
結果をフラグレジスタにセットする

MUL BL

ALレジスタの内容(8ビット)にBLレジスタの内容(8ビット)を掛け、
結果をAXレジスタ(16ビット)にセットする

MUL BX

AXレジスタの内容(16ビット)にBXレジスタの内容(16ビット)を掛け、
結果をDX:AXレジスタ(32ビット)にセットする

DIV BL

AXレジスタの内容(16ビット)をBLレジスタの内容(8ビット)で割り、
商をALレジスタ(8ビット)に、余りをAHレジスタ(8ビット)にセットする

DIV BX

DX:AXレジスタの内容(32ビット)をBXレジスタの内容(16ビット)で割り、
商をAXレジスタ(16ビット)に、余りをDXレジスタ(16ビット)にセットする

ジャンプ命令

JMP XX

オフセットアドレス「XX」からのプログラムを実行する(無条件ジャンプ)

JZ XX

ZFがセットされていれば、オフセットアドレス「XX」からのプログラムを実行する
これ以外にも、「CMP AL,0DH」という命令の後ならば、次のような条件ジャンプ命令を使うことができる。

JZ XX

(AL=0DH)ならばジャンプする

JNZ XX

(AL≠0DH)ならばジャンプする

JB XX

(AL<0DH)ならばジャンプする

JA XX

(AL>0DH)ならばジャンプする

JBE XX

(AL≦0DH)ならばジャンプする

JAE XX

(AL≧0DH)ならばジャンプする
ここに示した条件ジャンプ命令は、比較した2つの値をそれぞれ符号なしの1バイトデータとみなした場合の命令だ。これに対して、1バイトのデータを符号ありと考えた場合の条件ジャンプ命令も用意されている。それを以下に挙げる。(つまり、負の数を扱う場合の条件ジャンプ命令。)

JL XX

(AL<0DH)ならばジャンプする

JG XX

(AL>0DH)ならばジャンプする

JLE XX

(AL≦0DH)ならばジャンプする

JGE XX

AL≧0DH)ならばジャンプする
ループ命令
コマンド 命令

LOOP XX

CXレジスタ(カウントレジスタ)の内容をデクリメントし、
0でなければオフセットアドレス「XX」へジャンプする

サブルーチン

CALL XX

オフセットアドレス「XX」から始まるサブルーチンを呼び出す

RET

サブルーチンを呼び出したCALL命令の次の命令に戻る

スタックポインタ命令

PUSH AX

スタックポインタ(SP)を2減らし、
その値をオフセットアドレスとするスタック領域にAXレジスタの内容を退避

POP AX

スタックポインタの値をオフセットアドレスとするスタック領域から
AXレジスタに1ワードデータを復帰し、スタックポインタに2を加える

論理演算命令

AND AL, XX

ALレジスタと1バイトデータ「XX」のANDをとり、
結果をALレジスタに残す

OR AL, XX

ALレジスタと1バイトデータ「XX」のORをとり、
結果をALレジスタに残す

入出力命令

IN AL, XX

ポートXXから入力されるデータを、
ALレジスタに、格納せよ

OUT XX, AL

ALレジスタにの内容を、
ポートXXに、出力せよ
ブザーはポートアドレス「37H」のOUTポートに接続されている。ポートアドレス「37H」はブザーを鳴らすためだけに用意されているわけではなく、ビット1と2が「1」のときにブザーは機能し、ビット0がブザーをON/OFFするスイッチとなる。
ブザーを鳴らすには、16進で「06H」という値をポート「37H」に出力し、止めるには16進で「07H」という値を同じポートに出力すれば良い。
ブザーをONにする(鳴らす)には、

MOV AL,06
OUT 37,AL

とし、ブザーをOFFにするには、

MOV AL,07
OUT 37,AL

とする。

ファンクションコール

ソフトウェア割り込みは、

INT XX

XX番のソフトウェア割り込み命令を実行する
という形式で表す。
割り込みタイプ20Hのソフトウェア割り込みは、「プログラム終了」のシステムコール
割り込みタイプ21Hのソフトウェア割り込みを使うことで、MS-DOSの機能を使うことができる。ファンクションコールでは、AHレジスタにファンクション番号を入れて目的の機能を指定する。

MOV AH, XXH
INT 21H

MS-DOSのファンクションXXの機能を
ソフトウェア割り込みにより呼び出す

よく使われるファンクション

以下は良く使われるファンクション。

01H

キーボードからの1文字入力とエコー表示
入力された文字をALレジスタに返す

MOV AH, 01H
INT 21H

02H

スクリーンへの1文字出力
DLレジスタの内容をスクリーンに表示する

MOV AH, 02H
MOV DL, キャラクタコード
INT 21H

06H

コンソールからの直接入力
DLレジスタに「FFH」をセットすると入力、
それ以外ではその文字をスクリーンに出力する

MOV AH, 06H
MOV DL, XXH
INT 21H

09H

スクリーンへの文字列
DXレジスタの内容をオフセットアドレスとするメモリから
連続するメモリの内容を文字列として出力する。
文字列の最後は"$"で指定する

MOV AH, 09H
MOV DX, XXXXH
INT 21H

0AH

コンソールからの文字列入力(バッファード・キーボード入力)
キーボードから1行入力し、
DXレジスタの内容をオフセットアドレスとするメモリに格納する

MOV AH, 0AH
MOV DX, XXXXH
INT 21H

マクロアセンブラ

マクロアセンブラ(MSAM)によって、ラベル(START:など)を使ったり、数値の豊かな表現('A'など)を使ったりすることができる。(注意:ここまでの記述はDEBUGコマンドにおける記法である)

START:

のように「:」が付いているのがラベルだ。ラベルはその次の命令が格納されているアドレスを意味する。ラベルを使うことで、ラベルに対応するアドレスを自動的に決定してくれる。