GCC如何知道在声明内存阻塞器时需要将寄存器刷新到内存中



扩展Asm手册https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html以下是关于"记忆"的打击:

"内存"clobber告诉编译器汇编代码对输入和输出操作数中列出的项以外的项执行内存读取或写入(例如,访问其中一个输入参数指向的内存)。为了确保内存包含正确的值,GCC可能需要在执行asm之前将特定的寄存器值刷新到内存中。此外,编译器不假设在asm之前从内存读取的任何值在该asm之后保持不变;它会根据需要重新加载它们。使用"内存"缓冲区有效地为编译器形成了一个读/写内存屏障。

我对刷新内存的决定感到困惑。在asm代码之前,GCC如何知道寄存器是否用作内存位置的缓存,因此需要刷新到内存?这是缓存一致性的一部分吗(我认为缓存一致性是一种硬件行为)?在asm代码之后,GCC如何将寄存器区分为缓存,并在下次读取寄存器时决定从内存中读取,因为缓存可能很旧?

在asm代码之前,GCC如何知道寄存器是否充当一个内存位置的缓存,因此需要刷新到内存中?

因为GCC是生成此代码的人。

一般来说,从GCC的角度来看:

[C code to compile]
[your inline asm with clobber]
[C code to compile]

GCC在内联asm之前和之后生成汇编指令,因此它知道之前和之后的一切

[GCC generated asm]
[compiler memory barrier]
[GCC generated asm]

所以GCC在屏障之前和之后生成程序集,并且它知道它不能有跨越内存屏障的内存访问。基本上,从GCC的角度来看,有代码要编译,然后是内存障碍,然后是更多的代码要编译。仅此而已,内存障碍在这里适用的唯一限制是GCC生成的代码的内存访问不能越过这个障碍。

因此,例如,如果GCC从内存加载一个具有值的寄存器,对其进行更改,并将其存储回内存,则加载和存储就无法跨越障碍。根据代码的不同,它们必须位于屏障之前或之后(或者两次,在两侧)。

我建议你阅读这个相关的SO线程。

最新更新