過去回でRISC-VやArmのアセンブラしていた時、やたらとこの命令はあの命令のエイリアス(別名)なんてことに遭遇してました。でもエイリアスはRISCどもの専売ではありませぬ。歴史を誇るx86にもしっかりエイリアスが存在してます。まあね、ちょこっとだけれども。エイリアスのお名前はみんな知ってるNOPじゃと。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
XCHG命令
どこかと別のどこかの内容を交換するXCHG命令(スワップ)は、XCHG命令が無かったとすると同じことを行うのに最低3命令が必要になる命令です(昔は一時退避場所など使わぬのがプロっぽいコードだったが、現代のプロセッサではそうでもない?奥深いのう。。。)
XCHGは、動作としては分かり易い命令ではあるものの、以下の意味でCISC的な命令です。
-
- 1命令で2か所に書き込みする必要がある
- そのうちの1か所をメモリ上の変数にしてもよい
そんな「CISCらしい」XCHG命令は、x86上でのNOP命令をも担ってます。第1バイトのオペコードマップ(部分)を見ると以下のようです。
つまり、AXとAXを交換するXCHG AX, AX命令こそが、NOPの実体であると。
また例によってオペコードの長さにえこひいきがキツイ命令でもあります。AXレジスタと他の「汎用」レジスタとの間の16ビットデータの交換は1バイト命令ですが、8ビットレジスタ間の交換は2バイト命令です。一方2バイト命令使えばメモリ上の変数とレジスタ間の交換もできます。AX=アキュムレータ優遇は時々でてくる御先祖との互換性のしがらみだと思います。知らんけど。
XCHG命令実験のアセンブリ言語ソース
以下XCHG命令をちょこっと触ってみるだけのソースです。強力なx86用アセンブラNASM用のソースです。ここで以下の2つが並んでいる部分があることをご注意くだされ。
-
- xchg ax, cxとxchg cx, ax
- xchg [bx], axとxchg ax, [bx]
x86のオペコードのエンコーディングからすると、1の例では1バイト命令と2バイト命令、2の例では後者のみ正しい書き方という解釈になりますが、NASM(多分他のアセンブラも)意味をくみ取って解釈してくれるので1バイトで書ける命令を2バイトにしたり、オペランドの順番に目くじらたててエラーにしたりはしません。ただし、オブジェクトコードからアセンブリコードを復元するディスアセンブラには伝わらない、ことを後で見るでしょう。
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 ax, 0x1234 mov cx, 0x5678 mov dx, 0x9ABC nop xchg ax, cx xchg cx, ax xchg dh, dl mov bx, v0 xchg [bx], ax xchg ax, [bx] fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 v0: dw 0xCDEF resb 1024 * 63 segment edata align=16 resb 1024 * 63 segment stack class=STACK resb 2048 stacktop:
アセンブルして実行
MS-DOS互換で機能強化されたFreeDOS上、以下のステップで上記アセンブラソース xchg.asm から実行可能なオブジェクトファイルを得て実行することができます(nasmとwatcom Cがインストール済であること。)
nasm -f obj xchg.asm wlink name xchg.exe format dos file xchg.obj debug xchg.exe
debugはオブジェクトの中に埋め込まれたシンボルやソースを使うわけでなく、オブジェクトコードそのものを素直に逆アセンブルするタイプのデバッガです。よってアセンブラソースではXCHG CX, AXと書かれていたコードがXCHG AX, CXとなってます。
まずは、オペコード 0x90 の XCHG AX, AXがNOPとして働くところを観察。以下の赤色のところが主に関係する部分です。
AXとAXの内容を交換しても何も変わったように見えんわね。時間を使うだけの(XCHGは2回レジスタに書き込むので8086/8088では単純なMOVよりも1サイクル時間は長くなる)NOP。
つづいてAXとCXの内容を交換2回。優遇されている1バイトのオペコードで出来てますな。
つづいて、8ビットのレジスタDHとDLを交換っと。注目するのはDX(DXの上8ビットがDH、DXの下8ビットがDL。)
ただし、バイト操作は2バイト命令になってますな。。。
しっかりXCHGできとるようです。当たりまえか。