C语言 asm、asm volatile和clobbering memory的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14449141/
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
The difference between asm, asm volatile and clobbering memory
提问by jleahy
When implementing lock-free data structures and timing code it's often necessary to suppress the compiler's optimisations. Normally people do this using asm volatilewith memoryin the clobber list, but you sometimes see just asm volatileor just a plain asmclobbering memory.
在实现无锁数据结构和时序代码时,通常需要抑制编译器的优化。通常人们会在 clobber 列表中使用asm volatilewithmemory来执行此操作,但有时您只会看到asm volatile或只是一个简单的asmclobbering 内存。
What impact do these different statements have on code generation (particularly in GCC, as it's unlikely to be portable)?
这些不同的语句对代码生成有什么影响(特别是在 GCC 中,因为它不太可能是可移植的)?
Just for reference, these are the interesting variations:
仅供参考,这些是有趣的变化:
asm (""); // presumably this has no effect on code generation
asm volatile ("");
asm ("" ::: "memory");
asm volatile ("" ::: "memory");
采纳答案by Matthew Slattery
See the "Extended Asm" page in the GCC documentation.
请参阅GCC 文档中的“扩展 Asm”页面。
You can prevent an
asminstruction from being deleted by writing the keywordvolatileafter theasm. [...] Thevolatilekeyword indicates that the instruction has important side-effects. GCC will not delete avolatileasm if it is reachable.
您可以
asm通过在volatile之后写入关键字来防止指令被删除asm。[...] 该volatile关键字表示该指令具有重要的副作用。volatile如果可以访问,GCC 不会删除asm。
and
和
An
asminstruction without any output operands will be treated identically to a volatileasminstruction.
asm没有任何输出操作数的指令将被视为与易失性asm指令相同。
None of your examples have output operands specified, so the asmand asm volatileforms behave identically: they create a point in the code which may not be deleted (unless it is proved to be unreachable).
您的示例都没有指定输出操作数,因此asm和asm volatile形式的行为相同:它们在代码中创建了一个可能不会被删除的点(除非它被证明无法访问)。
This is not quite the same as doing nothing. See this questionfor an example of a dummy asmwhich changes code generation - in that example, code that goes round a loop 1000 times gets vectorised into code which calculates 16 iterations of the loop at once; but the presence of an asminside the loop inhibits the optimisation (the asmmust be reached 1000 times).
这与什么都不做完全一样。有关更改代码生成的虚拟示例,请参阅此问题asm- 在该示例中,循环 1000 次的代码被向量化为一次计算 16 次循环迭代的代码;但是asm循环内部的存在会抑制优化(asm必须达到 1000 次)。
The "memory"clobber makes GCC assume that any memory may be arbitrarily read or written by the asmblock, so will prevent the compiler from reordering loads or stores across it:
所述"memory"撞使得GCC假定任何存储器可以被任意地读取或写入asm块,所以会防止编译器通过它重新排序加载或存储:
This will cause GCC to not keep memory values cached in registers across the assembler instruction and not optimize stores or loads to that memory.
这将导致 GCC 不会通过汇编指令将内存值缓存在寄存器中,并且不会优化对该内存的存储或加载。
(That does not prevent a CPU from reordering loads and stores with respect to another CPU, though; you need real memory barrier instructions for that.)
(不过,这并不能阻止 CPU 重新排序相对于另一个 CPU 的加载和存储;为此您需要真正的内存屏障指令。)
回答by Lily Ballard
asm ("")does nothing (or at least, it's not supposed to do anything.
asm ("")什么都不做(或者至少,它不应该做任何事情。
asm volatile ("")also does nothing.
asm volatile ("")也什么都不做。
asm ("" ::: "memory")is a simple compiler fence.
asm ("" ::: "memory")是一个简单的编译器栅栏。
asm volatile ("" ::: "memory")AFAIK is the same as the previous. The volatilekeyword tells the compiler that it's not allowed to move this assembly block. For example, it may be hoisted out of a loop if the compiler decides that the input values are the same in every invocation. I'm not really sure under what conditions the compiler will decide that it understands enough about the assembly to try to optimize its placement, but the volatilekeyword suppresses that entirely. That said, I would be very surprised if the compiler attempted to move an asmstatement that had no declared inputs or outputs.
asm volatile ("" ::: "memory")AFAIK 与之前的相同。该volatile关键字告诉编译器,它不允许移动该组装块。例如,如果编译器决定每次调用中的输入值都相同,则它可能会被提升到循环之外。我不确定在什么条件下编译器会决定它对程序集有足够的了解以尝试优化其位置,但volatile关键字完全抑制了这一点。也就是说,如果编译器试图移动asm没有声明输入或输出的语句,我会感到非常惊讶。
Incidentally, volatilealso prevents the compiler from deleting the expression if it decides that the output values are unused. This can only happen if there are output values though, so it doesn't apply to asm ("" ::: "memory").
顺便说一句,volatile如果编译器决定输出值未使用,它还会阻止编译器删除表达式。这只会发生在有输出值的情况下,所以它不适用于asm ("" ::: "memory").
回答by James
Just for completeness on Lily Ballard's answer, Visual Studio 2010 offers _ReadBarrier(), _WriteBarrier()and _ReadWriteBarrier()to do the same (VS2010 doesn't allow inline assembly for 64-bit apps).
只是为了Lily Ballard 的回答的完整性,Visual Studio 2010 提供_ReadBarrier(),_WriteBarrier()并_ReadWriteBarrier()执行相同的操作(VS2010 不允许 64 位应用程序的内联程序集)。
These don't generate any instructions but affect the behaviour of the compiler. A nice example is here.
这些不会生成任何指令,但会影响编译器的行为。一个很好的例子是here。
MemoryBarrier()generates lock or DWORD PTR [rsp], 0
MemoryBarrier()产生 lock or DWORD PTR [rsp], 0

