Подтвердить что ты не робот

Ярлыки встроенной сборки GCC

В моих текущих экспериментах с встроенной сборкой GCC я столкнулся с новой проблемой в отношении меток и встроенного кода.

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

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

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

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

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

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

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

Итак, любые предложения, подсказки, ответы...?

4b9b3361

Ответ 1

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

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

Ответ 2

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

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");