长的多字节NOP:通常理解为宏或其他符号表示法。

45

众所周知,x86(和x86_64)处理器不仅具有单字节的NOP指令,还具有各种类型的多字节NOP类指令。

以下是我找到的:

推荐使用AMD,参考AMD家族15h处理器软件优化指南,文档#47414,第5.8节“使用操作数大小覆盖和多字节NOP进行代码填充”,第94页)

90                              NOP1_OVERRIDE_NOP
6690                            NOP2_OVERRIDE_NOP
0f1f00                          NOP3_OVERRIDE_NOP
0f1f4000                        NOP4_OVERRIDE_NOP
0f1f440000                      NOP5_OVERRIDE_NOP
660f1f440000                    NOP6_OVERRIDE_NOP
0f1f8000000000                  NOP7_OVERRIDE_NOP
0f1f840000000000                NOP8_OVERRIDE_NOP
660f1f840000000000              NOP9_OVERRIDE_NOP
66660f1f840000000000            NOP10_OVERRIDE_NOP
6666660f1f840000000000          NOP11_OVERRIDE_NOP

推荐使用Intel,参考Intel 64和IA-32体系结构软件开发人员手册卷2B:指令集参考,N-Z,第“NOP”节

90                              NOP
6690                            66 NOP
0f1f00                          NOP DWORD ptr [EAX]
0f1f4000                        NOP DWORD ptr [EAX + 00H]
0f1f440000                      NOP DWORD ptr [EAX + EAX*1 + 00H]
660f1f440000                    66 NOP DWORD ptr [EAX + EAX*1 + 00H]
0f1f8000000000                  NOP DWORD ptr [EAX + 00000000H]
0f1f840000000000                NOP DWORD ptr [EAX + EAX*1 + 00000000H]
660f1f840000000000              66 NOP DWORD ptr [EAX + EAX*1 + 00000000H]

GNU汇编器(在binutils / gas中)包括以下模式:

f32(旧的与英特尔兼容的CPU,直到Pentium):

90                              nop
6690                            xchg %ax,%ax
8d7600                          leal 0(%esi),%esi
8d742600                        leal 0(%esi,1),%esi
908d742600                      nop; leal 0(%esi,1),%esi
8db600000000                    leal 0L(%esi),%esi
8db42600000000                  leal 0L(%esi,1),%esi
908db42600000000                nop; leal 0L(%esi,1),%esi
89f68dbc2700000000              movl %esi,%esi; leal 0L(%edi,1),%edi
8d76008dbc2700000000            leal 0(%esi),%esi; leal 0L(%edi,1),%edi
8d7426008dbc2700000000          leal 0(%esi,1),%esi; leal 0L(%edi,1),%edi
8db6000000008dbf00000000        leal 0L(%esi),%esi; leal 0L(%edi),%edi
8db6000000008dbc2700000000      leal 0L(%esi),%esi; leal 0L(%edi,1),%edi
8db426000000008dbc2700000000    leal 0L(%esi,1),%esi; leal 0L(%edi,1),%edi

alt(适用于现代CPU,Intel和AMD相同):

0f1f00                          nopl (%[re]ax)
0f1f4000                        nopl 0(%[re]ax)
0f1f440000                      nopl 0(%[re]ax,%[re]ax,1)
660f1f440000                    nopw 0(%[re]ax,%[re]ax,1)
0f1f8000000000                  nopl 0L(%[re]ax)
0f1f840000000000                nopl 0L(%[re]ax,%[re]ax,1)
660f1f840000000000              nopw 0L(%[re]ax,%[re]ax,1)
662e0f1f840000000000            nopw %cs:0L(%[re]ax,%[re]ax,1)

alt_short(适用于现代AMD家族CPU):

0f1f440000660f1f440000          nopl 0(%[re]ax,%[re]ax,1); nopw 0(%[re]ax,%[re]ax,1)
660f1f440000660f1f440000        nopw 0(%[re]ax,%[re]ax,1); nopw 0(%[re]ax,%[re]ax,1)
660f1f4400000f1f8000000000      nopw 0(%[re]ax,%[re]ax,1); nopl 0L(%[re]ax)
0f1f80000000000f1f8000000000    nopl 0L(%[re]ax); nopl 0L(%[re]ax)
0f1f80000000000f1f840000000000  nopl 0L(%[re]ax); nopl 0L(%[re]ax,%[re]ax,1)

alt_long(适用于现代英特尔系列CPU):

66662e0f1f840000000000          data16; nopw %cs:0L(%[re]ax,%[re]ax,1)
6666662e0f1f840000000000        data16; data16; nopw %cs:0L(%[re]ax,%[re]ax,1)
666666662e0f1f840000000000      data16; data16; data16; nopw %cs:0L(%[re]ax,%[re]ax,1)
66666666662e0f1f840000000000    data16; data16; data16; data16; nopw %cs:0L(%[re]ax,%[re]ax,1)
6666666666662e0f1f840000000000  data16; data16; data16; data16; data16; nopw %cs:0L(%[re]ax,%[re]ax,1)

我的问题是:所有这些字节序列是否有任何广泛/常见的命名,例如宏、伪助记符或类似的东西?到目前为止,我只发现:

  • AMD 建议将它们命名为 NOPx_OVERRIDE_NOPx = 字节长度)。
  • gas 理解 nopw(作为 2 字节 nop)和 nopl(作为 4 字节 nop)

现代反汇编器如何输出这些值呢?

相关但不重复的问题:What does NOPL do in x86 system?


4
这段话的意思是,对齐指令通常会产生这些结果,因为大多数情况下,程序员只关心如何到达特定对齐地址,而不知道或不关心从当前位置开始需要多少字节。请注意,这里的"它们"指的是对齐所产生的填充字节。 - Jester
@Jester,你能说出一些可靠的对齐指令/汇编器,以便给这些NOP填充提供支持吗?到目前为止,我已经发现普通的“align”用0填充(这是完全可以理解的-例如,在非代码部分中,您不会想要使用其他任何内容进行填充)。到目前为止,我只发现了[nasm feature request](http://sourceforge.net/p/nasm/feature-requests/69/)关于拟议的“calign”指令来实现这一点,但据我所见,它从未被实现。 - GreyCat
4
GAS中,所有对齐指令(.align.p2align.balign)在代码段中使用时都是这样工作的。如你所说,nasm似乎缺少了这个特性。 - Jester
2
这是一个老问题,但我刚遇到了由Visual Studio生成的长nop指令之一,用于C / C ++代码流入循环。 nop用于填充代码,以便循环分支目标位于16字节边界上(在我看到的情况下,它恰好是32字节边界)。 - rcgldr
1
真实二进制模式分析: https://gist.github.com/stevemk14ebr/d117e8d0fd1432fb2a92354a034ce5b9 - Stephen Eckels
显示剩余2条评论
1个回答

4

最近binutils中出现了一个新的GAS,它有一个.nops N伪指令,该指令将扩展到目标所请求的字节数:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接