MIPS: support specify isa level when configure

Message ID 20230223111115.3752443-1-yunqiang.su@cipunited.com
State Accepted
Headers
Series MIPS: support specify isa level when configure |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

YunQiang Su Feb. 23, 2023, 11:11 a.m. UTC
  PR 25494.

1. Add mipsisa[32,64][,rN] support.
   the output of gas and ld will fellow this isa level.
   > ld -r -b binary xx.dat -o xx.o
   > as -march=from-abi xx.s
2. Support --with-arch=isa_level build option.
   If this option is used, the default isa_level for gas and ld
   will change.
---
 bfd/Makefile.in                               |  1 +
 bfd/config.bfd                                | 70 ++++++++++++++++++-
 bfd/configure                                 | 14 ++++
 bfd/configure.ac                              | 11 +++
 bfd/elfxx-mips.c                              | 61 +++++++++++++++-
 .../binutils-all/mips/mips-note-2-n32.d       |  1 +
 gas/config/tc-mips.c                          | 70 +++++++++++++++++--
 gas/configure                                 | 20 +++++-
 gas/configure.ac                              | 18 ++++-
 gold/configure.tgt                            | 14 ++++
 ld/configure.tgt                              | 12 +++-
 11 files changed, 279 insertions(+), 13 deletions(-)
  

Comments

Richard Sandiford March 30, 2023, 4:53 p.m. UTC | #1
Sorry for the slow reply, been away several weeks recently.

YunQiang Su <yunqiang.su@cipunited.com> writes:
> PR 25494.
>
> 1. Add mipsisa[32,64][,rN] support.
>    the output of gas and ld will fellow this isa level.
>    > ld -r -b binary xx.dat -o xx.o
>    > as -march=from-abi xx.s
> 2. Support --with-arch=isa_level build option.
>    If this option is used, the default isa_level for gas and ld
>    will change.

I'm no longer a stakeholder, so I shouldn't have a say, but: I disagree
with Maciej's comment in the PR.  Since r6 is incompatible (both ways)
with r2 and earlier, the choice between "r2 and earlier" and r6 is an
ABI one and deserves to be reflected in the target triplet.  In what
I understood to be good practice (back when I was involved with MIPS):

- --with-abi=X selects the default ABI, but X should be an ABI that is
  normally built for the target triple.

- --with-arch=X selects the default architecture, but X should be extension
  of the architecture normally selected by the target triplet (for the
  default ABI, as modified by --with-abi).

Redundantly specifying the default choice is OK too of course (and a no-op).

So I think keying off the mipsisa32/64r6 in the target triple would
be best, and that would work with good uses of --with-arch.

E.g. with --with-arch=mips2, there is no reason why ld should produce
mips2 binaries by default even when no code has been linked in.
I think the current default makes sense for --with-arch=mips2.

It might still be useful to support --with-arch for MIPS.  If we do,
it could be localised to GAS, like it is for nds32 and riscv.

To me, the fact that we need bfd/ changes for --with-arch is an
indication that --with-arch is doing too much work.

Thanks,
Richard

> ---
>  bfd/Makefile.in                               |  1 +
>  bfd/config.bfd                                | 70 ++++++++++++++++++-
>  bfd/configure                                 | 14 ++++
>  bfd/configure.ac                              | 11 +++
>  bfd/elfxx-mips.c                              | 61 +++++++++++++++-
>  .../binutils-all/mips/mips-note-2-n32.d       |  1 +
>  gas/config/tc-mips.c                          | 70 +++++++++++++++++--
>  gas/configure                                 | 20 +++++-
>  gas/configure.ac                              | 18 ++++-
>  gold/configure.tgt                            | 14 ++++
>  ld/configure.tgt                              | 12 +++-
>  11 files changed, 279 insertions(+), 13 deletions(-)
>
> diff --git a/bfd/Makefile.in b/bfd/Makefile.in
> index 82aa96f30e5..7b7b262d64e 100644
> --- a/bfd/Makefile.in
> +++ b/bfd/Makefile.in
> @@ -332,6 +332,7 @@ CPPFLAGS = @CPPFLAGS@
>  CYGPATH_W = @CYGPATH_W@
>  DATADIRNAME = @DATADIRNAME@
>  DEBUGDIR = @DEBUGDIR@
> +DEFAULT_ARCH = @DEFAULT_ARCH@
>  DEFS = @DEFS@
>  DEPDIR = @DEPDIR@
>  DSYMUTIL = @DSYMUTIL@
> diff --git a/bfd/config.bfd b/bfd/config.bfd
> index 0b0f7d50602..cea93016105 100644
> --- a/bfd/config.bfd
> +++ b/bfd/config.bfd
> @@ -227,6 +227,62 @@ z8k*)		 targ_archs=bfd_z8k_arch ;;
>  *)		 targ_archs=bfd_${targ_cpu}_arch ;;
>  esac
>  
> +# Build option --with-arch. Only MIPS supports it now.
> +case "${targ}" in
> +  mips*)
> +    case "${DEFAULT_ARCH}" in
> +      "")
> +	case "${targ}" in
> +	  mipsisa64r6*)
> +	    DEFAULT_ARCH=mips64r6
> +	    ;;
> +	  mipsisa64r5*)
> +	    DEFAULT_ARCH=mips64r5
> +	    ;;
> +	  mipsisa64r3*)
> +	    DEFAULT_ARCH=mips64r3
> +	    ;;
> +	  mipsisa64r2*)
> +	    DEFAULT_ARCH=mips64r2
> +	    ;;
> +	  mipsisa64*)
> +	    DEFAULT_ARCH=mips64
> +	    ;;
> +	  mipsisa32r6*)
> +	    DEFAULT_ARCH=mips32r6
> +	    ;;
> +	  mipsisa32r5*)
> +	    DEFAULT_ARCH=mips32r5
> +	    ;;
> +	  mipsisa32r3*)
> +	    DEFAULT_ARCH=mips32r3
> +	    ;;
> +	  mipsisa32r2*)
> +	    DEFAULT_ARCH=mips32r2
> +	    ;;
> +	  mipsisa32*)
> +	    DEFAULT_ARCH=mips32
> +	    ;;
> +	  *)
> +	    ;;
> +	esac
> +	;;
> +      mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
> +      mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
> +	;;
> +      *)
> +	echo "The arch name doesn't exits: ${DEFAULT_ARCH}" >&2
> +	exit -1
> +	;;
> +     esac
> +    ;;
> +  *)
> +    if test x"${DEFAULT_ARCH}" != x""; then
> +      echo "The value of option --with-arch is ignored for this arch: ${DEFAULT_ARCH}" >&2
> +    fi
> +    DEFAULT_ARCH=
> +    ;;
> +esac
>  
>  # WHEN ADDING ENTRIES TO THIS MATRIX:
>  #  Make sure that the left side always has two dashes.  Otherwise you
> @@ -941,11 +997,21 @@ case "${targ}" in
>      targ_defvec=mips_elf32_be_vec
>      targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec"
>      ;;
> -  mips64*el-*-linux*)
> +  mips*64*el-*-linux*-gnuabi64)
> +    targ_defvec=mips_elf64_trad_le_vec
> +    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec"
> +    want64=true
> +    ;;
> +  mips*64*-*-linux*-gnuabi64)
> +    targ_defvec=mips_elf64_trad_be_vec
> +    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_le_vec"
> +    want64=true
> +    ;;
> +  mips*64*el-*-linux*)
>      targ_defvec=mips_elf32_ntrad_le_vec
>      targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec"
>      ;;
> -  mips64*-*-linux*)
> +  mips*64*-*-linux*)
>      targ_defvec=mips_elf32_ntrad_be_vec
>      targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec"
>      ;;
> diff --git a/bfd/configure b/bfd/configure
> index 41d280ef461..a92d2d2251d 100755
> --- a/bfd/configure
> +++ b/bfd/configure
> @@ -695,6 +695,7 @@ WARN_CFLAGS
>  REPORT_BUGS_TEXI
>  REPORT_BUGS_TO
>  PKGVERSION
> +DEFAULT_ARCH
>  DEBUGDIR
>  ENABLE_BFD_64_BIT_FALSE
>  ENABLE_BFD_64_BIT_TRUE
> @@ -12033,6 +12034,15 @@ fi
>  
>  
>  
> +DEFAULT_ARCH=
> +
> +# Check whether --with-arch was given.
> +if test "${with_arch+set}" = set; then :
> +  withval=$with_arch; DEFAULT_ARCH="${withval}"
> +fi
> +
> +
> +
>  
>  
>  # Check whether --with-pkgversion was given.
> @@ -13775,6 +13785,10 @@ do
>      fi
>  done
>  
> +if test -n "$DEFAULT_ARCH"; then
> +  TDEFINES="$TDEFINES -DDEFAULT_ARCH=\\\"${DEFAULT_ARCH}\\\""
> +fi
> +
>  
>  # This processing still needs to be done if we're to decide properly whether
>  # 64-bit support needs to be compiled in.  Currently, it will be included if
> diff --git a/bfd/configure.ac b/bfd/configure.ac
> index f044616f4d9..570a5e8bb7d 100644
> --- a/bfd/configure.ac
> +++ b/bfd/configure.ac
> @@ -168,6 +168,13 @@ AC_ARG_WITH(separate-debug-dir,
>  [DEBUGDIR="${withval}"])
>  AC_SUBST(DEBUGDIR)
>  
> +DEFAULT_ARCH=
> +AC_ARG_WITH(arch,
> +  AS_HELP_STRING([--with-arch=ARCH],
> +                 [Set the default arch for bfd [[default=]]]),
> +[DEFAULT_ARCH="${withval}"])
> +AC_SUBST(DEFAULT_ARCH)
> +
>  ACX_PKGVERSION([GNU Binutils])
>  ACX_BUGURL([https://sourceware.org/bugzilla/])
>  
> @@ -341,6 +348,10 @@ do
>  	TDEFINES="$TDEFINES $targ_cflags"
>      fi
>  done
> +
> +if test -n "$DEFAULT_ARCH"; then
> +  TDEFINES="$TDEFINES -DDEFAULT_ARCH=\\\"${DEFAULT_ARCH}\\\""
> +fi
>  AC_SUBST(TDEFINES)
>  
>  # This processing still needs to be done if we're to decide properly whether
> diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
> index e9fb61ff9e7..338e7fdd0d6 100644
> --- a/bfd/elfxx-mips.c
> +++ b/bfd/elfxx-mips.c
> @@ -47,6 +47,15 @@
>  
>  #include "hashtab.h"
>  
> +/* A table describing all ISA and its 32bit and 64bit version for best matching */
> +struct mips_eflags_32_64
> +{
> +  const char *name;
> +  flagword e_mips_arch;
> +  flagword e_mips_arch32;
> +  flagword e_mips_arch64;
> +};
> +
>  /* Types of TLS GOT entry.  */
>  enum mips_got_tls_type {
>    GOT_TLS_NONE,
> @@ -1306,6 +1315,28 @@ bfd_get_micromips_32 (const bfd *abfd, const bfd_byte *ptr)
>  #define TP_OFFSET 0x7000
>  #define DTP_OFFSET 0x8000
>  
> +/* A table describing all ISA and its 32bit and 64bit version for best matching */
> +__attribute__ ((unused))
> +static const struct mips_eflags_32_64 mips_eflags_32_64_table[] =
> +{
> +  { "mips1", E_MIPS_ARCH_1, E_MIPS_ARCH_1, E_MIPS_ARCH_3},
> +  { "mips2", E_MIPS_ARCH_2, E_MIPS_ARCH_2, E_MIPS_ARCH_3},
> +  { "mips3", E_MIPS_ARCH_3, E_MIPS_ARCH_2, E_MIPS_ARCH_3},
> +  { "mips4", E_MIPS_ARCH_3, E_MIPS_ARCH_2, E_MIPS_ARCH_4},
> +  { "mips5", E_MIPS_ARCH_5, E_MIPS_ARCH_2, E_MIPS_ARCH_5},
> +  { "mips32", E_MIPS_ARCH_32, E_MIPS_ARCH_32, E_MIPS_ARCH_64},
> +  { "mips32r2", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips32r3", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips32r5", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips32r6", E_MIPS_ARCH_32R6, E_MIPS_ARCH_32R6, E_MIPS_ARCH_64R6},
> +  { "mips64", E_MIPS_ARCH_64, E_MIPS_ARCH_32, E_MIPS_ARCH_64},
> +  { "mips64r2", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips64r3", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips64r5", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
> +  { "mips64r6", E_MIPS_ARCH_64R6, E_MIPS_ARCH_32R6, E_MIPS_ARCH_64R6},
> +  { NULL, 0, 0, 0 }
> +};
> +
>  static bfd_vma
>  dtprel_base (struct bfd_link_info *info)
>  {
> @@ -12283,6 +12314,30 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
>  }
>  
>  
> +/* Get the E_MIPA_ARCH_?? value for the DEFAULT_ARCH 
> +   The value of bits can be 32/64 or 0 (guess from DEFAULT_ARCH)
> +   */
> +static flagword mips_get_default_arch_eflags(int bits)
> +{
> +#ifdef DEFAULT_ARCH
> +  int i;
> +
> +  for (i = 0; mips_eflags_32_64_table[i].name; i++)
> +    if (strcasecmp (mips_eflags_32_64_table[i].name, DEFAULT_ARCH) != 0)
> +      continue;
> +    else if (bits == 32)
> +      return mips_eflags_32_64_table[i].e_mips_arch32;
> +    else if (bits == 64)
> +      return mips_eflags_32_64_table[i].e_mips_arch64;
> +    else if (bits == 0)
> +      return mips_eflags_32_64_table[i].e_mips_arch;
> +#endif
> +
> +  if (bits == 64)
> +    return E_MIPS_ARCH_3;
> +  return E_MIPS_ARCH_1;
> +}
> +
>  /* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */
>  
>  static void
> @@ -12294,9 +12349,11 @@ mips_set_isa_flags (bfd *abfd)
>      {
>      default:
>        if (ABI_N32_P (abfd) || ABI_64_P (abfd))
> -        val = E_MIPS_ARCH_3;
> +	 val = mips_get_default_arch_eflags(64);
> +      else if (ABI_O32_P (abfd))
> +	 val = mips_get_default_arch_eflags(32);
>        else
> -        val = E_MIPS_ARCH_1;
> +	 val = mips_get_default_arch_eflags(0);
>        break;
>  
>      case bfd_mach_mips3000:
> diff --git a/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d b/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
> index c2a581858ed..5e24e7a115e 100644
> --- a/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
> +++ b/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
> @@ -1,4 +1,5 @@
>  #PROG: objcopy
> +#as: -n32
>  #readelf: --notes --wide
>  #objcopy: --merge-notes
>  #name: MIPS merge notes section (n32)
> diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
> index e911aaa904a..c906471eb92 100644
> --- a/gas/config/tc-mips.c
> +++ b/gas/config/tc-mips.c
> @@ -1422,6 +1422,15 @@ static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
>  static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
>  static void file_mips_check_options (void);
>  
> +/* A table describing all ISA and its 32bit and 64bit version for best matching */
> +
> +struct mips_isa_32_64
> +{
> +  int isa;
> +  int isa_32;
> +  int isa_64;
> +};
> +
>  /* Table and functions used to map between CPU/ISA names, and
>     ISA levels, and CPU numbers.  */
>  
> @@ -1439,6 +1448,7 @@ struct mips_cpu_info
>  static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
>  static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
>  static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
> +static int mips_cpu_isa_32_64(int isa, int bits);
>  
>  /* Command-line options.  */
>  const char *md_shortopts = "O::g::G:";
> @@ -19979,6 +19989,28 @@ s_mips_mask (int reg_type)
>      }
>  }
>  
> +
> +/* A table describing all ISA and its 32bit and 64bit version for best matching */
> +static const struct mips_isa_32_64 mips_isa_32_64_table[] =
> +{
> +  { ISA_MIPS1, ISA_MIPS1, ISA_MIPS3 },
> +  { ISA_MIPS2, ISA_MIPS2, ISA_MIPS3 },
> +  { ISA_MIPS3, ISA_MIPS2, ISA_MIPS3 },
> +  { ISA_MIPS4, ISA_MIPS2, ISA_MIPS4 },
> +  { ISA_MIPS5, ISA_MIPS2, ISA_MIPS5 },
> +  { ISA_MIPS32, ISA_MIPS32, ISA_MIPS64 },
> +  { ISA_MIPS32R2, ISA_MIPS32R2, ISA_MIPS64R2 },
> +  { ISA_MIPS32R3, ISA_MIPS32R3, ISA_MIPS64R3 },
> +  { ISA_MIPS32R5, ISA_MIPS32R5, ISA_MIPS64R5 },
> +  { ISA_MIPS32R6, ISA_MIPS32R6, ISA_MIPS64R6 },
> +  { ISA_MIPS64, ISA_MIPS32, ISA_MIPS64 },
> +  { ISA_MIPS64R2, ISA_MIPS32R2, ISA_MIPS64R2 },
> +  { ISA_MIPS64R3, ISA_MIPS32R3, ISA_MIPS64R3 },
> +  { ISA_MIPS64R5, ISA_MIPS32R5, ISA_MIPS64R5 },
> +  { ISA_MIPS64R6, ISA_MIPS32R6, ISA_MIPS64R6 },
> +  { 0, 0, 0 }
> +};
> +
>  /* A table describing all the processors gas knows about.  Names are
>     matched in the order listed.
>  
> @@ -20223,6 +20255,9 @@ static const struct mips_cpu_info *
>  mips_parse_cpu (const char *option, const char *cpu_string)
>  {
>    const struct mips_cpu_info *p;
> +  const struct mips_cpu_info *default_cpu;
> +  int default_isa32 = ISA_MIPS1;
> +  int default_isa64 = ISA_MIPS3;
>  
>    /* 'from-abi' selects the most compatible architecture for the given
>       ABI: MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs.  For the
> @@ -20236,19 +20271,26 @@ mips_parse_cpu (const char *option, const char *cpu_string)
>       'mips64', just as we did in the days before 'from-abi'.  */
>    if (strcasecmp (cpu_string, "from-abi") == 0)
>      {
> +	for (default_cpu = mips_cpu_info_table; default_cpu->name != 0; default_cpu++)
> +	  if (mips_matching_cpu_name_p (default_cpu->name, MIPS_CPU_STRING_DEFAULT))
> +	    {
> +	      default_isa32 = mips_cpu_isa_32_64 (default_cpu->isa, 32);
> +	      default_isa64 = mips_cpu_isa_32_64 (default_cpu->isa, 64);
> +	      break;
> +	    }
>        if (ABI_NEEDS_32BIT_REGS (mips_abi))
> -	return mips_cpu_info_from_isa (ISA_MIPS1);
> +	return mips_cpu_info_from_isa (default_isa32);
>  
>        if (ABI_NEEDS_64BIT_REGS (mips_abi))
> -	return mips_cpu_info_from_isa (ISA_MIPS3);
> +	return mips_cpu_info_from_isa (default_isa64);
>  
>        if (file_mips_opts.gp >= 0)
>  	return mips_cpu_info_from_isa (file_mips_opts.gp == 32
> -				       ? ISA_MIPS1 : ISA_MIPS3);
> +				       ? default_isa32 : default_isa64);
>  
>        return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
> -				     ? ISA_MIPS3
> -				     : ISA_MIPS1);
> +				     ? default_isa64
> +				     : default_isa32);
>      }
>  
>    /* 'default' has traditionally been a no-op.  Probably not very useful.  */
> @@ -20263,6 +20305,24 @@ mips_parse_cpu (const char *option, const char *cpu_string)
>    return 0;
>  }
>  
> +/* Return the best matching 32bit/64bit ISA of a ISA, according the table
> +   mips_isa_32_64_table */
> +static int
> +mips_cpu_isa_32_64(int isa, int bits)
> +{
> +  int i;
> +
> +  for (i = 0; mips_isa_32_64_table[i].isa != 0; i++)
> +    if (isa != mips_isa_32_64_table[i].isa)
> +      continue;
> +    else if (bits == 32)
> +      return mips_isa_32_64_table[i].isa_32;
> +    else if (bits == 64)
> +      return mips_isa_32_64_table[i].isa_64;
> +
> +  return 0;
> +}
> +
>  /* Return the canonical processor information for ISA (a member of the
>     ISA_MIPS* enumeration).  */
>  
> diff --git a/gas/configure b/gas/configure
> index b56836998ef..11b0a56bbd4 100755
> --- a/gas/configure
> +++ b/gas/configure
> @@ -12201,6 +12201,21 @@ _ACEOF
>  	    as_fn_error $? "$target_cpu isn't a supported MIPS CPU name" "$LINENO" 5
>  	    ;;
>  	esac
> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-arch" >&5
> +$as_echo_n "checking for default configuration of --with-arch... " >&6; }
> +	if test "x${with_arch}" != x; then
> +	  case ${with_arch} in
> +	    mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
> +	    mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
> +	      mips_cpu=${with_arch}
> +	      ;;
> +	    *)
> +	      as_fn_error $? "This kind of arch name does *NOT* exist!" "$LINENO" 5
> +	      ;;
> +	  esac
> +	fi
> +	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_arch" >&5
> +$as_echo "$with_arch" >&6; }
>  	# See whether it's appropriate to set E_MIPS_ABI_O32 for o32
>  	# binaries.  It's a GNU extension that some OSes don't understand.
>  	case ${target} in
> @@ -12223,7 +12238,10 @@ _ACEOF
>  	esac
>  	# Decide which ABI to target by default.
>  	case ${target} in
> -	  mips64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
> +	  mips*64*-linux-gnuabi64)
> +	    mips_default_abi=N64_ABI
> +	    ;;
> +	  mips*64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
>  	  | mips64*-kfreebsd*-gnu | mips64*-ps2-elf*)
>  	    mips_default_abi=N32_ABI
>  	    ;;
> diff --git a/gas/configure.ac b/gas/configure.ac
> index 6a68fd7c4e6..a126a3fda5d 100644
> --- a/gas/configure.ac
> +++ b/gas/configure.ac
> @@ -370,6 +370,19 @@ changequote([,])dnl
>  	    AC_MSG_ERROR($target_cpu isn't a supported MIPS CPU name)
>  	    ;;
>  	esac
> +	AC_MSG_CHECKING(for default configuration of --with-arch)
> +	if test "x${with_arch}" != x; then
> +	  case ${with_arch} in
> +	    mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
> +	    mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
> +	      mips_cpu=${with_arch}
> +	      ;;
> +	    *)
> +	      AC_MSG_ERROR(This kind of arch name does *NOT* exist!)
> +	      ;;
> +	  esac
> +	fi
> +	AC_MSG_RESULT($with_arch)
>  	# See whether it's appropriate to set E_MIPS_ABI_O32 for o32
>  	# binaries.  It's a GNU extension that some OSes don't understand.
>  	case ${target} in
> @@ -392,7 +405,10 @@ changequote([,])dnl
>  	esac
>  	# Decide which ABI to target by default.
>  	case ${target} in
> -	  mips64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
> +	  mips*64*-linux-gnuabi64)
> +	    mips_default_abi=N64_ABI
> +	    ;;
> +	  mips*64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
>  	  | mips64*-kfreebsd*-gnu | mips64*-ps2-elf*)
>  	    mips_default_abi=N32_ABI
>  	    ;;
> diff --git a/gold/configure.tgt b/gold/configure.tgt
> index 4b54e08d27f..ef47ce079f1 100644
> --- a/gold/configure.tgt
> +++ b/gold/configure.tgt
> @@ -153,6 +153,13 @@ aarch64*-*)
>   targ_big_endian=false
>   targ_extra_big_endian=true
>   ;;
> +mips*64*el*-*-*|mips*64*le*-*-*)
> + targ_obj=mips
> + targ_machine=EM_MIPS_RS3_LE
> + targ_size=64
> + targ_big_endian=false
> + targ_extra_big_endian=true
> + ;;
>  mips*el*-*-*|mips*le*-*-*)
>   targ_obj=mips
>   targ_machine=EM_MIPS_RS3_LE
> @@ -160,6 +167,13 @@ mips*el*-*-*|mips*le*-*-*)
>   targ_big_endian=false
>   targ_extra_big_endian=true
>   ;;
> +mips*64*-*-*)
> + targ_obj=mips
> + targ_machine=EM_MIPS
> + targ_size=64
> + targ_big_endian=true
> + targ_extra_big_endian=false
> + ;;
>  mips*-*-*)
>   targ_obj=mips
>   targ_machine=EM_MIPS
> diff --git a/ld/configure.tgt b/ld/configure.tgt
> index efd43095844..5ccaca37f16 100644
> --- a/ld/configure.tgt
> +++ b/ld/configure.tgt
> @@ -577,11 +577,19 @@ mips*-*-vxworks*)	targ_emul=elf32ebmipvxworks
>  			;;
>  mips*-*-windiss)	targ_emul=elf32mipswindiss
>  			;;
> -mips64*el-*-linux-*)	targ_emul=elf32ltsmipn32
> +mips*64*el-*-linux-gnuabi64)	targ_emul=elf64ltsmip
> +			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32ltsmip elf32btsmip elf64btsmip"
> +			targ_extra_libpath=$targ_extra_emuls
> +			;;
> +mips*64*el-*-linux-*)	targ_emul=elf32ltsmipn32
>  			targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip"
>  			targ_extra_libpath=$targ_extra_emuls
>  			;;
> -mips64*-*-linux-*)	targ_emul=elf32btsmipn32
> +mips*64*-*-linux-gnuabi64)	targ_emul=elf64btsmip
> +			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32btsmip elf32ltsmip elf64ltsmip"
> +			targ_extra_libpath=$targ_extra_emuls
> +			;;
> +mips*64*-*-linux-*)	targ_emul=elf32btsmipn32
>  			targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip"
>  			targ_extra_libpath=$targ_extra_emuls
>  			;;
  

Patch

diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 82aa96f30e5..7b7b262d64e 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -332,6 +332,7 @@  CPPFLAGS = @CPPFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DATADIRNAME = @DATADIRNAME@
 DEBUGDIR = @DEBUGDIR@
+DEFAULT_ARCH = @DEFAULT_ARCH@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DSYMUTIL = @DSYMUTIL@
diff --git a/bfd/config.bfd b/bfd/config.bfd
index 0b0f7d50602..cea93016105 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -227,6 +227,62 @@  z8k*)		 targ_archs=bfd_z8k_arch ;;
 *)		 targ_archs=bfd_${targ_cpu}_arch ;;
 esac
 
+# Build option --with-arch. Only MIPS supports it now.
+case "${targ}" in
+  mips*)
+    case "${DEFAULT_ARCH}" in
+      "")
+	case "${targ}" in
+	  mipsisa64r6*)
+	    DEFAULT_ARCH=mips64r6
+	    ;;
+	  mipsisa64r5*)
+	    DEFAULT_ARCH=mips64r5
+	    ;;
+	  mipsisa64r3*)
+	    DEFAULT_ARCH=mips64r3
+	    ;;
+	  mipsisa64r2*)
+	    DEFAULT_ARCH=mips64r2
+	    ;;
+	  mipsisa64*)
+	    DEFAULT_ARCH=mips64
+	    ;;
+	  mipsisa32r6*)
+	    DEFAULT_ARCH=mips32r6
+	    ;;
+	  mipsisa32r5*)
+	    DEFAULT_ARCH=mips32r5
+	    ;;
+	  mipsisa32r3*)
+	    DEFAULT_ARCH=mips32r3
+	    ;;
+	  mipsisa32r2*)
+	    DEFAULT_ARCH=mips32r2
+	    ;;
+	  mipsisa32*)
+	    DEFAULT_ARCH=mips32
+	    ;;
+	  *)
+	    ;;
+	esac
+	;;
+      mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
+      mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
+	;;
+      *)
+	echo "The arch name doesn't exits: ${DEFAULT_ARCH}" >&2
+	exit -1
+	;;
+     esac
+    ;;
+  *)
+    if test x"${DEFAULT_ARCH}" != x""; then
+      echo "The value of option --with-arch is ignored for this arch: ${DEFAULT_ARCH}" >&2
+    fi
+    DEFAULT_ARCH=
+    ;;
+esac
 
 # WHEN ADDING ENTRIES TO THIS MATRIX:
 #  Make sure that the left side always has two dashes.  Otherwise you
@@ -941,11 +997,21 @@  case "${targ}" in
     targ_defvec=mips_elf32_be_vec
     targ_selvecs="mips_elf32_le_vec mips_elf64_be_vec mips_elf64_le_vec mips_ecoff_be_vec mips_ecoff_le_vec"
     ;;
-  mips64*el-*-linux*)
+  mips*64*el-*-linux*-gnuabi64)
+    targ_defvec=mips_elf64_trad_le_vec
+    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec"
+    want64=true
+    ;;
+  mips*64*-*-linux*-gnuabi64)
+    targ_defvec=mips_elf64_trad_be_vec
+    targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_le_vec"
+    want64=true
+    ;;
+  mips*64*el-*-linux*)
     targ_defvec=mips_elf32_ntrad_le_vec
     targ_selvecs="mips_elf32_ntrad_be_vec mips_elf32_trad_le_vec mips_elf32_trad_be_vec mips_elf64_trad_le_vec mips_elf64_trad_be_vec"
     ;;
-  mips64*-*-linux*)
+  mips*64*-*-linux*)
     targ_defvec=mips_elf32_ntrad_be_vec
     targ_selvecs="mips_elf32_ntrad_le_vec mips_elf32_trad_be_vec mips_elf32_trad_le_vec mips_elf64_trad_be_vec mips_elf64_trad_le_vec"
     ;;
diff --git a/bfd/configure b/bfd/configure
index 41d280ef461..a92d2d2251d 100755
--- a/bfd/configure
+++ b/bfd/configure
@@ -695,6 +695,7 @@  WARN_CFLAGS
 REPORT_BUGS_TEXI
 REPORT_BUGS_TO
 PKGVERSION
+DEFAULT_ARCH
 DEBUGDIR
 ENABLE_BFD_64_BIT_FALSE
 ENABLE_BFD_64_BIT_TRUE
@@ -12033,6 +12034,15 @@  fi
 
 
 
+DEFAULT_ARCH=
+
+# Check whether --with-arch was given.
+if test "${with_arch+set}" = set; then :
+  withval=$with_arch; DEFAULT_ARCH="${withval}"
+fi
+
+
+
 
 
 # Check whether --with-pkgversion was given.
@@ -13775,6 +13785,10 @@  do
     fi
 done
 
+if test -n "$DEFAULT_ARCH"; then
+  TDEFINES="$TDEFINES -DDEFAULT_ARCH=\\\"${DEFAULT_ARCH}\\\""
+fi
+
 
 # This processing still needs to be done if we're to decide properly whether
 # 64-bit support needs to be compiled in.  Currently, it will be included if
diff --git a/bfd/configure.ac b/bfd/configure.ac
index f044616f4d9..570a5e8bb7d 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -168,6 +168,13 @@  AC_ARG_WITH(separate-debug-dir,
 [DEBUGDIR="${withval}"])
 AC_SUBST(DEBUGDIR)
 
+DEFAULT_ARCH=
+AC_ARG_WITH(arch,
+  AS_HELP_STRING([--with-arch=ARCH],
+                 [Set the default arch for bfd [[default=]]]),
+[DEFAULT_ARCH="${withval}"])
+AC_SUBST(DEFAULT_ARCH)
+
 ACX_PKGVERSION([GNU Binutils])
 ACX_BUGURL([https://sourceware.org/bugzilla/])
 
@@ -341,6 +348,10 @@  do
 	TDEFINES="$TDEFINES $targ_cflags"
     fi
 done
+
+if test -n "$DEFAULT_ARCH"; then
+  TDEFINES="$TDEFINES -DDEFAULT_ARCH=\\\"${DEFAULT_ARCH}\\\""
+fi
 AC_SUBST(TDEFINES)
 
 # This processing still needs to be done if we're to decide properly whether
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c
index e9fb61ff9e7..338e7fdd0d6 100644
--- a/bfd/elfxx-mips.c
+++ b/bfd/elfxx-mips.c
@@ -47,6 +47,15 @@ 
 
 #include "hashtab.h"
 
+/* A table describing all ISA and its 32bit and 64bit version for best matching */
+struct mips_eflags_32_64
+{
+  const char *name;
+  flagword e_mips_arch;
+  flagword e_mips_arch32;
+  flagword e_mips_arch64;
+};
+
 /* Types of TLS GOT entry.  */
 enum mips_got_tls_type {
   GOT_TLS_NONE,
@@ -1306,6 +1315,28 @@  bfd_get_micromips_32 (const bfd *abfd, const bfd_byte *ptr)
 #define TP_OFFSET 0x7000
 #define DTP_OFFSET 0x8000
 
+/* A table describing all ISA and its 32bit and 64bit version for best matching */
+__attribute__ ((unused))
+static const struct mips_eflags_32_64 mips_eflags_32_64_table[] =
+{
+  { "mips1", E_MIPS_ARCH_1, E_MIPS_ARCH_1, E_MIPS_ARCH_3},
+  { "mips2", E_MIPS_ARCH_2, E_MIPS_ARCH_2, E_MIPS_ARCH_3},
+  { "mips3", E_MIPS_ARCH_3, E_MIPS_ARCH_2, E_MIPS_ARCH_3},
+  { "mips4", E_MIPS_ARCH_3, E_MIPS_ARCH_2, E_MIPS_ARCH_4},
+  { "mips5", E_MIPS_ARCH_5, E_MIPS_ARCH_2, E_MIPS_ARCH_5},
+  { "mips32", E_MIPS_ARCH_32, E_MIPS_ARCH_32, E_MIPS_ARCH_64},
+  { "mips32r2", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips32r3", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips32r5", E_MIPS_ARCH_32R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips32r6", E_MIPS_ARCH_32R6, E_MIPS_ARCH_32R6, E_MIPS_ARCH_64R6},
+  { "mips64", E_MIPS_ARCH_64, E_MIPS_ARCH_32, E_MIPS_ARCH_64},
+  { "mips64r2", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips64r3", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips64r5", E_MIPS_ARCH_64R2, E_MIPS_ARCH_32R2, E_MIPS_ARCH_64R2},
+  { "mips64r6", E_MIPS_ARCH_64R6, E_MIPS_ARCH_32R6, E_MIPS_ARCH_64R6},
+  { NULL, 0, 0, 0 }
+};
+
 static bfd_vma
 dtprel_base (struct bfd_link_info *info)
 {
@@ -12283,6 +12314,30 @@  _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd,
 }
 
 
+/* Get the E_MIPA_ARCH_?? value for the DEFAULT_ARCH 
+   The value of bits can be 32/64 or 0 (guess from DEFAULT_ARCH)
+   */
+static flagword mips_get_default_arch_eflags(int bits)
+{
+#ifdef DEFAULT_ARCH
+  int i;
+
+  for (i = 0; mips_eflags_32_64_table[i].name; i++)
+    if (strcasecmp (mips_eflags_32_64_table[i].name, DEFAULT_ARCH) != 0)
+      continue;
+    else if (bits == 32)
+      return mips_eflags_32_64_table[i].e_mips_arch32;
+    else if (bits == 64)
+      return mips_eflags_32_64_table[i].e_mips_arch64;
+    else if (bits == 0)
+      return mips_eflags_32_64_table[i].e_mips_arch;
+#endif
+
+  if (bits == 64)
+    return E_MIPS_ARCH_3;
+  return E_MIPS_ARCH_1;
+}
+
 /* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */
 
 static void
@@ -12294,9 +12349,11 @@  mips_set_isa_flags (bfd *abfd)
     {
     default:
       if (ABI_N32_P (abfd) || ABI_64_P (abfd))
-        val = E_MIPS_ARCH_3;
+	 val = mips_get_default_arch_eflags(64);
+      else if (ABI_O32_P (abfd))
+	 val = mips_get_default_arch_eflags(32);
       else
-        val = E_MIPS_ARCH_1;
+	 val = mips_get_default_arch_eflags(0);
       break;
 
     case bfd_mach_mips3000:
diff --git a/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d b/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
index c2a581858ed..5e24e7a115e 100644
--- a/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
+++ b/binutils/testsuite/binutils-all/mips/mips-note-2-n32.d
@@ -1,4 +1,5 @@ 
 #PROG: objcopy
+#as: -n32
 #readelf: --notes --wide
 #objcopy: --merge-notes
 #name: MIPS merge notes section (n32)
diff --git a/gas/config/tc-mips.c b/gas/config/tc-mips.c
index e911aaa904a..c906471eb92 100644
--- a/gas/config/tc-mips.c
+++ b/gas/config/tc-mips.c
@@ -1422,6 +1422,15 @@  static int relaxed_micromips_16bit_branch_length (fragS *, asection *, int);
 static int relaxed_micromips_32bit_branch_length (fragS *, asection *, int);
 static void file_mips_check_options (void);
 
+/* A table describing all ISA and its 32bit and 64bit version for best matching */
+
+struct mips_isa_32_64
+{
+  int isa;
+  int isa_32;
+  int isa_64;
+};
+
 /* Table and functions used to map between CPU/ISA names, and
    ISA levels, and CPU numbers.  */
 
@@ -1439,6 +1448,7 @@  struct mips_cpu_info
 static const struct mips_cpu_info *mips_parse_cpu (const char *, const char *);
 static const struct mips_cpu_info *mips_cpu_info_from_isa (int);
 static const struct mips_cpu_info *mips_cpu_info_from_arch (int);
+static int mips_cpu_isa_32_64(int isa, int bits);
 
 /* Command-line options.  */
 const char *md_shortopts = "O::g::G:";
@@ -19979,6 +19989,28 @@  s_mips_mask (int reg_type)
     }
 }
 
+
+/* A table describing all ISA and its 32bit and 64bit version for best matching */
+static const struct mips_isa_32_64 mips_isa_32_64_table[] =
+{
+  { ISA_MIPS1, ISA_MIPS1, ISA_MIPS3 },
+  { ISA_MIPS2, ISA_MIPS2, ISA_MIPS3 },
+  { ISA_MIPS3, ISA_MIPS2, ISA_MIPS3 },
+  { ISA_MIPS4, ISA_MIPS2, ISA_MIPS4 },
+  { ISA_MIPS5, ISA_MIPS2, ISA_MIPS5 },
+  { ISA_MIPS32, ISA_MIPS32, ISA_MIPS64 },
+  { ISA_MIPS32R2, ISA_MIPS32R2, ISA_MIPS64R2 },
+  { ISA_MIPS32R3, ISA_MIPS32R3, ISA_MIPS64R3 },
+  { ISA_MIPS32R5, ISA_MIPS32R5, ISA_MIPS64R5 },
+  { ISA_MIPS32R6, ISA_MIPS32R6, ISA_MIPS64R6 },
+  { ISA_MIPS64, ISA_MIPS32, ISA_MIPS64 },
+  { ISA_MIPS64R2, ISA_MIPS32R2, ISA_MIPS64R2 },
+  { ISA_MIPS64R3, ISA_MIPS32R3, ISA_MIPS64R3 },
+  { ISA_MIPS64R5, ISA_MIPS32R5, ISA_MIPS64R5 },
+  { ISA_MIPS64R6, ISA_MIPS32R6, ISA_MIPS64R6 },
+  { 0, 0, 0 }
+};
+
 /* A table describing all the processors gas knows about.  Names are
    matched in the order listed.
 
@@ -20223,6 +20255,9 @@  static const struct mips_cpu_info *
 mips_parse_cpu (const char *option, const char *cpu_string)
 {
   const struct mips_cpu_info *p;
+  const struct mips_cpu_info *default_cpu;
+  int default_isa32 = ISA_MIPS1;
+  int default_isa64 = ISA_MIPS3;
 
   /* 'from-abi' selects the most compatible architecture for the given
      ABI: MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs.  For the
@@ -20236,19 +20271,26 @@  mips_parse_cpu (const char *option, const char *cpu_string)
      'mips64', just as we did in the days before 'from-abi'.  */
   if (strcasecmp (cpu_string, "from-abi") == 0)
     {
+	for (default_cpu = mips_cpu_info_table; default_cpu->name != 0; default_cpu++)
+	  if (mips_matching_cpu_name_p (default_cpu->name, MIPS_CPU_STRING_DEFAULT))
+	    {
+	      default_isa32 = mips_cpu_isa_32_64 (default_cpu->isa, 32);
+	      default_isa64 = mips_cpu_isa_32_64 (default_cpu->isa, 64);
+	      break;
+	    }
       if (ABI_NEEDS_32BIT_REGS (mips_abi))
-	return mips_cpu_info_from_isa (ISA_MIPS1);
+	return mips_cpu_info_from_isa (default_isa32);
 
       if (ABI_NEEDS_64BIT_REGS (mips_abi))
-	return mips_cpu_info_from_isa (ISA_MIPS3);
+	return mips_cpu_info_from_isa (default_isa64);
 
       if (file_mips_opts.gp >= 0)
 	return mips_cpu_info_from_isa (file_mips_opts.gp == 32
-				       ? ISA_MIPS1 : ISA_MIPS3);
+				       ? default_isa32 : default_isa64);
 
       return mips_cpu_info_from_isa (MIPS_DEFAULT_64BIT
-				     ? ISA_MIPS3
-				     : ISA_MIPS1);
+				     ? default_isa64
+				     : default_isa32);
     }
 
   /* 'default' has traditionally been a no-op.  Probably not very useful.  */
@@ -20263,6 +20305,24 @@  mips_parse_cpu (const char *option, const char *cpu_string)
   return 0;
 }
 
+/* Return the best matching 32bit/64bit ISA of a ISA, according the table
+   mips_isa_32_64_table */
+static int
+mips_cpu_isa_32_64(int isa, int bits)
+{
+  int i;
+
+  for (i = 0; mips_isa_32_64_table[i].isa != 0; i++)
+    if (isa != mips_isa_32_64_table[i].isa)
+      continue;
+    else if (bits == 32)
+      return mips_isa_32_64_table[i].isa_32;
+    else if (bits == 64)
+      return mips_isa_32_64_table[i].isa_64;
+
+  return 0;
+}
+
 /* Return the canonical processor information for ISA (a member of the
    ISA_MIPS* enumeration).  */
 
diff --git a/gas/configure b/gas/configure
index b56836998ef..11b0a56bbd4 100755
--- a/gas/configure
+++ b/gas/configure
@@ -12201,6 +12201,21 @@  _ACEOF
 	    as_fn_error $? "$target_cpu isn't a supported MIPS CPU name" "$LINENO" 5
 	    ;;
 	esac
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for default configuration of --with-arch" >&5
+$as_echo_n "checking for default configuration of --with-arch... " >&6; }
+	if test "x${with_arch}" != x; then
+	  case ${with_arch} in
+	    mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
+	    mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
+	      mips_cpu=${with_arch}
+	      ;;
+	    *)
+	      as_fn_error $? "This kind of arch name does *NOT* exist!" "$LINENO" 5
+	      ;;
+	  esac
+	fi
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_arch" >&5
+$as_echo "$with_arch" >&6; }
 	# See whether it's appropriate to set E_MIPS_ABI_O32 for o32
 	# binaries.  It's a GNU extension that some OSes don't understand.
 	case ${target} in
@@ -12223,7 +12238,10 @@  _ACEOF
 	esac
 	# Decide which ABI to target by default.
 	case ${target} in
-	  mips64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
+	  mips*64*-linux-gnuabi64)
+	    mips_default_abi=N64_ABI
+	    ;;
+	  mips*64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
 	  | mips64*-kfreebsd*-gnu | mips64*-ps2-elf*)
 	    mips_default_abi=N32_ABI
 	    ;;
diff --git a/gas/configure.ac b/gas/configure.ac
index 6a68fd7c4e6..a126a3fda5d 100644
--- a/gas/configure.ac
+++ b/gas/configure.ac
@@ -370,6 +370,19 @@  changequote([,])dnl
 	    AC_MSG_ERROR($target_cpu isn't a supported MIPS CPU name)
 	    ;;
 	esac
+	AC_MSG_CHECKING(for default configuration of --with-arch)
+	if test "x${with_arch}" != x; then
+	  case ${with_arch} in
+	    mips1 | mips2 | mips32 | mips32r2 | mips32r3 | mips32r5 | mips32r6 | \
+	    mips3 | mips4 | mips5 | mips64 | mips64r2 | mips64r3 | mips64r5 | mips64r6)
+	      mips_cpu=${with_arch}
+	      ;;
+	    *)
+	      AC_MSG_ERROR(This kind of arch name does *NOT* exist!)
+	      ;;
+	  esac
+	fi
+	AC_MSG_RESULT($with_arch)
 	# See whether it's appropriate to set E_MIPS_ABI_O32 for o32
 	# binaries.  It's a GNU extension that some OSes don't understand.
 	case ${target} in
@@ -392,7 +405,10 @@  changequote([,])dnl
 	esac
 	# Decide which ABI to target by default.
 	case ${target} in
-	  mips64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
+	  mips*64*-linux-gnuabi64)
+	    mips_default_abi=N64_ABI
+	    ;;
+	  mips*64*-linux* | mips-sgi-irix6* | mips64*-freebsd* \
 	  | mips64*-kfreebsd*-gnu | mips64*-ps2-elf*)
 	    mips_default_abi=N32_ABI
 	    ;;
diff --git a/gold/configure.tgt b/gold/configure.tgt
index 4b54e08d27f..ef47ce079f1 100644
--- a/gold/configure.tgt
+++ b/gold/configure.tgt
@@ -153,6 +153,13 @@  aarch64*-*)
  targ_big_endian=false
  targ_extra_big_endian=true
  ;;
+mips*64*el*-*-*|mips*64*le*-*-*)
+ targ_obj=mips
+ targ_machine=EM_MIPS_RS3_LE
+ targ_size=64
+ targ_big_endian=false
+ targ_extra_big_endian=true
+ ;;
 mips*el*-*-*|mips*le*-*-*)
  targ_obj=mips
  targ_machine=EM_MIPS_RS3_LE
@@ -160,6 +167,13 @@  mips*el*-*-*|mips*le*-*-*)
  targ_big_endian=false
  targ_extra_big_endian=true
  ;;
+mips*64*-*-*)
+ targ_obj=mips
+ targ_machine=EM_MIPS
+ targ_size=64
+ targ_big_endian=true
+ targ_extra_big_endian=false
+ ;;
 mips*-*-*)
  targ_obj=mips
  targ_machine=EM_MIPS
diff --git a/ld/configure.tgt b/ld/configure.tgt
index efd43095844..5ccaca37f16 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -577,11 +577,19 @@  mips*-*-vxworks*)	targ_emul=elf32ebmipvxworks
 			;;
 mips*-*-windiss)	targ_emul=elf32mipswindiss
 			;;
-mips64*el-*-linux-*)	targ_emul=elf32ltsmipn32
+mips*64*el-*-linux-gnuabi64)	targ_emul=elf64ltsmip
+			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32ltsmip elf32btsmip elf64btsmip"
+			targ_extra_libpath=$targ_extra_emuls
+			;;
+mips*64*el-*-linux-*)	targ_emul=elf32ltsmipn32
 			targ_extra_emuls="elf32btsmipn32 elf32ltsmip elf32btsmip elf64ltsmip elf64btsmip"
 			targ_extra_libpath=$targ_extra_emuls
 			;;
-mips64*-*-linux-*)	targ_emul=elf32btsmipn32
+mips*64*-*-linux-gnuabi64)	targ_emul=elf64btsmip
+			targ_extra_emuls="elf32btsmipn32 elf32ltsmipn32 elf32btsmip elf32ltsmip elf64ltsmip"
+			targ_extra_libpath=$targ_extra_emuls
+			;;
+mips*64*-*-linux-*)	targ_emul=elf32btsmipn32
 			targ_extra_emuls="elf32ltsmipn32 elf32btsmip elf32ltsmip elf64btsmip elf64ltsmip"
 			targ_extra_libpath=$targ_extra_emuls
 			;;