1

I want to emit absolute far jump using asmjit. Bytes of this jump:

FF 25 00 00 00 00 // jmp qword ptr [null offset]
00 00 00 00 00 00 00 00 // 8-byte jump target address

But I don't know how to emit jmp qword ptr [*] with 0 offset and raw address bytes after it.
Can someone help me?
Thanks in advance!

UPD: I know how to emit jmp qword ptr [*].

a.jmp(asmjit::x86::ptr(asmjit::x86::rip));

But how can I emit raw address bytes?

rabtors
  • 75
  • 5
  • 1
    What are you trying to achieve? A far jump should only be needed in operating system code if you are programming for 64 bit mode. – fuz Aug 18 '20 at 18:21
  • `FF /5 JMP m16:32` takes a pointer to a 6-byte memory operand, `REX.W FF /5 JMP m16:64` takes a pointer to a 10-byte memory operand. 8-byte would only make sense for an absolute *near* jump that sets a new RIP but leaves CS alone. (And in that case, it's better to use a free register and `mov rax, imm64` / `jmp rax`, instead of using RIP-rel=0 to do a data load from the code, requiring the cache line to be in L1d cache as well as L1i cache, and the page in the dTLB as well as iTLB.) [Handling calls to far away ahead-of-time compiled functions from JITed code](//stackoverflow.com/q/54947302) – Peter Cordes Aug 18 '20 at 18:26
  • 1
    Also [How to execute a call instruction with a 64-bit absolute address?](https://stackoverflow.com/q/38961192) – Peter Cordes Aug 18 '20 at 18:29
  • 1
    But `FF 25` is not a "far jump" in x86 terminology, it's just plain `FF /4 jmp r/m64` near indirect. So yeah, `mov rax, imm64` / `jmp rax` would be equivalent and better, or pick any other register you can destroy. (ping @fuz) – Peter Cordes Aug 18 '20 at 18:33
  • @PeterCordes, I know, I just want to emit raw address bytes.I already tested this assembly code, it works cool, but I don't know how to assemble this code using asmjit. I can't edit registers – rabtors Aug 18 '20 at 18:42
  • 2
    If you know that, then don't write "far jump". That has a specific technical meaning for x86 / x86-64. Anyway, you don't have *any* scratch registers in your calling convention? x86-64 System V leaves R11 unused for arg passing or return so trampolines can stuff can use it. If you can't do that, consider allocating your JIT buffer near what it needs to call, so a `call rel32` can reach. – Peter Cordes Aug 18 '20 at 18:51
  • 1
    Otherwise a low performance option is `push imm32` / `mov [rsp+4], imm32` / `ret` which causes a branch mispredict that's only detected after a store-forwarding stall, and unbalances the return predictor. That might be even worse than this idea, though; your RIP-relative load just wastes a bit of space in L1d and dTLB. – Peter Cordes Aug 18 '20 at 18:52

1 Answers1

4

There are multiple options:

a) Embed the address after jump, this answers the question:

a.jmp(asmjit::x86::ptr(asmjit::x86::rip));
a.embedUInt64(addressToEmbed);

b) Do the same with Label:

Label constPool = a.newLabel();
a.jmp(x86::ptr(constPool));

// later in the code.
a.bind(constPool);
a.embedUInt64(addressToEmbed);
// possibly more addresses in the pool.
embedUInt64(anotherAddress);

c) Use absolute address in the jmp itself as AsmJit would add that address to AddressTable that will be emitted at the end of the instruction stream (it would basically do (b) by itself or use 32-bit relative displacement if that's possible).

a.jmp(absoluteAddress);

d) If you want the constant pool approach (b), but you want to emit the address immediately it's also possible to use multiple sections - multiple sections are like having multiple buffers that will be flattened at the end of assembling. I would point you to AsmJit test called asmjit_test_x86_sections.cpp in AsmJit's test directory.

Additionally, Asmjit has a documentation available here: https://asmjit.com/doc/index.html - it's regularly updated and reflects master branch.

Petr
  • 750
  • 6
  • 8
  • Note that some future readers won't have the restriction of not clobbering any registers. In that case, a `mov reg, imm64` / `jmp reg` is normally best, if you can't manage to put your JIT buffer within +-2GiB of the target for `jmp rel32`. [How to execute a call instruction with a 64-bit absolute address?](https://stackoverflow.com/q/38961192). Anyway, +1, nice that AsmJit makes it easy to put data somewhere so you can separate code from read-only data. – Peter Cordes Aug 20 '20 at 08:11