在我正在进行的GCC内联汇编实验中,我遇到了一个关于标签和内联代码的新问题。
考虑以下简单的跳转:
__asm__
(
"jmp out;"
"out:;"
:
:
);
除了跳转到out
标签外,这没有任何作用。这样,这段代码编译得很好。但是如果你把它放在一个函数中,然后用优化标志进行编译,编译器就会抱怨:“错误:符号'out'已经被定义了。”
似乎正在发生的事情是编译器每次内联函数时都会重复此汇编代码。这会导致标签out
重复,从而导致多个out
标签。
那么,我该如何解决这个问题呢?在内联装配中是否真的不可能使用标签?这tutorial on GCC inline assembly提到:
因此,你可以把你的组装 到CPP宏和内联C 功能,所以任何人都可以使用它 任何C函数/宏。内联函数 非常像宏,但是 有时更清洁使用。要小心 在所有这些情况下,代码将是 重复,所以只有本地标签( 1:style)应该在那里定义 asm代码。
我试图找到有关这些“本地标签”的更多信息,但似乎无法找到与内联汇编有关的任何内容。看起来本教程说的是本地标签是一个后面跟冒号的数字(如1:
),所以我尝试使用这样的标签。有趣的是,代码已编译,但在运行时它只是触发了分段错误。嗯...
那么任何建议,提示,答案......?
答案 0 :(得分:48)
本地标签的声明确实是一个后跟冒号的数字。但是,对于本地标签的引用需要f
或b
的后缀,具体取决于您是要向前还是向后看 - 即1f
指的是向前方向的下一个1:
标签。
因此将标签声明为1:
是正确的;但要引用它,你需要说jmp 1f
(因为你在这种情况下是向前跳跃)。
答案 1 :(得分:29)
嗯,这个问题并没有变得更年轻,但还有另外两个有趣的解决方案。
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");