ぐだぐだ低レベルプログラミング(236)x86(16bit)、80186/80286追加命令

Joseph Halfmoon

長らく8087FPUの命令の練習を続けてきましたが、前回にて一応の完了といたしたいと思います(本人まだやる気ですが別シリーズ化の予定。)今回から32ビット、とも思いましたが、x86(16bit)範疇にはまだまだ命令が存在します。80186と80286で追加された命令どもです。なかなか32ビットモードに入れんぞなもし。

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

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

    •  Windows 11 PC (i5-1235U)
    •  Ubuntu 24.04 LTS on WSL2
    •  QEMU 8.2.2
    •  FreeDOS 1.3
現在までに練習してきた命令の範囲

x86(x64)は、広大無辺な命令セットを3つの世界に散りばめております。

    1. インテル8086を起源とする16ビット世界
    2. インテル80386を起源とする32ビット世界
    3. AMD64を起源とする64ビット世界

ここまで「1」のカテゴリを x86(16bit)と題して練習してきたつもりであったのですが、練習済の範囲は以下のようです。

    • 8086/8088の命令セット
    • 8087の命令セット

8086と8088の命令セットは同一、違いはバス幅とプリフェッチ・キューの深さのみです(蛇足ですが、8086のプリフェッチキュー2バイト分の面積を潰して、バス幅が常に8ビットになるように細工を施したものが8088デス。)

一方8087のFPU命令セットも、後継機種(80387など)が追加されるにつれ「拡張」されてますが、今までの練習では原則8087範囲といいつつ、メンドイところ(三角関数とか)は80387範囲にはみだして練習してしまってます。

さてまだ16ビット世界には残りがあります。

    1. 80186/80286に共通の拡張命令群
    2. 80286で導入された16ビット・プロテクトモードの命令群

「1」のカテゴリの命令は、8086/8088には無い命令ですが、長らく後継機種で活用されるものどもなので、飛ばすわけにもいきませぬ。

「2」のカテゴリの命令は、今やx86の黒歴史的な扱いでアプリケーションレベルではお目にかかることはないかと思います。しかしOSやBIOSによっては今でもブートの奥底に潜んでいるかもな命令どもデス。

今回は次回以降、そそくさと練習するつもりの命令共の一覧を掲げたいと思います。

80186/80286に共通の拡張命令群

この範疇の命令どもが以下に。

mnemonic 命令動作
ENTER プロシージャに入る(スタックフレーム生成)
LEAVE プロシージャを去る(スタックフレーム消去)
BOUND 配列アクセスの検証命令
INS ブロック入力
OUTS ブロック出力
PUSHA 汎用レジスタを全てプッシュ
POPA 汎用レジスタを全てポップ
PUSHI 即値のプッシュ
IMUL immS 符号付即値の掛け算、結果は16ビット
shift/rotate imm 即値指定のシフト、ローテイト

32ビット以降でも使われている命令もあり、そうでない命令もあり。上記テーブルの先頭部分におかれたENTER/LEAVE命令などは、「セマンティック・ギャップ」が問題と叫ばれていたころに、PASCALコンパイラなどのコード生成で使われているのを見た記憶があります(いつの時代だ?) しかし、最近は使っているのを見ないなあ、残念。因みにENTER/LEAVE命令については186以降の拡張命令なのですが、x86の「標準的なスタックフレーム」を説明するのにドンピシャな命令であるので、以下の過去回で先走って既に練習済です。

ぐだぐだ低レベルプログラミング(199)x86(16bit)、ENTER、LEAVEその1

ぐだぐだ低レベルプログラミング(200)x86(16bit)、ENTER、LEAVEその2

次回以降、残りいくつかを16ビット環境で練習して、お茶を濁したいと思います。

80286で導入された16ビット・プロテクトモードの命令群

80286において導入されたプロテクトモードは、x86に4層の特権構造に基づく保護機構を導入した上で、仮想記憶も構築してくれる当時過激な「新モード」でした。ただし、286時点では16ビットの処理であり、メモリモデルはセグメンテーションのみです。

80386以降、プロテクトモードの中で32ビットのセグメントという新概念が有効となった上で、そのセグメント内でさらにページング機構によりメモリマネージメントを行う仕組みができました。すると多くのオペレーティング・システムはメンドクさいセグメンテーションの仕組みを後ろに隠し(無くなったわけではなく、初期設定時に通り抜けるのですが)、「32ビットのフラットでリニアな」メモリ空間の中で32ビットのネイティブ・アプリケーションを動かすようになりました。以降、セグメンテーションによるプロテクトモードは忘れ去られていきます。しかし、ハードウエアの奥底に隠れており、OSやBIOSのシステムブート時にこっそり動いていたりするみたいです。

この範疇の命令どもが以下に。

mnemonic 命令動作 リアルモードでの実行可否
LMSW MSWへのロード 実行可能
SMSW MSWのストア 実行可能
LGDT GDTRへのロード 実行可能
SGDT GDTRのストア 実行可能
LLDT LDTRへのロード #UD
SLDT LDTRのストア #UD
LIDT IDTRへのロード 実行可能
SIDT IDTRのストア 実行可能
LTR TRへのロード #UD
STR TRのストア #UD
VERR 読み取り可能か検証 #UD
VERW 書き込み可能か検証 #UD
LAR アクセス権バイトのロード #UD
LSL セグメントリミットロード #UD
ARPL 特権レベルの調整 #UD
CLTS TSフラグのクリア 実行可能

上記の命令どものうち限られたいくつかは、RESET時のデフォルトである16ビット・リアルモードから、プロテクトモードへ遷移するのに必要なので、リアルモードでも実行可能です。一方、上記で#UDと書かれた命令共は、リアルモード実行中では無用の命令どもで、実行すると未定義命令例外を引き起こすことになります。

こいつ等の練習は、ちょっとメンドイ。多分、すごくメンドイ。特にFreeDOS上で練習するのはどしたら良いの?まあ、考えてみるのが練習か。大丈夫か。

ぐだぐだ低レベルプログラミング(235)x86(16bit)、FSAVE、全レジスタセーブ へ戻る

コメントを残す

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