2010-10-10 209 views
33

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

考虑以下简单的跳转:

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

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

看上去正在发生的事情是,编译器在每次内联函数时重复该汇编代码。这会导致标签out重复,导致多个out标签。

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

​​

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

因此,任何建议,提示,答案......?

回答

44

A 声明确实是一个数字,后跟一个冒号。但参考到本地标签需要后缀fb,具体取决于您是要向前还是向后 - 即1f引用向前方向上的下一个1:标签。

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

+1

@MichaelGraczyk局部标签就不是一个具体的x86的功能。 GAS支持它们,无论CPU或目标文件格式如何,几乎所有其他的Unixy汇编程序都是如此(即使在1995年,我也从未见过这种汇编程序)。 – zwol 2013-12-20 04:29:53

+1

事实上,'jmp 1'将被视为跳转到位置1,因此是段错误。 – greggo 2017-01-24 17:32:17

24

嗯,这个问题没有变得更年轻,但还有两个有趣的解决方案。

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跳转(由在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"); 
+4

我喜欢这样的东西的爱情stackoverflow。 – demonkoryu 2013-05-10 19:02:27