12月
24
GAS のマクロ定義の中で、マクロ引数(パラメーター)の後ろに文字を結合したい場合、引数名と後ろの文字とがくっつかないように境界を明示するためには \()
を使え、とマニュアルに書いてあります。
単純なマクロ定義ならこれでいいんですが、ネストした定義だと外側の定義を展開する時に \()
が解釈されて消滅するので、うまく働きません。
[umezawa@devubuntu:pts/0 ~]$ cat gas_nested_macro_expansion.cc void foo() { asm volatile ( R"( nop .macro MACRO_OUTER x .macro MACRO_INNER y cmp %al, %r\x\()b cmp %al, %r\y\()b .endm MACRO_INNER 8 .endm MACRO_OUTER 9 nop )"); } [umezawa@devubuntu:pts/0 ~]$ g++ -c gas_nested_macro_expansion.cc gas_nested_macro_expansion.cc: Assembler messages: gas_nested_macro_expansion.cc:12: Error: invalid character '\' in operand 2 [umezawa@devubuntu:pts/0 ~]$ clang++ -c gas_nested_macro_expansion.cc:2:11: error: invalid register name cmp %al, %r\yb ^ :5:2: note: while in macro instantiation MACRO_INNER 8 ^ gas_nested_macro_expansion.cc:13:1: note: while in macro instantiation MACRO_OUTER 9 ^ :10:2: note: instantiated into assembly here MACRO_OUTER 9 ^ 1 error generated.
数年前にこれに困ってたんですが、最近 \(\())
と書けば回避できることに気づきました。
[umezawa@devubuntu:pts/0 ~]$ !cat void foo() { asm volatile ( R"( nop .macro MACRO_OUTER x .macro MACRO_INNER y cmp %al, %r\x\(\())b cmp %al, %r\y\(\())b .endm MACRO_INNER 8 .endm MACRO_OUTER 9 nop )"); } [umezawa@devubuntu:pts/0 ~]$ g++ -c gas_nested_macro_expansion.cc [umezawa@devubuntu:pts/0 ~]$ objdump -d gas_nested_macro_expansion.o gas_nested_macro_expansion.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <_Z3foov>: 0: f3 0f 1e fa endbr64 4: 55 push %rbp 5: 48 89 e5 mov %rsp,%rbp 8: 90 nop 9: 41 38 c1 cmp %al,%r9b c: 41 38 c0 cmp %al,%r8b f: 90 nop 10: 90 nop 11: 5d pop %rbp 12: c3 ret
上では x
の方でも \(\())
と書いていますが、x
を展開するのは外側のマクロの展開時なので、\()
と書いても期待通りの動作になります。
no comment untill now