私はここの新人で、アセンブリ言語を勉強し始めました。ですから、私が間違っている場合、またはこの投稿が意味をなさない場合は削除してください。
X86-64 Intelアーキテクチャでのデータ移動命令について話している。私は、通常のmovq
命令は32ビットの2の補数として表すことができる即時ソースオペランドしか持てないのに対し、movabsq
命令は次のように任意の64ビットの即値を持つことができることを読みましたそのソースオペランドであり、宛先としてのみレジスタを持つことができます。
これについて詳しく説明してもらえますか?つまり、movabsq
命令のみを使用して64ビットの即値を移動できるということですか?そして、即値からレジスターまで? 64ビットの即値をメモリに移動する方法がわかりません。あるいは、ここで何か重要なことを間違えたのかもしれません。
NASM/Intel構文では、_mov r64, 0x...
_は定数に基づいて MOVエンコーディング を選択します。即値オペランドで選択できる4つがあります。
mov r32, imm32
_。 ( 64ビットレジスタを満たすために常に拡張されるゼロ拡張 )。 AT&T:mov
/movl
mov r/m32, imm32
_。メモリの宛先にのみ役立ちます。 AT&T:mov
/movl
mov r/m64, sign-extended-imm32
_。 メモリに8バイトを格納できます、または64ビットレジスタを負の値に設定できます。 AT&T:mov
/movq
mov r64, imm64
_。 (これは_mov r32, imm32
_と同じ非ModRMオペコードのREX.W = 1バージョンです)AT&T:mov
/movq
/movabs
(バイトカウントは、レジスタの宛先、またはSIBバイトまたはdisp8/disp32を必要としないアドレッシングモードの場合のみです。opcode+ ModR/M + imm32のみです。)
一部のインテル構文アセンブラー(GASは除く)は、_mov rax, 1
_などの32ビット定数を5バイト_mov r32, imm32
_(NASMがこれを行う)に最適化しますが、他の(YASMなど)は7バイト_mov r/m64, sign-extended-imm32
_。どちらも、特別なニーモニックを使用せずに、大きな定数に対してのみimm64エンコーディングを選択します。
または、equ
定数を使用すると、YASMは残念ながら小さな定数でも10バイトバージョンを使用します。
AT&T構文のGASで
movabsq
は、マシンコードのエンコードに64ビット値が含まれることを意味します:即時定数または絶対メモリアドレス(別のグループがありますal/ax/eax/rax from/toから絶対アドレスをロード/ストアするmov
の特殊な形式、および64ビットバージョンは相対ではなく64ビットの絶対アドレスを使用します。AT&T構文はmovabs
も呼び出します。たとえば、 _movabs 0x123456789abc0, %eax
_)。
_movabs $1, %rax
_のように数が少ない場合でも、10バイトバージョンを取得します。
この一部は、AT&T構文を使用したこの x86-64ガイドの新機能 で言及されています。
ただし、mov
ニーモニック(q
オペランドサイズサフィックスの有無にかかわらず)は、イミディエートのサイズに応じて、_mov r/m64, imm32
_と_mov r64, imm64
_の間で選択します。 ( x86-64 AT&T命令movqとmovabsqの違いは何ですか を参照してください。この回答の最初のバージョンは、movq
の大規模なアセンブル時定数を使用してGASが何をしたかを誤って推測したために存在します。)
ただし、シンボルアドレスはリンク時まで認識されないため、アセンブラがエンコーディングを選択している場合は使用できません。少なくともLinux ELFオブジェクトを対象とする場合ファイル、GASは、movabs
を使用しなかった場合は、32ビットのアブソリュートを意図していると想定します。 (YASMは、R_X86_64_32再配置で_mov rsi, string
_に対して同じことを行いますが、NASMはデフォルトでmovabs
になり、R_X86_64_64再配置を生成します。)
何らかの理由でシンボル名を(通常より優れたRIP相対LEAではなく)絶対イミディエイトとして使用する場合は、movabs
が必要です
(OS XのMach-O64のようなターゲットでは、32ビットの絶対アドレスは決して有効ではないため、_movq $symbol, %rax
_は常にimm64エンコーディングを選択する場合があります。SO人々は、コードがmovq
と連携してデータアドレスをレジスターに入れると言ったと思います)
$symbol
_即時のLinux/ELFの例_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
_(符号付き)と_R_X86_64_32
_(符号なし)と_R_X86_64_PC32
_(PC相対)の32ビット再配置の違いに注意してください。
_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
_
そしてもちろん、32ビットの絶対再配置のため、これはPIE実行可能ファイルにリンクしません。 _movq $symbol, %rax
_は、最新のLinuxディストリビューションでは通常の_gcc foo.S
_では機能しません。 2ビット絶対アドレスは、x86-64 Linuxでは許可されなくなりましたか? 。 (正しいソリューションは、RIP相対LEA、または実際にmovabs
を使用せずに静的実行可能ファイルを作成することです)。
movq
は常に7バイトまたは10バイトの形式であるため、(後でNOPでパディングするのではなく)整列のために長い命令が必要でない限り、_mov $1, %rax
_を使用しないでください。 効率的に使用できるメソッド最新のx86で命令長を拡張しますか? )。 _mov $1, %eax
_を使用して、5バイト形式を取得します。
_movq $0xFFFFFFFF, %rax
_は7バイト形式を使用できないことに注意してください。これは、sign-extended32ビット即値では表現できず、imm64エンコードまたは_%eax
_宛先エンコーディング。 GASはこの最適化を行わないため、10バイトのエンコーディングのままです。あなたは間違いなく_mov $0xFFFFFFFF, %eax
_を求めています。
直接ソースを持つmovabs
は常にimm64形式です。
(movabs
は、64ビットの絶対アドレスとRAXをソースまたは宛先として持つ MOVエンコーディング にすることもできます:_REX.W + A3
_ _MOV moffs64, RAX
_など)。
64ビットの即値をメモリに移動する方法がわかりません。
それは別の質問であり、答えは次のとおりです。できません。 MOVのinsn ref手動エントリ は、これを明確にします。imm64即値オペランドを持つ唯一の形式は、r/m64ではなく、レジスタの宛先のみを持ちます。
値が符号拡張された32ビットの即値に収まる場合、movq $0x123456, 32(%rdi)
はメモリに8バイトのストアを行います。制限は、上位32ビットがビット31のコピーでなければならないことです。これは、符号拡張されたimm32としてエンコード可能でなければならないためです。