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



我正在使用libdis,来自混蛋的x86反汇编器库,我正在尝试找出哪些指令访问内存。

参考以下两个说明:

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

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

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

prefetch系列

指令(prefetcht1,prefetcht2,prefetcht3,prefetchnta(要求处理器将这些内存行拉入缓存,因为它们很快就会被需要。但是,英特尔的文档清楚地表明,传递给预取的错误地址不会导致任何故障。这样,软件就可以将潜在的越界地址传递到预取,而无需先检查它们,以便在执行这些检查时数据可以处于动态状态。

LEA不同,预取也没有"输出"。

英特尔有一个多字节的"NOP"指令,带有操作码0F 1F /0,需要内存寻址操作数。 来自英特尔手册:

多字节NOP指令不会改变寄存器的内容,也不会发出存储器操作

注释中的讨论是关于将nop的操作码字节放在未映射页面的末尾,如果它无法读取包括 ModR/M 和位移字节在内的完整指令,则代码获取错误。 这与这个问题是正交的。


您可以将 long-NOP 视为按如下方式工作:

  • 指令解码硬件知道如何找到采用 ModRM 的指令的结尾(这意味着可选的 SIB 和/或位移(。
  • 基于该操作码专门作为NOP,CPU的其余部分不会对ModRM编码的寻址模式执行任何操作。

这使得软件可以使用各种寻址模式和前缀对多字节 NOP 进行编码。 CPU可以设计为处理它,除了将另一个操作码识别为nop之外,不需要任何特殊硬件。 整体指令格式与大多数指令格式相同。

不需要有效地址

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

任何 AVX512 屏蔽加载或存储与全零掩码,如 vmovaps [rdi]{k1}, zmm1 . 或AVX vmaskmovps/vpmaskmovd. AVX2 聚集/AVX512 聚拢或散射,全零掩码。 这些都对无效地址执行故障抑制。 (速度较慢,但没有实际的内存访问。

invlpg m8采用指定虚拟地址的 ModRM。 (特权指导(。 它不会从该地址加载,而是使该地址的 TLB 条目失效,并使页面步行者中缓存的更高级别页面目录条目失效。

verr/verw — 验证段以进行读取或写入:它们采用 ModRM 寻址模式并根据段限制检查地址,设置 FLAGS。 (以及最近的微码更新。 verw 还会清除内部 CPU 缓冲区,以便操作系统可以使用它来缓解 L1TF/MDS 漏洞(。

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

cldemote(Intel Tremont 中的新功能(——与预取相反;性能提示,将数据推送到共享 L3,以加快从另一个内核的首次访问。 它解码为没有该功能的硬件上的NOP。 预取不会对无效地址出错(尽管当它们采用微码辅助来抑制错误时,它们可能会很慢(;对于cldemote来说,手册并不是100%清楚的,但确实称之为推测性的提示。

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

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

MPX bndcl bnd, r/m64/bndcu/bndcn/bndmk - 内存源形式具有内置的 LEA:操作部分的伪代码甚至说 TEMP ← LEA(mem); . 寄存器源表单仅直接使用寄存器值作为地址。 正如手册所说,此指令不会导致任何内存访问,也不会读取或写入任何标志。 (它引发了一个关于越界的#BR例外(。 请注意,MPX 已弃用。

<小时 />

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

clflush/clflushopt/clwb都采用内存操作数来指定要刷新或写回DRAM的缓存行,可与非易失性DIMM一起使用以确保提交到NV存储(因此与cldemote不同,这些不仅仅是提示CPU在繁忙或找不到地址时可能会丢弃(。 它们确实需要有效的虚拟地址,并且会影响相应缓存行的 MESI 状态。 但是,如果 L1d 缓存中不存在缓存行,则不会引入它,然后再次刷新。 我认为它会从所有内核的缓存中逐出,因此一个内核在一行上发送垃圾邮件clflush会影响另一个内核的读取/写入。

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

MONITOR将内存地址作为隐式DS:RAX/EAX/AX,而不是在ModRM中编码。 它实际上并没有从中加载,而只是设置内核以注意到另一个内核何时更改该内存。 但是,它确实像负载一样工作。 (大概是让线路进入 MESI 共享状态,以便它可以在写入之前注意到另一个内核何时使其无效。

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

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

最新更新