From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 99197 invoked by alias); 11 Feb 2020 10:27:03 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 99178 invoked by uid 89); 11 Feb 2020 10:27:03 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-9.5 required=5.0 tests=AWL,BAYES_00,GIT_PATCH_2,GIT_PATCH_3,SPF_PASS autolearn=ham version=3.3.1 spammy= X-HELO: mx2.suse.de Received: from mx2.suse.de (HELO mx2.suse.de) (195.135.220.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 11 Feb 2020 10:26:57 +0000 Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id EEF99AEBF; Tue, 11 Feb 2020 10:26:54 +0000 (UTC) Subject: [PATCH v5 5/5] x86-64: Intel64 adjustments for insns dealing with far pointers From: Jan Beulich To: "binutils@sourceware.org" Cc: "H.J. Lu" References: <1e1b8eba-93ff-39ed-460a-a922d12af27e@suse.com> Message-ID: Date: Tue, 11 Feb 2020 10:27:00 -0000 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:68.0) Gecko/20100101 Thunderbird/68.4.2 MIME-Version: 1.0 In-Reply-To: <1e1b8eba-93ff-39ed-460a-a922d12af27e@suse.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes X-SW-Source: 2020-02/txt/msg00170.txt.bz2 AMD and Intel differ in their handling of far indirect branches as well as LFS/LGS/LSS: AMD CPUs ignore REX.W while Intel ones honors it. (Note how the latter three were hybrids so far, while far branches were fully AMD-like.) gas/ 2020-02-XX Jan Beulich PR gas/24546 * config/tc-i386-intel.c (i386_intel_operand): Also handle CALL/JMP in O_tbyte_ptr case. * doc/c-i386.texi: Mention far call and full pointer load ISA differences. * testsuite/gas/i386/x86-64-branch-3.s, testsuite/gas/i386/x86-64-intel64.s: Add 64-bit far call cases. * testsuite/gas/i386/x86-64-branch-3.d, testsuite/gas/i386/x86-64-intel64.d: Adjust expectations. * testsuite/gas/i386/x86-64-branch-5.l, testsuite/gas/i386/x86-64-branch-5.s: New. * testsuite/gas/i386/i386.exp: Run new test. opcodes/ 2020-02-XX Jan Beulich PR gas/24546 * i386-dis.c (putop): Handle REX.W in '^' case for Intel64 mode. * i386-opc.tbl (lfs, lgs, lss, lcall, ljmp): Split into Amd64 and Intel64 templates. (call, jmp): Likewise for far indirect variants. Dro Unspecified. * i386-tbl.h: Re-generate. --- v5: Re-base. v4: Add documentation. v3: New. --- a/gas/config/tc-i386-intel.c +++ b/gas/config/tc-i386-intel.c @@ -694,9 +694,11 @@ i386_intel_operand (char *operand_string if (got_a_float == 1) suffix = LONG_DOUBLE_MNEM_SUFFIX; else if ((current_templates->start->operand_types[0].bitfield.fword - || current_templates->start->operand_types[0].bitfield.tbyte) + || current_templates->start->operand_types[0].bitfield.tbyte + || current_templates->start->opcode_modifier.jump == JUMP_DWORD + || current_templates->start->opcode_modifier.jump == JUMP) && flag_code == CODE_64BIT) - suffix = QWORD_MNEM_SUFFIX; /* l[fgs]s, [ls][gi]dt */ + suffix = QWORD_MNEM_SUFFIX; /* l[fgs]s, [ls][gi]dt, call, jmp */ else i.types[this_operand].bitfield.byte = 1; /* cause an error */ break; --- a/gas/doc/c-i386.texi +++ b/gas/doc/c-i386.texi @@ -1455,6 +1455,18 @@ There are some discrepancies between AMD @item For @samp{movsxd} with 16-bit destination register, AMD64 supports 32-bit source operand and Intel64 supports 16-bit source operand. + +@item For far branches (with explicit memory operand), both ISAs support +32- and 16-bit operand size. Intel64 additionally supports 64-bit +operand size, encoded as @samp{ljmpq} and @samp{lcallq} in AT&T syntax +and with an explicit @samp{tbyte ptr} operand size specifier in Intel +syntax. + +@item @samp{lfs}, @samp{lgs}, and @samp{lss} similarly allow for 16- +and 32-bit operand size (32- and 48-bit memory operand) in both ISAs, +while Intel64 additionally supports 64-bit operand sise (80-bit memory +operands). + @end itemize @node i386-Bugs --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -1142,6 +1142,7 @@ if [expr ([istarget "i*86-*-*"] || [ista run_dump_test "x86-64-branch-2" run_dump_test "x86-64-branch-3" run_list_test "x86-64-branch-4" "-al -mintel64" + run_list_test "x86-64-branch-5" "-al" run_dump_test "x86-64-gotpcrel" run_dump_test "x86-64-gotpcrel-no-relax" --- a/gas/testsuite/gas/i386/x86-64-branch-3.d +++ b/gas/testsuite/gas/i386/x86-64-branch-3.d @@ -16,4 +16,6 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 66 48 e8 00 00 00 00 data16 rex\.W callq 1c 18: R_X86_64_PLT32 foo-0x4 [ ]*[a-f0-9]+: 66 c7 f8 00 00 xbeginw 21 1f: R_X86_64_PC16 foo-0x2 [ ]*[a-f0-9]+: 66 48 c7 f8 00 00 00 00 data16 xbeginq 29 25: R_X86_64_PLT32 foo-0x4 +[ ]*[a-f0-9]+: 48 ff 18 lcallq \*\(%rax\) +[ ]*[a-f0-9]+: 48 ff 29 ljmpq \*\(%rcx\) #pass --- a/gas/testsuite/gas/i386/x86-64-branch-3.s +++ b/gas/testsuite/gas/i386/x86-64-branch-3.s @@ -10,3 +10,6 @@ bar: data16 xbegin foo data16 rex.w xbegin foo + + lcallq *(%rax) + ljmpq *(%rcx) --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-branch-5.l @@ -0,0 +1,19 @@ +.*: Assembler messages: +.*:2: Error: unsupported syntax for `lcall' +.*:3: Error: unsupported syntax for `lfs' +.*:4: Error: unsupported syntax for `lfs' +.*:5: Error: unsupported syntax for `lgs' +.*:6: Error: unsupported syntax for `lgs' +.*:7: Error: unsupported syntax for `ljmp' +.*:8: Error: unsupported syntax for `lss' +.*:9: Error: unsupported syntax for `lss' +.*:12: Error: unsupported syntax for `call' +.*:13: Error: unsupported syntax for `lfs' +.*:14: Error: unsupported syntax for `lfs' +.*:15: Error: unsupported syntax for `lgs' +.*:16: Error: unsupported syntax for `lgs' +.*:17: Error: unsupported syntax for `jmp' +.*:18: Error: unsupported syntax for `lss' +.*:19: Error: unsupported syntax for `lss' +GAS LISTING .* +#pass --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-branch-5.s @@ -0,0 +1,19 @@ + .text + lcallq *(%rax) + lfs (%rax), %rax + lfsq (%rax), %rax + lgs (%rax), %rax + lgsq (%rax), %rax + ljmpq *(%rax) + lss (%rax), %rax + lssq (%rax), %rax + + .intel_syntax noprefix + call TBYTE PTR [rax] + lfs rax, [rax] + lfs rax, TBYTE PTR [rax] + lgs rax, [rax] + lgs rax, TBYTE PTR [rax] + jmp TBYTE PTR [rax] + lss rax, [rax] + lss rax, TBYTE PTR [rax] --- a/gas/testsuite/gas/i386/x86-64-intel64.d +++ b/gas/testsuite/gas/i386/x86-64-intel64.d @@ -12,6 +12,8 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 48 0f b5 11 lgs \(%rcx\),%rdx [ ]*[a-f0-9]+: 48 0f b2 1a lss \(%rdx\),%rbx [ ]*[a-f0-9]+: 48 0f b2 1a lss \(%rdx\),%rbx +[ ]*[a-f0-9]+: 48 ff 18 rex\.W lcall \*\(%rax\) +[ ]*[a-f0-9]+: 48 ff 29 rex\.W ljmp \*\(%rcx\) [ ]*[a-f0-9]+: 0f 05 syscall [ ]*[a-f0-9]+: 0f 07 sysret [ ]*[a-f0-9]+: 48 0f 07 sysretq * @@ -21,4 +23,6 @@ Disassembly of section .text: [ ]*[a-f0-9]+: 48 0f b5 0a lgs \(%rdx\),%rcx [ ]*[a-f0-9]+: 48 0f b2 13 lss \(%rbx\),%rdx [ ]*[a-f0-9]+: 48 0f b2 13 lss \(%rbx\),%rdx +[ ]*[a-f0-9]+: 48 ff 19 rex\.W lcall \*\(%rcx\) +[ ]*[a-f0-9]+: 48 ff 2a rex\.W ljmp \*\(%rdx\) #pass --- a/gas/testsuite/gas/i386/x86-64-intel64.s +++ b/gas/testsuite/gas/i386/x86-64-intel64.s @@ -10,6 +10,9 @@ _start: lss (%rdx), %rbx lssq (%rdx), %rbx + lcallq *(%rax) + ljmpq *(%rcx) + syscall sysretl sysretq @@ -21,3 +24,6 @@ _start: lgs rcx, tbyte ptr [rdx] lss rdx, [rbx] lss rdx, tbyte ptr [rbx] + + call tbyte ptr [rcx] + jmp tbyte ptr [rdx] --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -2331,8 +2331,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). + '^' => print 'w', 'l', or 'q' (Intel64 ISA only) depending on operand size + prefix or suffix_always is true (lcall/ljmp). '@' => print 'q' for Intel64 ISA, 'w' or 'q' for AMD64 ISA depending on operand size prefix. '&' => print 'q' in 64bit mode for Intel64 ISA or if instruction @@ -13296,6 +13296,12 @@ case_S: case '^': if (intel_syntax) break; + if (isa64 == intel64 && (rex & REX_W)) + { + USED_REX (REX_W); + *obufp++ = 'q'; + break; + } if ((prefixes & PREFIX_DATA) || (sizeflag & SUFFIX_ALWAYS)) { if (sizeflag & DFLAG) --- a/opcodes/i386-opc.tbl +++ b/opcodes/i386-opc.tbl @@ -197,9 +197,12 @@ lea, 2, 0x8d, None, 1, 0, Modrm|Anysize| // Load segment registers from memory. lds, 2, 0xc5, None, 1, CpuNo64, Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { DWord|Fword|Unspecified|BaseIndex, Reg16|Reg32 } les, 2, 0xc4, None, 1, CpuNo64, Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { DWord|Fword|Unspecified|BaseIndex, Reg16|Reg32 } -lfs, 2, 0xfb4, None, 2, Cpu386, Modrm|No_bSuf|No_sSuf|No_ldSuf, { DWord|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } -lgs, 2, 0xfb5, None, 2, Cpu386, Modrm|No_bSuf|No_sSuf|No_ldSuf, { DWord|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } -lss, 2, 0xfb2, None, 2, Cpu386, Modrm|No_bSuf|No_sSuf|No_ldSuf, { DWord|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } +lfs, 2, 0xfb4, None, 2, Cpu386, Amd64|Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Dword|Fword|Unspecified|BaseIndex, Reg16|Reg32 } +lfs, 2, 0xfb4, None, 2, Cpu64, Intel64|Modrm|No_bSuf|No_sSuf|No_ldSuf, { Dword|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } +lgs, 2, 0xfb5, None, 2, Cpu386, Amd64|Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Dword|Fword|Unspecified|BaseIndex, Reg16|Reg32 } +lgs, 2, 0xfb5, None, 2, Cpu64, Intel64|Modrm|No_bSuf|No_sSuf|No_ldSuf, { Dword|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } +lss, 2, 0xfb2, None, 2, Cpu386, Amd64|Modrm|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Dword|Fword|Unspecified|BaseIndex, Reg16|Reg32 } +lss, 2, 0xfb2, None, 2, Cpu64, Intel64|Modrm|No_bSuf|No_sSuf|No_ldSuf, { Dword|Fword|Tbyte|Unspecified|BaseIndex, Reg16|Reg32|Reg64 } // Flags register instructions. clc, 0, 0xf8, None, 1, 0, No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { 0 } @@ -375,12 +378,13 @@ call, 1, 0xe8, None, 1, Cpu64, Intel64|J call, 1, 0xff, 0x2, 1, CpuNo64, Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg32|Unspecified|BaseIndex } call, 1, 0xff, 0x2, 1, Cpu64, Amd64|Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg64|Unspecified|BaseIndex } call, 1, 0xff, 0x2, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg64|Unspecified|BaseIndex } -// Intel Syntax +// Intel Syntax remaining call instances. call, 2, 0x9a, None, 1, CpuNo64, JumpInterSegment|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 } -// Intel Syntax -call, 1, 0xff, 0x3, 1, 0, Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf, { Dword|Fword|Unspecified|BaseIndex } +call, 1, 0xff, 0x3, 1, 0, Amd64|Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf, { Dword|Fword|BaseIndex } +call, 1, 0xff, 0x3, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Dword|Fword|Tbyte|BaseIndex } lcall, 2, 0x9a, None, 1, CpuNo64, JumpInterSegment|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 } -lcall, 1, 0xff, 0x3, 1, 0, Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Unspecified|BaseIndex } +lcall, 1, 0xff, 0x3, 1, 0, Amd64|Modrm|JumpAbsolute|DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Unspecified|BaseIndex } +lcall, 1, 0xff, 0x3, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_ldSuf, { Unspecified|BaseIndex } jmp, 1, 0xeb, None, 1, CpuNo64, Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32 } jmp, 1, 0xeb, None, 1, Cpu64, Amd64|Jump|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk, { Disp8|Disp16|Disp32S } @@ -388,12 +392,13 @@ jmp, 1, 0xeb, None, 1, Cpu64, Intel64|Ju jmp, 1, 0xff, 0x4, 1, CpuNo64, Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg32|Unspecified|BaseIndex } jmp, 1, 0xff, 0x4, 1, Cpu64, Amd64|Modrm|JumpAbsolute|No_bSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg16|Reg64|Unspecified|BaseIndex } jmp, 1, 0xff, 0x4, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_ldSuf|NoRex64|BNDPrefixOk|NoTrackPrefixOk, { Reg64|Unspecified|BaseIndex } -// Intel Syntax. +// Intel Syntax remaining jmp instances. jmp, 2, 0xea, None, 1, CpuNo64, JumpInterSegment|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 } -// Intel Syntax. -jmp, 1, 0xff, 0x5, 1, 0, Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf, { Dword|Fword|Unspecified|BaseIndex } +jmp, 1, 0xff, 0x5, 1, 0, Amd64|Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf, { Dword|Fword|BaseIndex } +jmp, 1, 0xff, 0x5, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_wSuf|No_lSuf|No_sSuf|No_qSuf|No_ldSuf, { Dword|Fword|Tbyte|BaseIndex } ljmp, 2, 0xea, None, 1, CpuNo64, JumpInterSegment|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Imm16, Imm16|Imm32 } -ljmp, 1, 0xff, 0x5, 1, 0, Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Unspecified|BaseIndex } +ljmp, 1, 0xff, 0x5, 1, 0, Amd64|Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_qSuf|No_ldSuf, { Unspecified|BaseIndex } +ljmp, 1, 0xff, 0x5, 1, Cpu64, Intel64|Modrm|JumpAbsolute|No_bSuf|No_sSuf|No_ldSuf, { Unspecified|BaseIndex } ret, 0, 0xc3, None, 1, CpuNo64, DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|RepPrefixOk|BNDPrefixOk, { 0 } ret, 1, 0xc2, None, 1, CpuNo64, DefaultSize|No_bSuf|No_sSuf|No_qSuf|No_ldSuf|RepPrefixOk|BNDPrefixOk, { Imm16 }