简体   繁体   English

为什么GCC内联汇编程序需要blobbering信息,但MSVC不需要

[英]Why does GCC inline assembler require clobbering information, but MSVC doesn't

I don't understand how this is supposed to work. 我不明白这是怎么回事。

GCC inline assembler is a pain to get right, but very specific about marking clobbering information, so that the compiler knows what you're doing. GCC内联汇编程序很难做到,但是对于标记符号信息非常具体,因此编译器知道你正在做什么。

Microsoft Visual C++'s inline assember is really easy to use (it always seems to Just Work), but I have no ideas what kinds of guarantees or assumptions it makes about your code. Microsoft Visual C ++的inline assember非常容易使用(它似乎总是Just Work),但我不知道它对你的代码有什么样的保证或假设。

Does VC++ try to "auto-detect" what registers are clobbered? VC ++是否试图“自动检测”哪些寄存器被破坏? How does it know how the registers and the stack pointer will be changed? 它如何知道如何更改寄存器和堆栈指针? Does it make any assumptions? 它做出任何假设吗? If so, how do you get around those assumptions? 如果是这样,你如何解决这些假设?

As for why GCC doesn't do it the way MSVC does, there are several reasons: 至于为什么海湾合作委员会不像MSVC那样做,有几个原因:

  1. GCC is a retargettable compiler, but the assembly syntax is just raw text. GCC是一个可重定向的编译器,但汇编语法只是原始文本。 In order for the clobber detection to be automatic, GCC would have to parse the assembly language to understand what registers are being clobbered (including implicitly clobbered ones by instructions whose opcodes do not name a register). 为了使clobber检测自动化,GCC必须解析汇编语言以了解哪些寄存器被破坏(包括由操作码未命名寄存器的指令隐式破坏的寄存器)。 This would have to work across all architectures. 这必须适用于所有架构。 Currently, GCC does not parse the assembly language; 目前,GCC不解析汇编语言; it just pastes it into the assembly output, after performing the % substitutions. 在执行%替换后,它只是将其粘贴到程序集输出中。 The idea is to generate, and avoid parsing. 我们的想法是生成并避免解析。

  2. In GCC inline assembly language, clobbering registers is the exception rather than the rule . 在GCC内联汇编语言中, clobbering寄存器是例外而不是规则 The reason is that it is a more sophisticated language than that in MSVC. 原因是它是一种比MSVC更复杂的语言。 GCC's inline assembly language allocates registers for you. GCC的内联汇编语言为您分配寄存器。 So you usually don't use something like %eax directly, but rather a code like %0 for which GCC substitutes an available register. 所以你通常不直接使用%eax类的东西,而是使用像%0这样的代码,GCC代替可用的寄存器。 (And to do that, the compiler doesn't have to understand the assembly language! you express the constraints which ensure that GCC substitutes an appropriate register for %0 which fits the usage.) You only need clobber if your assembly code is overwriting hard-coded registers, not if it is overwriting the output operands allocated for you by GCC . (要做到这一点,编译器不必理解汇编语言!你表达了约束,这些约束确保GCC用适当的寄存器替换适合用法的%0 。) 如果你的汇编代码被重写,你只需要clobber - 编码寄存器,而不是它覆盖GCC为您分配的输出操作数

Note that with GCC inline assembly, you don't have to write the code which loads your assembly language operands from the C expressions that produce their initial values, or which stores your result operands into the C destinations. 请注意,使用GCC内联汇编时,您不必编写从生成其初始值的C表达式加载汇编语言操作数的代码,也不必将结果操作数存储到C目标中。 For instance you just express that there is to be an input operand of type "r" (register) which is derived from the expression foo->bar + 1 . 例如,您只是表示存在类型为"r" (寄存器)的输入操作数,该操作数派生自表达式foo->bar + 1 GCC allocates the register and generates the code to load it from foo->bar + 1 , and then replaces occurences of %0 in your assembly template with the name of that register. GCC分配寄存器并生成代码以从foo->bar + 1加载它,然后将汇编模板中%0出现替换为该寄存器的名称。

Quote from the docs : 文档引用:

When using __asm to write assembly language in C/C++ functions, you don't need to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers. 使用__asm在C / C ++函数中编写汇编语言时,不需要保留EAX,EBX,ECX,EDX,ESI或EDI寄存器。 For example, in the POWER2.C example in Writing Functions with Inline Assembly , the power2 function doesn't preserve the value in the EAX register. 例如,在使用内联汇编编写函数的POWER2.C示例中,power2函数不会保留EAX寄存器中的值。 However, using these registers will affect code quality because the register allocator cannot use them to store values across __asm blocks. 但是,使用这些寄存器会影响代码质量,因为寄存器分配器不能使用它们来跨__asm块存储值。 In addition, by using EBX, ESI or EDI in inline assembly code, you force the compiler to save and restore those registers in the function prologue and epilogue. 此外,通过在内联汇编代码中使用EBX,ESI或EDI,可以强制编译器在函数序言和结尾中保存和恢复这些寄存器。

You should preserve other registers you use (such as DS, SS, SP, BP, and flags registers) for the scope of the __asm block. 您应该保留您使用的其他寄存器(例如DS,SS,SP,BP和标志寄存器)作为__asm块的范围。 You should preserve the ESP and EBP registers unless you have some reason to change them (to switch stacks, for example). 您应该保留ESP和EBP寄存器,除非您有某些理由更改它们(例如,切换堆栈)。 Also see Optimizing Inline Assembly . 另请参阅优化内联汇编

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

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