アセンブリを学習しようとしていますが(我慢してください)、次の行でコンパイルエラーが発生します。
mov byte [t_last], [t_cur]
エラーは
error: invalid combination of opcode and operands
このエラーの原因は、mov命令が2つのメモリアドレス間を移動できないことであると思われますが、30分グーグルしてこれを確認できませんでした-これは本当ですか?
また、私が正しいと仮定すると、メモリをコピーするための中間点としてレジスタを使用する必要があることを意味します。
mov cl, [t_cur]
mov [t_last], cl
使用する推奨レジスタは何ですか(または代わりにスタックを使用する必要があります)?
あなたの疑惑は正しいです、あなたは記憶から記憶へと移動することはできません。
どんな汎用レジスタでもかまいません。レジスターの内容がわからない場合は、レジスターをプッシュし、完了したら元に戻すことを忘れないでください。
それは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
注:レジスターの内容を保存する必要がある場合は、プッシュとポップが必要です。
データをメモリからメモリに移動するMOVSコマンドもあります。
MOV SI, OFFSET variable1
MOV DI, OFFSET variable2
MOVS
メモリからメモリに移動することは技術的に可能です。
[〜#〜] 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ベクトルのロード/ストア命令を使用したループの速度に近いです。)
正解です。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を参照してください。