15

Have a doubt regarding the hex code conversion of JMP machine instruction. I have the absolute address I want to jump to, say "JMP 0x400835". First of all, is this allowed? If yes, what would be the corresponding hex code? If not, can I first store the address in some register, say EAX and then put "JMP EAX"? I am working on x86(64b) architecture.

I have tried to print out the hex code from the diassem output in gdb, but there is no consistency, ie, I do not see the destination address in the hex code.

I am new to hex code and machine instructions, so pardon my ignorance.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Deepanjan Mazumdar
  • 1,447
  • 3
  • 13
  • 20
  • Related: [How to write an absolute target for a near direct relative call/jmp in MASM](https://stackoverflow.com/q/50058523). If the jump target is in range, some toolchains (e.g. NASM + `ld` on Linux) will assemble+link a jmp to an absolute address as a relative jmp from a known address (in position-dependent code). – Peter Cordes Dec 20 '18 at 21:22

2 Answers2

36

There is no jump of the form JMP absaddr to an absolute address in 64 bit mode. The operand of a jump is always a 32 bit relative displacement to rip, which gets sign extended to 64 bit.

The reason you see no consistency is possibly that the offset depends on the the current instruction pointer and you didn't recognize that.

jmp eax isn't allowed either, as addresses are of course always 64 bit wide on a 64 bit architecture. A sequence mov rax, addr + jmp rax is possible, it would look like

48 c7 c0 35 08 40 00            mov rax, 0x00400835
ff e0                           jmp rax

or

48 b8 35 08 40 00 00 00 00 00   mov rax, 0x0000000000400835
ff e0                           jmp rax

How did I know these hex codes? Well, I did ask my compiler. I compiled with gcc -c and disassembled with objdump. I didn't bother to use Intel syntax, because I don't need it. So this is in AT&T syntax.

echo 'asm("mov $400835, %rax\n jmp *%rax\n");' > test.c
gcc -c test.c
objdump -d test.o
Gunther Piez
  • 29,760
  • 6
  • 71
  • 103
  • Thank you for the answer. This really helped me. objdump is seriously a good tool! – Deepanjan Mazumdar Mar 24 '12 at 00:12
  • Hey.. I have marked your post as "useful".. that's what is needed I guess, right? – Deepanjan Mazumdar Mar 25 '12 at 19:58
  • Do you mean "jmp absaddr" will be "jmp %rip + absaddr" (where absaddr has to be equal or less than 32bit)? – Man of One Way Jul 03 '14 at 14:21
  • @ManofOneWay Nor sure what you are trying to ask, as there is no `jmp absaddr` and `jmp %rip+absaddr` isn't absolute. If you tell the assembler to translate some code in the kind of `jmp someaddr` it will calculate the relative distance from the current address (which will later on execution time be in `%rip`) to `someaddr` and emit `e9 xx xx xx xx`, where the four xx bytes correspond to the calculated address difference. – Gunther Piez Jul 06 '14 at 10:29
  • Here you write "jmp *%rax". Can you please tell where I can find description of this syntax? Because everywhere AT&T syntax is explained, this JMP syntax is not listed. – Kibernetik Jan 15 '15 at 17:15
  • `mov eax, 0x00400835` / `mov $0x00400835, %eax` is only 5 bytes. There's zero benefit to sign-extending that immediate with a 64-bit `mov` instead of relying on implicit zero-extension from writing EAX. [Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?](https://stackoverflow.com/q/11177137) – Peter Cordes Dec 20 '18 at 21:25
  • This comment is only 10 years old :) but I don't think "The operand of a jump is always a 32 bit relative displacement to rip" is not fully accurate. An example from this answer itself contradicts it: `jmp *rax` is an absolute (indirect) jump. And thanks a lot for the "verify it yourself" sequence (`echo 'asm...', gcc, objdump`) -- very helpful (of course replacing `gcc` with `clang -x c`)! – Vivek Aug 09 '22 at 05:47
  • @Vivek: Yes, indirect jumps exist. More precisely, the operand of *direct* jumps/calls is always relative. (64-bit mode doesn't have a version of `jmp far ptr16:64`, so we don't need to say "near" to be precise.) So if the target address is encoded into the machine code itself, it's relative. (Intel's [APX extensions](https://www.intel.com/content/www/us/en/developer/articles/technical/advanced-performance-extensions-apx.html) announced this week will add `jmpabs target64`, an absolute direct jump. It'll be years before many people have CPUs with it, though.) – Peter Cordes Jul 29 '23 at 22:18
10

If you don't want to use a register for whatever reason, it's also possible to encode a 64 bit absolute immediate jump as

ff 25 00 00 00 00           jmp qword ptr [rip]      jmp *(%rip)
yo ur ad dr re ss he re     some random assembly

rip refers to the instruction pointer AFTER the jmp instruction itself, so it's a pointer to your address.