简体   繁体   中英

Conditional jump to memory address

Is something like the following possible?

cmp $3, %rdi
jz (%r11)

file.s:52: Error: operand type mismatch for `jz'

Or:

Warning: indirect jmp without `*'

Or do you have to jump 'through' a label which can then do the jmp %r11 . Or how does that work?

It seems there are at least a few things going on here, but one of them is:

  • Giving a warning unless I change jmp %r11 to jmp *%r11 (why?)

Currently what I'm doing is the roundabout:

cmp $3, %rdi
jz fast_ret

fast_ret:
    jmp *%r11

No, all the conditional jump instructions on x86 are immediate ; they take the destination address encoded directly into the instruction (as a displacement from the address of the jump instruction itself). You can't conditionally jump to an address from a register or memory location.

You can do what you did, and jump to the desired jump instruction. Or you can reverse the test and jump around the register or indirect jump that you really want.

    cmp $3, %rdi
    jnz dont_go
    jmp *%r11
dont_go:
    // rest of your program

Your way has the advantage that no jump is taken in the "not equal" case, though branch prediction on modern processors shouldn't leave much difference between "taken" and "not taken". My way has the advantage that neither case involves taking two jumps, and there isn't a jump to some relatively distant intermediate address that may be cold in cache.

Be careful of the difference between:

  • jmp %r11 : invalid syntax for AT&T, absolute jumps always take * prefix, see https://sourceware.org/binutils/docs/as/i386_002dVariations.html#i386_002dVariations .

  • jmp *%r11 : use the contents of %r11 as the address to jump to. You can think of it as doing mov %r11, %rip .

  • jmp *(%r11) : indirect jump, fetch the destination address from the address which %r11 contains. You can think of it as doing mov (%r11), %rip .

Nope it's not, assembly language can only do what machine code allows, see https://www.felixcloutier.com/x86/jcc and notice that they're all jcc rel8/rel32 relative direct, not indirect.

You could cmov to select between addresses for jmp *%reg so it jumps to the next instruction by using something like this:

# possible, but not recommended
# %r11 holds a target address you might want to jump to
   lea    .Lfallthrough(%rip), %r10
   cmp     ...
   cmovne  %r11, %r10           # make the jump go to R11 if !=
   jmp    *%r10
.Lfallthrough:

Normally it's better to just conditionally jump to or over an indirect jmp or ret for an early out ret , or conditional indirect jump, if you can't easily make fallthrough one of your indirect-branch target possibilities.

If the indirect-branch predictor doesn't have a target-address prediction, the default is the next instruction, because it's possible to construct cases like this where one of the actual possibilities is there.


Giving a warning unless I change jmp %r11 to jmp *%r11 (why?)

Because that's how AT&T syntax works. https://sourceware.org/binutils/docs/as/i386_002dVariations.html - AT&T absolute (as opposed to PC relative) jump/call operands are prefixed by *

This is necessary to disambiguate bare memory operands, and for consistency the decoration is expected with all indirect jumps / calls.

  • jmp foobar (jump to that symbol, setting EIP/RIP= foobar )
  • jmp *foobar (load a pointer into EIP/RIP from absolute address of symbol foobar )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM