JMP命令のセグメントとオフセット - HobbyOSs/opennask GitHub Wiki

JMP命令のセグメントとオフセットについて

  • はりぼてOS3日目harib00i、のJMP命令には一部「:」つなぎでアドレスを指定する謎記法が出てくる
    • これ JMP DWORD 2*8:0x0000001b
  • これに関する説明はOS自作入門の書籍において下記部分で現れる
    • 8-5: 32ビットモードへの道 p.171
    • 15: マルチタスク-1 p.294
  • p.171でははりぼてOSのメモリマップについて記載される、これはJMPで2*8:0x0000001bを指定する理由に関わる
  • p.294ではJMP命令におけるFARジャンプ(↑に現れる記法を使うとFARジャンプになる)について述べられている

このページではまずJMP命令におけるFARジャンプの仕組みと出力される機械語の仕様について備忘録を残す。

  • はりぼてOSのメモリマップについては別ページ参照

JMP命令におけるFARジャンプ

  • まず、このJMPのアドレスに「:」を使う謎記法は下記のようなオペランドが使用可能
0xEA cd | JMP ptr16:16 | オペランドで指定されるアドレスに絶対ファージャンプする
0xEA cp | JMP ptr16:32 | オペランドで指定されるアドレスに絶対ファージャンプする
0xFF /5 | JMP m16:16 | m16:16で指定されるアドレスに絶対間接ファージャンプする
0xFF /5 | JMP m16:32 | m16:32で指定されるアドレスに絶対間接ファージャンプする

実アドレスモードまたは仮想 8086 モードでの far ジャンプ :

実アドレスモードまたは仮想 8086 モードでfarジャンプを実行すると、 プロセッサはターゲット・オペランドで指定されたコード・セグメントとオフセットにジャンプする。 この場合は、ターゲット・オペランドは、 絶対farアドレスをポインタ( ptr16:16 または ptr16:32)で直接に、 またはメモリ・ロケーション(m16:16 または m16:32)で間接的に指定する。

ポインタ方式

  • 今回気になる部分はこちら

ポインタ方式では、4 バイト(16 ビット・オペランド・サイズ) または 6 バイト(32 ビット・オペランド・サイズ)の far アドレス即値を使用して、 コール先プロシージャのセグメントおよびアドレスが命令内にコード化される。

間接方式

  • 今回気になる部分はこちらではない

間接方式では、ターゲット・オペランドが 4 バイト(16 ビット・オペランド・サイズ) または 6 バイト(32 ビット・オペランド・サイズ)の far アドレスを内容とする メモリ・ロケーションを指定する。

far アドレスは、CS および EIP レジスタに直接ロードされる。 オペランド・サイズ属性が 16 である場合は、EIP レジスタの上位 2 バイトはクリアされる。

  • 「far アドレスは、CS および EIP レジスタに直接ロードされる」という部分はOS自作入門p.294でも述べられている
  • わかりやすく書くと、 JMP <CS>:<EIP> という感じで読み込まれる
    • EIPはCPUが次に実行するアドレスとなるので、 JMP DWORD 2*8:0x0000001b は次に 0x0000001b のアドレスにCPUの処理を飛ばしてなにかさせたいわけである

出力される機械語について

JMP DWORD 2*8:0x0000001b	; 66ea 1b000000 1000 ; JMP ptr16:32
                                  ^^^^^^^^  ^^^^
                                  offset    ptr16
  • 仕様書にはない 1000 が現れているが、これはセグメントアドレスであるようだ
    • 1000 は10進数で16であるところがリトルエンディアンの16進数で格納されてる
    • 1b000000 は10進数で27であるところがリトルエンディアンの16進数で格納されてる

物理アドレスは、最終的にセグメントベースとオフセットアドレスを加算した数値になります

足し算すればいいはず

  • ptr16 = 16 (=2*8)
  • offset = 27 (=0x0000001b)

43

よもやま話

  • この項はChatGPTに聞きながら書き進めたのだが、通常のシステムプログラミングではセグメントアドレスはセグメントレジスタに入れてやれば直接指定する必要はない
  • 単にセグメントアドレスを16にして、 0x0000001b にジャンプしたいだけならば下記でもよかったのではないか
MOV AX, 16
MOV DS, AX
JMP 0x0000001b
⚠️ **GitHub.com Fallback** ⚠️