声明内存破坏者时,GCC如何知道需要将寄存器刷新到内存中?

时间:2019-01-26 16:09:06

标签: gcc assembly memory

Extended Asm手册https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html对“内存”破坏者说了以下几点:

  

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

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

1 个答案:

答案 0 :(得分:1)

  

在asm代码之前,GCC如何知道寄存器是否用作   缓存到某个内存位置,因此需要刷新到内存?

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

通常,从海湾合作委员会的角度来看:

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

GCC会在您的嵌入式asm之前和之后生成汇编指令,因此它知道之前和之后的所有信息。现在,由于内存破坏器意味着sw内存屏障,因此适用以下条件:

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

因此,GCC会在屏障之前和之后生成程序集,并且它知道无法通过内存屏障访问内存。基本上,从GCC的角度来看,先要编译代码,然后是内存屏障,然后再编译更多代码,就是这样,内存屏障在这里适用的唯一限制是GCC生成的代码一定不能具有跨越此屏障的内存访问。

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

我建议您阅读与此相关的thread