From a72d2af2c76f82cc8a198919f73585e11d0a4c60 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Fri, 8 May 2015 17:13:30 -0700 Subject: [PATCH] Ignore 0x66 prefix for call/jmp/jcc in 64-bit mode The operand size prefix (0x66) is ignored for 32-bit PC-relative call, jmp and jcc in 64-bit mode. gas/testsuite/ PR binutis/18386 * gas/i386/i386.exp: Run x86-64-jump. * gas/i386/x86-64-branch.d: Updated. * gas/i386/ilp32/x86-64-branch.d: Likewise. * gas/i386/x86-64-branch.s: Add tests for the operand size prefix with call, jmp and jb. * gas/i386/x86-64-jump.d: New file. * gas/i386/x86-64-jump.s: Likewise. ld/testsuite/ PR binutis/18386 * ld-x86-64/tlsgdesc.dd: Updated. * ld-x86-64/tlspic.dd: Likewise. opcodes/ PR binutis/18386 * i386-dis.c (X86_64_E8): New. (X86_64_E9): Likewise. Update comments on 'T', 'U', 'V'. Add comments for '^'. (dis386): Replace callT/jmpT with X86_64_E8/X86_64_E9. (x86_64_table): Add X86_64_E8 and X86_64_E9. (mod_table): Replace {T|} with ^ on Jcall/Jmp. (putop): Handle '^'. (OP_J): Ignore the operand size prefix in 64-bit. Don't check REX_W. --- gas/testsuite/gas/i386/i386.exp | 2 ++ gas/testsuite/gas/i386/ilp32/x86-64-branch.d | 9 +++-- gas/testsuite/gas/i386/x86-64-branch.d | 9 +++-- gas/testsuite/gas/i386/x86-64-branch.s | 7 ++++ gas/testsuite/gas/i386/x86-64-jump.d | 43 ++++++++++++++++++++++++ gas/testsuite/gas/i386/x86-64-jump.s | 41 +++++++++++++++++++++++ ld/testsuite/ld-x86-64/tlsgdesc.dd | 4 +-- ld/testsuite/ld-x86-64/tlspic.dd | 8 ++--- opcodes/i386-dis.c | 50 ++++++++++++++++++++++------ 9 files changed, 151 insertions(+), 22 deletions(-) create mode 100644 gas/testsuite/gas/i386/x86-64-jump.d create mode 100644 gas/testsuite/gas/i386/x86-64-jump.s diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index bedd84c..9492e80 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -754,6 +754,8 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t run_dump_test "x86-64-relax-2" run_dump_test "x86-64-relax-3" + + run_dump_test "x86-64-jump" } set ASFLAGS "$old_ASFLAGS" diff --git a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d index 9118db1..9fcb8ca 100644 --- a/gas/testsuite/gas/i386/ilp32/x86-64-branch.d +++ b/gas/testsuite/gas/i386/ilp32/x86-64-branch.d @@ -1,7 +1,7 @@ #source: ../x86-64-branch.s #as: -J #objdump: -drw -#name: x86-64 (ILP32) indirect branch +#name: x86-64 (ILP32) branch .*: +file format .* @@ -20,6 +20,9 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 66 ff 20 jmpw \*\(%rax\) [ ]*[a-f0-9]+: e8 00 00 00 00 callq 0x1f 1b: R_X86_64_PC32 \*ABS\*\+0x10003c [ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 0x24 20: R_X86_64_PC32 \*ABS\*\+0x10003c +[ ]*[a-f0-9]+: 66 e8 00 00 00 00 data16 callq 0x2a 26: R_X86_64_PC32 foo-0x4 +[ ]*[a-f0-9]+: 66 e9 00 00 00 00 data16 jmpq 0x30 2c: R_X86_64_PC32 foo-0x4 +[ ]*[a-f0-9]+: 66 0f 82 00 00 00 00 data16 jb 0x37 33: R_X86_64_PC32 foo-0x4 [ ]*[a-f0-9]+: ff d0 callq \*%rax [ ]*[a-f0-9]+: ff d0 callq \*%rax [ ]*[a-f0-9]+: 66 ff d0 callw \*%ax @@ -30,6 +33,6 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 66 ff e0 jmpw \*%ax [ ]*[a-f0-9]+: 66 ff e0 jmpw \*%ax [ ]*[a-f0-9]+: 66 ff 20 jmpw \*\(%rax\) -[ ]*[a-f0-9]+: e8 00 00 00 00 callq 0x43 3f: R_X86_64_PC32 \*ABS\*\+0x10003c -[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 0x48 44: R_X86_64_PC32 \*ABS\*\+0x10003c +[ ]*[a-f0-9]+: e8 00 00 00 00 callq 0x56 52: R_X86_64_PC32 \*ABS\*\+0x10003c +[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 0x5b 57: R_X86_64_PC32 \*ABS\*\+0x10003c #pass diff --git a/gas/testsuite/gas/i386/x86-64-branch.d b/gas/testsuite/gas/i386/x86-64-branch.d index fee2099..49e17a4 100644 --- a/gas/testsuite/gas/i386/x86-64-branch.d +++ b/gas/testsuite/gas/i386/x86-64-branch.d @@ -1,6 +1,6 @@ #as: -J #objdump: -dw -#name: x86-64 indirect branch +#name: x86-64 branch .*: +file format .* @@ -19,6 +19,9 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 66 ff 20 jmpw \*\(%rax\) [ ]*[a-f0-9]+: e8 (00|5b) 00 (00|10) 00 callq (0x1f|10007a <.text\+0x10007a>) [ ]*[a-f0-9]+: e9 (00|60) 00 (00|10) 00 jmpq (0x24|100084 <.text\+0x100084>) +[ ]*[a-f0-9]+: 66 e8 00 00 00 00 data16 callq (0x2a|2a <.text\+0x2a>) +[ ]*[a-f0-9]+: 66 e9 00 00 00 00 data16 jmpq (0x30|30 <.text\+0x30>) +[ ]*[a-f0-9]+: 66 0f 82 00 00 00 00 data16 jb (0x37|37 <.text\+0x37>) [ ]*[a-f0-9]+: ff d0 callq \*%rax [ ]*[a-f0-9]+: ff d0 callq \*%rax [ ]*[a-f0-9]+: 66 ff d0 callw \*%ax @@ -29,6 +32,6 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 66 ff e0 jmpw \*%ax [ ]*[a-f0-9]+: 66 ff e0 jmpw \*%ax [ ]*[a-f0-9]+: 66 ff 20 jmpw \*\(%rax\) -[ ]*[a-f0-9]+: e8 (00|7f) 00 (00|10) 00 callq (0x43|1000c2 <.text\+0x1000c2>) -[ ]*[a-f0-9]+: e9 (00|84) 00 (00|10) 00 jmpq (0x48|1000cc <.text\+0x1000cc>) +[ ]*[a-f0-9]+: e8 (00|92) 00 (00|10) 00 callq (0x56|1000e8 <.text\+0x1000e8>) +[ ]*[a-f0-9]+: e9 (00|97) 00 (00|10) 00 jmpq (0x5b|1000f2 <.text\+0x1000f2>) #pass diff --git a/gas/testsuite/gas/i386/x86-64-branch.s b/gas/testsuite/gas/i386/x86-64-branch.s index 4c1861f..9451d76 100644 --- a/gas/testsuite/gas/i386/x86-64-branch.s +++ b/gas/testsuite/gas/i386/x86-64-branch.s @@ -12,6 +12,13 @@ call 0x100040 jmp 0x100040 + .byte 0x66 + call foo + .byte 0x66 + jmp foo + .byte 0x66 + jb foo + .intel_syntax noprefix call rax callq rax diff --git a/gas/testsuite/gas/i386/x86-64-jump.d b/gas/testsuite/gas/i386/x86-64-jump.d new file mode 100644 index 0000000..edb34e6 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-jump.d @@ -0,0 +1,43 @@ +#objdump: -drw +#name: x86-64 jump + +.*: +file format .* + + +Disassembly of section .text: + +0+ <.text>: +[ ]*[a-f0-9]+: eb fe jmp (0x0|0 <.text>) +[ ]*[a-f0-9]+: e9 00 00 00 00 jmpq 0x7 3: R_X86_64_PC32 xxx-0x4 +[ ]*[a-f0-9]+: ff 24 25 00 00 00 00 jmpq \*0x0 a: R_X86_64_32S xxx +[ ]*[a-f0-9]+: ff e7 jmpq \*%rdi +[ ]*[a-f0-9]+: ff 27 jmpq \*\(%rdi\) +[ ]*[a-f0-9]+: ff 2c bd 00 00 00 00 ljmp \*0x0\(,%rdi,4\) 15: R_X86_64_32S xxx +[ ]*[a-f0-9]+: 66 ff 2c bd 00 00 00 00 ljmpw \*0x0\(,%rdi,4\) 1d: R_X86_64_32S xxx +[ ]*[a-f0-9]+: ff 2c 25 00 00 00 00 ljmp \*0x0 24: R_X86_64_32S xxx +[ ]*[a-f0-9]+: 66 ff 2c 25 00 00 00 00 ljmpw \*0x0 2c: R_X86_64_32S xxx +[ ]*[a-f0-9]+: e8 cb ff ff ff callq 0x0 +[ ]*[a-f0-9]+: e8 00 00 00 00 callq 0x3a 36: R_X86_64_PC32 xxx-0x4 +[ ]*[a-f0-9]+: ff 14 25 00 00 00 00 callq \*0x0 3d: R_X86_64_32S xxx +[ ]*[a-f0-9]+: ff d7 callq \*%rdi +[ ]*[a-f0-9]+: ff 17 callq \*\(%rdi\) +[ ]*[a-f0-9]+: ff 1c bd 00 00 00 00 lcall \*0x0\(,%rdi,4\) 48: R_X86_64_32S xxx +[ ]*[a-f0-9]+: 66 ff 1c bd 00 00 00 00 lcallw \*0x0\(,%rdi,4\) 50: R_X86_64_32S xxx +[ ]*[a-f0-9]+: ff 1c 25 00 00 00 00 lcall \*0x0 57: R_X86_64_32S xxx +[ ]*[a-f0-9]+: 66 ff 1c 25 00 00 00 00 lcallw \*0x0 5f: R_X86_64_32S xxx +[ ]*[a-f0-9]+: 67 e3 00 jecxz 0x66 65: R_X86_64_PC8 \$\+0x2 +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: e3 00 jrcxz 0x69 68: R_X86_64_PC8 \$\+0x1 +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: 66 ff 13 callw \*\(%rbx\) +[ ]*[a-f0-9]+: ff 1b lcall \*\(%rbx\) +[ ]*[a-f0-9]+: 66 ff 23 jmpw \*\(%rbx\) +[ ]*[a-f0-9]+: ff 2b ljmp \*\(%rbx\) +[ ]*[a-f0-9]+: eb 00 jmp 0x76 +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: 67 e3 00 jecxz 0x7a +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: e3 00 jrcxz 0x7d +[ ]*[a-f0-9]+: 90 nop +[ ]*[a-f0-9]+: eb 00 jmp 0x80 +#pass diff --git a/gas/testsuite/gas/i386/x86-64-jump.s b/gas/testsuite/gas/i386/x86-64-jump.s new file mode 100644 index 0000000..96ae66e --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-jump.s @@ -0,0 +1,41 @@ +.psize 0 +.text +.extern xxx + +1: jmp 1b + jmp xxx + jmp *xxx + jmp *%rdi + jmp *(%rdi) + ljmp *xxx(,%rdi,4) + ljmpw *xxx(,%rdi,4) + ljmp *xxx + ljmpw *xxx + + call 1b + call xxx + call *xxx + call *%rdi + call *(%rdi) + lcall *xxx(,%rdi,4) + lcallw *xxx(,%rdi,4) + lcall *xxx + lcallw *xxx + + jecxz 3+$ + nop + jrcxz 2+$ + nop + + .intel_syntax noprefix + call word ptr [rbx] + call fword ptr [rbx] + jmp word ptr [rbx] + jmp fword ptr [rbx] + jmp $+2 + nop + jecxz 3+$ + nop + jrcxz 2+$ + nop + jmp .+2 diff --git a/ld/testsuite/ld-x86-64/tlsgdesc.dd b/ld/testsuite/ld-x86-64/tlsgdesc.dd index 85b219f..88eb953 100644 --- a/ld/testsuite/ld-x86-64/tlsgdesc.dd +++ b/ld/testsuite/ld-x86-64/tlsgdesc.dd @@ -41,7 +41,7 @@ Disassembly of section .text: +[0-9a-f]+: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x180> +[0-9a-f]+: [0-9a-f]{2} * # -> R_X86_64_DTPMOD64 sG1 - +[0-9a-f]+: 66 66 48 e8 ([0-9a-f]{2} ){3}[ ]+data16 data16 callq [0-9a-f]+ <__tls_get_addr@plt> + +[0-9a-f]+: 66 66 48 e8 ([0-9a-f]{2} ){3}[ ]+data16 data16 rex.W callq [0-9a-f]+ <__tls_get_addr@plt> +[0-9a-f]+: [0-9a-f]{2} * # -> R_X86_64_JUMP_SLOT __tls_get_addr +[0-9a-f]+: 90[ ]+nop * @@ -66,7 +66,7 @@ Disassembly of section .text: +[0-9a-f]+: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x160> +[0-9a-f]+: [0-9a-f]{2} * # -> R_X86_64_DTPMOD64 sG2 - +[0-9a-f]+: 66 66 48 e8 ([0-9a-f]{2} ){3}[ ]+data16 data16 callq [0-9a-f]+ <__tls_get_addr@plt> + +[0-9a-f]+: 66 66 48 e8 ([0-9a-f]{2} ){3}[ ]+data16 data16 rex.W callq [0-9a-f]+ <__tls_get_addr@plt> +[0-9a-f]+: [0-9a-f]{2} * # -> R_X86_64_JUMP_SLOT __tls_get_addr +[0-9a-f]+: 90[ ]+nop * diff --git a/ld/testsuite/ld-x86-64/tlspic.dd b/ld/testsuite/ld-x86-64/tlspic.dd index 26d83e9..aab8181 100644 --- a/ld/testsuite/ld-x86-64/tlspic.dd +++ b/ld/testsuite/ld-x86-64/tlspic.dd @@ -20,7 +20,7 @@ Disassembly of section .text: +1008: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x180> +100f: [0-9a-f ]+ # -> R_X86_64_DTPMOD64 sg1 - +1010: 66 66 48 e8 [0-9a-f ]+data16 data16 callq [0-9a-f]+ <.*> + +1010: 66 66 48 e8 [0-9a-f ]+data16 data16 rex.W callq [0-9a-f]+ <.*> # -> R_X86_64_JUMP_SLOT __tls_get_addr +1017: [0-9a-f ]+ +1018: 90[ ]+nop * @@ -40,7 +40,7 @@ Disassembly of section .text: +1030: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x130> +1037: [0-9a-f ]+ # -> R_X86_64_DTPMOD64 [0 0x2000000000000000] - +1038: 66 66 48 e8 [0-9a-f ]+data16 data16 callq [0-9a-f]+ <.*> + +1038: 66 66 48 e8 [0-9a-f ]+data16 data16 rex.W callq [0-9a-f]+ <.*> # -> R_X86_64_JUMP_SLOT __tls_get_addr +103f: [0-9a-f ]+ +1040: 90[ ]+nop * @@ -60,7 +60,7 @@ Disassembly of section .text: +1058: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x1a8> +105f: [0-9a-f ]+ # -> R_X86_64_DTPMOD64 [0 0x4000000000000000] - +1060: 66 66 48 e8 [0-9a-f ]+data16 data16 callq [0-9a-f]+ <.*> + +1060: 66 66 48 e8 [0-9a-f ]+data16 data16 rex.W callq [0-9a-f]+ <.*> # -> R_X86_64_JUMP_SLOT __tls_get_addr +1067: [0-9a-f ]+ +1068: 90[ ]+nop * @@ -80,7 +80,7 @@ Disassembly of section .text: +1080: 66 48 8d 3d ([0-9a-f]{2} ){3}[ ]+data16 lea 0x[0-9a-f]+\(%rip\),%rdi +# [0-9a-f]+ <_DYNAMIC\+0x160> +1087: [0-9a-f ]+ # -> R_X86_64_DTPMOD64 [0 0x6000000000000000] - +1088: 66 66 48 e8 [0-9a-f ]+data16 data16 callq [0-9a-f]+ <.*> + +1088: 66 66 48 e8 [0-9a-f ]+data16 data16 rex.W callq [0-9a-f]+ <.*> # -> R_X86_64_JUMP_SLOT __tls_get_addr +108f: [0-9a-f ]+ +1090: 90[ ]+nop * diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 88c1758..941f699 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -1632,6 +1632,8 @@ enum X86_64_CE, X86_64_D4, X86_64_D5, + X86_64_E8, + X86_64_E9, X86_64_EA, X86_64_0F01_REG_0, X86_64_0F01_REG_1, @@ -2401,9 +2403,12 @@ struct dis386 { is true 'R' => print 'w', 'l' or 'q' ('d' for 'l' and 'e' in Intel mode) 'S' => print 'w', 'l' or 'q' if suffix_always is true - 'T' => print 'q' in 64bit mode and behave as 'P' otherwise - 'U' => print 'q' in 64bit mode and behave as 'Q' otherwise - 'V' => print 'q' in 64bit mode and behave as 'S' otherwise + 'T' => print 'q' in 64bit mode if instruction has no operand size + prefix and behave as 'P' otherwise + 'U' => print 'q' in 64bit mode if instruction has no operand size + prefix and behave as 'Q' otherwise + 'V' => print 'q' in 64bit mode if instruction has no operand size + prefix and behave as 'S' otherwise 'W' => print 'b', 'w' or 'l' ('d' in Intel mode) 'X' => print 's', 'd' depending on data16 prefix (for XMM) 'Y' => 'q' if instruction has an REX 64bit overwrite prefix and @@ -2411,6 +2416,8 @@ struct dis386 { 'Z' => print 'q' in 64bit mode and behave as 'L' otherwise '!' => change condition from true to false or from false to true. '%' => add 1 upper case letter to the macro. + '^' => print 'w' or 'l' depending on operand size prefix or + suffix_always is true (lcall/ljmp). 2 upper case letter macros: "XY" => print 'x' or 'y' if suffix_always is true or no register @@ -2697,8 +2704,8 @@ static const struct dis386 dis386[] = { { "outB", { Ib, AL }, 0 }, { "outG", { Ib, zAX }, 0 }, /* e8 */ - { "callT", { Jv, BND }, 0 }, - { "jmpT", { Jv, BND }, 0 }, + { X86_64_TABLE (X86_64_E8) }, + { X86_64_TABLE (X86_64_E9) }, { X86_64_TABLE (X86_64_EA) }, { "jmp", { Jb, BND }, 0 }, { "inB", { AL, indirDX }, 0 }, @@ -6834,6 +6841,18 @@ static const struct dis386 x86_64_table[][2] = { { "aad", { Ib }, 0 }, }, + /* X86_64_E8 */ + { + { "callP", { Jv, BND }, 0 }, + { "callq", { Jv, BND }, 0 } + }, + + /* X86_64_E9 */ + { + { "jmpP", { Jv, BND }, 0 }, + { "jmpq", { Jv, BND }, 0 } + }, + /* X86_64_EA */ { { "Jjmp{T|}", { Ap }, 0 }, @@ -11576,11 +11595,11 @@ static const struct dis386 mod_table[][2] = { }, { /* MOD_FF_REG_3 */ - { "Jcall{T|}", { indirEp }, 0 }, + { "Jcall^", { indirEp }, 0 }, }, { /* MOD_FF_REG_5 */ - { "Jjmp{T|}", { indirEp }, 0 }, + { "Jjmp^", { indirEp }, 0 }, }, { /* MOD_0F01_REG_0 */ @@ -14177,6 +14196,18 @@ case_S: *obufp++ = vex.w ? 'q': 'd'; } break; + case '^': + if (intel_syntax) + break; + if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) + { + if (sizeflag & DFLAG) + *obufp++ = 'l'; + else + *obufp++ = 'w'; + used_prefixes |= (prefixes & PREFIX_DATA); + } + break; } alt = 0; } @@ -15693,8 +15724,7 @@ OP_J (int bytemode, int sizeflag) disp -= 0x100; break; case v_mode: - USED_REX (REX_W); - if ((sizeflag & DFLAG) || (rex & REX_W)) + if (address_mode == mode_64bit || (sizeflag & DFLAG)) disp = get32s (); else { @@ -15710,7 +15740,7 @@ OP_J (int bytemode, int sizeflag) segment = ((start_pc + codep - start_codep) & ~((bfd_vma) 0xffff)); } - if (!(rex & REX_W)) + if (address_mode != mode_64bit) used_prefixes |= (prefixes & PREFIX_DATA); break; default: -- 2.7.4