C Выпуск этикеток в сборке
В настоящее время я начинающий с ассемблера и изучаю, как использовать ассемблер, встроенный в C, для класса. При этом у меня возникают трудности с этой конкретной ошибкой при компиляции моего файла:
/tmp/cckHnU89.s: Сообщения ассемблера: /tmp/cckHnU89.s:550: Ошибка: символ `.L16'уже определен /tmp/cckHnU89.s:571: Ошибка: символ `.L18'уже определен /tmp/cckHnU89.s:576: Ошибка: символ `.L17'уже определен
Я попытался заменить имена меток другими именами, поскольку из файла.s заметил, что метки.L16, .L17 и.L18 используются в моем основном методе, а также в одной из моих функций. Тем не менее, когда я это сделал, у меня просто возникла ошибка сегментации при запуске программы. Есть ли способ изменить имена меток или что-то еще, чтобы исправить, что, по-видимому, конфликт имен?
Что касается моего процессора, я использую процессор Intel Pentium T4500, и я компилирую с gcc версии 4.4.3. Мой код содержит более 300 строк для встроенной части сборки, поэтому я буду жалеть того, кто это читает. По сути, я просто ищу общий ответ о том, как обычно можно исправить конфликт имен, который приводит к ошибке выше. Любое понимание будет с благодарностью.
1 ответ
Моя догадка здесь (и я только что проверил это с g++ -S
а также gcc -S
) что ваши собственные метки точно имитируют схему именования (.L<num>
) для меток, автоматически назначаемых ассемблерному коду в GCC.
Сделайте следующее:
# for C:
gcc -S source.c
# for C++
g++ -S source.cpp
... а потом cat
(или же less
) результирующий .s
файл (то же самое базовое имя, .s
суффикс, например source.s
). Вы найдете многочисленные ярлыки этой схемы (.L<num>
). Теперь, если вы сами создадите встроенную сборку, содержащую те же имена, что и автоматически созданные метки (из вашего кода C), это, очевидно, приведет к конфликтам.
Так что суть: не использовать .L<num>
как ваша схема именования для ярлыков, потому что это будет конфликтовать.
Обычно имена начинаются с .L
кажется, напрашивается на неприятности здесь.
Пример (test.cpp
), скомпилировать с 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;
}
Скомпилировано на x64 (содержимое 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
Соблюдайте названия, начинающиеся с .L
в полученном файле ассемблера.