问题描述
回忆一下,x86 架构将 0x0F 0x1F [mod R/M]
定义为多字节 NOP.
As a small recall, the x86 architecture defines 0x0F 0x1F [mod R/M]
as a multi-byte NOP.
现在我正在查看 8 字节 NOP 的具体情况:我有
Now I'm looking at the specific case of an 8-byte NOP: I have got
0x0F 0x1F 0x84 0x__ 0x__ 0x__ 0x__ 0x__
其中最后 5 个字节具有任意值.
where the last 5 bytes have got arbitrary values.
第三个字节,[mod R/M]
,拆分后给出:
The third byte, [mod R/M]
, split up gives:
mod = 10b
:参数是reg1
+ DWORD 大小的位移reg2 = 000b
:(我们不在乎)reg1 = 100b
:表示参数是SIB
字节 + 一个 DWORD 大小的位移.
mod = 10b
: argument isreg1
+ a DWORD-sized displacementreg2 = 000b
: (we don't care)reg1 = 100b
: indicates that the argument is instead theSIB
byte + a DWORD-sized displacement.
现在,作为一个具体的例子,如果我取
Now, as a concrete example, if I take
0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
我有
SIB = 0x12
位移 = 0x9A785634
:一个双字
现在我添加 0x66
指令前缀以指示位移应该是 WORD 而不是 DWORD:
Now I add the 0x66
instruction prefix to indicate that the displacement should be a WORD instead of a DWORD:
0x66 0x0F 0x1F 0x84 0x12 0x34 0x56 0x78 0x9A
我希望 0x78 0x9A
被切断"并被视为一条新指令.但是,当编译它并在生成的可执行文件上运行 objdump
时,它仍然使用所有 4 个字节(一个 DWORD)作为位移.
I expect 0x78 0x9A
to be 'cut off' and be treated as a new instruction. However, when compiling this and running objdump
on the resulting executable, it still uses all 4 bytes (a DWORD) as displacement.
在这种情况下,我是否误解了位移"的含义?还是 0x66
前缀对多字节 NOP 指令没有任何影响?
Am I misunderstanding the meaning of 'displacement' in this context? Or does the 0x66
prefix not have any effect on multi-byte NOP instructions?
推荐答案
66H
前缀将操作数的大小覆盖为 16 位.
它不会覆盖地址的大小,如果您希望使用 67H
The 66H
prefix overrides the size of the operand to 16 bit.
It does not override the size of the address, if you want that you use 67H
这是所有操作数的列表.
Here's a list of all operands.
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 指令,而是坚持推荐的(多字节)nop.
However it is best not to create your own nop instructions, but stick to the recommended (multi-byte) nops.
根据 AMD 推荐的多字节 nops 如下:
According to AMD the recommended multibytes nops are as follows:
表 4-9.NOP指令的推荐多字节序列
Table 4-9. Recommended Multi-Byte Sequence of NOP Instruction
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]
Intel 不介意最多 3 个冗余前缀,因此可以像这样构造最多 11 个字节的 nop.
Intel does not mind up to 3 redundant prefixes, so nop's up to 11 bytes can be constructed like so.
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.
Of course you can also eliminate nops by prefixing normal instructions with redundant prefixes.
例如
rep mov reg,reg //one extra byte
或强制 cpu 使用相同指令的更长版本.
or forcing the cpu to use longer versions of the same instruction.
test r8d,r8d is one byte longer than: test edx,edx
带有立即操作数的指令有短版和长版.
The instructions with immediate operands have short and long versions.
and edx,7 //short
and edx,0000007 //long
大多数汇编程序都会帮助您缩短所有指令,因此您必须使用 db
Most assembler will helpfully shorten all instructions for you, so you'll have to code the longer instructions yourself using db
将这些散布在战略位置可以帮助您对齐跳跃目标,而不必因 nop 的解码或执行而产生延迟.
Interspersing these in strategic locations can help you align jump targets without having to incur delays due to the decoding or execution of a nop.
请记住,大多数 CPU 执行 nop 仍然会消耗资源.
Remember on most CPU's executing nop's still uses up resources.
这篇关于x86 多字节 NOP 和指令前缀的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!