我正在使用来自混蛋libdis
的 x86 反汇编程序库,我试图找出哪些指令访问内存。
参考这两个指令:
mov eax, [ebx + 10]
lea eax, [ebx + 10]
在libdis
中,两者都以指令类型列出insn_mov
,并且地址操作数在两种情况下都具有相同的标志。因此,我可以判断是否访问内存的唯一方法是查看指令助记符。
因此我的问题是:LEA 是唯一使用实际上不访问内存的内存操作数的指令吗?任何指向参考的链接都会很好。
我正在使用来自混蛋libdis
的 x86 反汇编程序库,我试图找出哪些指令访问内存。
参考这两个指令:
mov eax, [ebx + 10]
lea eax, [ebx + 10]
在libdis
中,两者都以指令类型列出insn_mov
,并且地址操作数在两种情况下都具有相同的标志。因此,我可以判断是否访问内存的唯一方法是查看指令助记符。
因此我的问题是:LEA 是唯一使用实际上不访问内存的内存操作数的指令吗?任何指向参考的链接都会很好。
指令系列(prefetcht1、prefetcht2、prefetcht3、prefetchnta)要求处理器将这些prefetch
内存线拉入高速缓存,因为它们很快就会被需要。但是,英特尔的文档清楚地表明,传递给预取的错误地址不会导致任何故障。这样一来,软件就可以将潜在的越界地址传递给预取,而无需先检查它们,以便在执行这些检查时数据可以在传输中。
与LEA
.
英特尔有一个带有操作码的多字节“NOP”指令,0F 1F /0
该指令采用内存寻址操作数。来自英特尔的手册:
多字节 NOP 指令不会改变寄存器的内容,也不会发出内存操作
评论中的讨论是关于将 a 的操作码字节放在nop
未映射页面的末尾,如果它无法读取包括 ModR/M 和位移字节的完整指令,则代码获取错误。这与这个问题正交。
您可以认为 long-NOP 的工作方式如下:
这使得软件可以通过使用各种寻址模式和前缀来编码多字节 NOP。CPU 可以设计为处理它,而不需要任何特殊硬件,除了将一个操作码识别为nop
. 整体指令格式与大多数相同。
prefetch
/prefetchw
并且nop
如其他答案中所述。
任何带有全零掩码的 AVX512 掩码加载或存储,例如vmovaps [rdi]{k1}, zmm1
. 或 AVX vmaskmovps
/ vpmaskmovd
. AVX2 聚集/ AVX512使用全零掩码聚集或分散。这些都对无效地址进行故障抑制。(缓慢,但没有实际的内存访问。)
invlpg m8
接受一个指定虚拟地址的 ModRM。(特权指令)。它不是从该地址加载,而是使该地址的 TLB 条目和缓存在 page walker 中的更高级别的页面目录条目无效。
verr
/verw
—验证读或写段:他们采用 ModRM 寻址模式并根据段限制检查地址,设置 FLAGS。(并且随着最近的微码更新。verw
还清除了内部 CPU 缓冲区,以便操作系统可以使用它来缓解 L1TF / MDS 漏洞)。
rep cmpsb
或其他 RCX = 0 的字符串指令执行零迭代,不访问[RDI]
或[RSI]
隐式内存操作数。我认为这意味着即使地址错误也不会出错。微码肯定够慢
cldemote
(Intel Tremont中的新功能)- 与预取相反;将数据推送到共享 L3 以加快从另一个内核的首次访问的性能提示。它在没有该功能的情况下解码为硬件上的 NOP。预取不会在无效地址上出错(尽管它们在使用微码辅助来抑制故障时可能会很慢);该手册不是 100% 明确的cldemote
,但确实称其为投机提示。
在某些处理器实现中,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
(用户空间版本)是相同的。