LEA、Load Effective Addressは孤高な命令と思いきや、メモリアクセスする命令共には裏で気脈を通じているみたい。そしてメモリアクセスするかのごときアセンブリ言語表記だけれども、決してメモリにアクセスすることなくレジスタ操作を行うだけの命令。必須なこともあれば、避けて通ることもできる?なんだそれ。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
LEA命令
ここまで「8ビットの御先祖の影響が」といった命令が多かったx86の16ビット命令ですが、LEA命令は御先祖には関係ない8086になったればこその命令であります。Effective Address (日本語では実効アドレスと訳すことが多いと思います)を計算し、デスティネーション・レジスタに格納するもの。
その動作の理解のためには、8086のメモリ・アドレシング・モードをちょいと復習しないとなりませぬ。8086の場合、メモリの物理アドレスは以下の4つの要素を加え合わせて決定します(スタック操作のぞく。)
-
- ベースレジスタ(BXまたはBPレジスタ、不在のことあり)
- インデックスレジスタ(SIもしくはDIレジスタ、不在のことあり)
- ディスプレースメント(16ビット、符号拡張8ビット、不在の場合あり)
- セグメントレジスタを4ビット左シフトした20ビット
このうち第1から第3の要素(すべて16ビット要素)までを加え合わせた部分がEffective Address (実効アドレス)です。加え合わせた結果は16ビットです。これと第4の20ビットのアドレスを加え合わせるとようやく物理アドレス20ビットが完成するということになっとります。
プログラム的には8086は最大64Kバイトのセグメントの中の何番地、という感じでアクセスすることが多いので、実効アドレスは何番地という部分にあたることが分かります。
メモリにアクセスする場合、1と2と3の足し算自体はハードが勝手にやってくれますが、実際に何番地なのか知りたいことがままあると思います。自分でアセンブラ書いているときもあるけれど、コンパイラにお願いしているときでもあるみたい。そんなときにお役立ちなのがLEA命令というわけです。
LEA命令実験のアセンブリ言語ソース
以下LEA命令をちょこっと触ってみるだけのソースです。強力なx86用アセンブラNASM用のソースです。
segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop mov ax, edata mov es, ax test: mov bx, array0 mov si, 3 lea ax, [bx] lea ax, [bx + si] lea ax, [bx + si + 1] fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 array0: dw 8 dup (0) segment edata align=16 resb 1024 * 63 segment stack class=STACK resb 2048 stacktop:
まんなか辺にLEA命令3連発で実効アドレスを次々計算しているだけのコードです。
アセンブルして実行
MS-DOS互換で機能強化されたFreeDOS上、以下のステップで上記アセンブラソース lea.asm から実行可能なオブジェクトファイルを得て実行することができます(nasmとwatcom Cがインストール済であること。)
nasm -f obj lea.asm wlink name lea.exe format dos file lea.obj debug lea.exe
オレンジ色の枠は、BXレジスタのみを指定したベース・アドレシングのときの様子です。BXレジスタの値をAXに転送しておしまい。
赤色の枠は、BX+SIのベース+インデックス・アドレシングのときの様子です(なお[BX][SI]のような表記法と同じです。)BX+SIの結果がAXに格納されとります。
緑の枠が、BX+SI+ディスプレースメント・アドレシングのときの様子です。ディスプレースメントは1(機械語エンコード上は8ビット、符号拡張して16ビット。)BX+SI+1がAXに格納されています。
変な例外もなく、素直な良い命令じゃないか。