12

今日テストを受けましたが、ダブルワードをクワッドワードに変換する問題だけが理解できませんでした。

なぜ/いつ乗算または除算の拡張に署名するのですか? また、cdq などの命令はいつ使用するのでしょうか。

4

1 に答える 1

21

cdq符号付き 32 ビット/ idiv32 ビット => 32 ビット除算には
xor edx,edx/を使用divし、符号なしには / を使用します。

EAX で被除数を開始し、除数を DIV または IDIV のオペランドとして指定します。

   mov  eax, 1234
   mov  ecx, 17
   cdq                   ; EDX = signbit(EAX)
   idiv  ecx             ; EAX = 1234/17     EDX = 1234%17

idivの前にEDX:EAX に符号拡張する代わりに EDX/RDX をゼロにすると、たとえば のように -5 / 2 に対して大きな正の結果を得ることができます

64 / 32ビット=> 32ビット除算の「フルパワー」を使用することは可能ですが、商がオーバーフローしないように除数が十分に大きいことがわかっていない限り安全ではありません。(つまり、EDX:EAX で/と 64 ビットのテンポラリ(a*b) / cのみを使用して一般に実装することはできません。)muldiv

除算は、商のオーバーフロー時に例外 (#DE) を発生させます。Unix/Linux では、カーネルは除算エラーを含む算術例外に対してSIGFPE を提供します。通常の符号またはゼロ拡張除算では、オーバーフローは of でのみ可能ですidiv(INT_MIN / -1つまり、最も負の数の 2 の補数の特殊なケース)。


insn ref マニュアルからわかるように ( タグ wiki のリンク):

  • 1 オペランドmul/ imul:edx:eax = eax * src
  • 2 オペランドimul: dst *= src. たとえばimul ecx, esi、eax や edx を読み書きしません。

  • div/ : src でidiv割ります。edx:eaxの商eax、残りのedx。入力を無視するdiv/の形式はありません。idivedx
  • cdqに符号拡張eaxしますedx:eax。つまり、 の符号ビットを のeaxすべてのビットにブロードキャストしedxます。cdqeをよりコンパクトな形式にした 64 ビット命令であると混同しないでくださいmovsxd rax, eax

    もともと (8086) はcbw( ax = sign_extend(al)) とcwd( dx:ax = sign_extend(ax)) だけでした。x86 から 32 ビットおよび 64 ビットへの拡張により、ニーモニックが少し曖昧になりました (ただし、cbweax 以外のバージョンは常にefor Extend で終わることに注意してください)。8bit mul と div は特殊なので dl=sign_bit(al) 命令はaxなく、 の代わりに使用しdl:alます。


への入力は単一のレジスタであるため、乗算の前に[i]mul何もする必要はありません。edx

入力が符号付きの場合は、それを符号拡張して、乗算への入力として使用しているレジスタを埋めます (例: movsxor cwde( eax = sign_extend(ax)))。入力が符号なしの場合、ゼロ拡張します。(ただし、たとえば、乗算結果の下位 16 ビットのみが必要な場合は、どちらかまたは両方の入力の上位 16 ビットにが含まれているかどうかは問題ではありません)。


除算の場合、eax を edx にゼロまたは符号拡張する必要があります。ゼロ拡張は、無条件に edx をゼロにすることと同じであるため、特別な指示はありません。ただxor edx,edx

cdqmov edx, eax/よりもはるかに短いためsar edx, 31、eaxの符号ビットをedxのすべてのビットにブロードキャストするために存在します。また、即時カウント > 1 のシフトは 186 まで存在せず、1 カウントあたり 1 サイクルのままだったため、8086 ではさらに悪いことを行う必要がありました (分岐するか、符号ビットを下に回転させて +negそれを分離するなど)。 )。したがってcwd、8086 では、必要なときに多くの時間/スペースを節約できました。


64 ビット モードでは、32 ビット値を 64 ビットに拡張する符号とゼロが一般的です。ABI では、32 ビット値を保持する 64 ビット レジスタの上位 32 ビットのガベージが許可されているため、関数が の下位 32 ビットのみを参照することになっている場合は、配列のインデックス付けediだけを使用することはできません。[array + rdi]

したがって、多くのmovsx rdi, edi(符号拡張) またはmov eax, edi(ゼロ拡張、そしてインテルの mov-elimination は では機能しないため、別のターゲット レジスタを使用する方が効率的ですmov same,same)

于 2016-04-07T01:18:26.217 に答える