简体   繁体   English

GCC内联汇编中的标签

[英]Labels in GCC inline assembly

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 out label. 这确实没有什么不同之处跳转到out标签。 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'已经被定义了”。

What seems to be happening is that the compiler is repeating this assembly code every time it inlines the function. 似乎正在发生的事情是编译器每次内联函数时都会重复此汇编代码。 This causes the label out to get duplicated, leading to multiple out labels. 这使标签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 assembly mentions 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. 因此,您可以将汇编放入CPP宏和内联C函数中,因此任何人都可以将其用作任何C函数/宏。 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. 请注意,在所有这些情况下,代码将被复制,因此只应在该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. 看起来教程是说本地标签是一个数字,后跟冒号(如1: :),所以我尝试使用这样的标签。 Interestingly, the code compiled, but at run time it simply triggered a Segmentation Fault. 有趣的是,代码已编译,但在运行时它只是触发了分段错误。 Hmm... 嗯...

So any suggestions, hints, answers...? 那么任何建议,提示,答案......?

A declaration of a local label is indeed a number followed by a colon. 本地标签的声明确实是一个数字后跟冒号。 But a reference to a local label needs a suffix of f or b , depending on whether you want to look forwards or backwards - ie 1f refers to the next 1: label in the forwards direction. 但是对本地标签的引用需要后缀为fb ,具体取决于您是要向前还是向后 - 即1f指向前进方向的下一个1:标签。

So declaring the label as 1: is correct; 因此将标签声明为1:是正确的; but to reference it, you need to say jmp 1f (because you are jumping forwards in this case). 但要引用它,你需要说jmp 1f (因为你在这种情况下是向前跳)。

Well, this question isn't getting any younger, but there are two other interesting solutions. 嗯,这个问题并没有变得更年轻,但还有另外两个有趣的解决方案。

1) This example uses %=. 1)此示例使用%=。 %= 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." 汇编程序模板中的%=被替换为“对整个编译中的每个insn唯一的数字。这对于制作在给定insn中多次引用的本地标签很有用。” Note that to use %=, you (apparently) must have at least one input (although you probably don't have to actually use it). 请注意,要使用%=,您(显然)必须至少有一个输入(尽管您可能不必实际使用它)。

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). 或者,您可以使用asm goto(我认为在v4.5中添加)。 This actually lets you jump to c labels instead of just asm labels: 这实际上允许您跳转到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");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM