Description
\@
is the macro expansion count, and is supposed to be unique in each expansion inside a translation unit. It is commonly used to generate unique local named labels.
However, Clang IAS doesn't get this quite right. https://godbolt.org/z/reedx7Gsr
Given:
asm ("toplevel:\n\t"
".macro M\n\t"
".L\\@: add $\\@, %eax\n\t"
".endm\n\t");
asm ("M"); // \@ = 0
asm ("M"); // \@ = 1
void a(void)
{
asm ("M"); // \@ should be 2, actually 0
asm ("M"); // \@ should be 3, actually 0
}
GCC/Binutils, and Clang without IAS (not surprising - it hands of to GAS) expand M
with 4 different numbers. However, Clang IAS does something a bit more weird.
(warning - stdout and stderr are mixed in the following transcript, but it's reasonably easy to follow)
$ clang -S m.c -o /dev/stdout
.text
.file "m.c"
# Start of file scope inline assembly
toplevel:
.L0:
addl $0, %eax
.L1:
addl $1, %eax
# End of file scope inline assembly
.globl a # -- Begin function a
.p2align 4, 0x90
.type a,@function
a: # @a
.cfi_startproc
# %bb.0:
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset %rbp, -16
movq %rsp, %rbp
.cfi_def_cfa_register %rbp
#APP
<instantiation>:1:1: error: invalid symbol redefinition
.L0: add $0, %eax
^
.L0:
addl $0, %eax
#NO_APP
#APP
<instantiation>:1:1: error: invalid symbol redefinition
.L0: add $0, %eax
^
.L0:
addl $0, %eax
#NO_APP
popq %rbp
.cfi_def_cfa %rsp, 8
retq
.Lfunc_end0:
.size a, .Lfunc_end0-a
.cfi_endproc
# -- End function
.ident "clang version 10.0.0-4ubuntu1 "
.section ".note.GNU-stack","",@progbits
.addrsig
2 errors generated.
At the top level, it maintains an incrementing expansion count across separate asm()
, so the 0 and 1 case expand correctly. However, when we come to the first asm()
in a()
, the expansion count resets back to 0.
This causes what should be unique local symbols to not be unique, and then suffer error: invalid symbol redefinition
.
For completeness, the second asm()
in a()
also resets back to 0 again, which is why we end up with two duplicate symbol redefinitions.