2

I'm a bit confused by how gcc encodes relative jumps. I have the following:

int main(void)
{
    __asm__ __volatile__(
        "jmp label\n"
        "label:\n"
        "nop\n"
    );

    return 0;
}

Building this (gcc -c -o test.o test.c) shows the following (objdump -M intel -d test.o):

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   eb 00                   jmp    6 <label>

0000000000000006 <label>:
   6:   90                      nop
   ...

rasm2 -d eb00 shows jmp 2, which means the jump is being performed with an offset of 2. Now, I had understood that relative jumps' offsets are added to the current value of eip, which should be pointing at the next instruction (i.e. nop). This encoding makes me think that the offset is relative to the address of the jmp itself. Shouldn't the jmp be encoded as jmp 0, since nop is already at label?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Martin
  • 940
  • 6
  • 26

1 Answers1

7

It is encoded with an offset of 0:

eb 00

However it is customary to abstract away from such encoding details in assembly (and therefore disassembler output) and denote relative jumps with an offset relative to the start of the instruction (eg $+2) or absolutely (as in jmp 6 <label>).

harold
  • 61,398
  • 6
  • 86
  • 164
  • If that's true, that's extremely confusing. I'm surprised that even radare would display the offset as 2. – Martin Feb 17 '19 at 05:20
  • @Martin wouldn't it be more confusing if radare decided to do it different from all the other tools? – harold Feb 17 '19 at 05:24
  • 1
    I don't know. Maybe radare should include an option to show the real offsets. In any case, this seems to clear things up for me. Thanks, harold – Martin Feb 17 '19 at 05:34
  • 2
    @martin Normally disassemblers display the absolute address of the destination for the operand of jump instructions. I would've expected `rasm2` to display `jmp 6` just like `objdump` did. It's possible that `rasm2` thinks that the JMP instruction is at address 0 for whatever reason. – Ross Ridge Feb 17 '19 at 05:58
  • @Martin: the machine code hexdump is right there if you want to look at the raw offset. x86 near jumps are always relative, and you can tell just by looking at the instruction length if it's a rel8 or rel32 (little-endian of course). objdump's output includes that hexdump by default; you didn't show radare2. (With Radare2 you're disassembling a single instruction, so yeah assuming it's at address 0 makes sense.) – Peter Cordes Feb 17 '19 at 16:52
  • @RossRidge it would only make sense that rasm2 assumed the jmp was at address zero. My command was literally just `rasm2 -d eb00`. @PeterCordes The reason I use a disassembler in the first place is that I don't (want to) care about the machine code. – Martin Feb 18 '19 at 14:39
  • Why would compiler ever generate `eb 00` instead of `nop` (`90`)? Both do exactly the same thing and `nop` encodes to shorter code. – Mikko Rantalainen Feb 26 '22 at 10:28
  • 1
    @MikkoRantalainen the compiler had no choice in this case because inline asm was used to create that useless jump – harold Feb 26 '22 at 10:38