web-dev-qa-db-ja.com

アセンブリ:2つのメモリアドレス間を移動する

アセンブリを学習しようとしていますが(我慢してください)、次の行でコンパイルエラーが発生します。

mov byte [t_last], [t_cur]

エラーは

error: invalid combination of opcode and operands

このエラーの原因は、mov命令が2つのメモリアドレス間を移動できないことであると思われますが、30分グーグルしてこれを確認できませんでした-これは本当ですか?

また、私が正しいと仮定すると、メモリをコピーするための中間点としてレジスタを使用する必要があることを意味します。

mov cl, [t_cur]
mov [t_last], cl

使用する推奨レジスタは何ですか(または代わりにスタックを使用する必要があります)?

19
Justin

あなたの疑惑は正しいです、あなたは記憶から記憶へと移動することはできません。

どんな汎用レジスタでもかまいません。レジスターの内容がわからない場合は、レジスターをプッシュし、完了したら元に戻すことを忘れないでください。

27

それは16ビットで本当に簡単です、ただ以下をしてください:

     Push     di
     Push     si
     Push     cx
     mov      cx,(number of bytes to move)
     lea      di,(destination address)
     lea      si,(source address)
     rep      movsb
     pop      cx
     pop      si
     pop      di

注:レジスターの内容を保存する必要がある場合は、プッシュとポップが必要です。

6
Will Mattison

データをメモリからメモリに移動するMOVSコマンドもあります。

MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS
3
ymv

メモリからメモリに移動することは技術的に可能です。

[〜#〜] moves [〜#〜](文字列の移動)を使用して、[E]を設定してみてくださいSIおよび[E] DI、バイト、ワードを転送するかどうかによって異なります、など。

mov si, t_cur    ; Load SI with address of 't_cur'
mov di, t_last   ; Load DI with address of 't_last'
movsb            ; Move byte from [SI] to [DI]

; Some dummy data
t_cur    db 0x9a ; DB tells NASM that we want to declare a byte
t_last   db 0x7f ; (See above)

これは、1つの一時レジスタで通常のロード+ストアを使用するよりも効率的ではありませんが、1つの命令で実際のコピーを実行します。

[〜#〜] movs [〜#〜]の使用方法とその仕組みは次のとおりです。 https:// www。 felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq

通常、ブロックコピーにはrepプレフィックスを付けてのみ使用され、単一の要素には使用されません。 (最新のCPUには、rep movsbのかなり効率的なマイクロコードがあり、AVXベクトルのロード/ストア命令を使用したループの速度に近いです。)

2
clapdrop

正解です。x86マシンコードは、2つのexplicitメモリオペランド([]で指定された任意のアドレス)を持つ命令をエンコードできません。

推奨レジスタは何ですか

保存/復元する必要のないレジスタ

すべての主流の32ビットおよび64ビットの呼び出し規約では、EAX、ECX、およびEDXはコールクローバーされているため、AL、CL、およびDLが適切な選択です。バイトまたはワードコピーの場合、通常はmovzxを32ビットレジスタにロードしてから、8ビットまたは16ビットストアにロードする必要があります。これにより、レジスタの古い値への誤った依存が回避されます。別の値の下位ビットにマージするためにアクティブにwantする場合にのみ、狭い16ビットまたは8ビットのmovロードを使用してください。 x86のmovzxは、ARM ldrbのような命令に類似しています。

    movzx   ecx,  byte [rdi]       ; load CL, zero-extending into RCX
    mov    [rdi+10], cl

64ビットモードでは、SIL、DIL、r8b、r9bなども適切な選択ですが、ストアのマシンコードにREXプレフィックスが必要なため、コードサイズにわずかな理由があります。

通常、パフォーマンス上の理由からAH、BH、CH、またはDHの記述は避けてください。ただし、次のリンクを読んで理解し、誤った依存関係や部分的なレジスタのマージストールが問題になったり、コードでまったく発生したりしない場合を除きます。 。


(または代わりにスタックを使用する必要があります)?

まず第一に、1バイトをプッシュすることはまったくできないため、スタックからバイトロード/バイトストアを実行する方法はありません。 Word、dword、またはqword(CPUモードによって異なります)の場合、Push [src]/pop [dst]を実行できますが、レジスタを介してコピーするよりもはるかに低速です。最終的な宛先からデータを読み取る前に、追加のストア/リロードストア転送レイテンシが発生し、より多くのuopsが必要になります。

スタックのどこかにis目的の宛先があり、そのローカル変数をレジスタに最適化できない場合を除いて、その場合はPush [src]でコピーできます。そこにスタックスペースを割り当てます。

https://agner.org/optimize/ およびその他のx86パフォーマンスリンク x86タグwikiを参照してください。

2
Peter Cordes