[解決済み] x86-64におけるmovqとmovabsqの違いについて
質問
私はここでアセンブリ言語を勉強し始めたばかりの新参者です。なので、間違っていたら訂正してください。また、この投稿が意味をなさない場合は削除します。
x86-64インテルアーキテクチャのデータ移動命令についてです。私が読んだのは、通常の
movq
命令は、32ビットの2の補数で表現できる即値オペランドしか持てないのに対して
movabsq
は、ソースオペランドに任意の64ビット即値を持つことができ、デスティネーションはレジスタのみです。
もう少し詳しく教えてください。つまり、64ビットの即値は
movabsq
命令のみですか?また、即値からレジスタにのみですか?64ビットの即値からメモリに移動する方法がわからないのですが。それとも、私はここで何か重要なことを勘違いしていたのでしょうか。
解決方法は?
NASM / Intelの構文で。
mov r64, 0x...
ピック
MOVエンコーディング
を定数で指定します。 即時オペランドで4つから選択できます。
-
5バイト
mov r32, imm32
. ( いつものように64ビットレジスタを埋めるためにゼロ拡張される ). AT&T:mov
/movl
-
6バイト以上
mov r/m32, imm32
.メモリー宛先としてのみ有効です。 AT&T:mov
/movl
-
7バイト以上
mov r/m64, sign-extended-imm32
. 8バイトをメモリに格納可能 , または64ビットレジスタに負の値を設定します。 AT&T:mov
/movq
-
10バイト
mov r64, imm64
. (と同じno-ModRMオペコードのREX.W=1版です)。mov r32, imm32
) AT&T:mov
/movq
/movabs
(バイト数のみは、レジスタのデスティネーション、またはSIBバイトやdisp8/disp32を必要としないアドレッシングモード:opcode + ModR/M + imm32だけです).
インテルシンタックスのアセンブラには、以下のような32ビット定数を最適化するものがあります (GASではありません)。
mov rax, 1
を5バイトの
mov r32, imm32
(NASMはこうしています)、一方(YASMのように)他の人は7バイトの
mov r/m64, sign-extended-imm32
. どちらも大きな定数のときだけ、特別なニーモニックを使わずにimm64エンコードを選択します。
または
equ
という定数の場合、YASMは小さい定数でも10バイト版を使います、残念ながら。
AT&T構文を持つGASの場合
movabsq
は、マシンコードエンコーディングが64ビット値(即値定数または絶対メモリアドレス)を含むことを意味します。
(の特殊な形式がもう一つあります。
mov
は、絶対アドレスから/への al/ax/eax/rax のロード/ストアで、その 64 ビットバージョンは相対ではなく 64 ビットの絶対アドレスを使用します。 AT&Tの構文では、それを
movabs
も同様に、例えば
movabs 0x123456789abc0, %eax
).
のように小さい数字でも
movabs $1, %rax
10バイトのままです。
この中には、以下のような記載があります。 x86-64ガイドの新機能 をAT&T構文で使用しています。
しかし
mov
ニーモニック(
q
オペランドサイズのサフィックスが
mov r/m64, imm32
と
mov r64, imm64
を、即時の大きさに応じて変更することができます。 (参照
x86-64のAT&T命令のmovqとmovabsqの違いは何ですか?
の大きなアセンブル時定数に対して GAS が何をしたのかについて、この回答の最初のバージョンが間違っていたため、そのフォローアップが存在します。
movq
.)
しかし、シンボルアドレスはリンク時まで分からないので、アセンブラがエンコーディングを選択するときには利用できません。
少なくとも Linux の ELF オブジェクトファイルをターゲットにする場合、GAS は
movabs
32ビット・アブソリュートを意図していたことになります。 (YASMも同じように
mov rsi, string
をR_X86_64_32リロケーションで指定しましたが、NASMのデフォルトは
movabs
R_X86_64_64リロケーションを生成します)。
何らかの理由でシンボル名を(通常より良いRIP相対LEAの代わりに)絶対即値で使用したい場合、以下のものが必要です。
movabs
(OS XのMach-O64のようなターゲットで。
movq $symbol, %rax
は、32ビットの絶対アドレスは決して有効ではないので、常にimm64エンコーディングを選択することができます。 SOにあるMacOSのQ&Aで、自分のコードが
movq
でレジスタにデータアドレスを入れることができます)。
Linux/ELFでの例で
$symbol
即時
mov $symbol, %rdi # GAS assumes the address fits in 32 bits
movabs $symbol, %rdi # GAS is forced to use an imm64
lea symbol(%rip), %rdi # 7 byte RIP-relative addressing, normally the best choice for position-independent code or code loaded outside the low 32 bits
mov $symbol, %edi # optimal in position-dependent code
GASでオブジェクトファイルにアセンブルされ、(
.bss; symbol:
ということで、このようなリロケーションになります。 の違いに注意してください。
R_X86_64_32S
(符号付き) vs.
R_X86_64_32
(符号なし) vs. (符号なし)
R_X86_64_PC32
(PC相対)32bitリロケーション。
0000000000000000 <.text>:
0: 48 c7 c7 00 00 00 00 mov $0x0,%rdi 3: R_X86_64_32S .bss
7: 48 bf 00 00 00 00 00 00 00 00 movabs $0x0,%rdi 9: R_X86_64_64 .bss
11: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 18 <.text+0x18> 14: R_X86_64_PC32 .bss-0x4
18: bf 00 00 00 00 mov $0x0,%edi 19: R_X86_64_32 .bss
PIE以外の実行ファイルにリンクされている(
gcc -no-pie -nostdlib foo.s
) が得られます。
4000d4: 48 c7 c7 f1 00 60 00 mov $0x6000f1,%rdi
4000db: 48 bf f1 00 60 00 00 00 00 00 movabs $0x6000f1,%rdi
4000e5: 48 8d 3d 05 00 20 00 lea 0x200005(%rip),%rdi # 6000f1 <__bss_start>
4000ec: bf f1 00 60 00 mov $0x6000f1,%edi
そしてもちろん、これはPIE実行ファイルにはリンクしません。なぜなら32ビットの絶対再配置があるからです。
movq $symbol, %rax
では動作しません。
gcc foo.S
最近のLinuxディストロでは
.
x86-64 Linuxでは32ビットの絶対アドレスは使えなくなった?
. (正しい解決策はRIP相対LEA、または静的な実行ファイルを作ることであって、実際に
movabs
).
movq
は常に7バイトまたは10バイトの形式である。
mov $1, %rax
アラインメントのために長い命令が必要な場合以外は(後でNOPでパディングする代わりに)。
最近のx86では、どのような方法で効率よく命令長を伸ばせるのでしょうか?
). 使用方法
mov $1, %eax
を使えば5バイトのフォームになります。
注目すべきは
movq $0xFFFFFFFF, %rax
は7バイトの形式を使うことができません。なぜなら、7バイトの形式は
符号拡張
32ビットの即値が必要で、imm64エンコーディングまたは
%eax
デスティネーションエンコーディングです。 GASはこの最適化をしてくれませんので、10バイトのエンコーディングから抜け出せないのです。 そのため
mov $0xFFFFFFFF, %eax
.
movabs
を直接入力する場合は、常に imm64 形式になります。
(
movabs
にもすることができます。
MOVエンコーディング
のように,64 ビットの絶対アドレスと RAX を送信元または送信先として指定します.
REX.W + A3
MOV moffs64, RAX
).
64ビットの即時値をメモリに移動させる方法がわからないのですが。
それは別の質問で、答えは「できない」です。 その MOVのinsn refマニュアルエントリ imm64即時オペランドを持つ唯一の形式は、r/m64ではなく、レジスタの行き先を持つだけだからです。
符号拡張された32ビット即値に値が収まる場合。
movq $0x123456, 32(%rdi)
は、8バイトのメモリへの保存を行います
. 符号拡張IMM32としてエンコード可能でなければならないため、上位32ビットはビット31のコピーでなければならないという制約があります。
関連する なぜ64ビットの即値はメモリに移動できないのか? - コンピュータ・アーキテクチャ / ISA設計上の理由。
関連
-
[解決済み】JNZとCMPのアセンブリ命令
-
[解決済み] MIPSの大、小、大
-
[解決済み] 着信側セーブレジスタ、発信側セーブレジスタとは何ですか?
-
[解決済み] MIPS浮動小数点:SWC1対S.S.
-
[解決済み] movsbl 命令は何をするのですか?重複
-
[解決済み] この状況でのlwとbneは何を意味するのか?
-
[解決済み] ST(0)をEAXに移動させる方法は?
-
[解決済み] 1サイクルあたり4FLOPの理論上の最大値を達成するにはどうすればよいですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
-
[解決済み] 32ビットレジスタに対するx86-64命令は、なぜフル64ビットレジスタの上部をゼロにするのですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】バイナリーボム - フェーズ4
-
[解決済み] MIPSの大、小、大
-
[解決済み] 018Hと0cHは、アセンブリでは何の略ですか?具体的には「cH」と「0」「h」のプリフィックス/ポストフィックス
-
[解決済み] アセンブリで数字をASCIIに変換する
-
[解決済み] 8086アセンブリ言語での2つのレジスタのスワッピング(16ビット)
-
[解決済み] error: invalid effective address エラー:有効なアドレスがありません。
-
[解決済み] cmovlオペコードの中で何と何が比較されるのですか?
-
[解決済み] movsbl 命令は何をするのですか?重複
-
[解決済み] movqアセンブリ機能
-
[解決済み] 32ビットレジスタに対するx86-64命令は、なぜフル64ビットレジスタの上部をゼロにするのですか?