web-dev-qa-db-ja.com

8086-イミディエートデータをセグメントレジスタに移動できないのはなぜですか?

8086アセンブリプログラミングでは、データをセグメントレジスタにロードするには、まず汎用レジスタにデータをロードしてから、この汎用レジスタからセグメントレジスタにデータを移動する必要があります。

直接ロードできないのはなぜですか?許可されない特別な理由はありますか?

違いは何ですか mov ax,5000Hおよびmov ax,[5000H][5000h]メモリ位置5000hのコンテンツを意味しますか?

17
Rijo Joseph

アセンブリ言語(任意のアセンブリ)の構文は、機械語を書くための人間が読める形式にすぎないことを忘れないでください。マシンコードで実行できるルールは、アセンブラ構文が簡単にサポートできるものではなく、プロセッサの電子機器がどのように設計されたかによって異なります。

だから、あなたがmov DS, [5000h]を書くことができるように見え、概念的にはそれを行うことができないはずの理由がないように見えるからといって、それは本当に「プロセッサは、メモリ位置のコンテンツからセグメントレジスタをロードできますか?」

8086アセンブリの場合、理由は単純に、エンジニアがメモリI/Oデータラインからセグメントレジスタに書き込むラインに信号を送ることができる電気パスを作成しなかったためだと思います。


どうして?私にはいくつかの理論がありますが、信頼できる知識はありません。

最も可能性の高い理由は、単純に設計を単純化することの1つです。それを行うには、追加の配線とゲートが必要です。また、チップ内の不動産に値しないほど珍しい操作(これは70年代)です。これは驚くべきことではありません。 8086はすでに使用されており、通常のレジスタのいずれかをALU(算術論理演算ユニット)に接続して、レジスタをアキュムレータとして使用することができます。安くはなかったと思います。当時のほとんどのプロセッサは、その目的で使用するために1つのレジスタ(theアキュムレータ)のみを許可していました。

セグメントレジスタをメモリ読み取りから書き込むことを許可すると、回路で正しく理解するのが困難ないくつかの奇妙なエッジケースが発生した可能性もあります。結局のところ、書き込まれるセグメントレジスタは、ソースオペランドをアドレス指定するために使用される可能性があります。


括弧に関する限り、あなたは正しいです。メモリ位置5000hに数値4321hが含まれているとしましょう。 mov ax, 5000hは値5000hをaxに入れ、mov ax, [5000h]は4321hをメモリからaxにロードします。基本的に、角かっこはCの*ポインター逆参照演算子のように機能します。

アセンブリがマシンコードで実行できることの理想的な抽象化であるという事実を強調するために、2つのバリエーションは、異なるパラメータを持つ同じ命令ではなく、完全に異なるオペコードであることに注意してください。最初のオペコードにMOV、2番目のオペコードにMVD(MoVeダイレクトアドレス指定メモリ)を使用することもできますが、プログラマーにとってブラケット構文の方が覚えやすいと判断したに違いありません。

16
Euro Micelli

x86マシンコードには、move-to-Sreg用のオペコードが1つだけあります。そのオペコードは
8E /rmov Sreg, r/m16 、およびはレジスタまたはメモリソースを許可します(ただし即時ではありません)。

他の回答の一部の主張とは異なり、アドレスmov ds, [5000h]の2バイトが有用なセグメントを保持していると仮定すると、5000hは正常に実行されます現在のモードの値。(数値として直接使用されるリアルモードと、Sreg値がLDT/GDTにインデックスを付けるセレクターである保護されたモード)。

x86は、命令の即時形式(マシンコードの一部としてエンコードされた定数を使用)とレジスタ/メモリソースバージョンでは常に異なるオペコードを使用します。例えばadd eax, 123は、add eax, ecxとは異なるオペコードにアセンブルします。ただし、add eax, [esi]add r, r/m32と同じオペコードadd eax, ecxオペコードであり、ModR/Mバイトが異なるだけです。


nasm sreg.asm -l/dev/stdoutからのNASMリスト、16ビットモードでフラットバイナリをアセンブルし、リストを作成します。

バイトをopcode modrm extraに分割するために手作業で編集しました。これらはすべて1バイトのオペコードです(ModRMバイトの/ rフィールドにスペースを借りる余分なオペコードビットはありません)。したがって、最初のバイトを見て、それが何であるかを確認し、2つの命令が同じオペコードを共有する場合に注意してください。

   address    machine code         source           ;  comments
 1 00000000 BE 0050           mov si, 5000h     ; mov si, imm16
 2 00000003 A1 0050           mov ax, [5000h]   ; special encoding for AX, no modrm
 3 00000006 8B 36 0050        mov si, [5000h]   ; mov r16, r/m16 disp16
 4 0000000A 89 C6             mov si, ax        ; mov r/m16, r16
 5                                  
 6 0000000C 8E 1E 0050        mov ds, [5000h]   ; mov Sreg, r/m16
 7 00000010 8E D8             mov ds, ax        ; mov Sreg, r/m16
 8                                  
 9                            mov ds, 5000h
 9          ******************       error: invalid combination of opcode and operands

mov Sreg, imm16エンコーディングをサポートするには、別のオペコードが必要になります。これは、8086がデコードするために余分なトランジスタを必要とし、将来の拡張のための余地を少なくして、より多くのオペコードコーディングスペースを消費します。これらのどれが8086 ISAの設計者によってより重要であると考えられたかはわかりません。

8086には、絶対アドレスからアキュムレータをロードするときに1バイトを節約する特別なmov AL/AX, moffsオペコードがあることに注意してください。しかし、Sregのmov- immediateのオペコードを節約できなかったのでしょうか。この設計上の決定は理にかなっています。どのくらいの頻度でセグメントレジスタをリロードする必要がありますか?非常にまれであり、実際の大規模なプログラムでは、定数がないことがよくあります(私は思います)。しかし、静的データを使用するコードでは、ループ内の固定アドレスにアキュムレータをロードまたは格納している可能性があります。 (8086のコードフェッチは非常に弱いため、ほとんどの場合、コードサイズ=速度)。

また、mov Sreg, r/m16は、1つの追加の命令(mov ax, 4321hなど)だけで、アセンブル時定数に使用できることにも注意してください。しかし、mov Sreg, imm16しかない場合、ランタイム変数セグメント値には自己変更コードが必要でした。 (したがって、明らかにr/m16ソースバージョンを除外することはありません。)私のポイントは、1つしかない場合は、間違いなくレジスタ/メモリソースバージョンになるということです。

7
Peter Cordes

セグメントレジスタについて

セグメントレジスタは、(ハードウェアレベルで)汎用レジスタと同じではありません。もちろん、Mike Wがコメントで述べたように、即時値をセグメントレジスタに直接移動できない正確な理由は、Intel開発者だけが知っています。でも、こういうのはデザインがシンプルだからだと思います。セグメントレジスタ操作は非常にまれであるため、この選択はプロセッサのパフォーマンスに影響を与えないことに注意してください。したがって、1つ多い命令、1つ少ない命令は、まったく重要ではありません。

構文について

X86アセンブラ構文のすべての妥当な実装では、mov reg, somethingは、即値somethingをレジスタregに移動します。例えば:

NamedConst = 1234h
SomeLabel:
    mov  edx, 1234h      ; moves the number 1234h to the register edx
    mov  eax, SomeLabel  ; moves the value (address) of SomeLabel to eax
    mov  ecx, NamedConst ; moves the value (1234h in this case) to ecx

角かっこで囲まれた数値は、このアドレスを持つメモリの内容がレジスタに移動されることを意味します。

SomeLabel dd 1234h, 5678h, 9abch

    mov  eax, [SomeLabel+4]  ; moves 5678h to eax
    mov  ebx, dword [100h]   ; moves double Word memory content from the 
                             ; address 100h in the data segment (DS) to ebx.
4
johnfound

その理由を昔に読んだことを思い出します。目の前にその書類はありませんので、手を振ってご容赦ください。

メモリの場所または定数からセグメントレジスタを読み込むには、メモリサイクルが必要です。メモリの配置が混乱している場合、16ビット値の読み取りには2メモリサイクルかかる可能性があります。サイクル間では、セグメントレジスタの値が無効です。ここで、スタックセグメントレジスタをいじっていて、割り込みが発生したと想像してください。これが手押し車です。ライドをお楽しみください!

0
trindflo