GCC 内联汇编中的标签

Posted

技术标签:

【中文标题】GCC 内联汇编中的标签【英文标题】:Labels in GCC inline assembly 【发布时间】:2011-04-23 08:13:46 【问题描述】:

在我正在进行的 GCC 内联汇编实验中,我遇到了一个关于标签和内联代码的新问题。

考虑以下简单的跳转:

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

除了跳转到out 标签之外,什么都不做。照原样,这段代码编译得很好。但是如果你把它放在一个函数中,然后用优化标志编译,编译器会报错:“错误:符号'out'已经定义了”。

似乎发生的事情是编译器每次内联函数时都会重复此汇编代码。这会导致标签 out 重复,从而导致多个 out 标签。

那么,我该如何解决这个问题?内联汇编中真的不能使用标签吗?这个tutorial on GCC inline assembly 提到:

因此,您可以将您的程序集 到 CPP 宏和内联 C 功能,所以任何人都可以使用它作为 任何 C 函数/宏。内联函数 非常类似于宏,但 有时更清洁使用。请注意 在所有这些情况下,代码将是 重复,所以只有本地标签( 1: style) 应该定义为 汇编代码。

我试图找到有关这些“本地标签”的更多信息,但似乎找不到与内联汇编相关的任何信息。看起来教程说本地标签是一个数字后跟一个冒号(如1:),所以我尝试使用这样的标签。有趣的是,代码已编译,但在运行时它只是触发了分段错误。嗯……

那么有什么建议、提示、答案...?

【问题讨论】:

【参考方案1】:

本地标签的声明确实是一个数字后跟一个冒号。但是对本地标签的reference 需要fb 的后缀,具体取决于您是要向前看还是向后看 - 即1f 指的是下一个1: 标签前进方向。

所以将标签声明为1: 是正确的;但要引用它,你需要说jmp 1f(因为在这种情况下你是向前跳跃)。

【讨论】:

@MichaelGraczyk 本地标签不是 x86 特定的功能。无论 CPU 或目标文件格式如何,GAS 都支持它们,几乎所有其他 Unixy 汇编器也是如此(例如,即使在 1995 年,我也从未见过这样的汇编器)。 确实,jmp 1 将被视为跳转到位置 1,因此是段错误。【参考方案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");

【讨论】:

以上是关于GCC 内联汇编中的标签的主要内容,如果未能解决你的问题,请参考以下文章

gcc中的arm内联汇编

gcc 内联汇编中的 min

GCC内联汇编中的C数组?

这个 GCC 内联汇编中的参数列表有啥问题?

ARM嵌入式开发中的GCC内联汇编__asm__

GCC 内联汇编到 IAR 内联汇编