作为一个小小的召回,x86架构将0x0F 0x1F [mod R/M]
定义为多字节NOP。
现在我看一下8字节NOP的具体情况:我有
0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__
最后5个字节有任意值。
第三个字节[mod R/M]
分裂给出:
mod = 10b
:论证是reg1
+一个DWORD大小的位移reg2 = 000b
:(我们不在乎)reg1 = 100b
:表示参数是SIB
字节+ DWORD大小的位移。现在,作为一个具体的例子,如果我采取
0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
我有
SIB = 0x12
displacement = 0x9A785634
:一个DWORD现在我添加0x66
指令前缀来指示位移应该是WORD而不是DWORD:
0x66 0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
我希望0x78 0x9A
被“切断”并被视为新指令。但是,在编译它并在生成的可执行文件上运行objdump
时,它仍然使用所有4个字节(DWORD)作为位移。
在这种情况下,我是否误解了“流离失所”的含义?或者0x66
前缀对多字节NOP指令没有任何影响?
66H
前缀会将操作数的大小覆盖为16位。
如果你想使用67H
,它不会覆盖地址的大小
这是所有操作数的列表。
F0h = LOCK -- locks memory reads/writes
String prefixes
F3h = REP, REPE
F2h = REPNE
Segment overrides
2Eh = CS
36h = SS
3Eh = DS
26h = ES
64h = FS
65h = GS
Operand override
66h. Changes size of data expected to 16-bit
Address override
67h. Changes size of address expected to 16-bit
但是最好不要创建自己的nop指令,而是坚持推荐的(多字节)nops。
根据AND推荐的多字节nops如下:
表4-9。推荐的NOP指令多字节序列
bytes sequence encoding
1 90H NOP
2 66 90H 66 NOP
3 0F 1F 00H NOP DWORD ptr [EAX]
4 0F 1F 40 00H NOP DWORD ptr [EAX + 00H]
5 0F 1F 44 00 00H NOP DWORD ptr [EAX + EAX*1 + 00H]
6 66 0F 1F 44 00 00H NOP DWORD ptr [AX + AX*1 + 00H]
7 0F 1F 80 00 00 00 00H NOP DWORD ptr [EAX + 00000000H]
8 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
9 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
英特尔最多不介意3个冗余前缀,因此nop最多可以构造11个字节。
10 66 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
11 66 66 66 0F 1F 84 00 00 00 00 00H NOP DWORD ptr [AX + AX*1 + 00000000H]
当然,您也可以通过在正常指令前加上冗余前缀来消除nops。
EG
rep mov reg,reg //one extra byte
或强制cpu使用相同指令的更长版本。
test r8d,r8d is one byte longer than: test edx,edx
具有立即操作数的指令具有短版和长版。
and edx,7 //short
and edx,0000007 //long
大多数汇编程序会帮助您缩短所有指令,因此您必须使用db
自行编写更长的指令
将这些分布在战略位置可以帮助您对齐跳转目标,而不必因为解码或执行nop而导致延迟。
请记住,大多数CPU的执行nop仍然耗尽资源。