From 285ca99246160d12a3173076a661b6c524338baf Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 2 May 2014 11:22:04 -0700 Subject: [PATCH] Properly handle multiple opcode prefixes This patch updates multiple opcode prefix processing: 1. Always print prefix together with bad opcode. 2. Since the last seen segment register prefix is active, we only print the active segment register in the memory operand. 3. The 0xf2 and 0xf3 prefixes take precedence over the 0x66 prefix as the opcode prefix. Also the last of the 0xf2 and 0xf3 prefixes wins. 4. Ignore invalid 0xf2/0xf3 prefixes if they aren't mandatory. gas/testsuite/ PR binutils/16893 * gas/i386/katmai.d: Expect "gs" as prefix. * gas/i386/long-1.s: Replace movapd with movss. * gas/i386/x86-64-long-1.s: Likewise. * gas/i386/long-1-intel.d: Updated. * gas/i386/long-1.d: Likewise. * gas/i386/x86-64-long-1-intel.d: Likewise. * gas/i386/x86-64-long-1.d: Likewise. * gas/i386/prefix.s: Add tests for multiple 0x66, 0x67, 0xf0, 0xf2 and 0xf3 prefixes. * gas/i386/prefix.d: Updated. opcodes/ PR binutils/16893 * i386-dis.c (twobyte_has_mandatory_prefix): New variable. (end_codep): Likewise. (mandatory_prefix): Likewise. (active_seg_prefix): Likewise. (ckprefix): Set active_seg_prefix to the active segment register prefix. (seg_prefix): Removed. (get_valid_dis386): Use the last of PREFIX_REPNZ and PREFIX_REPZ for prefix index. Ignore the index if it is invalid and the mandatory prefix isn't required. (print_insn): Set mandatory_prefix if the PREFIX_XXX prefix is mandatory. Don't set PREFIX_REPZ/PREFIX_REPNZ/PREFIX_LOCK bits in used_prefixes here. Don't print unused prefixes. Check active_seg_prefix for the active segment register prefix. Restore the DFLAG bit in sizeflag if the data size prefix is unused. Check the unused mandatory PREFIX_XXX prefixes (append_seg): Only print the segment register which gets used. (OP_E_memory): Check active_seg_prefix for the segment register prefix. (OP_OFF): Likewise. (OP_OFF64): Likewise. (OP_DSreg): Set active_seg_prefix to PREFIX_DS if it is unset. --- gas/testsuite/ChangeLog | 16 + gas/testsuite/gas/i386/katmai.d | 3 +- gas/testsuite/gas/i386/long-1-intel.d | 4 +- gas/testsuite/gas/i386/long-1.d | 4 +- gas/testsuite/gas/i386/long-1.s | 4 +- gas/testsuite/gas/i386/prefix.d | 63 +++- gas/testsuite/gas/i386/prefix.s | 352 +++++++++++++++++++ gas/testsuite/gas/i386/x86-64-long-1-intel.d | 4 +- gas/testsuite/gas/i386/x86-64-long-1.d | 4 +- gas/testsuite/gas/i386/x86-64-long-1.s | 4 +- opcodes/ChangeLog | 26 ++ opcodes/i386-dis.c | 249 +++++++------ 12 files changed, 598 insertions(+), 135 deletions(-) diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 928adc4a001..8a92fe925a3 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,19 @@ +2014-05-05 H.J. Lu + + PR binutils/16893 + * gas/i386/katmai.d: Expect "gs" as prefix. + + * gas/i386/long-1.s: Replace movapd with movss. + * gas/i386/x86-64-long-1.s: Likewise. + * gas/i386/long-1-intel.d: Updated. + * gas/i386/long-1.d: Likewise. + * gas/i386/x86-64-long-1-intel.d: Likewise. + * gas/i386/x86-64-long-1.d: Likewise. + + * gas/i386/prefix.s: Add tests for multiple 0x66, 0x67, 0xf0, + 0xf2 and 0xf3 prefixes. + * gas/i386/prefix.d: Updated. + 2014-05-02 H.J. Lu * gas/i386/opcode-intel.d: Undo the last change. diff --git a/gas/testsuite/gas/i386/katmai.d b/gas/testsuite/gas/i386/katmai.d index a1c6b97964a..50e573f60e3 100644 --- a/gas/testsuite/gas/i386/katmai.d +++ b/gas/testsuite/gas/i386/katmai.d @@ -160,7 +160,6 @@ Disassembly of section .text: 237: 0f 18 0c 98 [ ]*prefetcht0 \(%eax,%ebx,4\) 23b: 0f 18 12 [ ]*prefetcht1 \(%edx\) 23e: 0f 18 19 [ ]*prefetcht2 \(%ecx\) - 241: 65 [ ]*gs - 242: 0f ae[ ]*\(bad\).* + 241: 65 0f ae[ ]*gs \(bad\).* 244: ff 00 [ ]*incl \(%eax\) #pass diff --git a/gas/testsuite/gas/i386/long-1-intel.d b/gas/testsuite/gas/i386/long-1-intel.d index 7a734626abf..2e5213641be 100644 --- a/gas/testsuite/gas/i386/long-1-intel.d +++ b/gas/testsuite/gas/i386/long-1-intel.d @@ -8,7 +8,7 @@ Disassembly of section .text: 0+ : -[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 66 0f 28 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) +[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 f3 0f 10 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) [ ]*[a-f0-9]+: 00 f2 add dl,dh -[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 66 0f 28 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movapd xmm0,XMMWORD PTR \[eax\] +[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 f3 0f 10 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movss xmm0,DWORD PTR \[eax\] #pass diff --git a/gas/testsuite/gas/i386/long-1.d b/gas/testsuite/gas/i386/long-1.d index 1dccd3674af..a8cd073b35a 100644 --- a/gas/testsuite/gas/i386/long-1.d +++ b/gas/testsuite/gas/i386/long-1.d @@ -7,7 +7,7 @@ Disassembly of section .text: 0+ : -[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 66 0f 28 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) +[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 f3 0f 10 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) [ ]*[a-f0-9]+: 00 f2 add %dh,%dl -[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 66 0f 28 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movapd \(%eax\),%xmm0 +[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 f3 0f 10 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movss \(%eax\),%xmm0 #pass diff --git a/gas/testsuite/gas/i386/long-1.s b/gas/testsuite/gas/i386/long-1.s index 4551068bc53..b7e509dea88 100644 --- a/gas/testsuite/gas/i386/long-1.s +++ b/gas/testsuite/gas/i386/long-1.s @@ -14,7 +14,7 @@ foo: .byte 0xf2 .byte 0xf0 .byte 0xf0 -movapd (%eax), %xmm0 +movss (%eax), %xmm0 .byte 0xf2 .byte 0xf0 .byte 0xf0 @@ -27,4 +27,4 @@ movapd (%eax), %xmm0 .byte 0xf0 .byte 0xf0 .byte 0xf0 -movapd (%eax), %xmm0 +movss (%eax), %xmm0 diff --git a/gas/testsuite/gas/i386/prefix.d b/gas/testsuite/gas/i386/prefix.d index 4139658cac8..d9f0ae2e787 100644 --- a/gas/testsuite/gas/i386/prefix.d +++ b/gas/testsuite/gas/i386/prefix.d @@ -5,11 +5,60 @@ Disassembly of section .text: -0+000 : - 0: 9b 26 67 d9 3c[ ]+fstcw[ ]+%es:\(%si\) - 5: 9b df e0 [ ]*fstsw %ax - 8: 9b df e0 [ ]*fstsw %ax - b: 9b 67 df e0 [ ]*addr16 fstsw %ax - f: 36 67 66 f3 a7 [ ]*repz cmpsw %es:\(%di\),%ss:\(%si\) - 14: 26 9b[ ]*es fwait +0+ : +[ ]*[a-f0-9]+: 9b 26 67 d9 3c fstcw %es:\(%si\) +[ ]*[a-f0-9]+: 9b df e0 fstsw %ax +[ ]*[a-f0-9]+: 9b df e0 fstsw %ax +[ ]*[a-f0-9]+: 9b 67 df e0 addr16 fstsw %ax +[ ]*[a-f0-9]+: 36 67 66 f3 a7 repz cmpsw %es:\(%di\),%ss:\(%si\) +[ ]*[a-f0-9]+: 26 9b es fwait +[ ]*[a-f0-9]+: 66 f2 0f 38 17 data16 \(bad\) +[ ]*[a-f0-9]+: f2 66 0f 54 repnz \(bad\) +[ ]*[a-f0-9]+: f2 0f 54 repnz \(bad\) +[ ]*[a-f0-9]+: f2 66 0f 11 22 data16 movsd %xmm4,\(%edx\) +[ ]*[a-f0-9]+: f2 67 66 0f 11 22 data16 movsd %xmm4,\(%bp,%si\) +[ ]*[a-f0-9]+: f2 67 f0 66 0f 11 22 lock data16 movsd %xmm4,\(%bp,%si\) +[ ]*[a-f0-9]+: f3 66 0f 11 22 data16 movss %xmm4,\(%edx\) +[ ]*[a-f0-9]+: f3 67 f0 66 0f 11 22 lock data16 movss %xmm4,\(%bp,%si\) +[ ]*[a-f0-9]+: f3 67 f2 66 0f 11 22 repz data16 movsd %xmm4,\(%bp,%si\) +[ ]*[a-f0-9]+: f3 66 3e 0f 11 22 data16 movss %xmm4,%ds:\(%edx\) +[ ]*[a-f0-9]+: f2 66 36 0f 11 22 data16 movsd %xmm4,%ss:\(%edx\) +[ ]*[a-f0-9]+: f3 f0 f2 66 36 0f 11 22 repz lock data16 movsd %xmm4,%ss:\(%edx\) +[ ]*[a-f0-9]+: f2 66 3e 36 0f 11 22 data16 ds movsd %xmm4,%ss:\(%edx\) +[ ]*[a-f0-9]+: f2 67 66 3e 36 0f 11 22 data16 ds movsd %xmm4,%ss:\(%bp,%si\) +[ ]*[a-f0-9]+: f2 67 f0 66 3e 36 0f 11 22 lock data16 ds movsd %xmm4,%ss:\(%bp,%si\) +[ ]*[a-f0-9]+: f3 66 3e 36 0f 11 22 data16 ds movss %xmm4,%ss:\(%edx\) +[ ]*[a-f0-9]+: f3 f0 66 3e 36 0f 11 22 lock data16 ds movss %xmm4,%ss:\(%edx\) +[ ]*[a-f0-9]+: f3 67 f2 66 3e 36 0f 11 22 repz data16 ds movsd %xmm4,%ss:\(%bp,%si\) +[ ]*[a-f0-9]+: f2 66 90 repnz xchg %ax,%ax +[ ]*[a-f0-9]+: f2 67 66 90 repnz addr16 xchg %ax,%ax +[ ]*[a-f0-9]+: f2 67 f0 66 90 repnz addr16 lock xchg %ax,%ax +[ ]*[a-f0-9]+: f3 66 90 data16 pause +[ ]*[a-f0-9]+: f3 67 f0 66 90 addr16 lock data16 pause +[ ]*[a-f0-9]+: f3 67 f2 66 90 repz addr16 repnz xchg %ax,%ax +[ ]*[a-f0-9]+: f2 3e 90 repnz ds nop +[ ]*[a-f0-9]+: f2 f0 67 3e 90 repnz lock addr16 ds nop +[ ]*[a-f0-9]+: f3 3e 90 ds pause +[ ]*[a-f0-9]+: f3 66 3e 90 data16 ds pause +[ ]*[a-f0-9]+: f3 f0 3e 90 lock ds pause +[ ]*[a-f0-9]+: f3 f0 67 3e 90 lock addr16 ds pause +[ ]*[a-f0-9]+: f3 f2 67 3e 90 repz repnz addr16 ds nop +[ ]*[a-f0-9]+: 66 f0 36 90 lock ss xchg %ax,%ax +[ ]*[a-f0-9]+: f2 36 90 repnz ss nop +[ ]*[a-f0-9]+: f2 66 36 90 repnz ss xchg %ax,%ax +[ ]*[a-f0-9]+: f2 f0 36 90 repnz lock ss nop +[ ]*[a-f0-9]+: f2 f0 67 36 90 repnz lock addr16 ss nop +[ ]*[a-f0-9]+: f3 36 90 ss pause +[ ]*[a-f0-9]+: f3 67 36 90 addr16 ss pause +[ ]*[a-f0-9]+: f3 f0 67 36 90 lock addr16 ss pause +[ ]*[a-f0-9]+: f3 f2 36 90 repz repnz ss nop +[ ]*[a-f0-9]+: f3 f2 67 36 90 repz repnz addr16 ss nop +[ ]*[a-f0-9]+: f3 f0 f2 66 36 90 repz lock repnz ss xchg %ax,%ax +[ ]*[a-f0-9]+: 66 3e 36 90 ds ss xchg %ax,%ax +[ ]*[a-f0-9]+: 67 66 3e 36 90 addr16 ds ss xchg %ax,%ax +[ ]*[a-f0-9]+: 67 f0 66 3e 36 90 addr16 lock ds ss xchg %ax,%ax +[ ]*[a-f0-9]+: f3 66 3e 36 90 data16 ds ss pause +[ ]*[a-f0-9]+: f3 f0 66 3e 36 90 lock data16 ds ss pause +[ ]*[a-f0-9]+: f3 f2 67 3e 36 90 repz repnz addr16 ds ss nop +[ ]*[a-f0-9]+: f3 67 f2 66 3e 36 90 repz addr16 repnz ds ss xchg %ax,%ax #pass diff --git a/gas/testsuite/gas/i386/prefix.s b/gas/testsuite/gas/i386/prefix.s index 2bf3c71f59e..07020ead08c 100644 --- a/gas/testsuite/gas/i386/prefix.s +++ b/gas/testsuite/gas/i386/prefix.s @@ -4,5 +4,357 @@ es fwait + .byte 0x66 + .byte 0xf2 + .byte 0x0f + .byte 0x38 + .byte 0x17 + + .byte 0xf2 + .byte 0x66 + .byte 0x0f + .byte 0x54 + + .byte 0xf2 + .byte 0x0f + .byte 0x54 + +# data16 movsd %xmm4,(%edx) + .byte 0xf2 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 movsd %xmm4,(%bp,%si) + .byte 0xf2 + .byte 0x67 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# lock data16 movsd %xmm4,(%bp,%si) + .byte 0xf2 + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 movss %xmm4,(%edx) + .byte 0xf3 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# lock data16 movss %xmm4,(%bp,%si) + .byte 0xf3 + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# repz data16 movsd %xmm4,(%bp,%si) + .byte 0xf3 + .byte 0x67 + .byte 0xf2 + .byte 0x66 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 movss %xmm4,%ds:(%edx) + .byte 0xf3 + .byte 0x66 + .byte 0x3e + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 movsd %xmm4,%ss:(%edx) + .byte 0xf2 + .byte 0x66 + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# repz lock data16 movsd %xmm4,%ss:(%edx) + .byte 0xf3 + .byte 0xf0 + .byte 0xf2 + .byte 0x66 + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 ds movsd %xmm4,%ss:(%edx) + .byte 0xf2 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 ds movsd %xmm4,%ss:(%bp,%si) + .byte 0xf2 + .byte 0x67 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# lock data16 ds movsd %xmm4,%ss:(%bp,%si) + .byte 0xf2 + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# data16 ds movss %xmm4,%ss:(%edx) + .byte 0xf3 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# lock data16 ds movss %xmm4,%ss:(%edx) + .byte 0xf3 + .byte 0xf0 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# repz data16 ds movsd %xmm4,%ss:(%bp,%si) + .byte 0xf3 + .byte 0x67 + .byte 0xf2 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x0f + .byte 0x11 + .byte 0x22 + +# repnz; xchg %ax,%ax + .byte 0xf2 + .byte 0x66 + .byte 0x90 + +# repnz; addr16 xchg %ax,%ax + .byte 0xf2 + .byte 0x67 + .byte 0x66 + .byte 0x90 + +# repnz; addr16 lock xchg %ax,%ax + .byte 0xf2 + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x90 + +# data16 pause + .byte 0xf3 + .byte 0x66 + .byte 0x90 + +# addr16 lock data16 pause + .byte 0xf3 + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x90 + +# repz; addr16; repnz; xchg %ax,%ax + .byte 0xf3 + .byte 0x67 + .byte 0xf2 + .byte 0x66 + .byte 0x90 + +# repnz; ds nop + .byte 0xf2 + .byte 0x3e + .byte 0x90 + +# repnz; lock addr16 ds nop + .byte 0xf2 + .byte 0xf0 + .byte 0x67 + .byte 0x3e + .byte 0x90 + +# ds pause + .byte 0xf3 + .byte 0x3e + .byte 0x90 + +# data16 ds pause + .byte 0xf3 + .byte 0x66 + .byte 0x3e + .byte 0x90 + +# lock ds pause + .byte 0xf3 + .byte 0xf0 + .byte 0x3e + .byte 0x90 + +# lock addr16 ds pause + .byte 0xf3 + .byte 0xf0 + .byte 0x67 + .byte 0x3e + .byte 0x90 + +# repz; repnz; addr16 ds nop + .byte 0xf3 + .byte 0xf2 + .byte 0x67 + .byte 0x3e + .byte 0x90 + +# lock ss xchg %ax,%ax + .byte 0x66 + .byte 0xf0 + .byte 0x36 + .byte 0x90 + +# repnz; ss nop + .byte 0xf2 + .byte 0x36 + .byte 0x90 + +# repnz; ss xchg %ax,%ax + .byte 0xf2 + .byte 0x66 + .byte 0x36 + .byte 0x90 + +# repnz; lock ss nop + .byte 0xf2 + .byte 0xf0 + .byte 0x36 + .byte 0x90 + +# repnz; lock addr16 ss nop + .byte 0xf2 + .byte 0xf0 + .byte 0x67 + .byte 0x36 + .byte 0x90 + +# ss pause + .byte 0xf3 + .byte 0x36 + .byte 0x90 + +# addr16 ss pause + .byte 0xf3 + .byte 0x67 + .byte 0x36 + .byte 0x90 + +# lock addr16 ss pause + .byte 0xf3 + .byte 0xf0 + .byte 0x67 + .byte 0x36 + .byte 0x90 + +# repz; repnz; ss nop + .byte 0xf3 + .byte 0xf2 + .byte 0x36 + .byte 0x90 + +# repz; repnz; addr16 ss nop + .byte 0xf3 + .byte 0xf2 + .byte 0x67 + .byte 0x36 + .byte 0x90 + +# repz; lock; repnz; ss xchg %ax,%ax + .byte 0xf3 + .byte 0xf0 + .byte 0xf2 + .byte 0x66 + .byte 0x36 + .byte 0x90 + +# ds ss xchg %ax,%ax + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# addr16 ds ss xchg %ax,%ax + .byte 0x67 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# addr16 lock ds ss xchg %ax,%ax + .byte 0x67 + .byte 0xf0 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# data16 ds ss pause + .byte 0xf3 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# lock data16 ds ss pause + .byte 0xf3 + .byte 0xf0 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# repz; repnz; addr16 ds ss nop + .byte 0xf3 + .byte 0xf2 + .byte 0x67 + .byte 0x3e + .byte 0x36 + .byte 0x90 + +# repz; addr16; repnz; ds ss xchg %ax,%ax + .byte 0xf3 + .byte 0x67 + .byte 0xf2 + .byte 0x66 + .byte 0x3e + .byte 0x36 + .byte 0x90 + # Get a good alignment. .p2align 4,0 diff --git a/gas/testsuite/gas/i386/x86-64-long-1-intel.d b/gas/testsuite/gas/i386/x86-64-long-1-intel.d index 28b291a5854..0ced3f0ba0f 100644 --- a/gas/testsuite/gas/i386/x86-64-long-1-intel.d +++ b/gas/testsuite/gas/i386/x86-64-long-1-intel.d @@ -8,7 +8,7 @@ Disassembly of section .text: 0+ : -[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 66 0f 28 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) +[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 f3 0f 10 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) [ ]*[a-f0-9]+: 00 f2 add dl,dh -[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 66 0f 28 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movapd xmm0,XMMWORD PTR \[rax\] +[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 f3 0f 10 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movss xmm0,DWORD PTR \[rax\] #pass diff --git a/gas/testsuite/gas/i386/x86-64-long-1.d b/gas/testsuite/gas/i386/x86-64-long-1.d index dbb603a9f32..20be6f431c5 100644 --- a/gas/testsuite/gas/i386/x86-64-long-1.d +++ b/gas/testsuite/gas/i386/x86-64-long-1.d @@ -7,7 +7,7 @@ Disassembly of section .text: 0+ : -[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 66 0f 28 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) +[ ]*[a-f0-9]+: f2 f0 f0 f0 f2 f2 f2 f2 f2 f2 f0 f0 f3 0f 10 repnz lock lock lock repnz repnz repnz repnz repnz repnz lock lock \(bad\) [ ]*[a-f0-9]+: 00 f2 add %dh,%dl -[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 66 0f 28 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movapd \(%rax\),%xmm0 +[ ]*[a-f0-9]+: f0 f0 f0 f2 f2 f2 f2 f0 f0 f0 f0 f3 0f 10 00 lock lock lock repnz repnz repnz repnz lock lock lock lock movss \(%rax\),%xmm0 #pass diff --git a/gas/testsuite/gas/i386/x86-64-long-1.s b/gas/testsuite/gas/i386/x86-64-long-1.s index 73f9a533a28..2b912428dc0 100644 --- a/gas/testsuite/gas/i386/x86-64-long-1.s +++ b/gas/testsuite/gas/i386/x86-64-long-1.s @@ -14,7 +14,7 @@ foo: .byte 0xf2 .byte 0xf0 .byte 0xf0 -movapd (%rax), %xmm0 +movss (%rax), %xmm0 .byte 0xf2 .byte 0xf0 .byte 0xf0 @@ -27,4 +27,4 @@ movapd (%rax), %xmm0 .byte 0xf0 .byte 0xf0 .byte 0xf0 -movapd (%rax), %xmm0 +movss (%rax), %xmm0 diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 2e4affeb471..47555e6b262 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,29 @@ +2014-05-05 H.J. Lu + + PR binutils/16893 + * i386-dis.c (twobyte_has_mandatory_prefix): New variable. + (end_codep): Likewise. + (mandatory_prefix): Likewise. + (active_seg_prefix): Likewise. + (ckprefix): Set active_seg_prefix to the active segment register + prefix. + (seg_prefix): Removed. + (get_valid_dis386): Use the last of PREFIX_REPNZ and PREFIX_REPZ + for prefix index. Ignore the index if it is invalid and the + mandatory prefix isn't required. + (print_insn): Set mandatory_prefix if the PREFIX_XXX prefix is + mandatory. Don't set PREFIX_REPZ/PREFIX_REPNZ/PREFIX_LOCK bits + in used_prefixes here. Don't print unused prefixes. Check + active_seg_prefix for the active segment register prefix. + Restore the DFLAG bit in sizeflag if the data size prefix is + unused. Check the unused mandatory PREFIX_XXX prefixes + (append_seg): Only print the segment register which gets used. + (OP_E_memory): Check active_seg_prefix for the segment register + prefix. + (OP_OFF): Likewise. + (OP_OFF64): Likewise. + (OP_DSreg): Set active_seg_prefix to PREFIX_DS if it is unset. + 2014-05-02 H.J. Lu PR binutils/16886 diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 99bb4828333..0ec27ca7077 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -2845,6 +2845,29 @@ static const unsigned char twobyte_has_modrm[256] = { /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ }; +static const unsigned char twobyte_has_mandatory_prefix[256] = { + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ + /* ------------------------------- */ + /* 00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0f */ + /* 10 */ 1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0, /* 1f */ + /* 20 */ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,0, /* 2f */ + /* 30 */ 0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, /* 3f */ + /* 40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 4f */ + /* 50 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5f */ + /* 60 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6f */ + /* 70 */ 1,0,0,0,1,1,1,1,0,0,1,1,1,1,1,1, /* 7f */ + /* 80 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 8f */ + /* 90 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 9f */ + /* a0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* af */ + /* b0 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* bf */ + /* c0 */ 0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0, /* cf */ + /* d0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* df */ + /* e0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* ef */ + /* f0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0 /* ff */ + /* ------------------------------- */ + /* 0 1 2 3 4 5 6 7 8 9 a b c d e f */ +}; + static char obuf[100]; static char *obufp; static char *mnemonicendp; @@ -2852,6 +2875,7 @@ static char scratchbuf[100]; static unsigned char *start_codep; static unsigned char *insn_codep; static unsigned char *codep; +static unsigned char *end_codep; static int last_lock_prefix; static int last_repz_prefix; static int last_repnz_prefix; @@ -2859,6 +2883,10 @@ static int last_data_prefix; static int last_addr_prefix; static int last_rex_prefix; static int last_seg_prefix; +/* The PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is mandatory. */ +static int mandatory_prefix; +/* The active segment register prefix. */ +static int active_seg_prefix; #define MAX_CODE_LENGTH 15 /* We can up to 14 prefixes since the maximum instruction length is 15bytes. */ @@ -11607,6 +11635,7 @@ ckprefix (void) last_addr_prefix = -1; last_rex_prefix = -1; last_seg_prefix = -1; + active_seg_prefix = 0; for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++) all_prefixes[i] = 0; i = 0; @@ -11656,26 +11685,32 @@ ckprefix (void) case 0x2e: prefixes |= PREFIX_CS; last_seg_prefix = i; + active_seg_prefix = PREFIX_CS; break; case 0x36: prefixes |= PREFIX_SS; last_seg_prefix = i; + active_seg_prefix = PREFIX_SS; break; case 0x3e: prefixes |= PREFIX_DS; last_seg_prefix = i; + active_seg_prefix = PREFIX_DS; break; case 0x26: prefixes |= PREFIX_ES; last_seg_prefix = i; + active_seg_prefix = PREFIX_ES; break; case 0x64: prefixes |= PREFIX_FS; last_seg_prefix = i; + active_seg_prefix = PREFIX_FS; break; case 0x65: prefixes |= PREFIX_GS; last_seg_prefix = i; + active_seg_prefix = PREFIX_GS; break; case 0x66: prefixes |= PREFIX_DATA; @@ -11718,28 +11753,6 @@ ckprefix (void) return 0; } -static int -seg_prefix (int pref) -{ - switch (pref) - { - case 0x2e: - return PREFIX_CS; - case 0x36: - return PREFIX_SS; - case 0x3e: - return PREFIX_DS; - case 0x26: - return PREFIX_ES; - case 0x64: - return PREFIX_FS; - case 0x65: - return PREFIX_GS; - default: - return 0; - } -} - /* Return the name of the prefix byte PREF, or NULL if PREF is not a prefix byte. */ @@ -11961,32 +11974,47 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) } else { + int last_prefix = -1; + int prefix = 0; vindex = 0; - used_prefixes |= (prefixes & PREFIX_REPZ); - if (prefixes & PREFIX_REPZ) - { - vindex = 1; - all_prefixes[last_repz_prefix] = 0; - } - else + /* We check PREFIX_REPNZ and PREFIX_REPZ before PREFIX_DATA. + When there are multiple PREFIX_REPNZ and PREFIX_REPZ, the + last one wins. */ + if ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) != 0) { - /* We should check PREFIX_REPNZ and PREFIX_REPZ before - PREFIX_DATA. */ - used_prefixes |= (prefixes & PREFIX_REPNZ); - if (prefixes & PREFIX_REPNZ) + if (last_repz_prefix > last_repnz_prefix) { - vindex = 3; - all_prefixes[last_repnz_prefix] = 0; + vindex = 1; + prefix = PREFIX_REPZ; + last_prefix = last_repz_prefix; } else { - used_prefixes |= (prefixes & PREFIX_DATA); - if (prefixes & PREFIX_DATA) - { - vindex = 2; - all_prefixes[last_data_prefix] = 0; - } + vindex = 3; + prefix = PREFIX_REPNZ; + last_prefix = last_repnz_prefix; } + + /* Ignore the invalid index if it isn't mandatory. */ + if (!mandatory_prefix + && (prefix_table[dp->op[1].bytemode][vindex].name + == NULL) + && (prefix_table[dp->op[1].bytemode][vindex].op[0].bytemode + == 0)) + vindex = 0; + } + + if (vindex == 0 && (prefixes & PREFIX_DATA) != 0) + { + vindex = 2; + prefix = PREFIX_DATA; + last_prefix = last_data_prefix; + } + + if (vindex != 0) + { + used_prefixes |= prefix; + all_prefixes[last_prefix] = 0; } } dp = &prefix_table[dp->op[1].bytemode][vindex]; @@ -12001,6 +12029,7 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) FETCH_DATA (info, codep + 2); vindex = *codep++; dp = &three_byte_table[dp->op[1].bytemode][vindex]; + end_codep = codep; modrm.mod = (*codep >> 6) & 3; modrm.reg = (*codep >> 3) & 7; modrm.rm = *codep & 7; @@ -12083,6 +12112,7 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) vindex = *codep++; dp = &xop_table[vex_table_index][vindex]; + end_codep = codep; FETCH_DATA (info, codep + 1); modrm.mod = (*codep >> 6) & 3; modrm.reg = (*codep >> 3) & 7; @@ -12144,6 +12174,7 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) codep++; vindex = *codep++; dp = &vex_table[vex_table_index][vindex]; + end_codep = codep; /* There is no MODRM byte for VEX [82|77]. */ if (vindex != 0x77 && vindex != 0x82) { @@ -12192,6 +12223,7 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) codep++; vindex = *codep++; dp = &vex_table[dp->op[1].bytemode][vindex]; + end_codep = codep; /* There is no MODRM byte for VEX [82|77]. */ if (vindex != 0x77 && vindex != 0x82) { @@ -12286,6 +12318,7 @@ get_valid_dis386 (const struct dis386 *dp, disassemble_info *info) codep++; vindex = *codep++; dp = &evex_table[vex_table_index][vindex]; + end_codep = codep; FETCH_DATA (info, codep + 1); modrm.mod = (*codep >> 6) & 3; modrm.reg = (*codep >> 3) & 7; @@ -12565,22 +12598,17 @@ print_insn (bfd_vma pc, disassemble_info *info) threebyte = *++codep; dp = &dis386_twobyte[threebyte]; need_modrm = twobyte_has_modrm[*codep]; + mandatory_prefix = twobyte_has_mandatory_prefix[*codep]; codep++; } else { dp = &dis386[*codep]; need_modrm = onebyte_has_modrm[*codep]; + mandatory_prefix = 0; codep++; } - if ((prefixes & PREFIX_REPZ)) - used_prefixes |= PREFIX_REPZ; - if ((prefixes & PREFIX_REPNZ)) - used_prefixes |= PREFIX_REPNZ; - if ((prefixes & PREFIX_LOCK)) - used_prefixes |= PREFIX_LOCK; - default_prefixes = 0; if (prefixes & PREFIX_ADDR) { @@ -12615,6 +12643,7 @@ print_insn (bfd_vma pc, disassemble_info *info) } } + end_codep = codep; if (need_modrm) { FETCH_DATA (info, codep + 1); @@ -12663,24 +12692,6 @@ print_insn (bfd_vma pc, disassemble_info *info) } } - /* See if any prefixes were not used. If so, print the first one - separately. If we don't do this, we'll wind up printing an - instruction stream which does not precisely correspond to the - bytes we are disassembling. */ - if ((prefixes & ~(used_prefixes | default_prefixes)) != 0) - { - for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++) - if (all_prefixes[i]) - { - const char *name; - name = prefix_name (all_prefixes[i], priv.orig_sizeflag); - if (name == NULL) - name = INTERNAL_DISASSEMBLER_ERROR; - (*info->fprintf_func) (info->stream, "%s", name); - return 1; - } - } - /* Check if the REX prefix is used. */ if (rex_ignored == 0 && (rex ^ rex_used) == 0 && last_rex_prefix >= 0) all_prefixes[last_rex_prefix] = 0; @@ -12688,8 +12699,7 @@ print_insn (bfd_vma pc, disassemble_info *info) /* Check if the SEG prefix is used. */ if ((prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS | PREFIX_ES | PREFIX_FS | PREFIX_GS)) != 0 - && (used_prefixes - & seg_prefix (all_prefixes[last_seg_prefix])) != 0) + && (used_prefixes & active_seg_prefix) != 0) all_prefixes[last_seg_prefix] = 0; /* Check if the ADDR prefix is used. */ @@ -12697,10 +12707,15 @@ print_insn (bfd_vma pc, disassemble_info *info) && (used_prefixes & PREFIX_ADDR) != 0) all_prefixes[last_addr_prefix] = 0; - /* Check if the DATA prefix is used. */ - if ((prefixes & PREFIX_DATA) != 0 - && (used_prefixes & PREFIX_DATA) != 0) - all_prefixes[last_data_prefix] = 0; + /* Check if the DATA prefix is used. Restore the DFLAG bit in + sizeflag if the DATA prefix is unused. */ + if ((prefixes & PREFIX_DATA) != 0) + { + if ((used_prefixes & PREFIX_DATA) != 0) + all_prefixes[last_data_prefix] = 0; + else if ((default_prefixes & PREFIX_DATA) == 0) + sizeflag ^= DFLAG; + } prefix_length = 0; for (i = 0; i < (int) ARRAY_SIZE (all_prefixes); i++) @@ -12714,6 +12729,26 @@ print_insn (bfd_vma pc, disassemble_info *info) (*info->fprintf_func) (info->stream, "%s ", name); } + /* If the mandatory PREFIX_REPZ/PREFIX_REPNZ/PREFIX_DATA prefix is + unused, opcode is invalid. Since the PREFIX_DATA prefix may be + used by putop and MMX/SSE operand and may be overriden by the + PREFIX_REPZ/PREFIX_REPNZ fix, we check the PREFIX_DATA prefix + separately. */ + if (mandatory_prefix + && dp != &bad_opcode + && (((prefixes + & (PREFIX_REPZ | PREFIX_REPNZ)) != 0 + && (used_prefixes + & (PREFIX_REPZ | PREFIX_REPNZ)) == 0) + || ((((prefixes + & (PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA)) + == PREFIX_DATA) + && (used_prefixes & PREFIX_DATA) == 0)))) + { + (*info->fprintf_func) (info->stream, "(bad)"); + return end_codep - priv.the_buffer; + } + /* Check maximum code length. */ if ((codep - start_codep) > MAX_CODE_LENGTH) { @@ -13681,35 +13716,33 @@ oappend (const char *s) static void append_seg (void) { - if (prefixes & PREFIX_CS) + /* Only print the active segment register. */ + if (!active_seg_prefix) + return; + + used_prefixes |= active_seg_prefix; + switch (active_seg_prefix) { - used_prefixes |= PREFIX_CS; + case PREFIX_CS: oappend_maybe_intel ("%cs:"); - } - if (prefixes & PREFIX_DS) - { - used_prefixes |= PREFIX_DS; + break; + case PREFIX_DS: oappend_maybe_intel ("%ds:"); - } - if (prefixes & PREFIX_SS) - { - used_prefixes |= PREFIX_SS; + break; + case PREFIX_SS: oappend_maybe_intel ("%ss:"); - } - if (prefixes & PREFIX_ES) - { - used_prefixes |= PREFIX_ES; + break; + case PREFIX_ES: oappend_maybe_intel ("%es:"); - } - if (prefixes & PREFIX_FS) - { - used_prefixes |= PREFIX_FS; + break; + case PREFIX_FS: oappend_maybe_intel ("%fs:"); - } - if (prefixes & PREFIX_GS) - { - used_prefixes |= PREFIX_GS; + break; + case PREFIX_GS: oappend_maybe_intel ("%gs:"); + break; + default: + break; } } @@ -14541,10 +14574,7 @@ OP_E_memory (int bytemode, int sizeflag) { if (modrm.mod != 0 || base == 5) { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else + if (!active_seg_prefix) { oappend (names_seg[ds_reg - es_reg]); oappend (":"); @@ -14617,10 +14647,7 @@ OP_E_memory (int bytemode, int sizeflag) } else if (intel_syntax) { - if (prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS)) - ; - else + if (!active_seg_prefix) { oappend (names_seg[ds_reg - es_reg]); oappend (":"); @@ -15178,8 +15205,7 @@ OP_OFF (int bytemode, int sizeflag) if (intel_syntax) { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + if (!active_seg_prefix) { oappend (names_seg[ds_reg - es_reg]); oappend (":"); @@ -15209,8 +15235,7 @@ OP_OFF64 (int bytemode, int sizeflag) if (intel_syntax) { - if (!(prefixes & (PREFIX_CS | PREFIX_SS | PREFIX_DS - | PREFIX_ES | PREFIX_FS | PREFIX_GS))) + if (!active_seg_prefix) { oappend (names_seg[ds_reg - es_reg]); oappend (":"); @@ -15286,14 +15311,10 @@ OP_DSreg (int code, int sizeflag) intel_operand_size (b_mode, sizeflag); } } - if ((prefixes - & (PREFIX_CS - | PREFIX_DS - | PREFIX_SS - | PREFIX_ES - | PREFIX_FS - | PREFIX_GS)) == 0) - prefixes |= PREFIX_DS; + /* Set active_seg_prefix to PREFIX_DS if it is unset so that the + default segment register DS is printed. */ + if (!active_seg_prefix) + active_seg_prefix = PREFIX_DS; append_seg (); ptr_reg (code, sizeflag); } -- 2.30.2