Ярлыки встроенной сборки GCC
В моих текущих экспериментах с встроенной сборкой GCC я столкнулся с новой проблемой в отношении меток и встроенного кода.
Рассмотрим следующий простой скачок:
__asm__
(
"jmp out;"
"out:;"
:
:
);
Это ничего не делает, кроме перехода на метку out
. Как есть, этот код компилируется отлично. Но если вы поместите его внутри функции и затем скомпилируете с помощью флагов оптимизации, компилятор жалуется: "Ошибка: символ" выход "уже определен".
Кажется, что происходит, что компилятор повторяет этот код сборки каждый раз, когда он встраивает функцию. Это приводит к дублированию метки out
, что приводит к нескольким меткам out
.
Итак, как мне обойти это? Действительно ли невозможно использовать метки в встроенной сборке? В этом руководстве по встроенной сборке GCC упоминается следующее:
Таким образом, вы можете сделать свою сборку в макросы CPP и встроенный C функций, поэтому каждый может использовать его в качестве любая функция C/macro. Встроенные функции очень похожи на макросы, но иногда чище использовать. Остерегайтесь во всех этих случаях код будет дублируется, поэтому только локальные метки (из 1: стиль) должны быть определены в этом код asm.
Я попытался найти дополнительную информацию об этих "локальных ярлыках", но, похоже, не нашел ничего, что связано с встроенной сборкой. Похоже, в учебнике говорится, что локальная метка - это число, за которым следует двоеточие (например, 1:
), поэтому я попытался использовать такой ярлык. Интересно, что код скомпилирован, но во время выполнения он просто вызвал ошибку сегментации. Хм...
Итак, любые предложения, подсказки, ответы...?
Ответы
Ответ 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");