Search code examples
assemblyx86clangx86-64gnu-assembler

How to jump to memory location in intel syntax for both x64 and x32


How would I jump to a known memory address in intel assembly syntax (both x32 and x64).

I think I have the 64 bit syntax down. For example, if in x64 I wanted to jmp to the code at 0x75767 and I was located at 0000, I would do:

0000: FF 25 01 00 00 00         jmp QWORD PTR [rip+0x75761]

Is that ^ correct? I thought I could dissemble those bytes that into x32 instruction using objdump objdump.exe -D -Mintel,i386 -b binary -m i386 test.bin which results in:

jmp    DWORD PTR 0x75761

Then just use clang++.exe -masm=intel -m32 -c test.o to convert this instruction to x32 bytes but it says:

error: invalid operand for instruction
jmp DWORD PTR 0x75761
^

I want to avoid writing into any registers.

Is my x64 jmp instruction correct?

How would I accomplish something similar in x32? Let's say in x32 I need to jmp to 0x400107 and I'm at 0x400000

I'm messing around with tweaking running process memory on Windows. Forgive me if my question has inaccuracies, I'm learning.


Solution

  • It's unclear whether you need assembly or machine code. If you want to jump to an absolute address then in 64 bit mode use an embedded pointer addressed rip relative:

    jmp [rip+foo]
    foo: .quad target_address
    

    Machine code: ff 25 00 00 00 00 xx xx xx xx xx xx xx xx (with the last 8 bytes being the target absolute address).
    The first 6 are the instruction, with 2 byte encoding the jmp opcode + modrm, and the 4 after that being rel32=0, so the load address is 0 bytes past the end of the whole instruction.

    Or if you can spare a register, mov r11, OFFSET target_address / jmp r11, or pick any register you can modify. This is often better performance than doing a data load from code, which normally won't be hot in L1d cache or L1dTLB (but probably is in L2 and maybe L2TLB. Normally you'd want to put the .quad constant somewhere else, along with other read-only data, if that's convenient.)


    In 32 bit code you can use the push+ret trick if you are not worried about branch prediction:

    push offset target_address
    ret
    

    Machine code: 68 xx xx xx xx c3

    If you can calculate the relative address you can of course just use a normal jmp which is e9 xx xx xx xx with the last 4 bytes being the distance to jump (counted from the byte following the instruction, where execution would normally continue).

    If performance does matter, mov eax, offset target_address / jmp eax is a pretty standard way. (Any register works if you don't need its value at this point.)