Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Syntax of short jmp instruction

Tags:

assembly

I'm reading http://thestarman.pcministry.com/asm/2bytejumps.htm but the text isn't very clear about how to do a JMP to an offset (a short jump to a relative address without using a label).

Let's say I have

NOP
NOP
NOP
NOP

(which is 4 bytes of instructions), and I want to skip them (skip 4 bytes). What would I write?

jmp $+4;?

jmp $+2+4;?

like image 300
alexandernst Avatar asked Dec 22 '13 15:12

alexandernst


2 Answers

A short jmp opcode uses two bytes. When you assemble that, the current position ( $ ) points to the beginning of the JMP instruction, not to the beginning of the following instruction.

To jump to the next instruction (a jump that does not actually jump), you do

jmp $+2

So, to jump over N bytes past the JMP instruction, you will do:

jmp $+2+N

In your example, 4 NOP's

jmp $+6

The assembler should detect that this is a jump to a near address and assemble it as a short jump. If want to be sure, use

jmp short $+6
like image 119
mcleod_ideafix Avatar answered Nov 11 '22 06:11

mcleod_ideafix


"Skipping" 4 bytes with a single jmp is awkward, because relative jmps occupy 2 or 5 bytes.

To skip over (a total) of 4 bytes, you could do:

  jmp   short $+4   ; the "short" forces a 2 byte relative branch
  nop
  nop

If your problem is to fill out a modest number N of bytes, you should emit an appropriately sized-nop. Here's what I use in a compiler I wrote:

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);
  }
  }
}

I prefer to use breakpoint instructions for inline padding that I do not intend to be executed, on the grounds that if it gets executed, the processor will trap and I'll find out about it. You can see that in the "default" case.

like image 31
Ira Baxter Avatar answered Nov 11 '22 06:11

Ira Baxter