nop指令的作用:

1)就是通过nop指令的填充(nop指令一个字节),使指令按字对齐,从而减少取指令时的内存访问次数。(一般用来内存地址偶数对齐,比如有一条指令,占3字节,这时候使用nop指令,cpu 就可以从第四个字节处读取指令了。)

2)通过nop指令产生一定的延迟,但是对于快速的CPU来说效果不明显,可以使用rep前缀,多延迟几个时钟;-->具体应该说是占用了3个时钟脉冲! 3)i/o传输时,也会用一下 nop,等待缓冲区清空,总线恢复;  4)清除由上一个算术逻辑指令设置的flag位;  5)破解:)对于原程序中验证部分使用nop来填充,使验证失效;  6)有一个朋友说的比较厉害--在航天飞机控制程序中防止程序跳飞!  解释如下:在空间放射性环境下,放射性子粒很容易使内存位元改变(呵呵,有点基因突变的感觉),这样如果改变的是jump,call指令的存贮位置的话,就会导致程序跳转到一个不可以预置的位置,对于关键系统来说的确是灾难性的。所以就在被调用程序之前填充nop指令,这样即使跳转到稍前或者稍后的位置,也不会造成影响。  这让我想起《C Traps and Pitfalls》中举的那个导弹软件中的致命错误:因为导弹是以0.1s为单位进行记时的,但是由于浮点数没有办法精确的表示0.1,造成了舍尾误差,这个误差在导弹开启3天的之后逐渐的积累,结果误差了一秒。

 

以下来自http://wapedia.mobi/zh/NOP

计算机科学中,NOP或NOOP(No Operation或No Operation Performed的缩写,意为无操作)是汇编语言的一个指令,一系列编程语句,或网络传输协议中的表示不做任何有效操作的命令。

目录: 1. NOP机器指令 2. NOP代码 3. NOP协议命令 4. 破解 5. 安全问题 6. 参见 7. 参考文献

1. NOP机器指令

有的计算机指令集包含一条指令,其主要目的是不改变任何程序可访问的寄存器,处理器状态标志或主存,而且可能需要特定的时钟周期来执行。在其它指令集中,NOP是用执行一条具有操作数,具有相同效果的指令来模拟的(例如SPARC处理器推荐使用sethi 0, %g0模拟NOP)。

NOP指令通常用于控制时序的目的,强制内存对齐,防止流水线灾难(en:Hazard (computer architecture)),占据分支指令造成的延迟(delay slot),或是作为占位符以供程序的改善(或替代被移除的指令)。在某些情况中,NOP指令会产生副作用;例如在摩托罗拉 68000处理器中,NOP操作码会产生流水线同步。

下表显示了部分CPU架构上NOP指令的特征:

CPU架构

助忆码

字长

操作码

备注

Intelx86系列CPU

NOP

1; i686中为1-9

0x90; 0x0f 0x1f [2]

x86 CPU上的NOP指令实质上是XCHG EAX, EAX(操作码同为0x90)--无任何作用的指令。

Intel 8051 /MCS-51系列

NOP

1

0x00

 

MIPS

NOP

4

0x00000000

 

MOS科技 65xx

NOP

1

0xea

65C02处理器发布时,之前多数的无效指令都被定义成了具有不同字长和需时的NOP指令。

PowerPC

NOP

4

0x60000000 (ori r0,r0,0的扩展操作码)

 

2. NOP代码

NOP有时可以描述函数或一系列编程语句的作用,若部分没有作用(也可以称为冗余代码)。常见的编译器优化的作用就包括检测和去除这样的代码。

下面是一个起NOP作用的C语言语句的例子(评判标准在于语句是否影响程序输出,而非编译器是否为语句产生代码): <source lang="C">

i+1;

</source> (该语句执行了一个加法,但结果被丢弃。)

C语言中最简单的NOP块被称为空语句;其只包括一个分号。(标准没有要求编译器在这个例子中生成NOP指令;通常这个语句会直接为编译器所忽略。) <source lang="C">

;

</source>

虽然空语句自身没有用处,但在某些情况下可以启动占位符的作用,例如在循环中: <source lang="C">

while (ReadChar() != '/n') ;

</source>

以上代码一直调用ReadChar函数,直到函数返回一个/n(NL,新行)字符。

Python中的pass语句不会产生作用,可以作为NOP使用。它的主要目的是保证语法正确,由于Python的缩进敏感语法。

3. NOP协议命令

许多协议,比如telnet,包含NOP指令,该指令允许客户端可以在不会引起其它操作的情况下向服务器请求回应。NOP指令可以用于检测连接是否断开,或服务器是否可以响应操作。下列协议中包含NOOP指令(不完全列表):

· telnet

· FTP

· SMTP

· X11

· POP3

· NNTP

· finger

· IMAP4

· BitTorrent

注意:与其它协议不同,IMAP4的NOP命令允许客户端响应服务器发送由其它客户端反应的操作信息。

虽然大多数telnet和FTP服务器用OK或+OK回应NOOP指令,有的程序员在对客户端的回应中加入了特别的内容。例如MINIX的ftpd守护进程会以以下消息回应NOOP:[3]

[[FTP服务器返回值列表|200]] NOOP to you too!

4. 破解

NOP通常在破解软件时有特殊用途,例如检查序列号,特定硬件或软件需求,加密狗等的软件。这是通过更改函数和/或子程序以跳过安全检查,直接返回期望的检测值实现的。由于大多数安全检查子程序中的指令会被废弃,它们会被NOP所代替。

5. 安全问题

NOP操作码可以被用于组成一个NOP slide,允许在指令指针值未定义时执行代码,例如缓存溢出导致栈上的函数返回地址被更改。

6. 参见

· 计算机系统结构

· HLT

· 指令集

· x86

· 恒等函数,函数式编程语言中NOOP的等效函数

· xyzzy,一个有时用来代替NOOP的命令

7. 参考文献

 

1 ^ Motorola 68000 Programmer's Reference Manual.

2 ^ Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference Manual [2007-07-13].
16进制机器码   x86汇编指令   指令意义   可能影响的寄存器或标志位  --------------   -------------   -------------------   ---------------------------  06   PUSHL   %es   es进栈   esp  0E   PUSHL   %cs   cs进栈   esp  16   PUSHL   %ss   ss进栈   esp  1E   PUSHL   %ds   ds进栈   esp  27   DAA   加法小数位调整   AF   CF   PF   SF   ZF   AL  2F   DAS   减法小数位调整   AF   CF   PF   SF   ZF   AL  37   AAA   加法的ASCII调整   AF   CF   AL  3F   AAS   减法小数位调整   AF   CF   AL  40   INC   %eax   %eax加1   AF   OF   PF   SF   ZF   eax  41   INC   %ecx   %ecx加1   AF   OF   PF   SF   ZF   ecx  42   INC   %edx   %edx加1   AF   OF   PF   SF   ZF   edx    43   INC   %ebx   %ebx加1   AF   OF   PF   SF   ZF   ebx  44   INC   %esp   %esp加1   AF   OF   PF   SF   ZF   esp  45   INC   %ebp   %ebp加1   AF   OF   PF   SF   ZF   ebp  46   INC   %esi   %esi加1   AF   OF   PF   SF   ZF   esi  47   INC   %edi   %edi加1   AF   OF   PF   SF   ZF   edi  48   DEC   %eax   %eax减1   AF   OF   PF   SF   ZF   eax  49   DEC   %ecx   %ecx减1   AF   OF   PF   SF   ZF   ecx  4A   DEC   %edx   %edx减1   AF   OF   PF   SF   ZF   edx  4B   DEC   %ebx   %ebx减1   AF   OF   PF   SF   ZF   ebx  4C   DEC   %esp   %esp减1   AF   OF   PF   SF   ZF   esp  4D   DEC   %ebp   %ebp减1   AF   OF   PF   SF   ZF   ebp  4E   DEC   %esi   %esi减1   AF   OF   PF   SF   ZF   esi  4F   DEC   %edi   %edi减1   AF   OF   PF   SF   ZF   edi  50   PUSHL   %eax   eax进栈   esp  51   PUSHL   %ecx   ecx进栈   esp  52   PUSHL   %edx   edx进栈   esp  53   PUSHL   %ebx   ebx进栈   esp  54   PUSHL   %esp   esp进栈   esp  55   PUSHL   %ebp   ebp进栈   esp  56   PUSHL   %esi   esi进栈   esp  57   PUSHL   %edi   edi进栈   esp  90   NOP   (NULL)   (NULL)  91   XCHG   %ecx,%eax   交换寄存器内容   eax,ecx  92   XCHG   %edx,%eax   交换寄存器内容   edx,eax  93   XCHG   %ebx,%eax   交换寄存器内容   ebx,eax  95   XCHG   %ebp,%eax   交换寄存器内容   ebp,eax  96   XCHG   %esi,%eax   交换寄存器内容   esi,eax  97   XCHG   %edi,%eax   交换寄存器内容   edi,eax  98   CBW   将byte的AL转换成word的EAX   EAX  9B   WAIT   等待CPU处理完数据   (NULL)  D6   无效指令   (NULL)   (NULL)  F5   CMC   转换CF标志位(开关)   CF  F8   CLC   清CF位(CF=0)   CF  F9   STC   设置CF位(CF=1)   CF  FC   CLD   设置DF位(DF=1)   DF  FD   STD   清理DF位(DF=0)   DF 
1.   上面利用XCHG/PUSHL/INC/DEC的方法程序应该不会出错, 可以正常到目的,   但寄存器内容被改变了.inc  eax就改变了eax的值, 只能算无奈的办法.  2.   利用改变标志寄存器位是个不错的想法,   基本上不会影响流程,   但看到还是改变了CPU的东西还是不满意.  3.   /x90(NOP),/x9b(wait),/xd6(bad)   这三个指令不错,   都不会改变程序的流程,   又不会改变寄存器的东东.  这里尤其指明的是/xd6指令,   在intel手册上没查到对应什么指令,   但在linux下和windows下发现系统对于这个是继续  执行下一条指令,和NOP相似.  在我看来,上面这些指令利用顺序优先级最好是: 
/x90(NOP)   >   /xd6   >   /x9b   >   改变标志寄存器的操作指令   >   INC/DEC/PUSHL/XCHG