简体   繁体   中英

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.

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.

Does VC++ try to "auto-detect" what registers are clobbered? 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:

  1. GCC is a retargettable compiler, but the assembly syntax is just raw text. 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). This would have to work across all architectures. Currently, GCC does not parse the assembly language; 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 . The reason is that it is a more sophisticated language than that in MSVC. GCC's inline assembly language allocates registers for you. So you usually don't use something like %eax directly, but rather a code like %0 for which GCC substitutes an available register. (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 .

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. 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 . 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.

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. 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. However, using these registers will affect code quality because the register allocator cannot use them to store values across __asm blocks. 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.

You should preserve other registers you use (such as DS, SS, SP, BP, and flags registers) for the scope of the __asm block. You should preserve the ESP and EBP registers unless you have some reason to change them (to switch stacks, for example). Also see Optimizing Inline Assembly .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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