C++ GCC 内联汇编中的标签

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3898435/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:59:46  来源:igfitidea点击:

Labels in GCC inline assembly

c++cgccassemblyinline-assembly

提问by Channel72

In my ongoing experimentation with GCC inline assembly, I've run into a new problem regarding labels and inlined code.

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

Consider the following simple jump:

考虑以下简单的跳转:

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

This does nothing except jump to the outlabel. As is, this code compiles fine. But if you place it inside a function, and then compile with optimization flags, the compiler complains: "Error: symbol 'out' is already defined".

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

What seems to be happening is that the compiler is repeating this assembly code every time it inlines the function. This causes the label outto get duplicated, leading to multiple outlabels.

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

So, how do I work around this? Is it really not possible to use labels in inline assembly? This tutorial on GCC inline assemblymentions that:

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

Thus, you can make put your assembly into CPP macros, and inline C functions, so anyone can use it in as any C function/macro. Inline functions resemble macros very much, but are sometimes cleaner to use. Beware that in all those cases, code will be duplicated, so only local labels(of 1: style) should be defined in that asm code.

因此,您可以将程序集放入 CPP 宏和内联 C 函数,因此任何人都可以将其用作任何 C 函数/宏。内联函数非常类似于宏,但有时使用起来更简洁。请注意,在所有这些情况下,代码都将重复,因此应在该 asm 代码中仅定义局部标签(1:样式)。

I tried to find more information about these "local labels", but can't seem to find anything relating to inline assembly. It looks like the tutorial is saying that a local label is a number followed by a colon, (like 1:), so I tried using a label like that. Interestingly, the code compiled, but at run time it simply triggered a Segmentation Fault. Hmm...

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

So any suggestions, hints, answers...?

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

回答by Matthew Slattery

A declarationof a local label is indeed a number followed by a colon. But a referenceto a local label needs a suffix of for b, depending on whether you want to look forwards or backwards - i.e. 1frefers to the next 1:label in the forwards direction.

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

So declaring the label as 1:is correct; but to reference it, you need to say jmp 1f(because you are jumping forwards in this case).

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

回答by David Wohlferd

Well, this question isn't getting any younger, but there are two other interesting solutions.

好吧,这个问题并没有变得更年轻,但还有另外两个有趣的解决方案。

1) This example uses %=. %= in an assembler template is replaced with a number that is "unique to each insn in the entire compilation. This is useful for making local labels that are referred to more than once in a given insn." Note that to use %=, you (apparently) must have at least one input (although you probably don't have to actually use it).

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));

This outputs:

这输出:

test %eax
jnz to_here14
jz to_there14
to_here14:
to_there14:

Alternately, you can use the asm goto (Added in v4.5 I think). This actually lets you jump to c labels instead of just asm labels:

或者,您可以使用 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");