标签: speculative-execution

指令顺序可以发生跨函数调用吗?

假设我有如下伪 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();
   compiler_mem_barrier();
   tmp = y;  (5)
   ...
}
Run Code Online (Sandbox Code Playgroud)

假设这是一个单线程进程,所以我们不需要担心锁。假设代码在 x86 系统上运行。我们还假设编译器不进行任何重新排序。

据我了解,x86 系统只能重新排序写入/读取指令(读取可能会与较旧的写入重新排序到不同的位置,但不能与较旧的写入重新排序到同一位置)。但我不清楚 call/ret 指令是否被视为 WRITE/READ 指令。这是我的问题:

  1. 在 x86 系统上,“call”是否被视为 WRITE 指令?我认为是这样,因为调用会将地址推入堆栈。但我没有找到官方文件正式这么说。所以请大家帮忙确认一下。

  2. 出于同样的原因,“ret”是否被视为 READ 指令(因为它从堆栈中弹出地址)?

  3. 实际上,“ret”指令可以在函数内重新排序吗?例如,下面的ASM代码中(3)可以在(2)之前执行吗?这对我来说没有意义,但“ret”不是序列化指令。我在英特尔手册中没有找到任何地方说“ret”不能重新排序。

  4. 上面的代码中,(1)可以先于(4)执行吗?据推测,读指令 (1) 可以在写指令 (4) 之前重新排序。“call”指令可能有“jmp”部分,但是具有推测执行......所以我觉得它可能会发生,但我希望更熟悉这个问题的人可以证实这一点。

  5. 上面的代码中,(5)可以先于(2)执行吗?如果“ret”被认为是一个READ指令,那么我认为它不会发生。但我再次希望有人能证实这一点。

如果需要 func1() 的汇编代码,它应该类似于:

mov    %gs:0x24,%eax          (1) 
orl    $0x8,%gs:0x24 …
Run Code Online (Sandbox Code Playgroud)

x86 assembly cpu-architecture speculative-execution

6
推荐指数
1
解决办法
1128
查看次数

当Skylake CPU错误预测分支时会发生什么?

我试图详细了解当分支预测错误时,skylake CPU管道的各个阶段中的指令会发生什么,以及从正确的分支目标开始执行指令的速度如何。

因此,让我们在这里将两个代码路径标记为红色(一个预测但未实际采用)和绿色(一个已预测但未预期)。所以问题是:1.在红色指令开始被丢弃之前,分支必须经过管道多远(以及在管道的哪个阶段被丢弃)?2.绿色指令(在分支到达的流水线阶段方面)多久可以开始执行?

我看过Agner Fogg的文档和许多讲义,但这些观点并不清楚。

x86 intel cpu-architecture speculative-execution branch-prediction

5
推荐指数
1
解决办法
369
查看次数

为什么这种谱线在Kaby湖上不起作用?

我正在尝试在我的Kabe湖7600U上创建一个光谱线(cfr。Henry Wong),正在运行CentOS 7。

完整的测试库可在GitHub找到

我的specpoline版本如下(cfr。spec.asm):

specpoline:
        ;Long dependancy chain
        fld1
        TIMES 4 f2xm1
        fcos
        TIMES 4 f2xm1
        fcos
        TIMES 4 f2xm1

        %ifdef ARCH_STORE
            mov DWORD [buffer], 241     ;Store in the first line
        %endif

        add rsp, 8
        ret
Run Code Online (Sandbox Code Playgroud)

此版本与黄宏Henry的版本不同,流程被转移到建筑路径中。当原始版本使用固定地址时,我将目标传递到堆栈中。
这样,add rsp, 8将删除原始的寄信人地址并使用人工地址。

在函数的第一部分中,我使用一些旧的FPU指令创建了一个长延迟依赖关系链,然后创建了一个独立的链,试图欺骗CPU返回堆栈预测变量。


代码说明

使用FLUSH + RELOAD 1将specpoline插入到配置文件上下文中,同一程序集文件还包含:

buffer

一个连续的缓冲区,它跨越256个不同的高速缓存行,每个高速缓存行之间用GAP-1行分隔开来,总共为256*64*GAP字节。

GAP用于防止硬件预取。

随后是图形描述(每个索引紧接另一个)。

F + R缓冲区

timings

256个DWORD数组,每个条目保存访问F + R缓冲区中相应行所需的时间(以核心周期为单位)。

flush

一个小功能,可以触摸F + R缓冲区的每一页(带有存储,请确保COW在我们这一边)并逐出指定的行。

“个人资料”

标准配置文件功能 …

assembly x86-64 cpu-architecture speculative-execution branch-prediction

5
推荐指数
1
解决办法
84
查看次数

模拟属性“不可预测”

现代 C++ 中有[[likely]]和属性。G++ 和 clang++ 中[[unlikely]]都有相应的__builtin_expect(x, 1)内置函数。__builtin_expect(x, 0)但也有__builtin_unpredictable(x)__builtin_expect_with_probability(x, 1, 0.5)或(同样)__builtin_expect_with_probability(x, 0, 0.5)内置函数,它告诉编译器防止 CPU 用来自(错误)预测分支的指令填充管道,因为从错误预测路径刷新+恢复管道的成本在统计上大于执行 w/o完全是投机执行。

在和分支上使用[[likely]]或同样[[unlikely]]使用属性(如以下代码片段所示)是否等同于使用假设属性?ifelse[[unpredictable]]

if (x) [[likely]] {
    // "if" branch
} else [[likely]] {
    // "else" branch
}
Run Code Online (Sandbox Code Playgroud)

或者

if (x) [[unlikely]] {
    // "if" branch
} else [[unlikely]] {
    // "else" branch
}
Run Code Online (Sandbox Code Playgroud)

据我所知,如果存在,if则编译器默认将分支视为默认情况,如果不存在(因为它通常是从当前函数提前退出的不愉快路径检查的形式)。因此,如果我只是省略任何一个属性,那么它并不等同于指定假设属性。[[likely]]else[[unlikely]]else[[unpredictable]]

c++ compiler-optimization speculative-execution branch-prediction c++-attributes

5
推荐指数
1
解决办法
160
查看次数

SERIALIZE 指令是否会阻止推测执行?

最近遇到了SERIALIZE指令。

串行化指令执行。在获取并执行下一条指令之前,SERIALIZE 指令可确保完成先前指令对标志、寄存器和内存的所有修改,从而耗尽对内存的所有缓冲写入。

这是一个示例 masm64 程序,其扩展名为Secret Key. 在访问密钥之前,它会通过调用包围敏感代码,SERIALIZE以期防止任何类型的推测执行。

option casemap:none

includelib kernel32.lib
includelib libcmt.lib

.data
sensitiveData db "My Secret Key", 0

.code
main proc
    SERIALIZE                     
    lea     eax, [sensitiveData]
    SERIALIZE                     
    ret
main endp

end
Run Code Online (Sandbox Code Playgroud)

问题

可以SERIALIZE用来缓解推测执行漏洞,例如Meltdown吗?

更新

刚刚发现这篇文章解释了这个新指令。

Linux 内核准备使用英特尔的新 SERIALIZE 指令

...英特尔 Linux 工程师发送了一系列补丁,以在内核的sync_core() 函数中使用英特尔 SERIALIZE 指令。Linux 的sync_core 函数被调用来停止推测执行和预取修改后的代码。...

x86 assembly cpu-architecture speculative-execution

5
推荐指数
0
解决办法
82
查看次数

为什么不预测两个分支?

CPU使用分支预测来加速代码,但仅限于实际采用第一个分支.

为什么不简单地采取两个分支?也就是说,假设两个分支都将被命中,缓存两侧,并在必要时采取适当的分支.缓存不需要无效.虽然这需要编译器预先加载两个分支(更多的内存,适当的布局等),但我认为适当的优化可以简化两者,以便可以从单个预测器获得接近最优的结果.也就是说,需要更多的内存来加载两个分支(对于N个分支是指数的),大多数时候应该能够在完成执行分支之前足够快地用新代码"重新缓存"失败的分支. .

if(x)Bl else Br;

不假设采用Bl,而是假设采用Bl和Br(某种类型的并行处理或特殊交织),并且在实际确定分支之后,一个分支随后无效,然后可以释放缓存以供使用(可能是一些需要特殊技术的类型才能正确填写和使用它.

实际上,不需要预测电路,并且所有用于此的设计可以用于处理两个分支.

任何想法,如果这是可行的?

cpu cpu-architecture prefetch speculative-execution branch-prediction

4
推荐指数
1
解决办法
584
查看次数

推测执行的 CPU 分支是否可以包含访问 RAM 的操作码?

据我了解,当 CPU 推测性地执行一段代码时,它会在切换到推测性分支之前“备份”寄存器状态,以便如果预测结果错误(使分支无用)——寄存器状态将是安全恢复,而不会破坏“状态”。

所以,我的问题是:推测执行的 CPU 分支是否可以包含访问 RAM 的操作码?

我的意思是,访问 RAM 不是“原子”操作——如果数据当前不在 CPU 缓存中,那么从内存中读取一个简单的操作码可能会导致实际的 RAM 访问,这可能会变成一个非常耗时的操作,从 CPU 的角度来看。

如果在推测分支中确实允许这种访问,它是否仅用于读取操作?因为,我只能假设,如果一个分支被丢弃并执行“回滚”,根据它的大小恢复写操作可能会变得非常缓慢和棘手。而且,可以肯定的是,至少在某种程度上支持读/写操作,因为寄存器本身,在某些 CPU 上,据我所知,物理上位于 CPU 缓存上。

所以,也许更精确的表述是:推测执行的一段代码有什么限制?

cpu cpu-architecture speculative-execution

4
推荐指数
1
解决办法
518
查看次数

MapReduce和Yarn之间的差异

我正在搜索关于落后问题的hadoop和mapreduce以及这个问题的论文
但是昨天我发现有纱线的hadoop 2,
遗憾的是没有纸张谈论纱线中的拖拉机问题
所以我想知道什么是区别部分落后者中的MapReduce和Yarn?纱线是否存在落后问题?
当MRmaster向资源经理询问资源时,资源经理会为MRmaster提供所需的所有资源,还是根据集群计算能力?
非常感谢,,

hadoop mapreduce speculative-execution hadoop-yarn

2
推荐指数
2
解决办法
1万
查看次数

为什么CPU推测执行不会导致OOB程序崩溃?

这些问题源于阅读Spectre 攻击论文。如果我理解正确的话,攻击源于 CPU 启发式推测执行(错误)代码分支的可能性。考虑这个例子(C 语言):

int arr[42];
if (i < 42) {
    int j = arr[i];
}
Run Code Online (Sandbox Code Playgroud)

如果我正确理解了这篇论文,int j = arr[i]即使在i >= 42. 我的问题是 - 当我访问超出其范围的数组时,我的程序经常会崩溃(Linux 上的分段错误,Windows 上的“程序执行了非法操作”错误)。

为什么在数组越界访问的情况下推测执行不会导致程序崩溃?

memory security cpu cpu-architecture speculative-execution

2
推荐指数
1
解决办法
500
查看次数