ぐだぐだ低レベルプログラミング(185)x86(16bit)、シフト、ローテイト練習(86)

Joseph Halfmoon

前回はx86命令(16bit)のうち「8086レベル」のシフト、ローテイト命令の動作を復習。コマケーところがメンドイものどもでした。前回は実機(実際はQEMUのエミュレーションだけれども)での動作確認をしなかったので、今回はデバッガで動かしながらの動作確認です。メンドイのでサラっと流していくぜ。いいのか?

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

※実機動作確認には以下を使用させていただいております。

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3
今回動かしてみるアセンブリ言語ソース

前回の命令動作の説明図を再掲させていただきます。x86SFTROTfuncs

上記の7種(ニーモニック的には8種)の命令を「テキトーに見繕ったオペランドにて」動作させてみるものが以下に。

org 100h
section .text
start:
    mov sp, stacktop
    mov bx, workb
    mov si, workw
    mov bp, sworkw
    mov word [bp], 0ABCDh
    mov ax, 1234h
    mov cx, 0004h
    mov dx, 0A5A5h
test:
    shl dx, 1
    mov dx, 0A5A5h
    sar dx, 1
    mov dx, 0A5A5h
    shr dx, 1
    nop
    rcl byte [bx], cl
    mov al, [bx]
    rcr word [si], cl
    mov ax, [si]
    rol word [bp], cl
    mov ax, [bp]
    ror     al, cl
fin:
    mov ax, 0x4c00
    int 0x21

section .data   align=16
workw:  dw  5678h
workb:  db  12h

section .bss    align=16
sworkw: resw    4
    resb    2048
stacktop:

なお、上記はMS-DOS超上位互換の FreeDOS 上の NASMアセンブラ用のソースです。NASMアセンブラはインテル式表記を受け付け、マイクロソフト社のMASMとも似てないこともない(微妙)アセンブラ(かなり強力)デス。

動作確認

上記のソースは、NASMだけでオブジェクトファイルを作れる .COM モデル用なので、以下のコマンドライン一発で実行可能なオブジェクトが得られます。

nasm sft.asm -fbin -o sft.com

動作確認は、FreeDOS上の debug コマンド(御本家 マイクロソフト社のdebugと同名で「互換」のデバッガだが、何気に超拡張されている)を使って行っております。

まずは、シフト系3兄弟から。着目すべきところに下線を引いてあります。x86SFTdebug

まず赤線が、左論理シフトSHL命令です。実際には左算術シフトSAL命令と同じ動作となりますが。DXレジスタの値を1ビット左シフトしてます。その際、CY(キャリーフラグ)がNC(0)からCY(1)へと変化していることをご確認くだされ。

お次は青線の算術右シフト命令です。これまた1ビットシフト形式。DXレジスタの値を右シフトしていますが、算術右シフトなので、DXレジスタのMSBの値は1のまま維持されます。LSBからシフトアウトされた値はCYに入りますが、元が1だったので変化なしです。

3つ目黄色は論理右シフト命令です。上の算術右シフトと同じ値に対して作用していますが、MSBには0がシフトインされてくるので結果のDXの値は異なることになります。

つづいてキャリーを含めるローテイト命令2つ。x86RCLRCRdebug

CISCらしく、メモリオペランドをとる命令としてあります。またシフト回数はCLレジスタに格納されている値を使う形式です。

赤線のRCL命令は、DS:0142h 番地に置かれた値 0x12 をキャリーフラグを含めた左ローテイトする命令です。0x12の下ニブルの0x2が結果の上位ニブルとなり、0x12の上位の0x1の1がCYフラグに追い出されることになります。また、ローテイト開始時点でCY=1であったので、その値が巡り巡ってメモリ上の0x28のビット3を立てることになってます。

青線のRCR命令は、ワード(繰り返しますがx86では16ビットです)幅であること、右ローテイトであることを除けば動作は「以上と」同文っす。

つづいて「キャリーを含めない」ローテイト2つ。x86ROLRORdebug

ここで注意するのは、「キャリーを含めない」のはローテイトするデータに対してであって、CYフラグとOV(オーバフロー)フラグは影響を受けることです。x86に精通されている姉貴兄貴の皆さんはよくご存じのとおり、x86で何か演算すれば漏れなくフラグに影響するのです。その辺の副作用を抑えたモダンなRISCとは設計思想が異なります。

上記の上の赤字は左ローテイトのROL命令です。メモリ上におかれた0xABCDを4ビット左ローテイトしているので結果が0xBCDAになってます。この処理の副作用としてCYがクリアされ、OVがセットされておると。

青地の方はレジスタALに対するバイト幅の右ローテイトです。4ビットのローテイトなので、ちょうど上下のニブル(4ビット)が入れ替わった形。

アセンブラ書いている分には何やらいろいろ使えそうな命令どもだが、C書いていたら<<と>>くらいしかないからなあ。活用はライブラリやコンパイラにお任せ?他の命令もお任せっちゃお任せか。

ぐだぐだ低レベルプログラミング(184)x86(16bit)、シフト、ローテイト(86のね) へ戻る

ぐだぐだ低レベルプログラミング(186)x86(16bit)、ASCII ADJUST一族 へ進む