问题
I'm currently a total beginner with assembly and am learning how to use assembly inline with C for a class. That being said, I'm having a hard time with this particular error when I'm compiling my file:
/tmp/cckHnU89.s: Assembler messages: /tmp/cckHnU89.s:550: Error: symbol `.L16' is already defined /tmp/cckHnU89.s:571: Error: symbol `.L18' is already defined /tmp/cckHnU89.s:576: Error: symbol `.L17' is already defined
I tried replacing the names of the labels with other names since I noticed from the .s file that the labels .L16, .L17, and .L18 are used in my main method as well as in one of my functions. However, when did that I just ended up with a segmentation fault from running the program. Is there a way to change the names of the labels or something else to fix which apparently seems to be a naming conflict?
As far as my CPU, I'm running an Intel Pentium T4500 processor and I'm compiling with gcc version 4.4.3. My code is 300+ lines for the inline assembly portion so I'll spare whoever reads this. Essentially, I'm just looking for a general answer on how one would normally fix the naming conflict that produces the error above. Anything insight would be greatly appreciated.
回答1:
My hunch here is (and I just verified it with g++ -S
and gcc -S
) that your own labels are exactly mimicking the naming scheme (.L<num>
) for labels automatically assigned to assembler code in GCC.
Do the following:
# for C:
gcc -S source.c
# for C++
g++ -S source.cpp
... and then cat
(or less
) the resulting .s
file (same base name, .s
suffix, e.g. source.s
). You will find numerous labels of that scheme (.L<num>
). Now, if you yourself create inline assembly containing the same names as already automatically created labels (from your C code), that would obviously lead to clashes.
So the gist: don't use .L<num>
as your naming scheme for labels, because it will clash.
Generally names starting with .L
seem to ask for trouble here.
Example (test.cpp
), compile with g++ -S test.cpp
:
#include <cstdio>
int main(int argc, char**argv)
{
switch(argc)
{
case 0:
printf("test 0\n");
break;
case 1:
printf("test %d\n", argc);
break;
case 2:
printf("test %d -> %s\n", argc, argv[0]);
break;
default:
printf("Default\n");
break;
}
return 0;
}
Compiled on x64 (contents of test.s
):
.file "test.cpp"
.section .rodata
.LC0:
.string "test 0"
.LC1:
.string "test %d\n"
.LC2:
.string "test %d -> %s\n"
.LC3:
.string "Default"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
.cfi_personality 0x3,__gxx_personality_v0
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl -4(%rbp), %eax
cmpl $1, %eax
je .L4
cmpl $2, %eax
je .L5
testl %eax, %eax
jne .L8
.L3:
movl $.LC0, %edi
call puts
jmp .L6
.L4:
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
jmp .L6
.L5:
movq -16(%rbp), %rax
movq (%rax), %rdx
movl -4(%rbp), %eax
movl %eax, %esi
movl $.LC2, %edi
movl $0, %eax
call printf
jmp .L6
.L8:
movl $.LC3, %edi
call puts
.L6:
movl $0, %eax
leave
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Debian 4.4.5-8) 4.4.5"
.section .note.GNU-stack,"",@progbits
Observe the names starting with .L
in the resulting assembler file.
来源:https://stackoverflow.com/questions/10080939/c-inline-assembly-label-issue