28

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

mov byte [t_last], [t_cur]

エラーは

error: invalid combination of opcode and operands

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

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

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

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

4

6 に答える 6

35

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

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

于 2009-08-19T10:48:07.387 に答える
6

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

おすすめのレジスターは何ですか

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

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

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

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

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

于 2018-11-25T18:42:33.700 に答える
5

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

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

于 2012-07-10T00:49:39.440 に答える
4

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

バイト、ワードなどを転送するかどうかに応じて、MOVS(文字列の移動)を使用し、 [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)

ただし、これはMOVを2回実行するよりも効率的ではありませんが、1つの命令でコピーを実行することに注意してください。

MOVSの使用方法と機能は次のとおりです 。https ://www.felixcloutier.com/x86/movs:movsb:movsw:movsd:movsq

命令MOVSは、それ自体で使用されることはほとんどなく、ほとんどの場合、REPプレフィックスと組み合わせて使用​​されます。

最新のCPUにはrep movs、AVXベクトルのロード/ストア命令を使用したループの速度に近い、かなり効率的な実装があります。

    ; - Assuming that 't_src' and 't_dst' are valid pointers
    mov esi, t_src  ; Load ESI with the address of 't_src'
    mov edi, t_dst  ; Load EDI with the address of 't_dst'
    mov ecx, 48     ; Load [ER]CX with the count (let's say 48 dwords =   blocks)
    rep movsd       ; Repeat copying until ECX == 0

論理的には、コピーは4バイトのdwordチャンクの48コピーで行われますが、実際の最新のCPU(高速文字列/ ERMSB)は、効率を上げるために16バイトまたは32バイトのチャンクを使用します。

このマニュアルでは、 REPの使用方法とその仕組みについて説明しています: https ://www.felixcloutier.com/x86/rep:repe:repz:repne:repnz

于 2019-06-16T18:33:01.450 に答える
3

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

MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS
于 2009-08-19T11:01:15.643 に答える
-2

「メモリバリア」について話し合いたいだけです。Cコードで

a = b;//Take data from b and puts it in a

に組み立てられます

mov %eax, b # suppose %eax is used as the temp
mov a, %eax

システムは、割り当ての原子性を保証できません。そのため、人民元(読み取りバリア)が必要です

于 2013-07-17T07:34:06.897 に答える