Этикетки в GCC встроенной сборки

В ходе моих экспериментов со встроенной сборкой GCC я столкнулся с новой проблемой, связанной с метками и встроенным кодом.

Рассмотрим следующий простой прыжок:

__asm__
(
    "jmp out;"
    "out:;"
    :
    :
);

Это ничего не делает, кроме прыжка к out этикетка. Как и этот код прекрасно компилируется. Но если вы поместите его в функцию, а затем скомпилируете с флагами оптимизации, компилятор скажет: "Ошибка: символ" out "уже определен".

Кажется, что происходит то, что компилятор повторяет этот ассемблерный код каждый раз, когда он указывает на функцию. Это вызывает метку out дублироваться, что приводит к множественному out этикетки.

Итак, как мне обойти это? Неужели нельзя использовать метки во встроенной сборке? В этом руководстве по встроенной сборке GCC упоминается, что:

Таким образом, вы можете поместить свою сборку в макросы CPP и встроенные функции C, так что любой может использовать ее как любую функцию / макрос C. Встроенные функции очень похожи на макросы, но иногда их удобнее использовать. Помните, что во всех этих случаях код будет продублирован, поэтому в этом ассемблерном коде должны быть определены только локальные метки (стиля 1: стиль).

Я пытался найти больше информации об этих "локальных метках", но не могу найти ничего, касающегося встроенной сборки. Похоже, что в учебнике говорится, что локальная метка - это число, за которым следует двоеточие (например, 1:), поэтому я попытался использовать такую ​​метку. Интересно, что код скомпилирован, но во время выполнения он просто вызвал ошибку сегментации. Хм...

Так какие-нибудь предложения, намеки, ответы...?

2 ответа

Решение

Объявление локальной метки - это действительно число, за которым следует двоеточие. Но ссылка на локальный ярлык требует суффикса f или же bв зависимости от того, хотите ли вы смотреть вперед или назад - то есть 1f относится к следующему 1: метка в прямом направлении.

Так объявив ярлык как 1: верно; но чтобы сослаться на это, нужно сказать jmp 1f (потому что в этом случае вы прыгаете вперед).

Ну, этот вопрос не молодеет, но есть два других интересных решения.

1) В этом примере используется%=. %= в шаблоне на ассемблере заменяется числом, которое "уникально для каждого insn во всей компиляции. Это полезно для создания локальных меток, которые упоминаются более одного раза в данном insn". Обратите внимание, что для использования% = у вас (по-видимому) должен быть хотя бы один вход (хотя вам, вероятно, не обязательно его использовать).

int a = 3;
asm (
    "test %0\n\t"
    "jnz to_here%=\n\t"
    "jz to_there%=\n\t"
    "to_here%=:\n\t"
    "to_there%=:"
    ::"r" (a));

Это выводит:

test %eax
jnz to_here14
jz to_there14
to_here14:
to_there14:

В качестве альтернативы, вы можете использовать asm goto (я думаю, что он добавлен в v4.5). Это фактически позволяет вам переходить к меткам c, а не просто к asm-меткам:

asm goto ("jmp %l0\n"
 : /* no output */
 : /* no input */
 : /* no clobber */
 : gofurther);

printf("Didn't jump\n");

// c label:
gofurther:
printf("Jumped\n");
Другие вопросы по тегам