GCC内联汇编中的标签

Cha*_*l72 38 c c++ assembly gcc inline-assembly

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

考虑以下简单的跳转:

__asm__
(
    "jmp out;"
    "out:;"
    :
    :
);
Run Code Online (Sandbox Code Playgroud)

除了跳转到out标签外,这没有任何作用.这样,这段代码编译得很好.但是如果你把它放在一个函数中,然后用优化标志进行编译,编译器就会抱怨:"错误:符号'out'已经被定义了".

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

那么,我该如何解决这个问题呢?在内联装配中是否真的不可能使用标签?关于GCC内联汇编的教程提到:

因此,您可以将汇编放入CPP宏和内联C函数中,因此任何人都可以将其用作任何C函数/宏.内联函数非常类似于宏,但有时使用起来更干净.请注意,在所有这些情况下,代码将被复制,因此只应在该asm代码中定义本地标签(1:样式).

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

那么任何建议,提示,答案......?

Mat*_*ery 49

一个声明局部标签的的确是一个数字,后跟一个冒号.但是对本地标签的引用需要后缀fb,取决于您是要向前还是向后 - 即1f指向1:向前方向的下一个标签.

因此宣布标签1:是正确的; 但要引用它,你需要说jmp 1f(因为你在这种情况下是向前跳).

  • @MichaelGraczyk本地标签不是x86特有的功能.无论CPU或目标文件格式如何,GAS都支持它们,所以几乎所有其他Unixy汇编程序都支持它们(就像在我从未见过的那样,即使在1995年也没有). (2认同)
  • 实际上,`jmp 1`将被视为跳转到位置1,因此是段错误. (2认同)

Dav*_*erd 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));
Run Code Online (Sandbox Code Playgroud)

这输出:

test %eax
jnz to_here14
jz to_there14
to_here14:
to_there14:
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用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");
Run Code Online (Sandbox Code Playgroud)