X86 指令顺序会发生跨函数调用吗?
假设我有如下伪C代码:X86 指令顺序会发生跨函数调用吗?,x86,cpu-architecture,X86,Cpu Architecture,假设我有如下伪C代码: int x = 0; int y = 0; int __attribute__ ((noinline)) func1(void) { int prev = x; (1) x |= FLAG; (2) return prev; (3) } int main(void) { int tmp; ... y = 5; (4) compiler_mem_barrier(); func1(); compi
int x = 0;
int y = 0;
int __attribute__ ((noinline)) func1(void)
{
int prev = x; (1)
x |= FLAG; (2)
return prev; (3)
}
int main(void)
{
int tmp;
...
y = 5; (4)
compiler_mem_barrier();
func1();
compiler_mem_barrier();
tmp = y; (5)
...
}
假设这是一个单线程进程,所以我们不必担心
关于锁。假设代码在x86系统上运行。我们还假设编译器不进行任何重新排序
我知道x86系统只能对写/读指令进行重新排序
(读操作可以通过旧的写操作重新排序到不同的位置,但是
不适用于对同一位置的较旧写入)。但我不清楚
如果call/ret指令被认为是写/读指令
说明书下面是我的问题:
mov %gs:0x24,%eax (1)
orl $0x8,%gs:0x24 (2)
retq (3)
请帮忙。谢谢 无序执行可以对任何东西重新排序,但它保留了代码按程序顺序执行的假象。OoOE的基本规则是不要破坏单线程程序。硬件跟踪依赖关系,因此指令可以在输入和执行单元准备就绪后立即执行,但保留了一切都按程序顺序发生的假象
您似乎混淆了单个核心上的OoOE与加载/存储对其他核心全局可见的顺序。() 如果有一个线程观察另一个线程在另一个内核上运行的堆栈内存,那么是的,
call
(推送返回地址)生成的存储将与其他存储一起订购
但是,在运行此代码的线程中无序执行实际上可以在存储因缓存未命中而延迟时或在执行长依赖链时执行调用
和ret
指令。多个缓存未命中可以同时执行。内存顺序缓冲区只需确保在之前的存储之后,后面的存储才真正成为全局可见的,以保留x86的内存顺序语义
如果您有关于硬件重新排序的特定问题,您可能应该发布asm代码,而不是C代码,因为在为x86这样的强顺序目标编译时,这一点不会改变 另请参见(一个Java问题,但我的答案不是Java特有的)
re:您的编辑 这个答案已经假设您的函数是
noinline
,并且您所说的ASM看起来像您的C,而不是编译器实际从您的代码生成的东西
mov %gs:0x24,%eax (1)
orl $0x8,%gs:0x24 (2)
retq (3)
因此
x
实际上在线程本地存储中,而不是一个普通的全局intx
。然而,这对于无序执行实际上并不重要;带有%gs
段重写的加载仍然是加载。问问自己:编译器可以内联函数吗?假设函数没有内联。如果函数是内联的,我知道会发生什么。当然,函数是编译器重新排序的障碍。但是对于处理器afaik来说,call
和ret
都没有强制序列化。请参阅8.3序列化说明。只要重新排序不改变应用程序的顺序(即,假设规则),编译器就可以自由地重新排序和重新排列,以优化代码。请注意,编译器执行的重新排序与处理器本身执行的无序执行非常不同。您的实际问题是什么?另请参见:,以及其他可通过搜索功能查找的问题。