【问题标题】:Labels in GCC inline assemblyGCC 内联汇编中的标签
【发布时间】: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:),所以我尝试使用这样的标签。有趣的是,代码已编译,但在运行时它只是触发了分段错误。嗯……

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

【问题讨论】:

    标签: c++ c gcc assembly inline-assembly


    【解决方案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");
    

    【讨论】:

      猜你喜欢
      • 2010-10-19
      • 2012-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多