コンパイルしgcc -masm=intel
、asm テンプレート文字列内でモードを切り替えようとしないでください。私の知る限り、clang に相当するものはありません (MacOS はデフォルトでclang をgcc
/としてインストールすることに注意してください)。g++
また、もちろん、有効な GNU C インライン asm を使用する必要があります。オペランドを使用して、読み書きする C オブジェクトをコンパイラに伝えます。
Intel の構文でパーセント記号が使用されているとは思えません。おそらく私は何かを逃していますか?
%operand
Extended-Asm テンプレート (単一 %
の を使用)への置換と、アセンブラーが認識する最終的な asm の間で混乱しています。
最後の asm で%%
リテラルを使用する必要があります。%
Intel-syntax inline asm では使用"mov %%eax, 1"
しませんが、それでも"mov %0, 1"
orを使用します%[named_operand]
。
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.htmlを参照してください。Basic asm (オペランドなし) では置換はなく、% はテンプレートで特別なものではないため、何らかの理由で orのようなオペランドを使用していない場合はmov $1, %eax
、Basic asm と Extended で記述します。mov $1, %%eax
mov $1, %[tmp]
mov $1, %0
uint32_t rnds_00_15;
自動ストレージ付きのローカルです。もちろん、その名前の asm シンボルはありません。
を使用%[rnds_00_15]
してコンパイルします-masm=intel
(最後に を削除し.att_syntax
ます。これにより、後に続くコンパイラ生成 asm が壊れます)。
また、DWORD PTR
オペランド展開には既に含まれているため、を削除する必要があります。(GASは問題なく受け入れますが、2番目のものが優先されるため、無意味で誤解を招く可能性があります。)DWORD PTR [rsp - 4]
DWORD PTR DWORD PTR [rsp - 4]
また"=m"
、コンパイラにスタック上のスクラッチ スペースを確保させたい場合は、出力オペランドが必要になります。C で使用されていない場合でも、入力専用オペランドを変更してはなりません。おそらく、コンパイラは、書き込まれておらず、初期化されていない (つまり UB) ため、他の何かとオーバーラップする可能性があると判断します。(あなたの"memory"
クロバーが安全かどうかはわかりませんが、ここで早期クロバー出力オペランドを使用しない理由はありません。)
%=
また、 を使用して一意の番号を取得することで、ラベル名の競合を回避する必要があります。
Godboltコンパイラエクスプローラー(-masm=intel
ドロップダウンのオプションに応じて使用)での作業例(GCCとICC、ただし残念ながらclangではありません)。「バイナリ モード」(11010 ボタン) を使用して、警告なしで asm にコンパイルした後に実際にアセンブルされることを証明できます。
int libtest_intel()
{
uint32_t rnds_00_15;
// Intel syntax operand-size can only be overridden with operand modifiers
// because the expansion includes an explicit DWORD PTR
__asm__ __volatile__
( // ".intel_syntax noprefix \n\t"
"mov %[rnds_00_15], 1 \n\t"
"cmp %[rnds_00_15], 1 \n\t"
"je .Ldone%= \n\t"
".Ldone%=: \n\t"
: [rnds_00_15] "=&m" (rnds_00_15)
:
: // no clobbers
);
return 0;
}
gcc -O3 -masm=intel
この asm に( を使用して) コンパイルします。gcc -m32 -masm=intel
もちろん、次のものでも動作します。
libtest_intel:
mov DWORD PTR [rsp-4], 1
cmp DWORD PTR [rsp-4], 1
je .Ldone8
.Ldone8:
xor eax, eax
ret
これをclangで動作させることができませんでした:.intel_syntax noprefix
明示的に残したときに窒息しました。
オペランド サイズのオーバーライド:
dword 入力オペランドの下位バイトのみにアクセスする%b[tmp]
ようにコンパイラに代入させるために使用する必要があります。BYTE PTR [rsp-4]
これをやりたい場合は、AT&T 構文をお勧めします。
%[rnds_00_15]
結果の使用Error: junk '(%ebp)' after expression.
これは、コンパイラに通知せずに Intel 構文に切り替えたためです。Intel アドレッシング モードを使用する場合は、 でコンパイルし-masm=intel
て、コンパイラが正しい構文でテンプレートに代入できるようにします。
これが、私がそのくだらない GCC インライン アセンブリをほぼすべての犠牲を払って回避する理由です。男私はこのくだらないツールを軽蔑します。
使い方が間違っているだけです。少し面倒ですが、設計方法を理解していれば理にかなっており、ほとんどの場合うまく機能します。
繰り返しますが、コンパイラは asm 文字列をまったく解析しませんが、%operand
. .intel_syntax noprefex
これが、 AT&T 構文に気付かず、代用し続ける理由です。
ただし、メモリ オペランドのオペランド サイズをオーバーライドしたり、オフセットを追加したりする場合など、AT&T 構文を使用すると、より適切かつ簡単に機能します。(たとえば4 + %[mem]
、AT&T 構文で動作します)。
方言の代替:
依存しないインライン asm を書きたい場合-masm=intel
は、Dialect の代替手段を使用します (コードが非常に醜くなります。1 つまたは 2 つの命令をラップする以外にはお勧めしません)。
オペランド サイズのオーバーライドも示します
#include <stdint.h>
int libtest_override_operand_size()
{
uint32_t rnds_00_15;
// Intel syntax operand-size can only be overriden with operand modifiers
// because the expansion includes an explicit DWORD PTR
__asm__ __volatile__
(
"{movl $1, %[rnds_00_15] | mov %[rnds_00_15], 1} \n\t"
"{cmpl $1, %[rnds_00_15] | cmp %k[rnds_00_15], 1} \n\t"
"{cmpw $1, %[rnds_00_15] | cmp %w[rnds_00_15], 1} \n\t"
"{cmpb $1, %[rnds_00_15] | cmp %b[rnds_00_15], 1} \n\t"
"je .Ldone%= \n\t"
".Ldone%=: \n\t"
: [rnds_00_15] "=&m" (rnds_00_15)
);
return 0;
}
Intel 構文では、gcc は次のようにコンパイルします。
mov DWORD PTR [rsp-4], 1
cmp DWORD PTR [rsp-4], 1
cmp WORD PTR [rsp-4], 1
cmp BYTE PTR [rsp-4], 1
je .Ldone38
.Ldone38:
xor eax, eax
ret
AT&T 構文を使用すると、次のようにコンパイルされます。
movl $1, -4(%rsp)
cmpl $1, -4(%rsp)
cmpw $1, -4(%rsp)
cmpb $1, -4(%rsp)
je .Ldone38
.Ldone38:
xorl %eax, %eax
ret