C语言 __asm__ __volatile__ 在 C 中有什么作用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26456510/
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
What does __asm__ __volatile__ do in C?
提问by user3692521
I looked into some C code from
我查看了一些 C 代码
http://www.mcs.anl.gov/~kazutomo/rdtsc.html
http://www.mcs.anl.gov/~kazutomo/rdtsc.html
They use stuff like "inline", "asm" etc like the following:
他们使用诸如“ inline”、“ asm”之类的东西,如下所示:
code1:
代码1:
static __inline__ tick gettick (void) {
unsigned a, d;
__asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) );
return (((tick)a) | (((tick)d) << 32));
}
code2:
代码2:
volatile int __attribute__((noinline)) foo2 (int a0, int a1) {
__asm__ __volatile__ ("");
}
I was wondering what does the code1 and code2 do?
我想知道 code1 和 code2 是做什么的?
回答by Cory Nelson
The __volatile__modifier on an __asm__block forces the compiler's optimizer to execute the code as-is. Without it, the optimizer may think it can be either removed outright, or lifted out of a loop and cached.
在__volatile__一个关于修改__asm__块迫使编译器的优化原样执行代码。没有它,优化器可能认为它可以被彻底删除,或者从循环中取出并缓存。
This is useful for the rdtscinstruction like so:
这对于rdtsc像这样的指令很有用:
__asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) )
This takes no dependencies, so the compiler might assume the value can be cached. Volatile is used to force it to read a fresh timestamp.
这不需要依赖项,因此编译器可能会假设可以缓存该值。Volatile 用于强制它读取新的时间戳。
When used alone, like this:
单独使用时,像这样:
__asm__ __volatile__ ("")
It will not actually execute anything. You can extend this, though, to get a compile-time memory barrier that won't allow reordering any memory access instructions:
它实际上不会执行任何操作。但是,您可以扩展它以获得编译时内存屏障,不允许重新排序任何内存访问指令:
__asm__ __volatile__ ("":::"memory")
The rdtscinstruction is a good example for volatile. rdtscis usually used when you need to time how long some instructions take to execute. Imagine some code like this, where you want to time r1and r2's execution:
该rdtsc指令是 volatile 的一个很好的例子。rdtsc通常在您需要计算某些指令执行所需的时间时使用。想象一些这样的代码,你想在其中计时r1和r2执行:
__asm__ ("rdtsc": "=a" (a0), "=d" (d0) )
r1 = x1 + y1;
__asm__ ("rdtsc": "=a" (a1), "=d" (d1) )
r2 = x2 + y2;
__asm__ ("rdtsc": "=a" (a2), "=d" (d2) )
Here the compiler is actually allowed to cache the timestamp, and valid output might show that each line took exactly 0 clocks to execute. Obviously this isn't what you want, so you introduce __volatile__to prevent caching:
这里编译器实际上被允许缓存时间戳,有效的输出可能显示每行刚好用了 0 个时钟来执行。显然这不是你想要的,所以你引入__volatile__防止缓存:
__asm__ __volatile__("rdtsc": "=a" (a0), "=d" (d0))
r1 = x1 + y1;
__asm__ __volatile__("rdtsc": "=a" (a1), "=d" (d1))
r2 = x2 + y2;
__asm__ __volatile__("rdtsc": "=a" (a2), "=d" (d2))
Now you'll get a new timestamp each time, but it still has a problem that both the compiler and the CPU are allowed to reorder all of these statements. It could end up executing the asm blocks after r1 and r2 have already been calculated. To work around this, you'd add some barriers that force serialization:
现在你每次都会得到一个新的时间戳,但它仍然存在一个问题,即编译器和 CPU 都被允许对所有这些语句重新排序。在已经计算出 r1 和 r2 之后,它可能最终会执行 asm 块。要解决此问题,您需要添加一些强制序列化的障碍:
__asm__ __volatile__("mfence;rdtsc": "=a" (a0), "=d" (d0) :: "memory")
r1 = x1 + y1;
__asm__ __volatile__("mfence;rdtsc": "=a" (a1), "=d" (d1) :: "memory")
r2 = x2 + y2;
__asm__ __volatile__("mfence;rdtsc": "=a" (a2), "=d" (d2) :: "memory")
Note the mfenceinstruction here, which enforces a CPU-side barrier, and the "memory" specifier in the volatile block which enforces a compile-time barrier. On modern CPUs, you can replace mfence:rdtscwith rdtscpfor something more efficient.
请注意mfence这里的指令,它强制执行 CPU 端屏障,以及 volatile 块中的“内存”说明符,它强制执行编译时屏障。在现代的CPU,你可以替换mfence:rdtsc使用rdtscp的东西更有效。
回答by tmlen
asmis for including native Assembly code into the C source code. E.g.
asm用于将本机汇编代码包含到 C 源代码中。例如
int a = 2;
asm("mov a, 3");
printf("%i", a); // will print 3
Compilers have different variants of it. __asm__should be synonymous, maybe with some compiler-specific differences.
编译器有不同的变体。__asm__应该是同义词,也许有一些特定于编译器的差异。
volatilemeans the variable can be modified from outside (aka not by the C program). For instance when programming a microcontroller where the memory address 0x0000x1234is mapped to some device-specific interface (i.e. when coding for the GameBoy, buttons/screen/etc are accessed this way.)
volatile意味着可以从外部修改变量(也就是不能被 C 程序修改)。例如,在对微控制器进行编程时,其中内存地址0x0000x1234映射到某些特定于设备的接口(即在为 GameBoy 编码时,按钮/屏幕/等以这种方式访问。)
volatile std::uint8_t* const button1 = 0x00001111;
This disabled compiler optimizations that rely on *button1not changing unless being changed by the code.
这禁用了依赖于*button1不更改的编译器优化,除非被代码更改。
It is also used in multi-threaded programming (not needed anymore today?) where a variable might be modified by another thread.
它也用于多线程编程(今天不再需要?),其中一个变量可能被另一个线程修改。
inlineis a hint to the compiler to "inline" calls to a function.
inline是对编译器“内联”调用函数的提示。
inline int f(int a) {
return a + 1
}
int a;
int b = f(a);
This should not be compiled into a function call to fbut into int b = a + 1. As if fwhere a macro. Compilers mostly do this optimization automatically depending on function usage/content. __inline__in this example might have a more specific meaning.
这不应该编译成函数调用,f而是编译成int b = a + 1. 好象f哪里有宏。编译器主要根据函数使用/内容自动进行此优化。__inline__在这个例子中可能有更具体的含义。
Similarily __attribute__((noinline))(GCC-specific syntax) prevents a function from being inlined.
类似地__attribute__((noinline))(特定于 GCC 的语法)防止函数被内联。
回答by David C. Rankin
The __asm__attribute specifies the name to be used in assembler code for the function or variable.
该__asm__属性指定要在函数或变量的汇编代码中使用的名称。
The __volatile__qualifier, generally used in Real-Time-Computing of embedded systems, addresses a problem with compiler tests of the status registerfor the ERRORor READYbit causing problems during optimization. __volatile__was introduced as a way of telling the compiler that the object is subject to rapid change and to force every reference of the object to be a genuine reference.
在__volatile__预选赛中,一般的实时计算的嵌入式系统,地址与编译器测试一个问题status register的ERROR或READY位造成优化过程中的问题。__volatile__引入是为了告诉编译器对象会快速变化并强制对象的每个引用都是真正的引用。

