首页 文章

x86多字节NOP和指令前缀

提问于
浏览
3

作为一个小小的召回,x86架构将 0x0F 0x1F [mod R/M] 定义为多字节NOP .

现在我看一下8字节NOP的具体情况:我有

0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__

最后5个字节有任意值 .

分开的第三个字节 [mod R/M] 给出:

modrm

  • 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 为'cut off'并被视为新指令 . 但是,在编译它并在生成的可执行文件上运行 objdump 时,它仍然使用所有4个字节(DWORD)作为位移 .

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

1 回答

  • 3

    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 .

    据AMD称,推荐的多字节数如下:

    表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 .

    例如

    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仍然耗尽资源 .

相关问题