From 20f0a1fc7d3349b326456c16297278dccd2686c9 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 21 Jul 2004 16:09:43 +0000 Subject: [PATCH] Corrections for x86_64 assembly. --- gas/ChangeLog | 18 +++++ gas/config/tc-i386.c | 116 ++++++++++++++------------------- gas/testsuite/ChangeLog | 8 +++ gas/testsuite/gas/i386/i386.exp | 2 + gas/testsuite/gas/i386/x86-64-addr32.d | 13 ++++ gas/testsuite/gas/i386/x86-64-addr32.s | 5 ++ gas/testsuite/gas/i386/x86-64-rip.d | 13 ++++ gas/testsuite/gas/i386/x86-64-rip.s | 5 ++ gas/testsuite/gas/i386/x86_64.d | 2 +- opcodes/ChangeLog | 9 +++ opcodes/i386-dis.c | 95 ++++++++++++++------------- 11 files changed, 172 insertions(+), 114 deletions(-) create mode 100644 gas/testsuite/gas/i386/x86-64-addr32.d create mode 100644 gas/testsuite/gas/i386/x86-64-addr32.s create mode 100644 gas/testsuite/gas/i386/x86-64-rip.d create mode 100644 gas/testsuite/gas/i386/x86-64-rip.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 33ac7fc..977d0d9 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,21 @@ +2004-07-21 Jan Beulich + + * config/tc-i386.c (optimize_imm): Adjust immediates to only those + permissible for the selected instruction suffix. + (match_template): Don't permit 64-bit general purpose operands in + 32-bit mode. + (finalize_imm): Permit 64-bit immediates. + (build_modrm_byte): Don't treat 32-bit addressing in 64-bit mode + specially except for the width of the used base and/or index + registers. For 32-bit displacements, use sign-extended + relocations only when using 64-bit addressing. + Force zero displacement on rip-relative addressing when there is + no other displacement. + (i386_index_check): Don't treat 32-bit addressing in 64-bit mode + specially except for the width of the used base and/or index + registers. + (parse_register): Disallow Reg64 registers in 32-bit mode. + 2004-07-20 Maciej W. Rozycki * config/tc-mips.c (append_insn): Handle constant expressions with diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c index 2dd834e..e73aa95 100644 --- a/gas/config/tc-i386.c +++ b/gas/config/tc-i386.c @@ -1922,15 +1922,13 @@ optimize_imm () i.types[op] = Imm64 | Imm32S; break; case LONG_MNEM_SUFFIX: - i.types[op] = Imm32 | Imm64; + i.types[op] = Imm32; break; case WORD_MNEM_SUFFIX: - i.types[op] = Imm16 | Imm32 | Imm64; - break; + i.types[op] = Imm16; break; case BYTE_MNEM_SUFFIX: - i.types[op] = Imm8 | Imm8S | Imm16 | Imm32S | Imm32; - break; + i.types[op] = Imm8 | Imm8S; break; } break; @@ -2018,9 +2016,18 @@ match_template () : (i.suffix == LONG_DOUBLE_MNEM_SUFFIX ? No_xSuf : 0)))))); - for (t = current_templates->start; - t < current_templates->end; - t++) + t = current_templates->start; + if (i.suffix == QWORD_MNEM_SUFFIX + && flag_code != CODE_64BIT + && (!intel_syntax + || (!(t->opcode_modifier & IgnoreSize) + && ! intel_float_operand (t->name))) + && (!(t->operand_types[0] & (RegMMX | RegXMM)) + || !(t->operand_types[t->operands > 1] & (RegMMX | RegXMM))) + && (t->base_opcode != 0x0fc7 + || t->extension_opcode != 1 /* cmpxchg8b */)) + t = current_templates->end; + for (; t < current_templates->end; t++) { /* Must have right number of operands. */ if (i.operands != t->operands) @@ -2504,7 +2511,7 @@ finalize_imm () unsigned int overlap0, overlap1, overlap2; overlap0 = i.types[0] & i.tm.operand_types[0]; - if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S)) + if ((overlap0 & (Imm8 | Imm8S | Imm16 | Imm32 | Imm32S | Imm64)) && overlap0 != Imm8 && overlap0 != Imm8S && overlap0 != Imm16 && overlap0 != Imm32S && overlap0 != Imm32 && overlap0 != Imm64) @@ -2733,21 +2740,7 @@ build_modrm_byte () if (i.index_reg == 0) { /* Operand is just */ - if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0) - && (flag_code != CODE_64BIT)) - { - i.rm.regmem = NO_BASE_REGISTER_16; - i.types[op] &= ~Disp; - i.types[op] |= Disp16; - } - else if (flag_code != CODE_64BIT - || (i.prefix[ADDR_PREFIX] != 0)) - { - i.rm.regmem = NO_BASE_REGISTER; - i.types[op] &= ~Disp; - i.types[op] |= Disp32; - } - else + if (flag_code == CODE_64BIT) { /* 64bit mode overwrites the 32bit absolute addressing by RIP relative addressing and @@ -2756,8 +2749,17 @@ build_modrm_byte () i.rm.regmem = ESCAPE_TO_TWO_BYTE_ADDRESSING; i.sib.base = NO_BASE_REGISTER; i.sib.index = NO_INDEX_REGISTER; - i.types[op] &= ~Disp; - i.types[op] |= Disp32S; + i.types[op] = ((i.prefix[ADDR_PREFIX] == 0) ? Disp32S : Disp32); + } + else if ((flag_code == CODE_16BIT) ^ (i.prefix[ADDR_PREFIX] != 0)) + { + i.rm.regmem = NO_BASE_REGISTER_16; + i.types[op] = Disp16; + } + else + { + i.rm.regmem = NO_BASE_REGISTER; + i.types[op] = Disp32; } } else /* !i.base_reg && i.index_reg */ @@ -2779,9 +2781,11 @@ build_modrm_byte () else if (i.base_reg->reg_type == BaseIndex) { i.rm.regmem = NO_BASE_REGISTER; - i.types[op] &= ~Disp; + i.types[op] &= ~ Disp; i.types[op] |= Disp32S; i.flags[op] = Operand_PCrel; + if (! i.disp_operands) + fake_zero_displacement = 1; } else if (i.base_reg->reg_type & Reg16) { @@ -2817,12 +2821,8 @@ build_modrm_byte () { if (flag_code == CODE_64BIT && (i.types[op] & Disp)) - { - if (i.types[op] & Disp8) - i.types[op] = Disp8 | Disp32S; - else - i.types[op] = Disp32S; - } + i.types[op] = (i.types[op] & Disp8) | (i.prefix[ADDR_PREFIX] == 0 ? Disp32S : Disp32); + i.rm.regmem = i.base_reg->reg_num; if ((i.base_reg->reg_flags & RegRex) != 0) i.rex |= REX_EXTZ; @@ -3999,30 +3999,18 @@ i386_index_check (operand_string) tryprefix: #endif ok = 1; - if (flag_code == CODE_64BIT) - { - if (i.prefix[ADDR_PREFIX] == 0) - { - /* 64bit checks. */ - if ((i.base_reg - && ((i.base_reg->reg_type & Reg64) == 0) - && (i.base_reg->reg_type != BaseIndex - || i.index_reg)) - || (i.index_reg - && ((i.index_reg->reg_type & (Reg64 | BaseIndex)) - != (Reg64 | BaseIndex)))) - ok = 0; - } - else - { - /* 32bit checks. */ - if ((i.base_reg - && (i.base_reg->reg_type & (Reg32 | RegRex)) != Reg32) - || (i.index_reg - && ((i.index_reg->reg_type & (Reg32 | BaseIndex | RegRex)) - != (Reg32 | BaseIndex)))) - ok = 0; - } + if (flag_code == CODE_64BIT) + { + unsigned RegXX = (i.prefix[ADDR_PREFIX] == 0 ? Reg64 : Reg32); + + if ((i.base_reg + && ((i.base_reg->reg_type & RegXX) == 0) + && (i.base_reg->reg_type != BaseIndex + || i.index_reg)) + || (i.index_reg + && ((i.index_reg->reg_type & (RegXX | BaseIndex)) + != (RegXX | BaseIndex)))) + ok = 0; } else { @@ -4055,8 +4043,7 @@ i386_index_check (operand_string) if (!ok) { #if INFER_ADDR_PREFIX - if (flag_code != CODE_64BIT - && i.prefix[ADDR_PREFIX] == 0 && stackop_size != '\0') + if (i.prefix[ADDR_PREFIX] == 0) { i.prefix[ADDR_PREFIX] = ADDR_PREFIX_OPCODE; i.prefixes += 1; @@ -4065,7 +4052,7 @@ i386_index_check (operand_string) FIXME. There doesn't seem to be any real need for separate Disp16 and Disp32 flags. The same goes for Imm16 and Imm32. Removing them would probably clean up the code quite a lot. */ - if (i.types[this_operand] & (Disp16 | Disp32)) + if (flag_code != CODE_64BIT && (i.types[this_operand] & (Disp16 | Disp32))) i.types[this_operand] ^= (Disp16 | Disp32); fudged = 1; goto tryprefix; @@ -4078,9 +4065,8 @@ i386_index_check (operand_string) as_bad (_("`%s' is not a valid %s bit base/index expression"), operand_string, flag_code_names[flag_code]); - return 0; } - return 1; + return ok; } /* Parse OPERAND_STRING into the i386_insn structure I. Returns non-zero @@ -4904,11 +4890,9 @@ parse_register (reg_string, end_op) } if (r != NULL - && (r->reg_flags & (RegRex64 | RegRex)) != 0 + && ((r->reg_flags & (RegRex64 | RegRex)) | (r->reg_type & Reg64)) != 0 && flag_code != CODE_64BIT) - { - return (const reg_entry *) NULL; - } + return (const reg_entry *) NULL; return r; } diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index 81027e4..e5689e6 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2004-07-21 Jan Beulich + + * testsuite/gas/i386/x86-64-addr32.[ds]: New test for x86-64 + 32-bit addressing in 64-bit mode. + * testsuite/gas/i386/x86-64-rip.[ds]: New test for x86-64 + rip-relative addressing. + * testsuite/gas/i386/i386.exp: Run the two new tests. + 2004-07-20 Maciej W. Rozycki * gas/mips/elf-rel19.d: Pass -march=mips1 to gas as the test diff --git a/gas/testsuite/gas/i386/i386.exp b/gas/testsuite/gas/i386/i386.exp index 1b8c401..bfd7cd5 100644 --- a/gas/testsuite/gas/i386/i386.exp +++ b/gas/testsuite/gas/i386/i386.exp @@ -105,7 +105,9 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t set ASFLAGS "$ASFLAGS --64" run_dump_test "x86_64" + run_dump_test "x86-64-addr32" run_dump_test "x86-64-opcode" + run_dump_test "x86-64-rip" run_list_test "x86-64-inval" "-al" set ASFLAGS "$old_ASFLAGS" diff --git a/gas/testsuite/gas/i386/x86-64-addr32.d b/gas/testsuite/gas/i386/x86-64-addr32.d new file mode 100644 index 0000000..c892fb1 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-addr32.d @@ -0,0 +1,13 @@ +#as: -J +#objdump: -drw +#name: x86-64 32-bit addressing + +.*: +file format elf64-x86-64 + +Disassembly of section .text: + +0+000 <.text>: +[ ]*0:[ ]+67 48 8d 80 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0\(%[re]ax\),%rax.* +[ ]*8:[ ]+67 49 8d 80 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0\(%r8d?\),%rax.* +[ ]*10:[ ]+67 48 8d 05 00 00 00 00[ ]+addr32[ ]+lea[ ]+0\(%[re]ip\),%rax.* +[ ]*18:[ ]+67 48 8d 04 25 00 00 00 00[ ]+addr32[ ]+lea[ ]+0x0,%rax.* diff --git a/gas/testsuite/gas/i386/x86-64-addr32.s b/gas/testsuite/gas/i386/x86-64-addr32.s new file mode 100644 index 0000000..d18cbb9 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-addr32.s @@ -0,0 +1,5 @@ +.text + lea symbol(%eax), %rax + lea symbol(%r8d), %rax + addr32 lea symbol(%rip), %rax + addr32 lea symbol, %rax diff --git a/gas/testsuite/gas/i386/x86-64-rip.d b/gas/testsuite/gas/i386/x86-64-rip.d new file mode 100644 index 0000000..1b1d6c8 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-rip.d @@ -0,0 +1,13 @@ +#as: -J +#objdump: -drw +#name: x86-64 rip addressing + +.*: +file format elf64-x86-64 + +Disassembly of section .text: + +0+000 <.text>: +[ ]*0:[ ]+8d 05 00 00 00 00[ ]+lea[ ]+0\(%rip\),%eax[ ]*(#.*)? +[ ]*6:[ ]+8d 05 11 11 11 11[ ]+lea[ ]+286331153\(%rip\),%eax[ ]*(#.*)? +[ ]*c:[ ]+8d 05 01 00 00 00[ ]+lea[ ]+1\(%rip\),%eax[ ]*(#.*)? +[ ]*12:[ ]+8d 05 00 00 00 00[ ]+lea[ ]+0\(%rip\),%eax[ ]*(#.*)? diff --git a/gas/testsuite/gas/i386/x86-64-rip.s b/gas/testsuite/gas/i386/x86-64-rip.s new file mode 100644 index 0000000..c6ac195 --- /dev/null +++ b/gas/testsuite/gas/i386/x86-64-rip.s @@ -0,0 +1,5 @@ +.text + leal symbol(%rip), %eax + leal 0x11111111(%rip), %eax + leal 1(%rip), %eax + leal (%rip), %eax diff --git a/gas/testsuite/gas/i386/x86_64.d b/gas/testsuite/gas/i386/x86_64.d index 1af2278..dd4526b 100644 --- a/gas/testsuite/gas/i386/x86_64.d +++ b/gas/testsuite/gas/i386/x86_64.d @@ -37,7 +37,7 @@ Disassembly of section .text: [ ]+5a: 44 0f 20 c0[ ]+mov[ ]+%cr8,%rax [ ]+5e: 44 0f 22 c0[ ]+mov[ ]+%rax,%cr8 [ ]+62: f3 48 a5[ ]+repz movsq %ds:\(%rsi\),%es:\(%rdi\) -[ ]+65: f3 66 a5[ ]+repz movsw %ds:\(%esi\),%es:\(%edi\) +[ ]+65: f3 66 a5[ ]+repz movsw %ds:\(%rsi\),%es:\(%rdi\) [ ]+68: f3 48 a5[ ]+repz movsq %ds:\(%rsi\),%es:\(%rdi\) [ ]+6b: b0 11[ ]+mov[ ]+\$0x11,%al [ ]+6d: b4 11[ ]+mov[ ]+\$0x11,%ah diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 23f2e1d..65fd78c 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,12 @@ +2004-07-21 Jan Beulich + + * i386-dis.c (OP_E): Show rip-relative addressing in 64-bit mode + regardless of address size prefix in effect. + (ptr_reg): Size or address registers does not depend on rex64, but + on the presence of an address size override. + (OP_MMX): Use rex.x only for xmm registers. + (OP_EM): Use rex.z only for xmm registers. + 2004-07-20 Maciej W. Rozycki * mips-opc.c (mips_builtin_opcodes): Move coprocessor 2 diff --git a/opcodes/i386-dis.c b/opcodes/i386-dis.c index 0bcd107..733267c 100644 --- a/opcodes/i386-dis.c +++ b/opcodes/i386-dis.c @@ -2,38 +2,34 @@ Copyright 1988, 1989, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. -This file is part of GDB. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* - * 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) - * July 1988 - * modified by John Hassey (hassey@dg-rtp.dg.com) - * x86-64 support added by Jan Hubicka (jh@suse.cz) - * VIA PadLock support by Michal Ludvig (mludvig@suse.cz) - */ - -/* - * The main tables describing the instructions is essentially a copy - * of the "Opcode Map" chapter (Appendix A) of the Intel 80386 - * Programmers Manual. Usually, there is a capital letter, followed - * by a small letter. The capital letter tell the addressing mode, - * and the small letter tells about the operand size. Refer to - * the Intel manual for details. - */ + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* 80386 instruction printer by Pace Willisson (pace@prep.ai.mit.edu) + July 1988 + modified by John Hassey (hassey@dg-rtp.dg.com) + x86-64 support added by Jan Hubicka (jh@suse.cz) + VIA PadLock support by Michal Ludvig (mludvig@suse.cz). */ + +/* The main tables describing the instructions is essentially a copy + of the "Opcode Map" chapter (Appendix A) of the Intel 80386 + Programmers Manual. Usually, there is a capital letter, followed + by a small letter. The capital letter tell the addressing mode, + and the small letter tells about the operand size. Refer to + the Intel manual for details. */ #include "dis-asm.h" #include "sysdep.h" @@ -3166,7 +3162,7 @@ OP_E (int bytemode, int sizeflag) if ((base & 7) == 5) { havebase = 0; - if (mode_64bit && !havesib && (sizeflag & AFLAG)) + if (mode_64bit && !havesib) riprel = 1; disp = get32s (); } @@ -3856,8 +3852,8 @@ ptr_reg (int code, int sizeflag) const char *s; *obufp++ = open_char; - USED_REX (REX_MODE64); - if (rex & REX_MODE64) + used_prefixes |= (prefixes & PREFIX_ADDR); + if (mode_64bit) { if (!(sizeflag & AFLAG)) s = names32[code - eAX_reg]; @@ -3939,15 +3935,17 @@ OP_Rd (int bytemode, int sizeflag) static void OP_MMX (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) { - int add = 0; - USED_REX (REX_EXTX); - if (rex & REX_EXTX) - add = 8; used_prefixes |= (prefixes & PREFIX_DATA); if (prefixes & PREFIX_DATA) - sprintf (scratchbuf, "%%xmm%d", reg + add); + { + int add = 0; + USED_REX (REX_EXTX); + if (rex & REX_EXTX) + add = 8; + sprintf (scratchbuf, "%%xmm%d", reg + add); + } else - sprintf (scratchbuf, "%%mm%d", reg + add); + sprintf (scratchbuf, "%%mm%d", reg); oappend (scratchbuf + intel_syntax); } @@ -3965,24 +3963,27 @@ OP_XMM (int bytemode ATTRIBUTE_UNUSED, int sizeflag ATTRIBUTE_UNUSED) static void OP_EM (int bytemode, int sizeflag) { - int add = 0; if (mod != 3) { OP_E (bytemode, sizeflag); return; } - USED_REX (REX_EXTZ); - if (rex & REX_EXTZ) - add = 8; /* Skip mod/rm byte. */ MODRM_CHECK; codep++; used_prefixes |= (prefixes & PREFIX_DATA); if (prefixes & PREFIX_DATA) - sprintf (scratchbuf, "%%xmm%d", rm + add); + { + int add = 0; + + USED_REX (REX_EXTZ); + if (rex & REX_EXTZ) + add = 8; + sprintf (scratchbuf, "%%xmm%d", rm + add); + } else - sprintf (scratchbuf, "%%mm%d", rm + add); + sprintf (scratchbuf, "%%mm%d", rm); oappend (scratchbuf + intel_syntax); } -- 2.7.4