glibc&x27的目的是什么;s原子强制读取函数?

glibc&x27的目的是什么;s原子强制读取函数?,c,atomic,glibc,inline-assembly,libc,C,Atomic,Glibc,Inline Assembly,Libc,我试图理解原子强制读取定义的目的,它经常出现在malloc.c的GNULIBC实现中 对于内联汇编,我并不擅长,但它看起来返回的值与输入值的类型完全相同。我错过了什么 原子.h中的原子强制读取定义 523 #ifndef atomic_forced_read 524 # define atomic_forced_read(x) \ 525 ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; }) 526 #endif 链

我试图理解原子强制读取定义的目的,它经常出现在malloc.c的GNULIBC实现中

对于内联汇编,我并不擅长,但它看起来返回的值与输入值的类型完全相同。我错过了什么

原子.h中的原子强制读取定义

523 #ifndef atomic_forced_read
524 # define atomic_forced_read(x) \
525   ({ __typeof (x) __x; __asm ("" : "=r" (__x) : "0" (x)); __x; })
526 #endif
链接到atomic.h


一种用法是原子强制读取:

#if HAVE_MALLOC_INIT_HOOK
  void (*hook) (void) = atomic_forced_read(__malloc_initialize_hook);
  if (hook != NULL)
    (*hook)();
#endif
似乎可以从另一个线程更改
\uuuuuuMalloc\uInitialize\uHook
,这样,如果
\uuuuMalloc\uInitialize\uHook
NULL
检查后再次从内存加载
则其值可能已更改回
NULL

atomic\u forced\u read
确保由于
=r
输出约束而将
\u malloc\u initialize\u hook
加载到寄存器中,以便
\u malloc\u initialize\u hook
检查后不会从内存中重新加载
\u malloc\u initialize\u hook
。这个空的
asm
打破了
钩子
\uu malloc\u initialize\u钩子
的编译器依赖性,因为
钩子
现在是用存储在寄存器中的
\uuuuuumalloc\u initialize\u钩子
初始化的。用
\uuux
初始化
钩子后,后者将消失,并且无法重新加载



在C11模式下,
\u malloc\u initialize\u hook
可以是
原子的\u uintpttr\u t
原子的\u load\u显式(&\u malloc\u initialize\u hook,memory\u order\u released)
可以用来代替
原子的强制读取
从内存加载
\u malloc\u initialize\u hook
?!原子强制读取与空指针有什么关系?!顺便说一句,C标准始终要求
free(0)
是安全的,什么也不做。曾经有(不合规的和/或1989年以前的)C库会崩溃,但现在你几乎肯定不会遇到这样的库,除非你在做逆向计算。(更多详细信息,请参阅dandan78的链接。)在我看来,它与Linux内核中的ACCESS_ONCE类似。它只是强制读取到寄存器中,但我不知道这与易失性读取相比如何。如果数据已经在寄存器中,它会强制重新加载吗?它会阻止编译器将对目标的访问转换为对源数据的访问吗?@PeterCordes:在malloc中,它用于防止在检查钩子函数指针是否为NULL和调用它之间出现竞争条件。它的目的是访问共享变量,因为您知道访问将是原子的(支持的平台的大小和对齐方式合适),并防止编译器省略/复制您的加载。我只是不知道它到底能提供什么保证,尤其是与不稳定的读取相比。@ninjalj:听起来像是大规模的过度复杂;只需将共享值加载到本地,然后在通过它调用之前检查其是否为非NULL。不需要特殊的魔法来防止空检查优化掉,除非指针在之前或之后被无条件地取消引用。(然后编译器将对其进行优化,因为deref由于UB而意味着非NULL)。OP仍然没有在问题中包括用例,我也没有费心去寻找自己。是的,它“清洗”了
\uuu malloc\u initialize\u hook
的值,因此优化器不能决定加载全局代码两次。正如ninjali对这个问题的评论,这表明即使在使用本地(但没有
asm
volatile
)的情况下,S390也会发生这种情况。@PeterCordes您提到的“清洗”,然而,
std::launder
是一个非常独特和有限的工具,请参阅。