[v2] MIPS: the default output fellows triple and with-arch

Message ID 20230403110635.23391-1-yunqiang.su@cipunited.com
State Accepted
Headers
Series [v2] MIPS: the default output fellows triple and with-arch |

Checks

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

Commit Message

YunQiang Su April 3, 2023, 11:06 a.m. UTC
  PR 25494.

1. as fellows the isa level in triple of target
   and the --with-arch buildtime option:
   > as -march=from-abi xx.s
   > as xx.s
2. ld fellows the isa level in triple of target
   > ld -r -b binary xx.dat -o xx.o
---
 bfd/Makefile.in                               |  1 +
 bfd/config.bfd                                | 48 ++++++++++++-
 bfd/configure                                 |  5 ++
 bfd/configure.ac                              |  4 ++
 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, 241 insertions(+), 13 deletions(-)
  

Comments

Richard Sandiford April 3, 2023, 12:40 p.m. UTC | #1
YunQiang Su <yunqiang.su@cipunited.com> writes:
> PR 25494.
>
> 1. as fellows the isa level in triple of target
>    and the --with-arch buildtime option:
>    > as -march=from-abi xx.s
>    > as xx.s
> 2. ld fellows the isa level in triple of target
>    > ld -r -b binary xx.dat -o xx.o
> ---
>  bfd/Makefile.in                               |  1 +
>  bfd/config.bfd                                | 48 ++++++++++++-
>  bfd/configure                                 |  5 ++
>  bfd/configure.ac                              |  4 ++
>  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, 241 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 7af481048db..f5f3b08e50b 100644
> --- a/bfd/config.bfd
> +++ b/bfd/config.bfd
> @@ -227,6 +227,40 @@ z8k*)		 targ_archs=bfd_z8k_arch ;;
>  *)		 targ_archs=bfd_${targ_cpu}_arch ;;
>  esac
>  
> +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
>  
>  # WHEN ADDING ENTRIES TO THIS MATRIX:
>  #  Make sure that the left side always has two dashes.  Otherwise you
> @@ -941,11 +975,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..3fc9aa6fdc2 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
> @@ -13775,6 +13776,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..b432d7cf10f 100644
> --- a/bfd/configure.ac
> +++ b/bfd/configure.ac
> @@ -341,6 +341,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 d34a755807b..61f00981bfc 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)
>  {
> @@ -12316,6 +12347,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

One of my points in the previous review was that I don't think we should
change the behaviour for mipsisa32/64r2 and earlier (unless there's
a specific reason that I'm missing).  Starting out at the minimum
MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs seems like the
correct behaviour, with the architecture being bumped once code is
linked in.

E.g. I don't see any reason in principle why mipsisa64-elf-ld should
behave differently from mips64-elf-ld for the same set of input objects.
If all the input objects are MIPS III then the output should be too.
Similarly, I think -march=from-abi should select MIPS I/III even
for mipsisa64-elf.  That matches the GCC documentation:

  The special value @samp{from-abi} selects the
  most compatible architecture for the selected ABI (that is,
  @samp{mips1} for 32-bit ABIs and @samp{mips3} for 64-bit ABIs)@.

AIUI, the motivation for the change is that mipsisa32/64r6 is not
compatible with r2 and earlier, and so defaulting to MIPS I or MIPS III
isn't correct.  I think that makes r6 architectures a new base architecture
for MIPS 32/64 r6 and above.  E.g. if there was an r7 that was backwards-
compatible with r6, r7 should IMO use r6 as the default here, just like
MIPS IV toolchains use MIPS III as the default for 64-bit ABIs.

E.g. maybe we could have a MIPSR6_TOOLCHAIN_P that is true for
toolchains that are for r6+.  Then select:

  MIPSR6_TOOLCHAIN_P ? E_MIPS_ARCH_64R6 : E_MIPS_ARCH_3

and

  MIPSR6_TOOLCHAIN_P ? E_MIPS_ARCH_32R6 : E_MIPS_ARCH_1

I can see the argument for changing -march=from-abi for r6+ too,
but we should try to keep the GCC and GAS handling compatible.

Thanks,
Richard

> @@ -12327,9 +12382,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 34c9d67c365..4a71f679e29 100644
> --- a/ld/configure.tgt
> +++ b/ld/configure.tgt
> @@ -580,11 +580,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
>  			;;
  
YunQiang Su April 10, 2023, 7:01 a.m. UTC | #2
https://sourceware.org/bugzilla/attachment.cgi?id=12247

It sounds like my earliest patch...

Richard Sandiford via Binutils <binutils@sourceware.org> 于2023年4月3日周一 20:40写道:
>
> YunQiang Su <yunqiang.su@cipunited.com> writes:
> > PR 25494.
> >
> > 1. as fellows the isa level in triple of target
> >    and the --with-arch buildtime option:
> >    > as -march=from-abi xx.s
> >    > as xx.s
> > 2. ld fellows the isa level in triple of target
> >    > ld -r -b binary xx.dat -o xx.o
> > ---
> >  bfd/Makefile.in                               |  1 +
> >  bfd/config.bfd                                | 48 ++++++++++++-
> >  bfd/configure                                 |  5 ++
> >  bfd/configure.ac                              |  4 ++
> >  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, 241 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 7af481048db..f5f3b08e50b 100644
> > --- a/bfd/config.bfd
> > +++ b/bfd/config.bfd
> > @@ -227,6 +227,40 @@ z8k*)             targ_archs=bfd_z8k_arch ;;
> >  *)            targ_archs=bfd_${targ_cpu}_arch ;;
> >  esac
> >
> > +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
> >
> >  # WHEN ADDING ENTRIES TO THIS MATRIX:
> >  #  Make sure that the left side always has two dashes.  Otherwise you
> > @@ -941,11 +975,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..3fc9aa6fdc2 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
> > @@ -13775,6 +13776,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..b432d7cf10f 100644
> > --- a/bfd/configure.ac
> > +++ b/bfd/configure.ac
> > @@ -341,6 +341,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 d34a755807b..61f00981bfc 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)
> >  {
> > @@ -12316,6 +12347,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
>
> One of my points in the previous review was that I don't think we should
> change the behaviour for mipsisa32/64r2 and earlier (unless there's
> a specific reason that I'm missing).  Starting out at the minimum
> MIPS I for 32-bit ABIs and MIPS III for 64-bit ABIs seems like the
> correct behaviour, with the architecture being bumped once code is
> linked in.
>
> E.g. I don't see any reason in principle why mipsisa64-elf-ld should
> behave differently from mips64-elf-ld for the same set of input objects.
> If all the input objects are MIPS III then the output should be too.
> Similarly, I think -march=from-abi should select MIPS I/III even
> for mipsisa64-elf.  That matches the GCC documentation:
>
>   The special value @samp{from-abi} selects the
>   most compatible architecture for the selected ABI (that is,
>   @samp{mips1} for 32-bit ABIs and @samp{mips3} for 64-bit ABIs)@.
>
> AIUI, the motivation for the change is that mipsisa32/64r6 is not
> compatible with r2 and earlier, and so defaulting to MIPS I or MIPS III
> isn't correct.  I think that makes r6 architectures a new base architecture
> for MIPS 32/64 r6 and above.  E.g. if there was an r7 that was backwards-
> compatible with r6, r7 should IMO use r6 as the default here, just like
> MIPS IV toolchains use MIPS III as the default for 64-bit ABIs.
>
> E.g. maybe we could have a MIPSR6_TOOLCHAIN_P that is true for
> toolchains that are for r6+.  Then select:
>
>   MIPSR6_TOOLCHAIN_P ? E_MIPS_ARCH_64R6 : E_MIPS_ARCH_3
>
> and
>
>   MIPSR6_TOOLCHAIN_P ? E_MIPS_ARCH_32R6 : E_MIPS_ARCH_1
>
> I can see the argument for changing -march=from-abi for r6+ too,
> but we should try to keep the GCC and GAS handling compatible.
>
> Thanks,
> Richard
>
> > @@ -12327,9 +12382,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 34c9d67c365..4a71f679e29 100644
> > --- a/ld/configure.tgt
> > +++ b/ld/configure.tgt
> > @@ -580,11 +580,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 7af481048db..f5f3b08e50b 100644
--- a/bfd/config.bfd
+++ b/bfd/config.bfd
@@ -227,6 +227,40 @@  z8k*)		 targ_archs=bfd_z8k_arch ;;
 *)		 targ_archs=bfd_${targ_cpu}_arch ;;
 esac
 
+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
 
 # WHEN ADDING ENTRIES TO THIS MATRIX:
 #  Make sure that the left side always has two dashes.  Otherwise you
@@ -941,11 +975,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..3fc9aa6fdc2 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
@@ -13775,6 +13776,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..b432d7cf10f 100644
--- a/bfd/configure.ac
+++ b/bfd/configure.ac
@@ -341,6 +341,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 d34a755807b..61f00981bfc 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)
 {
@@ -12316,6 +12347,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
@@ -12327,9 +12382,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 34c9d67c365..4a71f679e29 100644
--- a/ld/configure.tgt
+++ b/ld/configure.tgt
@@ -580,11 +580,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
 			;;