ぐだぐだ低レベルプログラミング(194)x86(16bit)、LEA 実効アドレス

Joseph Halfmoon

LEA、Load Effective Addressは孤高な命令と思いきや、メモリアクセスする命令共には裏で気脈を通じているみたい。そしてメモリアクセスするかのごときアセンブリ言語表記だけれども、決してメモリにアクセスすることなくレジスタ操作を行うだけの命令。必須なこともあれば、避けて通ることもできる?なんだそれ。

※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら

※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3
LEA命令

ここまで「8ビットの御先祖の影響が」といった命令が多かったx86の16ビット命令ですが、LEA命令は御先祖には関係ない8086になったればこその命令であります。Effective Address (日本語では実効アドレスと訳すことが多いと思います)を計算し、デスティネーション・レジスタに格納するもの。

その動作の理解のためには、8086のメモリ・アドレシング・モードをちょいと復習しないとなりませぬ。8086の場合、メモリの物理アドレスは以下の4つの要素を加え合わせて決定します(スタック操作のぞく。)

    1. ベースレジスタ(BXまたはBPレジスタ、不在のことあり)
    2. インデックスレジスタ(SIもしくはDIレジスタ、不在のことあり)
    3. ディスプレースメント(16ビット、符号拡張8ビット、不在の場合あり)
    4. セグメントレジスタを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

実行結果の肝心要の部分が以下に。LEAcom

オレンジ色の枠は、BXレジスタのみを指定したベース・アドレシングのときの様子です。BXレジスタの値をAXに転送しておしまい。

赤色の枠は、BX+SIのベース+インデックス・アドレシングのときの様子です(なお[BX][SI]のような表記法と同じです。)BX+SIの結果がAXに格納されとります。

緑の枠が、BX+SI+ディスプレースメント・アドレシングのときの様子です。ディスプレースメントは1(機械語エンコード上は8ビット、符号拡張して16ビット。)BX+SI+1がAXに格納されています。

変な例外もなく、素直な良い命令じゃないか。

ぐだぐだ低レベルプログラミング(193)x86(16bit)、86のNOPはXCHGの別名? へ戻る

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です