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ではどうするのかって? さあ…

Trackback

no comment untill now

Add your comment now