我正在阅读http://thestarman.pcministry.com/asm/2bytejumps.htm,但文字不清楚如何对偏移量进行JMP
(不使用标签而跳转到相对地址)。
假设我有
NOP
NOP
NOP
NOP
(这是4个字节的指令),我想跳过它们(跳过4个字节)。我会写什么?
jmp $+4;
?
jmp $+2+4;
?
答案 0 :(得分:7)
一个简短的jmp操作码使用两个字节。汇编时,当前位置($
)指向JMP指令的开头,而不是指向下一条指令的开头。
要跳转到下一条指令(实际上没有跳转的跳转),你可以
jmp $+2
因此,要跳过JMP指令的N个字节,您将执行:
jmp $+2+N
在你的例子中,4 NOP的
jmp $+6
汇编程序应检测到这是跳转到近地址并将其组合为短跳转。如果想确定,请使用
jmp short $+6
答案 1 :(得分:1)
使用单个jmp“跳过”4个字节是不方便的,因为相对的jmps占用2或5个字节。
要跳过(总共)4个字节,您可以这样做:
jmp short $+4 ; the "short" forces a 2 byte relative branch
nop
nop
如果你的问题是要填写适当数量的N个字节,你应该发出一个适当大小的nop。 这是我在编写的编译器中使用的内容:
void ObjectCodeEmitNByteNop(natural n)
{ // See http://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2010-September/003881.html GOOD INFO
/* The Intel Architecture Software developer's guide, volume 2B (instructions N-Z) contains the following table (pg 4-12) about NOP:
Table 4-9. Recommended Multi-Byte Sequence of NOP Instruction
Length Assembly Byte Sequence
=================================================================================
2 bytes 66 NOP 66 90H
3 bytes NOP DWORD ptr [EAX] 0F 1F 00H
4 bytes NOP DWORD ptr [EAX + 00H] 0F 1F 40 00H
5 bytes NOP DWORD ptr [EAX + EAX*1 + 00H] 0F 1F 44 00 00H
6 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00H] 66 0F 1F 44 00 00H
7 bytes NOP DWORD ptr [EAX + 00000000H] 0F 1F 80 00 00 00 00H
8 bytes NOP DWORD ptr [EAX + EAX*1 + 00000000H] 0F 1F 84 00 00 00 00 00H
9 bytes 66 NOP DWORD ptr [EAX + EAX*1 + 00000000H] 66 0F 1F 84 00 00 00 00 00H
*/
switch(n)
{
case 0:
break; // accidentally aligned
case 1:
ObjectCodeEmitByte(0x90); // sequence recommended by AMD optimization manual
break;
case 2:
ObjectCodeEmitWord(0x9066); // sequence recommended by AMD and Intel optimization manual
// MS assembler suggests: ObjectCodeEmitWord(0xFF8B); "MOV EDI,EDI"
break;
case 3:
ObjectCodeEmitThreeByteNOP();
break;
case 4:
ObjectCodeEmitFourByteNOP();
// ObjectCodeEmitDword(0x90666666); // sequence recommended by AMD optimization manual
// MS assembler suggests: ObjectCodeEmitDword(0x0024648D); // LEA ESP,0[ESP]
break;
case 5:
#if 0
ObjectCodeEmitByte(0x05); // ADD EAX, imm32
ObjectCodeEmitDword(0);
#else
ObjectCodeEmitByte(0x0F); // NOP ...
ObjectCodeEmitDword(0x0000441F); // ... DWORD ptr [EAX + EAX*1 + 00H]
#endif
break;
case 6:
ObjectCodeEmitWord(0x9B8D); // LEA EBX,disp32[EBX] (Microsoft assembler emits this)
ObjectCodeEmitDword(0x00000000); // offset = 0 --> don't change EBX
break;
case 7:
ObjectCodeEmitByte(0x8D); // LEA opcode byte
ObjectCodeEmitWord(0x24A4); // ESP,disp32[ESP]
ObjectCodeEmitDword(0x00000000); // offset = 0 --> don't change ESP
break;
case 8:
ObjectCodeEmitDword(0x00841F0F); // NOP DWORD ptr [EAX + EAX*1 + ...
ObjectCodeEmitDword(0x00000000); // ...00000000H]
break;
case 9:
ObjectCodeEmitByte(0x66); // 66 0F 1F 84 00 00 00 00 00H
ObjectCodeEmitDword(0x00841F0F); // NOP DWORD ptr [EAX + EAX*1 + ...
ObjectCodeEmitDword(0x00000000); // ...00000000H]
break;
default:
{ ObjectCodeEmitJmpRelativeShort(ObjectCodeSize+n);
// ObjectCodeEmitJmpRelativeLong(DesiredObjectLocation); // 5 bytes is safe; 1-4 bytes handled above
ObjectCodeEmitNBreakpoints(n-2);
}
}
}
我更喜欢使用断点指令进行内联填充,我不打算执行, 因为如果它被执行,处理器将陷阱,我会发现它。您可以在“默认”情况下看到它。