LEA是x86中唯一一条内存操作数不能访问内存的指令吗?

时间:2013-12-16 23:26:21

标签: assembly x86

我正在使用来自the bastard的x86反汇编程序库libdis,我正在尝试查找哪些指令访问内存。

参考这两条指示:

mov eax, [ebx + 10]
lea eax, [ebx + 10]

libdis中,两者都以指令类型insn_mov列出,并且地址操作数在两种情况下都具有相同的标志。因此,我可以判断是否访问内存的唯一方法是查看指令助记符。

因此我的问题是:LEA是使用内存操作数的唯一指令,它实际上并不访问内存吗?任何引用的链接都会很好。

3 个答案:

答案 0 :(得分:10)

prefetch指令族(prefetcht1,prefetcht2,prefetcht3,prefetchnta)要求处理器将这些内存行拉入缓存中,因为很快就会需要它们。但是,英特尔的文档清楚地表明,传递给预取的错误地址不会导致任何错误。这样软件就可以将可能超出范围的地址传递给预取而不先检查它们,以便在执行这些检查时数据可以在飞行中。

预取也没有“输出”,与LEA不同。

答案 1 :(得分:7)

英特尔有一套“NOP”指令,用于记忆操作数。

我不认为他们触摸记忆;实际上,我不确定他们是否真的形成了一个地址并通过内存映射运行它并检查保护。我不这么认为;我构建了一个编译器,它可以生成各种各样的寻址模式,作为不同大小的空间填充NOP,并且永远不会陷入陷阱。

答案 2 :(得分:4)

不需要有效地址

prefetch / prefetchwnop,如其他答案中所述。

任何AVX512屏蔽的加载或存储都使用全零掩码,例如vmovaps [rdi]{k1}, zmm1。或AVX vmaskmovps / vpmaskmovdAVX2 gather / AVX512 gather或使用全零掩码散布。这些都对无效地址进行故障抑制。 (速度很慢,但是没有实际的内存访问。)

invlpg m8采用一个ModRM,它指定了一个虚拟地址。 (特权指令)。代替从该地址加载,它使该地址的TLB条目以及缓存在页面行程序中的更高级页面目录条目无效。

verr / verw验证要读取或写入的段:它们采用ModRM寻址模式,并根据段限制检查地址,并设置FLAGS。 (以及最近的微码更新。verw also clears internal CPU buffers so OSes can use it to mitigate L1TF / MDS vulnerabilities)。

rep cmpsb或其他RCX = 0的字符串指令执行零次迭代,而不访问[RDI][RSI]隐式内存操作数。我认为这意味着即使地址错误也不会出错。微码肯定足够慢

cldemote(Intel Tremont的新功能)-预取相反;性能提示,可将数据推向共享的L3,以加快从另一个内核的首次访问。如果没有该功能,它将在硬件上解码为NOP。预取不会对无效地址造成错误(尽管在使用微码辅助来抑制错误时它们可能很慢);对于cldemote,该手册不是一种或另一种方式都100%清晰的方法,但确实将其称为一种推测性提示。

在某些处理器实现中,CLDEMOTE指令可以设置页表中的A位,而不设置D位。

如果在缓存中找不到该行,则该指令将被视为NOP。

MPX bndcl bnd, r/m64 / bndcu / bndcn / bndmk-内存源表单具有内置的LEA:Operation部分的伪代码甚至说{{1} }。寄存器源形式仅将寄存器值直接用作地址。如手册所述,该指令不会导致任何内存访问,并且不会读取或写入任何标志。(它会在边界上引发TEMP ← LEA(mem);异常)。请注意,不推荐使用MPX。


需要有效地址,但本身不需要加载或存储。

#BR / clflushopt / clflush 都使用一个内存操作数来指定要刷新或完全写回DRAM的缓存行,可用于非易失性DIMM以确保提交到NV存储(因此与clwb不同,它们不是 not 只是暗示如果繁忙或找不到地址,CPU可能会掉线)。它们确实需要有效的虚拟地址,并且确实会影响相应高速缓存行的MESI状态。但是,如果L1d缓存中不存在该缓存行,则不会将其引入,然后再次刷新。我认为它会从所有内核的缓存中逐出,因此一行上的一个内核垃圾邮件cldemote会影响另一内核对其的读写。

The CLFLUSHOPT instruction可以在所有特权级别上使用,并且受所有权限检查和与字节加载相关的错误的约束(此外,CLFLUSHOPT指令允许刷新线性仅执行段中的地址)。像加载一样,CLFLUSHOPT指令将页表中的A设置为A,而不将D设置为

MONITOR 将内存地址视为隐式clflush,未在ModRM中进行编码。它实际上并不从中加载,而是仅设置内核以通知另一个内核何时更改该内存。但是,它确实像负载一样工作。 (大概使该行进入MESI共享状态,这样它就可以在写入之前通知另一个内核何时使它无效。)

将MONITOR指令作为相对于其他内存事务的装入操作进行排序。该指令需要进行权限检查以及与字节加载相关的错误。像加载一样,MONITOR在页表中设置A位,但不设置D位。

umonitor(用户空间版本)是相同的。