x86多字节NOP和指令前缀

aye*_*kat 5 x86 prefix nop

回想一下,x86体系结构定义0x0F 0x1F [mod R/M]为多字节NOP。

现在,我看一个8字节NOP的特殊情况:

0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__
Run Code Online (Sandbox Code Playgroud)

最后5个字节具有任意值。

第三个字节[mod R/M]拆分得到:

现代

  • mod = 10b:参数为reg1+ DWORD大小的位移
  • reg2 = 000b:(我们不在乎)
  • reg1 = 100b:表示参数改为SIB字节+ DWORD大小的位移。

现在,举一个具体的例子

0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
Run Code Online (Sandbox Code Playgroud)

我有

  • SIB = 0x12
  • displacement = 0x9A785634:DWORD

现在,我添加0x66指令前缀以指示位移应为WORD而不是DWORD:

0x66 0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
Run Code Online (Sandbox Code Playgroud)

我希望0x78 0x9A被“切断”并被视为新的指示。但是,当编译它并objdump在生成的可执行文件上运行时,它仍然使用所有4个字节(一个DWORD)作为位移。

在这种情况下,我是否误解了“位移”的含义?还是0x66前缀对多字节NOP指令没有任何影响?

Joh*_*ica 6

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
Run Code Online (Sandbox Code Playgroud)

但是,最好不要创建自己的nop指令,而要遵循建议的(多字节)nop。

根据AMD,建议的多字节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]
Run Code Online (Sandbox Code Playgroud)

Intel不介意最多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]
Run Code Online (Sandbox Code Playgroud)

当然,您也可以通过在正常指令前添加冗余前缀来消除延迟。

例如

rep mov reg,reg //one extra byte
Run Code Online (Sandbox Code Playgroud)

或强制CPU使用同一指令的较长版本。

test r8d,r8d is one byte longer than: test edx,edx
Run Code Online (Sandbox Code Playgroud)

带有立即操作数的指令有短版和长版。

and edx,7 //short
and edx,0000007  //long
Run Code Online (Sandbox Code Playgroud)

大多数汇编程序会帮助您缩短所有指令,因此您必须自己编写使用较长指令的代码 db

将这些散布在关键位置可以帮助您对齐跳跃目标,而不必由于nop的解码或执行而导致延迟。

请记住,在大多数CPU上,执行nop仍会占用资源。

  • 我建议避免使用尚未定义的 `rep` 前缀,因为英特尔稍后会赋予它们新的含义。例如,`rep mov` 现在在英特尔 HLE 中具有意义。 (3认同)

归档时间:

查看次数:

2513 次

最近记录:

7 年 前