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