Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

jmp absolute indirect r/m32 in x64??

2,576 views
Skip to first unread message

flt...@mungedyahoo.com

unread,
May 12, 2009, 7:04:14 AM5/12/09
to

I looked up the Intel 64 and IA-32 programmers manual,
it says JMP r/m32 is not supported in 64 bit mode...

But I wrote a program in 64 bit mode, using the
FF/4 encoding with 0 offset from RIP

FFh 25h 0h 0h 0h 0h 12h 34h 56h 78h

It worked... it jumped to address 78563412....
I am sure my program ran in 64 bit mode...
Why does it work while the manual says not supported?


Karel Lejska

unread,
May 12, 2009, 9:48:44 AM5/12/09
to

FF/4 is documented as JMP r/m64 in 64-bit mode:

Opcode | Instruction | 64-Bit Mode | Compat/Leg Mode
FF /4 JMP r/m64 Valid N.E.

Rod Pemberton

unread,
May 12, 2009, 9:11:45 PM5/12/09
to

<flt...@MUNGEDyahoo.com> wrote in message
news:4a0957ae$0$11854$9a6e...@unlimited.newshosting.com...

>
> I looked up the Intel 64 and IA-32 programmers manual,
> it says JMP r/m32 is not supported in 64 bit mode...
>

True. The 64-bit AMD and Intel manuals that I have agree.

> But I wrote a program in 64 bit mode, using the
> FF/4 encoding with 0 offset from RIP
>
> FFh 25h 0h 0h 0h 0h 12h 34h 56h 78h
>

The offset here is 64-bits in length since there are 8-bytes following the
instruction byte and modregr/m byte. Yes? I.e., this is JMP r/m64.

It looks to me like you used a 64-bit offset form of the instruction. What
are those four zero bytes if not half of a 64-bit offset? I'd expect a
32-bit offset form of the instruction to look like:

FFh 25h 12h 34h 56h 78h

The offset here is 32-bits in length. I.e., this is JMP r/m32.

> It worked...

It should. Shouldn't it? A JMP will jump... but whereto is the question.
;)

> it jumped to address 78563412....

I'm not sure about that... That doesn't seem correct to me. It looks like
you've said 0x78563412 or 78563412h. 0x78563412 is a 32-bit address. But,
it's clear that it should've jumped to a 64-bit address. 0x78563412 is a
32-bit address that's the same as the 64-bit address 0x0000000078563412, but
from the byte sequence you posted the 64-bit address should be
0x7856341200000000, if 64-bit mode is still little-endian.

So, by "jumped to address 78563412..." are you saying it jumped to
0x7856341200000000 or 0x0000000078563412? Where are the zeroes in this
64-bit address? You can't ignore or deceptively not present the zeroes.

It might help if you use specify all bits of a hexadecimal value in hex.
I.e., for a zero, 00h for 8-bits and 00000000h for 32-bits and
0000000000000000h for 64-bits. Personally, I prefer this form for hex since
it encourages you to write out all bits for a specific size of object: 0x00,
0x00000000, 0x0000000000000000.

If 0x7856341200000000, I'd expect the byte sequence you posted, but that
shouldn't JMP to 32-bit address of 0x78563412:

FFh 25h 00h 00h 00h 00h 12h 34h 56h 78h

If 0x0000000078563412, I'd expect the offset byte order to be different from
what you posted, and this should JMP to 32-bit address of 0x78563412:

FFh 25h 12h 34h 56h 78h 00h 00h 00h 00h

So, something else seems wrong to me: either it's an incorrect byte sequence
or it's an incorrect jump address.

BTW, were you using an emulator or debugger or pure 64-bit code? If an
emulator or debugger doesn't properly support 64-bits, it might be giving
bad data.

> I am sure my program ran in 64 bit mode...
> Why does it work while the manual says not supported?

It's not supported. Something worked.

Let's break down that byte sequence:

FFh 25h 0h 0h 0h 0h 12h 34h 56h 78h

FFh is Group 5, which are CALL,JMP,INC,DEC,PUSH.

25h is the modregr/m byte:

mod=00
reg=100
r/m=101

The modregr/m fields select the [rIP+disp32] memory addressing mode and /4
reg field.

So, we have an FF/4 JMP as:

JMP [rIP+disp32]

However, the AMD and Intel JMP documentation indicates there is no FF/4 JMP
[rIP+disp32] form, but a 64-bit offset form in 64-bit mode. From one of the
manuals:

"In 64-bit mode, the operand size for all near branches (CALL, RET, JCC,
JCXZ, JMP, and LOOP) is forced to 64 bits. These instructions update the
64-bit RIP without the need for a REX operand-size prefix."

So, the FF/4 JMP is actually force to be:

JMP [rIP+disp64]

HTH,


Rod Pemberton


Alexei A. Frounze

unread,
May 13, 2009, 3:04:56 AM5/13/09
to

On May 12, 6:11=A0pm, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
> <flt...@MUNGEDyahoo.com> wrote in message
>
> news:4a0957ae$0$11854$9a6e...@unlimited.newshosting.com...
>
>
>
> > I looked up the Intel 64 and IA-32 programmers manual,
> > it says JMP r/m32 is not supported in 64 bit mode...
>
> True. =A0The 64-bit AMD and Intel manuals that I have agree.

>
> > But I wrote a program in 64 bit mode, using the
> > FF/4 encoding with 0 offset from RIP
>
> > FFh 25h 0h 0h 0h 0h 12h 34h 56h 78h
>
> The offset here is 64-bits in length since there are 8-bytes following th=
e
> instruction byte and modregr/m byte. =A0Yes? =A0I.e., this is JMP r/m64.
>
> It looks to me like you used a 64-bit offset form of the instruction. =A0=
What
> are those four zero bytes if not half of a 64-bit offset? =A0I'd expect a

> 32-bit offset form of the instruction to look like:
>
> =A0 FFh 25h 12h 34h 56h 78h
>
> The offset here is 32-bits in length. =A0I.e., this is JMP r/m32.
>
> > It worked...
>
> It should. =A0Shouldn't it? =A0A JMP will jump... =A0but whereto is the q=

uestion.
> ;)
>
> > it jumped to address 78563412....
>
> I'm not sure about that... =A0That doesn't seem correct to me. =A0It look=
s like
> you've said 0x78563412 or 78563412h. =A00x78563412 is a 32-bit address. =
=A0But,
> it's clear that it should've jumped to a 64-bit address. =A00x78563412 is=
a
> 32-bit address that's the same as the 64-bit address 0x0000000078563412, =

but
> from the byte sequence you posted the 64-bit address should be
> 0x7856341200000000, if 64-bit mode is still little-endian.
>
> So, by "jumped to address 78563412..." are you saying it jumped to
> 0x7856341200000000 or 0x0000000078563412? =A0Where are the zeroes in this
> 64-bit address? =A0You can't ignore or deceptively not present the zeroes=

.
>
> It might help if you use specify all bits of a hexadecimal value in hex.
> I.e., for a zero, 00h for 8-bits and 00000000h for 32-bits and
> 0000000000000000h for 64-bits. =A0Personally, I prefer this form for hex =
since
> it encourages you to write out all bits for a specific size of object: 0x=

00,
> 0x00000000, 0x0000000000000000.
>
> If 0x7856341200000000, I'd expect the byte sequence you posted, but that
> shouldn't JMP to 32-bit address of 0x78563412:
>
> =A0 FFh 25h 00h 00h 00h 00h 12h 34h 56h 78h
>
> If 0x0000000078563412, I'd expect the offset byte order to be different f=

rom
> what you posted, and this should JMP to 32-bit address of 0x78563412:
>
> =A0 FFh 25h 12h 34h 56h 78h 00h 00h 00h 00h
>
> So, something else seems wrong to me: either it's an incorrect byte seque=

nce
> or it's an incorrect jump address.
>
> BTW, were you using an emulator or debugger or pure 64-bit code? =A0If an

> emulator or debugger doesn't properly support 64-bits, it might be giving
> bad data.
>
> > I am sure my program ran in 64 bit mode...
> > Why does it work while the manual says not supported?
>
> It's not supported. =A0Something worked.

>
> Let's break down that byte sequence:
>
> =A0 FFh 25h 0h 0h 0h 0h 12h 34h 56h 78h

>
> FFh is Group 5, which are CALL,JMP,INC,DEC,PUSH.
>
> 25h is the modregr/m byte:
>
> =A0mod=3D00
> =A0reg=3D100
> =A0r/m=3D101
>
> The modregr/m fields select the [rIP+disp32] memory addressing mode and /=

4
> reg field.
>
> So, we have an FF/4 JMP as:
>
> =A0 JMP [rIP+disp32]
>
> However, the AMD and Intel JMP documentation indicates there is no FF/4 J=
MP
> [rIP+disp32] form, but a 64-bit offset form in 64-bit mode. =A0From one o=

f the
> manuals:
>
> "In 64-bit mode, the operand size for all near branches (CALL, RET, JCC,
> JCXZ, JMP, and LOOP) is forced to 64 bits. These instructions update the
> 64-bit RIP without the need for a REX operand-size prefix."
>
> So, the FF/4 JMP is actually force to be:
>
> =A0 JMP [rIP+disp64]

I don't know if you've noticed it or not, but in 64-bit mode it's
still JMP [RIP+disp32], disp32 is simply sign-extended to 64 bits
prior to addition to RIP, which allows to access the memory within +/-
2GB range of the current RIP value. disp32 denotes that the
displacement portion of the instruction occupies 32 bits in the
instruction's encoding (just like immN, relN and the like). Then 64-
bit value is extracted from [RIP+signextend(disp32)] and loaded into
RIP. The operand size doesn't dictate/control the disp's size.

Alex

Rod Pemberton

unread,
May 13, 2009, 10:24:22 AM5/13/09
to

"Alexei A. Frounze" <alexf...@MUNGEDmicrocosmotalk.com> wrote in message
news:4a0a7117$0$11818$9a6e...@unlimited.newshosting.com...

Where is that in the manuals *exactly*? Everything I've found indicates
that FF/4 has a 8-byte offset, unlike FF/3 or E9 which are sign-extended:

"r/m64 - A quadword general-purpose register or memory operand used for
instructions whose operand-size attribute is 64 bits when using REX.W. ...
The contents of memory are found at the address provided by the effective
address computation."

FF/3
"In 64-bit mode: If selector points to a gate, then RIP = 64-bit
displacement taken from gate; else RIP = zero extended 32-bit offset from
far pointer referenced in the instruction."

REX.W + FF /3
"In 64-bit mode: If selector points to a gate, then RIP = 64-bit
displacement taken from gate; else RIP = 64-bit offset from far pointer
referenced in the instruction."

E9
"Jump near, relative, RIP = RIP + 32-bit displacement sign extended to
64-bits"

FF/4
"Jump near, absolute indirect, RIP = 64-Bit offset from register or memory."

E9
"Promoted to 64 bits. Operand Size: 64 bits. Can't encode in 32-bits. RIP =
RIP + 32-bit displacement sign-extended to 64 bits."

"FF /3 Promoted to 64 bits. Operand Size: 32 bits. If selector points to a
gate, then RIP = 64-bit offset from gate, else RIP = zero-extended 32-bit
offset from far pointer referenced in instruction."

"FF /4 Promoted to 64 bits. Operand Size: 64 bits. Can't encode in 32-bits.
RIP = 64-bit offset from register or memory."

"Promoted to 64 Bit: If an instruction's operand size (16-bit or 32-bit) in
legacy and compatibility modes depends on the CS.D bit and the operand-size
override prefix, then the operand-size choices in 64-bit mode are extended
from 16-bit and 32-bit to include 64 bits (with a REX prefix), or the
operand size is fixed at 64 bits. Such instructions are said to be "Promoted
to 64 bits" in Table B-1. However, byte-operand opcodes of such instructions
are not promoted."

"Default Operand Size: The default operand size for most instructions is 32
bits, and a REX prefix must be used to change the operand size to 64 bits.
However, two groups of instructions default to 64-bit operand size and do
not need a REX prefix: (1) near branches and (2) all instructions, except
far branches, that implicitly reference the RSP. See Table B-5 on page 400
for a list of all instructions that default to 64-bit operand size."

"In 64-bit mode, two groups of instructions default to 64-bit operand size
without the need for a REX prefix:
Near branches -CALL, Jcc, JrCX, JMP, LOOP, and RET.
All instructions, except far branches, that implicitly reference the
RSP-CALL, ENTER, LEAVE, POP, PUSH, and RET (CALL and RET are in both groups
of instructions)."

B-5 has
CALL E8, CALL FF/2, ENTER C8, Jcc "many", JMP E9, JMP EB, JMP FF/4, LEAVE
C9, LOOP E2

"1.1 Instruction Byte Order"
Legacy Prefix; Rex Prefix; Opcode- 1 or 2 bytes; ModRM; SIB; Displacement -
1, 2, 4, or 8 bytes; Immediate - 1, 2, 4, or 8 bytes


Rod Pemberton

Sebastian Biallas

unread,
May 13, 2009, 11:59:26 AM5/13/09
to

Rod Pemberton wrote:
> "Alexei A. Frounze" <alexf...@MUNGEDmicrocosmotalk.com> wrote in message
> news:4a0a7117$0$11818$9a6e...@unlimited.newshosting.com...
>> On May 12, 6:11=A0pm, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wrote:
>>
>>> "In 64-bit mode, the operand size for all near branches (CALL, RET, JCC,
>>> JCXZ, JMP, and LOOP) is forced to 64 bits. These instructions update the
>>> 64-bit RIP without the need for a REX operand-size prefix."
>>>
>>> So, the FF/4 JMP is actually force to be:
>>>
>>> =A0 JMP [rIP+disp64]
>> I don't know if you've noticed it or not, but in 64-bit mode it's
>> still JMP [RIP+disp32], disp32 is simply sign-extended to 64 bits
>
> Where is that in the manuals *exactly*? Everything I've found indicates
> that FF/4 has a 8-byte offset,

It *refers* to a 8-byte value, but the (optional) displacement in the
operand is 32 bit sign-extended. Like for all other instructions except
the MOV with absolute address.

--
Gru�,
Sebastian

Karel Lejska

unread,
May 14, 2009, 5:12:37 AM5/14/09
to

On 13 kv=C4=9B, 17:59, Sebastian Biallas <groups.5.s...@spamgourmet.com>
wrote:
> Rod Pemberton wrote:
> > "Alexei A. Frounze" <alexfrun...@MUNGEDmicrocosmotalk.com> wrote in mes=
sage
> >news:4a0a7117$0$11818$9a6e...@unlimited.newshosting.com...
> >> On May 12, 6:11=3DA0pm, "Rod Pemberton" <do_not_h...@nohavenot.cmm> wr=
ote:
>
> >>> "In 64-bit mode, the operand size for all near branches (CALL, RET, J=
CC,
> >>> JCXZ, JMP, and LOOP) is forced to 64 bits. These instructions update =

the
> >>> 64-bit RIP without the need for a REX operand-size prefix."
>
> >>> So, the FF/4 JMP is actually force to be:
>
> >>> =3DA0 JMP [rIP+disp64]

> >> I don't know if you've noticed it or not, but in 64-bit mode it's
> >> still JMP [RIP+disp32], disp32 is simply sign-extended to 64 bits
>
> > Where is that in the manuals *exactly*? =C2=A0Everything I've found ind=

icates
> > that FF/4 has a 8-byte offset,
>
> It *refers* to a 8-byte value, but the (optional) displacement in the
> operand is 32 bit sign-extended. Like for all other instructions except
> the MOV with absolute address.
>
> --
> Gru=C3=9F,
> Sebastian

Yes, in other words and in Intel's terms, no 64-bit displacement
exists, only moffs64 in case of few forms of MOV instruction.

Wolfgang Kern

unread,
May 14, 2009, 4:57:27 PM5/14/09
to

Rod Pemberton wrote:
[...about 64-bit...]

the only 8 byte parameters for Address in my list are:

A1 (mem64)
A3 (mem64)

all others use 32-bit sign-extended to 64 bit.

And for DATA I got only 16 variants which show 8 databytes in the code:

48 B8 (imm64)
...
49 BF (imm64)

others may quietly use 32-bit zero-extended to 64 bit without further
notice while others become sign-extended ...
__
wolfgang


0 new messages