如果预取了无效地址会怎样?

时间:2016-10-19 10:02:49

标签: c caching assembly disassembly prefetch

简单MWE:

int* ptr = (int*)malloc(64 * sizeof(int));
_mm_prefetch((const char*)(ptr + 64), _MM_HINT_0);
  1. 这是定义的还是未定义的行为?
  2. 这会引发信号并中止程序运行吗?
  3. 我问,因为我可以在编译器生成的代码中看到这样的预取,其中在循环预取中完成而不检查地址(存储在rbx中):

    400e73:       49 83 c5 40             add    r13,0x40
    400e77:       62 f1 f9 08 28 03       vmovapd zmm0,ZMMWORD PTR [rbx]
    400e7d:       4d 3b ec                cmp    r13,r12
    400e80:       62 d1 f9 08 eb 4d ff    vporq  zmm1,zmm0,ZMMWORD PTR [r13-0x40]
    400e87:       90                      nop
    400e88:       62 d1 78 08 29 4d ff    vmovaps ZMMWORD PTR [r13-0x40],zmm1
    400e8f:       72 03                   jb     400e94 <main+0x244>
    400e91:       49 89 c5                mov    r13,rax
    400e94:       62 f1 78 08 18 53 1d    vprefetch1 [rbx+0x740]
    400e9b:       ff c1                   inc    ecx
    400e9d:       62 f1 78 08 18 4b 02    vprefetch0 [rbx+0x80]
    400ea4:       48 83 c3 40             add    rbx,0x40
    400ea8:       81 f9 00 00 10 00       cmp    ecx,0x100000
    400eae:       72 c3                   jb     400e73 <main+0x223>
    

1 个答案:

答案 0 :(得分:4)

首先,编译器或者你这样做在理论上是非常不同的东西。仅仅因为它看起来是等同的并不是这样的,所以允许编译器使用任何有效的黑客攻击,无论它们是否可以在完全标准的C中表达或定义。

当然,预取不会产生信号*,如果确实如此,它几乎是无用的。但是对于某些无效指针来说可能非常慢,这取决于它们是否触发TLB未命中。所以编译器可以安全地使用它,但它不应该随意使用它。

现在使用指针算法来创建越界指针(除了刚刚结束)理论上是UB,但是当应用于指针时,无论如何它都是UB的类型(具有平坦的内存和它#39; s只是一个补充,唯一可能失败的方法是编译器不顾一切地检测它,这意味着它必须推理动态大小)。显然上述案例必须得到声称支持SSE内在函数的编译器的支持,否则你无法合理地使用预取,正如这个答案所证明的那样(并且他们必须在标准之上做出更多额外的保证)

*来自手册:

  

PREFETCHh指令只是一个提示,不会影响程序行为。

信号会影响程序行为,因此无法生成它们。