2月
02
GCC のインラインアセンブラは以下のような構文をしています。(https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html)
asm [volatile] ( AssemblerTemplate : OutputOperands [ : InputOperands [ : Clobbers ] ])
AssemblerTemplate の部分がアセンブリ言語で書く部分ですが、Visual C++ などとは違ってここは文字列リテラルを書くことになっています。例えばこんな感じになります。(以下、例は全て -masm=intel
による Intel 記法)
asm volatile( "cpuid" : "=a"(dst) : "a"(src));
複数行になる場合はこんな感じになります。
asm volatile( "xor eax, eax\n\t" "cpuid" : "=a"(dst));
インラインアセンブラは AssemblerTemplate の部分を多少修飾してからそのままC言語の部分をコンパイルした結果と一緒にアセンブリソースに埋め込み、それがアセンブラに回される、という挙動をします。そのため、\n
が含まれていないとアセンブラからは2行と見なされなくなります。実際、以下のように書くとコンパイルエラーになります。
asm volatile( "xor eax, eax" "cpuid" : "=a"(dst));
/usr/lib/gcc/x86_64-redhat-linux/4.4.7/../../../../lib64/crt1.o: In function `_start': (.text+0x20): undefined reference to `main' /tmp/ccWJ7Odd.o: In function `foo(unsigned int)': atest.c:(.text+0xd): undefined reference to `eaxcpuid' collect2: ld returned 1 exit status
これは以下のように書いたのと同じと見なされているわけです。
asm volatile( "xor eax, eaxcpuid" : "=a"(dst));
残念ながら? C では改行やダブルクオートやバックスラッシュを(エスケープせずに)文字列リテラルに含めることはできません。行末に \
を書いておけばよいかと言うとそんなことは無くて、これは単に1つの長い行として扱われます。結局 \n
は必須です。
ここまで前置き。
さて、 C++11 には「生文字列リテラル」 (raw string literals) というものがあり、任意の文字シーケンスをエスケープ不要で文字列リテラルにすることができます。もちろん改行も例外ではありません。なので以下のように書くことができます。
asm volatile( R"( xor eax, eax cpuid )" : "=a"(dst));
行ごとのダブルクオートも \n
も排除され、とても読みやすくなりました。やったぜ。
えっ、生Cではどうするのかって? さあ…
no comment untill now