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