0

As a follow up to: jmp absolute far 64 bit address.

I need to write the equivalent of the following in linux extended assembly as mentioned here . Where foo is a 64 bit absolute address.

jmp [rip+foo]

Or I need gcc/g++ to compile the following assembly: ff 25 00 00 00 00 xx xx xx xx xx xx xx xx

Where xx xx xx xx xx xx xx xx is the 64 bit absolute address from an extended assembly line.

I can write the assembly in a separate .s file and then link with my c files but prefer to keep it contained in my c file.

The compiler complained on all the following:

__asm__("jmp $1000000000000000(%rip)");

__asm__("jmp *$1000000000000000(%rip)");
unsigned long absAddr
__asm__("jmp %0(%rip)":: "r"(absAddr));

__asm__("jmp *%0(%rip)":: "r"(absAddr));

I believe the '*' is for indirect access, which probably isn't needed here but trying to see what would compile.


Concerning the feedback: asm("jmp *%0":: "r"(absAddr)); This was the output:

00000000000000f1 <_Z11asmFarJmp64m>:
  f1:   f3 0f 1e fa             endbr64
  f5:   55                      push   %rbp
  f6:   48 89 e5                mov    %rsp,%rbp
  f9:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  fd:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 101:   ff e0                   jmp    *%rax
 103:   90                      nop
 104:   5d                      pop    %rbp
 105:   c3                      ret

Unfortunately, I cannot clobber any registers before the actual jump including rax. This is a one-direction jump, and need it to be done as an intermediate like : "ff 25 00 00 00 00 xx xx xx xx xx xx xx xx" I understand this is a very particular use case.

How do I apply the .quad in inline asm? I see it use as a qualifier for data region initialized memory. I tried asserting it as "jmp .quad ..." but the compiler complained.

Thanks


concerning "ff 25 00 00 00 00 xx xx xx xx xx xx xx xx"

I wrote an asm file to test and compiled with nasm, where the test target address is 0x12345678aabbccdd

SECTION .text
    ;;jmp 0x12345678aabbccdd
    db 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xaa, 0xbb, 0xcc, 0xdd

The objdump is:

jmp64.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <.text>:
   0:   ff 25 00 00 00 00       jmp    *0x0(%rip)        # 0x6
   6:   12 34 56                adc    (%rsi,%rdx,2),%dh
   9:   78 aa                   js     0xffffffffffffffb5
   b:   bb                      .byte 0xbb
   c:   cc                      int3
   d:   dd                      .byte 0xdd

Objdmp did not read this as an 64 bit absolute jmp? Maybe objdmp isn't updated to properly decode this?

As Jester mentioned, it is properyly decoded. I realized later that:

"ff 25 00 00 00 00" is simply jmp quad ptr [rip+0000], meaning the offset of 0000 is right after the instruction size of this rawinst. So the quad word immediately after this rawinst is the jump address to use.

Thanks

suncowiam
  • 1
  • 1
  • 2
    Well, if you allow an `r` constraint then why not just use that for the jump? `"jmp *%0" :: "r"(absAddr)`. If you need the `ff 25` then place the address with a `.quad` after the `jmp` – Jester Dec 27 '22 at 16:41
  • Don't forget to put `__builtin_unreachable()` after the `asm()` statement to tell the compiler that execution doesn't come out the other side, if the jump targets aren't limited to things in the same function (which you could tell the compiler about with `asm goto`). – Peter Cordes Dec 27 '22 at 17:43
  • 1
    It is properly decoded. It isn't a single instruction. The instruction is just the `jmp *0x0(%rip)` which says "there is a pointer in memory after this instruction, use that as the jump target". The only reason I mentioned the register version is because you yourself have showed asm block with `r` constraint which hinted that you are fine with clobbering a register. – Jester Dec 27 '22 at 18:47
  • "I cannot clobber any registers before the actual jump" The only general purpose registers that have a defined value at the beginning of GCC style inline assembly are those explicitly specified as inputs. Also a `"memory"` clobber is required if inline assembly depends on any variable not listed as an input. – Timothy Baldwin Dec 28 '22 at 16:34

1 Answers1

1

You can use:

__asm__ __volatile__(
    "jmp *1f(%%rip)\n\t"
    "1: .quad %p0"
    :: "i" (0x12345678abcdef00ULL));
__builtin_unreachable();

Note your address needs to be a compile time constant for this.

Jester
  • 56,577
  • 4
  • 81
  • 125