Bug 13668 - x86: objdump gets the wrong length for 66-prefixed direct jumps in 64-bit mode
Summary: x86: objdump gets the wrong length for 66-prefixed direct jumps in 64-bit mode
Status: NEW
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.24
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-02-06 18:45 UTC by Mark Seaborn
Modified: 2012-02-10 17:08 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Seaborn 2012-02-06 18:45:47 UTC
"objdump -d" produces the following disassembly for x86-64 and shows this "jb" as taking a 2-byte jump offset:

  400515:       66 0f 82 00 00          jb     51a
  40051a:       eb 02                   jmp    40051e

This is correct for 32-bit mode, but in 64-bit mode this "jb" should take a 4-byte jump offset.

I'm not sure where that CPU behaviour is documented (I find the AMD manuals unclear on the matter), but the following test demonstrates it empirically:


#include <stdio.h>

asm(".global test\n"
    "test:\n"
    /* Clear the carry flag so that the following "jc" does not jump. */
    "clc\n"
    /* "66 0f 82" is the encoding for "data16 jc".  "jc" is also known
       as "jb".  On x86-32, this takes a 2-byte operand, so it
       executes "jmp size2".  On x86-64, this takes a 4-byte operand,
       so it executes "jmp size4". */
    ".ascii \"\\x66\\x0f\\x82\\x00\\x00\"\n"
    /* We assume that this jump is encoded as a 2-byte instruction. */
    "jmp size2\n"
    "jmp size4\n"
    "size2: jmp size_is_2\n"
    "size4: jmp size_is_4\n"
    );
void test(void);

void size_is_2() { printf("operand size is 2 bytes\n"); }
void size_is_4() { printf("operand size is 4 bytes\n"); }

int main() {
  test();
  return 0;
}


$ gcc test.c -o test -m32 && ./test
operand size is 2 bytes
$ gcc test.c -o test -m64 && ./test
operand size is 4 bytes

Since using the 66 prefix on direct jumps is not very useful on x86-64 -- it only increases the size of the encoding -- we wouldn't expect to see it very often.
Comment 1 Mikael Pettersson 2012-02-09 11:19:19 UTC
AFAIK 66-prefixed branches are invalid on x86_64.  When I looked into them about a year ago, I found that they also behaved very differently on Intel and AMD, so you really shouldn't be using them.
Comment 2 Mark Seaborn 2012-02-10 17:08:55 UTC
Yes, you're right.  I was testing on an Intel machine.  When I tested on an AMD machine, it produced:

$ gcc test.c -o test -m64 && ./test
operand size is 2 bytes

It looks like Intel failed to copy AMD in this regard.  The Intel docs implicitly acknowledge this and say that the behaviour of this instruction is not specified.

Ideally objdump's disassembler would treat this byte sequence as undefined.