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