|  | diff -ruN binutils-2.24/bfd/archures.c binutils-2.24-riscv/bfd/archures.c | 
|  | --- binutils-2.24/bfd/archures.c	2013-11-08 02:02:26.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/archures.c	2014-12-02 16:05:44.901434894 -0800 | 
|  | @@ -583,6 +583,7 @@ | 
|  | extern const bfd_arch_info_type bfd_plugin_arch; | 
|  | extern const bfd_arch_info_type bfd_powerpc_archs[]; | 
|  | #define bfd_powerpc_arch bfd_powerpc_archs[0] | 
|  | +extern const bfd_arch_info_type bfd_riscv_arch; | 
|  | extern const bfd_arch_info_type bfd_rs6000_arch; | 
|  | extern const bfd_arch_info_type bfd_rl78_arch; | 
|  | extern const bfd_arch_info_type bfd_rx_arch; | 
|  | @@ -669,6 +670,7 @@ | 
|  | &bfd_or32_arch, | 
|  | &bfd_pdp11_arch, | 
|  | &bfd_powerpc_arch, | 
|  | +    &bfd_riscv_arch, | 
|  | &bfd_rs6000_arch, | 
|  | &bfd_rl78_arch, | 
|  | &bfd_rx_arch, | 
|  | diff -ruN binutils-2.24/bfd/bfd-in2.h binutils-2.24-riscv/bfd/bfd-in2.h | 
|  | --- binutils-2.24/bfd/bfd-in2.h	2013-11-18 00:40:15.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/bfd-in2.h	2014-12-02 16:17:22.313790749 -0800 | 
|  | @@ -2003,6 +2003,9 @@ | 
|  | #define bfd_mach_ppc_e6500     5007 | 
|  | #define bfd_mach_ppc_titan     83 | 
|  | #define bfd_mach_ppc_vle       84 | 
|  | +  bfd_arch_riscv,     /* RISC-V */ | 
|  | +#define bfd_mach_riscv_rocket32 132 | 
|  | +#define bfd_mach_riscv_rocket64 164 | 
|  | bfd_arch_rs6000,    /* IBM RS/6000 */ | 
|  | #define bfd_mach_rs6k          6000 | 
|  | #define bfd_mach_rs6k_rs1      6001 | 
|  | @@ -5227,6 +5230,14 @@ | 
|  | value in a word.  The relocation is relative offset from  */ | 
|  | BFD_RELOC_MICROBLAZE_32_GOTOFF, | 
|  |  | 
|  | +  /* RISC-V relocations */ | 
|  | +  BFD_RELOC_RISCV_TLS_GOT_HI16, | 
|  | +  BFD_RELOC_RISCV_TLS_GOT_LO16, | 
|  | +  BFD_RELOC_RISCV_TLS_GD_HI16, | 
|  | +  BFD_RELOC_RISCV_TLS_GD_LO16, | 
|  | +  BFD_RELOC_RISCV_TLS_LDM_HI16, | 
|  | +  BFD_RELOC_RISCV_TLS_LDM_LO16, | 
|  | + | 
|  | /* This is used to tell the dynamic linker to copy the value out of | 
|  | the dynamic object into the runtime process image.  */ | 
|  | BFD_RELOC_MICROBLAZE_COPY, | 
|  | diff -ruN binutils-2.24/bfd/config.bfd binutils-2.24-riscv/bfd/config.bfd | 
|  | --- binutils-2.24/bfd/config.bfd	2013-11-04 07:33:37.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/config.bfd	2014-12-02 16:05:44.901434894 -0800 | 
|  | @@ -114,6 +114,7 @@ | 
|  | pdp11*)		 targ_archs=bfd_pdp11_arch ;; | 
|  | pj*)		 targ_archs="bfd_pj_arch bfd_i386_arch";; | 
|  | powerpc*)	 targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; | 
|  | +riscv*)		 targ_archs=bfd_riscv_arch ;; | 
|  | rs6000)		 targ_archs="bfd_rs6000_arch bfd_powerpc_arch" ;; | 
|  | s390*)		 targ_archs=bfd_s390_arch ;; | 
|  | sh*)		 targ_archs=bfd_sh_arch ;; | 
|  | @@ -1295,6 +1296,14 @@ | 
|  | targ_defvec=bfd_elf32_rl78_vec | 
|  | ;; | 
|  |  | 
|  | +#ifdef BFD64 | 
|  | +  riscv*-*-*) | 
|  | +    targ_defvec=bfd_elf64_littleriscv_vec | 
|  | +    targ_selvecs="bfd_elf32_littleriscv_vec bfd_elf64_littleriscv_vec" | 
|  | +    want64=true | 
|  | +    ;; | 
|  | +#endif | 
|  | + | 
|  | rx-*-elf) | 
|  | targ_defvec=bfd_elf32_rx_le_vec | 
|  | targ_selvecs="bfd_elf32_rx_be_vec bfd_elf32_rx_le_vec bfd_elf32_rx_be_ns_vec" | 
|  | diff -ruN binutils-2.24/bfd/configure binutils-2.24-riscv/bfd/configure | 
|  | --- binutils-2.24/bfd/configure	2013-12-02 01:30:30.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/configure	2014-12-02 16:19:07.382447865 -0800 | 
|  | @@ -15280,6 +15280,7 @@ | 
|  | tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; | 
|  | bfd_elf32_littlemoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_littlenios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;; | 
|  | +    bfd_elf32_littleriscv_vec) 	tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo" ;; | 
|  | bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_m32r_vec)		tb="$tb elf32-m32r.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;; | 
|  | @@ -15384,6 +15385,7 @@ | 
|  | bfd_elf32_littleaarch64_vec)tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_littlemips_vec) 	tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; | 
|  | +    bfd_elf64_littleriscv_vec) 	tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; | 
|  | bfd_elf64_mmix_vec) 	tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;; | 
|  | bfd_elf64_powerpc_vec)	tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_powerpcle_vec)	tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;; | 
|  | diff -ruN binutils-2.24/bfd/configure.in binutils-2.24-riscv/bfd/configure.in | 
|  | --- binutils-2.24/bfd/configure.in	2013-12-02 01:30:28.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/configure.in	2014-12-02 16:18:24.430179236 -0800 | 
|  | @@ -769,6 +769,7 @@ | 
|  | tb="$tb elf32-mips.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo" ;; | 
|  | bfd_elf32_littlemoxie_vec)	tb="$tb elf32-moxie.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_littlenios2_vec)	tb="$tb elf32-nios2.lo elf32.lo $elf" ;; | 
|  | +    bfd_elf32_littleriscv_vec) 	tb="$tb elf32-riscv.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo" ;; | 
|  | bfd_elf32_m32c_vec)         tb="$tb elf32-m32c.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_m32r_vec)		tb="$tb elf32-m32r.lo elf32.lo $elf" ;; | 
|  | bfd_elf32_m32rle_vec)       tb="$tb elf32-m32r.lo elf32.lo $elf" ;; | 
|  | @@ -873,6 +874,7 @@ | 
|  | bfd_elf32_littleaarch64_vec)tb="$tb elf32-aarch64.lo elfxx-aarch64.lo elf-ifunc.lo elf32.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_little_generic_vec) tb="$tb elf64-gen.lo elf64.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_littlemips_vec) 	tb="$tb elf64-mips.lo elf64.lo elfxx-mips.lo elf-vxworks.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; | 
|  | +    bfd_elf64_littleriscv_vec) 	tb="$tb elf64-riscv.lo elf64.lo elfxx-riscv.lo elf32.lo $elf ecofflink.lo"; target_size=64 ;; | 
|  | bfd_elf64_mmix_vec) 	tb="$tb elf64-mmix.lo elf64.lo $elf" target_size=64 ;; | 
|  | bfd_elf64_powerpc_vec)	tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf"; target_size=64 ;; | 
|  | bfd_elf64_powerpcle_vec)	tb="$tb elf64-ppc.lo elf64-gen.lo elf64.lo $elf" target_size=64 ;; | 
|  | diff -ruN binutils-2.24/bfd/cpu-riscv.c binutils-2.24-riscv/bfd/cpu-riscv.c | 
|  | --- binutils-2.24/bfd/cpu-riscv.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/cpu-riscv.c	2014-12-02 16:05:44.905434919 -0800 | 
|  | @@ -0,0 +1,78 @@ | 
|  | +/* bfd back-end for mips support | 
|  | +   Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, | 
|  | +   2002, 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc. | 
|  | +   Written by Steve Chamberlain of Cygnus Support. | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | +#include "sysdep.h" | 
|  | +#include "bfd.h" | 
|  | +#include "libbfd.h" | 
|  | + | 
|  | +static const bfd_arch_info_type *mips_compatible | 
|  | +  (const bfd_arch_info_type *, const bfd_arch_info_type *); | 
|  | + | 
|  | +/* The default routine tests bits_per_word, which is wrong on mips as | 
|  | +   mips word size doesn't correlate with reloc size.  */ | 
|  | + | 
|  | +static const bfd_arch_info_type * | 
|  | +mips_compatible (const bfd_arch_info_type *a, const bfd_arch_info_type *b) | 
|  | +{ | 
|  | +  if (a->arch != b->arch) | 
|  | +    return NULL; | 
|  | + | 
|  | +  /* Machine compatibility is checked in | 
|  | +     _bfd_mips_elf_merge_private_bfd_data.  */ | 
|  | + | 
|  | +  return a; | 
|  | +} | 
|  | + | 
|  | +#define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT)		\ | 
|  | +  {							\ | 
|  | +    BITS_WORD, /*  bits in a word */			\ | 
|  | +    BITS_ADDR, /* bits in an address */			\ | 
|  | +    8,	/* 8 bits in a byte */				\ | 
|  | +    bfd_arch_riscv,					\ | 
|  | +    NUMBER,						\ | 
|  | +    "riscv",						\ | 
|  | +    PRINT,						\ | 
|  | +    3,							\ | 
|  | +    DEFAULT,						\ | 
|  | +    mips_compatible,					\ | 
|  | +    bfd_default_scan,					\ | 
|  | +    NEXT,						\ | 
|  | +  } | 
|  | + | 
|  | +enum | 
|  | +{ | 
|  | +  I_riscv_rocket64, | 
|  | +  I_riscv_rocket32 | 
|  | +}; | 
|  | + | 
|  | +#define NN(index) (&arch_info_struct[(index) + 1]) | 
|  | + | 
|  | +static const bfd_arch_info_type arch_info_struct[] = | 
|  | +{ | 
|  | +  N (64, 64, bfd_mach_riscv_rocket64, "riscv:rocket64", FALSE, NN(I_riscv_rocket64)), | 
|  | +  N (32, 32, bfd_mach_riscv_rocket32, "riscv:rocket32", FALSE, 0) | 
|  | +}; | 
|  | + | 
|  | +/* The default architecture is riscv:rocket64. */ | 
|  | + | 
|  | +const bfd_arch_info_type bfd_riscv_arch = | 
|  | +N (64, 64, 0, "riscv", TRUE, &arch_info_struct[0]); | 
|  | diff -ruN binutils-2.24/bfd/elf32-riscv.c binutils-2.24-riscv/bfd/elf32-riscv.c | 
|  | --- binutils-2.24/bfd/elf32-riscv.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/elf32-riscv.c	2014-12-02 16:05:44.905434919 -0800 | 
|  | @@ -0,0 +1,2170 @@ | 
|  | +/* MIPS-specific support for 32-bit ELF | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | 
|  | +   2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. | 
|  | + | 
|  | +   Most of the information added by Ian Lance Taylor, Cygnus Support, | 
|  | +   <ian@cygnus.com>. | 
|  | +   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC. | 
|  | +   <mark@codesourcery.com> | 
|  | +   Traditional MIPS targets support added by Koundinya.K, Dansk Data | 
|  | +   Elektronik & Operations Research Group. <kk@ddeorg.soft.net> | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | + | 
|  | +/* This file handles MIPS ELF targets.  SGI Irix 5 uses a slightly | 
|  | +   different MIPS ELF from other targets.  This matters when linking. | 
|  | +   This file supports both, switching at runtime.  */ | 
|  | + | 
|  | +#include "sysdep.h" | 
|  | +#include "bfd.h" | 
|  | +#include "libbfd.h" | 
|  | +#include "bfdlink.h" | 
|  | +#include "genlink.h" | 
|  | +#include "elf-bfd.h" | 
|  | +#include "elfxx-riscv.h" | 
|  | +#include "elf/riscv.h" | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +/* Get the ECOFF swapping routines.  */ | 
|  | +#include "coff/sym.h" | 
|  | +#include "coff/symconst.h" | 
|  | +#include "coff/internal.h" | 
|  | +#include "coff/ecoff.h" | 
|  | +#include "coff/mips.h" | 
|  | +#define ECOFF_SIGNED_32 | 
|  | +#include "ecoffswap.h" | 
|  | + | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +static bfd_boolean mips_elf_assign_gp | 
|  | +  (bfd *, bfd_vma *); | 
|  | +static bfd_reloc_status_type mips_elf_final_gp | 
|  | +  (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *); | 
|  | +static bfd_reloc_status_type mips_elf_gprel16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_reloc_status_type mips_elf_literal_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_reloc_status_type mips_elf_gprel32_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_reloc_status_type gprel32_with_gp | 
|  | +  (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma); | 
|  | +static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup | 
|  | +  (bfd *, bfd_reloc_code_real_type); | 
|  | +static reloc_howto_type *mips_elf_n32_rtype_to_howto | 
|  | +  (unsigned int, bfd_boolean); | 
|  | +static void mips_info_to_howto_rel | 
|  | +  (bfd *, arelent *, Elf_Internal_Rela *); | 
|  | +static void mips_info_to_howto_rela | 
|  | +  (bfd *, arelent *, Elf_Internal_Rela *); | 
|  | +static bfd_boolean mips_elf_sym_is_global | 
|  | +  (bfd *, asymbol *); | 
|  | +static bfd_boolean mips_elf_n32_object_p | 
|  | +  (bfd *); | 
|  | +static bfd_boolean elf32_mips_grok_prstatus | 
|  | +  (bfd *, Elf_Internal_Note *); | 
|  | +static bfd_boolean elf32_mips_grok_psinfo | 
|  | +  (bfd *, Elf_Internal_Note *); | 
|  | + | 
|  | +extern const bfd_target bfd_elf32_nbigmips_vec; | 
|  | +extern const bfd_target bfd_elf32_nlittlemips_vec; | 
|  | + | 
|  | +/* The number of local .got entries we reserve.  */ | 
|  | +#define MIPS_RESERVED_GOTNO (2) | 
|  | + | 
|  | +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value | 
|  | +   from smaller values.  Start with zero, widen, *then* decrement.  */ | 
|  | +#define MINUS_ONE	(((bfd_vma)0) - 1) | 
|  | + | 
|  | +/* The relocation table used for SHT_REL sections.  */ | 
|  | + | 
|  | +static reloc_howto_type elf_mips_howto_table_rel[] = | 
|  | +{ | 
|  | +  /* No relocation.  */ | 
|  | +  HOWTO (R_RISCV_NONE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_NONE",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (1), | 
|  | + | 
|  | +  /* 32 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_32",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit symbol relative relocation.  */ | 
|  | +  HOWTO (R_RISCV_REL32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 26 bit jump address.  */ | 
|  | +  HOWTO (R_RISCV_26,		/* type */ | 
|  | +	 RISCV_JUMP_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_JUMP_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_TARGET,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +				/* This needs complex overflow | 
|  | +				   detection, because the upper 36 | 
|  | +				   bits must match the PC + 4.  */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_26",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* src_mask */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* dst_mask */ | 
|  | +	 TRUE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* R_RISCV_HI16 and R_RISCV_LO16 are unsupported for NewABI REL. | 
|  | +     However, the native IRIX6 tools use them, so we try our best. */ | 
|  | + | 
|  | +  /* High 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_HI16,		/* type */ | 
|  | +	 RISCV_IMM_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_hi16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_HI16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_LO16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_lo16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LO16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf_gprel16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to literal section.  */ | 
|  | +  HOWTO (R_RISCV_LITERAL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf_literal_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LITERAL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_got16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GOT16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit PC relative reference.  Note that the ABI document has a typo | 
|  | +     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless. | 
|  | +     We do the right thing here.  */ | 
|  | +  HOWTO (R_RISCV_PC16,		/* type */ | 
|  | +	 RISCV_BRANCH_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_PC16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 TRUE),			/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit call through global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 mips_elf_gprel32_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (13), | 
|  | +  EMPTY_HOWTO (14), | 
|  | +  EMPTY_HOWTO (15), | 
|  | +  EMPTY_HOWTO (16), | 
|  | +  EMPTY_HOWTO (17), | 
|  | + | 
|  | +  /* 64 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_64,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_64",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Displacement in the global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_DISP",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (20), | 
|  | +  EMPTY_HOWTO (21), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 64 bit subtraction.  */ | 
|  | +  HOWTO (R_RISCV_SUB,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SUB",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_A,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_A",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction, and change all relocations | 
|  | +     to refer to the old instruction at the address.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_B,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_B",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Delete a 32 bit instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_DELETE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_DELETE",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (28), | 
|  | +  EMPTY_HOWTO (29), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Section displacement, used by an associated event location section.  */ | 
|  | +  HOWTO (R_RISCV_SCN_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SCN_DISP",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_REL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 1,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* These two are obsolete.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE), | 
|  | +  EMPTY_HOWTO (R_RISCV_PJUMP), | 
|  | + | 
|  | +  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section. | 
|  | +     It must be used for multigot GOT's (and only there).  */ | 
|  | +  HOWTO (R_RISCV_RELGOT,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_RELGOT",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO(37), | 
|  | + | 
|  | +  /* TLS relocations.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPMOD32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPMOD32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD64), | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPREL64), | 
|  | + | 
|  | +  /* TLS general dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOTTPREL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOTTPREL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS IE dynamic relocations.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_TPREL64), | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_HI16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_LO16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit relocation with no addend.  */ | 
|  | +  HOWTO (R_RISCV_GLOB_DAT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GLOB_DAT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | +}; | 
|  | + | 
|  | +/* The relocation table used for SHT_RELA sections.  */ | 
|  | + | 
|  | +static reloc_howto_type elf_mips_howto_table_rela[] = | 
|  | +{ | 
|  | +  /* No relocation.  */ | 
|  | +  HOWTO (R_RISCV_NONE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_NONE",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (1), | 
|  | + | 
|  | +  /* 32 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_32",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit symbol relative relocation.  */ | 
|  | +  HOWTO (R_RISCV_REL32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL32",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 26 bit jump address.  */ | 
|  | +  HOWTO (R_RISCV_26,		/* type */ | 
|  | +	 RISCV_JUMP_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_JUMP_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_TARGET,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +				/* This needs complex overflow | 
|  | +				   detection, because the upper 36 | 
|  | +				   bits must match the PC + 4.  */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_26",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* dst_mask */ | 
|  | +	 TRUE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_HI16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_HI16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_LO16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_LO16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf_gprel16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to literal section.  */ | 
|  | +  HOWTO (R_RISCV_LITERAL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf_literal_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LITERAL",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GOT16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit PC relative reference.  Note that the ABI document has a typo | 
|  | +     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless. | 
|  | +     We do the right thing here.  */ | 
|  | +  HOWTO (R_RISCV_PC16,		/* type */ | 
|  | +	 2,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_PC16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 TRUE),			/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit call through global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 mips_elf_gprel32_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL32",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (13), | 
|  | +  EMPTY_HOWTO (14), | 
|  | +  EMPTY_HOWTO (15), | 
|  | +  EMPTY_HOWTO (16), | 
|  | +  EMPTY_HOWTO (17), | 
|  | + | 
|  | +  /* 64 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_64,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_64",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Displacement in the global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_DISP",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (20), | 
|  | +  EMPTY_HOWTO (21), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 64 bit subtraction.  */ | 
|  | +  HOWTO (R_RISCV_SUB,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SUB",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_A,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_A",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction, and change all relocations | 
|  | +     to refer to the old instruction at the address.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_B,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_B",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Delete a 32 bit instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_DELETE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_DELETE",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (28), | 
|  | +  EMPTY_HOWTO (29), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Section displacement, used by an associated event location section.  */ | 
|  | +  HOWTO (R_RISCV_SCN_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SCN_DISP",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_REL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 1,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* These two are obsolete.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE), | 
|  | +  EMPTY_HOWTO (R_RISCV_PJUMP), | 
|  | + | 
|  | +  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section. | 
|  | +     It must be used for multigot GOT's (and only there).  */ | 
|  | +  HOWTO (R_RISCV_RELGOT,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_RELGOT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO(37), | 
|  | + | 
|  | +  /* TLS relocations.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPMOD32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPMOD32", /* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD64), | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPREL64), | 
|  | + | 
|  | +  /* TLS general dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOTTPREL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOTTPREL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_TPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL32",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_TPREL64), | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_HI16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_LO16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit relocation with no addend.  */ | 
|  | +  HOWTO (R_RISCV_GLOB_DAT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GLOB_DAT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | +}; | 
|  | + | 
|  | +/* GNU extension to record C++ vtable hierarchy */ | 
|  | +static reloc_howto_type elf_mips_gnu_vtinherit_howto = | 
|  | +  HOWTO (R_RISCV_GNU_VTINHERIT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 NULL,			/* special_function */ | 
|  | +	 "R_RISCV_GNU_VTINHERIT", /* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* GNU extension to record C++ vtable member usage */ | 
|  | +static reloc_howto_type elf_mips_gnu_vtentry_howto = | 
|  | +  HOWTO (R_RISCV_GNU_VTENTRY,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */ | 
|  | +	 "R_RISCV_GNU_VTENTRY",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* 16 bit offset for pc-relative branches.  */ | 
|  | +static reloc_howto_type elf_mips_gnu_rel16_s2 = | 
|  | +  HOWTO (R_RISCV_GNU_REL16_S2,	/* type */ | 
|  | +	 2,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 16,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GNU_REL16_S2",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0x0000ffff,		/* src_mask */ | 
|  | +	 0x0000ffff,		/* dst_mask */ | 
|  | +	 TRUE);			/* pcrel_offset */ | 
|  | + | 
|  | +/* 16 bit offset for pc-relative branches.  */ | 
|  | +static reloc_howto_type elf_mips_gnu_rela16_s2 = | 
|  | +  HOWTO (R_RISCV_GNU_REL16_S2,	/* type */ | 
|  | +	 2,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 16,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GNU_REL16_S2",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0x0000ffff,		/* dst_mask */ | 
|  | +	 TRUE);			/* pcrel_offset */ | 
|  | + | 
|  | +/* Originally a VxWorks extension, but now used for other systems too.  */ | 
|  | +static reloc_howto_type elf_mips_copy_howto = | 
|  | +  HOWTO (R_RISCV_COPY,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* this one is variable size */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_bitfield, /* complain_on_overflow */ | 
|  | +	 bfd_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_COPY",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,         		/* src_mask */ | 
|  | +	 0x0,		        /* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* Originally a VxWorks extension, but now used for other systems too.  */ | 
|  | +static reloc_howto_type elf_mips_jump_slot_howto = | 
|  | +  HOWTO (R_RISCV_JUMP_SLOT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_bitfield, /* complain_on_overflow */ | 
|  | +	 bfd_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_JUMP_SLOT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,         		/* src_mask */ | 
|  | +	 0x0,		        /* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a | 
|  | +   dangerous relocation.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp) | 
|  | +{ | 
|  | +  unsigned int count; | 
|  | +  asymbol **sym; | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  /* If we've already figured out what GP will be, just return it.  */ | 
|  | +  *pgp = _bfd_get_gp_value (output_bfd); | 
|  | +  if (*pgp) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  count = bfd_get_symcount (output_bfd); | 
|  | +  sym = bfd_get_outsymbols (output_bfd); | 
|  | + | 
|  | +  /* The linker script will have created a symbol named `_gp' with the | 
|  | +     appropriate value.  */ | 
|  | +  if (sym == NULL) | 
|  | +    i = count; | 
|  | +  else | 
|  | +    { | 
|  | +      for (i = 0; i < count; i++, sym++) | 
|  | +	{ | 
|  | +	  register const char *name; | 
|  | + | 
|  | +	  name = bfd_asymbol_name (*sym); | 
|  | +	  if (*name == '_' && strcmp (name, "_gp") == 0) | 
|  | +	    { | 
|  | +	      *pgp = bfd_asymbol_value (*sym); | 
|  | +	      _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +	      break; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if (i >= count) | 
|  | +    { | 
|  | +      /* Only get the error once.  */ | 
|  | +      *pgp = 4; | 
|  | +      _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* We have to figure out the gp value, so that we can adjust the | 
|  | +   symbol value correctly.  We look up the symbol _gp in the output | 
|  | +   BFD.  If we can't find it, we're stuck.  We cache it in the ELF | 
|  | +   target data.  We don't need to adjust the symbol value for an | 
|  | +   external symbol if we are producing relocatable output.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, | 
|  | +		   char **error_message, bfd_vma *pgp) | 
|  | +{ | 
|  | +  if (bfd_is_und_section (symbol->section) | 
|  | +      && ! relocatable) | 
|  | +    { | 
|  | +      *pgp = 0; | 
|  | +      return bfd_reloc_undefined; | 
|  | +    } | 
|  | + | 
|  | +  *pgp = _bfd_get_gp_value (output_bfd); | 
|  | +  if (*pgp == 0 | 
|  | +      && (! relocatable | 
|  | +	  || (symbol->flags & BSF_SECTION_SYM) != 0)) | 
|  | +    { | 
|  | +      if (relocatable) | 
|  | +	{ | 
|  | +	  /* Make up a value.  */ | 
|  | +	  *pgp = symbol->section->output_section->vma /*+ 0x4000*/; | 
|  | +	  _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +	} | 
|  | +      else if (!mips_elf_assign_gp (output_bfd, pgp)) | 
|  | +	{ | 
|  | +	  *error_message = | 
|  | +	    (char *) _("GP relative relocation when _gp not defined"); | 
|  | +	  return bfd_reloc_dangerous; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_GPREL16 relocation.  This is a 16 bit value which must | 
|  | +   become the offset from the gp register.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf_gprel16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, | 
|  | +			asymbol *symbol, void *data ATTRIBUTE_UNUSED, | 
|  | +			asection *input_section, bfd *output_bfd, | 
|  | +			char **error_message ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  if (output_bfd != NULL) | 
|  | +    relocatable = TRUE; | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | +    } | 
|  | + | 
|  | +  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, | 
|  | +			   &gp); | 
|  | +  if (ret != bfd_reloc_ok) | 
|  | +    return ret; | 
|  | + | 
|  | +  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry, | 
|  | +					input_section, relocatable, | 
|  | +					data, gp); | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_LITERAL relocation.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			void *data, asection *input_section, bfd *output_bfd, | 
|  | +			char **error_message) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  /* R_RISCV_LITERAL relocations are defined for local symbols only.  */ | 
|  | +  if (output_bfd != NULL | 
|  | +      && (symbol->flags & BSF_SECTION_SYM) == 0 | 
|  | +      && (symbol->flags & BSF_LOCAL) != 0) | 
|  | +    { | 
|  | +      *error_message = (char *) | 
|  | +	_("literal relocation occurs for an external symbol"); | 
|  | +      return bfd_reloc_outofrange; | 
|  | +    } | 
|  | + | 
|  | +  /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.  */ | 
|  | +  if (output_bfd != NULL) | 
|  | +    relocatable = TRUE; | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | +    } | 
|  | + | 
|  | +  ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, | 
|  | +			   &gp); | 
|  | +  if (ret != bfd_reloc_ok) | 
|  | +    return ret; | 
|  | + | 
|  | +  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry, | 
|  | +					input_section, relocatable, | 
|  | +					data, gp); | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_GPREL32 relocation.  This is a 32 bit value which must | 
|  | +   become the offset from the gp register.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			void *data, asection *input_section, bfd *output_bfd, | 
|  | +			char **error_message) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  /* R_RISCV_GPREL32 relocations are defined for local symbols only.  */ | 
|  | +  if (output_bfd != NULL | 
|  | +      && (symbol->flags & BSF_SECTION_SYM) == 0 | 
|  | +      && (symbol->flags & BSF_LOCAL) != 0) | 
|  | +    { | 
|  | +      *error_message = (char *) | 
|  | +	_("32bits gp relative relocation occurs for an external symbol"); | 
|  | +      return bfd_reloc_outofrange; | 
|  | +    } | 
|  | + | 
|  | +  if (output_bfd != NULL) | 
|  | +    { | 
|  | +      relocatable = TRUE; | 
|  | +      gp = _bfd_get_gp_value (output_bfd); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | + | 
|  | +      ret = mips_elf_final_gp (output_bfd, symbol, relocatable, | 
|  | +			       error_message, &gp); | 
|  | +      if (ret != bfd_reloc_ok) | 
|  | +	return ret; | 
|  | +    } | 
|  | + | 
|  | +  return gprel32_with_gp (abfd, symbol, reloc_entry, input_section, | 
|  | +			  relocatable, data, gp); | 
|  | +} | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, | 
|  | +		 asection *input_section, bfd_boolean relocatable, | 
|  | +		 void *data, bfd_vma gp) | 
|  | +{ | 
|  | +  bfd_vma relocation; | 
|  | +  unsigned long val; | 
|  | + | 
|  | +  if (bfd_is_com_section (symbol->section)) | 
|  | +    relocation = 0; | 
|  | +  else | 
|  | +    relocation = symbol->value; | 
|  | + | 
|  | +  relocation += symbol->section->output_section->vma; | 
|  | +  relocation += symbol->section->output_offset; | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  if (reloc_entry->howto->src_mask == 0) | 
|  | +    val = 0; | 
|  | +  else | 
|  | +    val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); | 
|  | + | 
|  | +  /* Set val to the offset into the section or symbol.  */ | 
|  | +  val += reloc_entry->addend; | 
|  | + | 
|  | +  /* Adjust val for the final section location and GP value.  If we | 
|  | +     are producing relocatable output, we don't want to do this for | 
|  | +     an external symbol.  */ | 
|  | +  if (! relocatable | 
|  | +      || (symbol->flags & BSF_SECTION_SYM) != 0) | 
|  | +    val += relocation - gp; | 
|  | + | 
|  | +  bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); | 
|  | + | 
|  | +  if (relocatable) | 
|  | +    reloc_entry->address += input_section->output_offset; | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* A mapping from BFD reloc types to MIPS ELF reloc types.  */ | 
|  | + | 
|  | +struct elf_reloc_map { | 
|  | +  bfd_reloc_code_real_type bfd_val; | 
|  | +  enum elf_riscv_reloc_type elf_val; | 
|  | +}; | 
|  | + | 
|  | +static const struct elf_reloc_map mips_reloc_map[] = | 
|  | +{ | 
|  | +  { BFD_RELOC_NONE, R_RISCV_NONE }, | 
|  | +  { BFD_RELOC_32, R_RISCV_32 }, | 
|  | +  /* There is no BFD reloc for R_RISCV_REL32.  */ | 
|  | +  { BFD_RELOC_CTOR, R_RISCV_32 }, | 
|  | +  { BFD_RELOC_64, R_RISCV_64 }, | 
|  | +  { BFD_RELOC_16_PCREL_S2, R_RISCV_PC16 }, | 
|  | +  { BFD_RELOC_HI16_S, R_RISCV_HI16 }, | 
|  | +  { BFD_RELOC_LO16, R_RISCV_LO16 }, | 
|  | +  { BFD_RELOC_GPREL16, R_RISCV_GPREL16 }, | 
|  | +  { BFD_RELOC_GPREL32, R_RISCV_GPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_JMP, R_RISCV_26 }, | 
|  | +  { BFD_RELOC_MIPS_LITERAL, R_RISCV_LITERAL }, | 
|  | +  { BFD_RELOC_MIPS_GOT16, R_RISCV_GOT16 }, | 
|  | +  { BFD_RELOC_MIPS_CALL16, R_RISCV_CALL16 }, | 
|  | +  { BFD_RELOC_MIPS_GOT_DISP, R_RISCV_GOT_DISP }, | 
|  | +  { BFD_RELOC_MIPS_GOT_HI16, R_RISCV_GOT_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_GOT_LO16, R_RISCV_GOT_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_SUB, R_RISCV_SUB }, | 
|  | +  { BFD_RELOC_MIPS_INSERT_A, R_RISCV_INSERT_A }, | 
|  | +  { BFD_RELOC_MIPS_INSERT_B, R_RISCV_INSERT_B }, | 
|  | +  { BFD_RELOC_MIPS_DELETE, R_RISCV_DELETE }, | 
|  | +  { BFD_RELOC_MIPS_CALL_HI16, R_RISCV_CALL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_CALL_LO16, R_RISCV_CALL_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_SCN_DISP, R_RISCV_SCN_DISP }, | 
|  | +  { BFD_RELOC_MIPS_REL16, R_RISCV_REL16 }, | 
|  | +  { BFD_RELOC_MIPS_RELGOT, R_RISCV_RELGOT }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_GD, R_RISCV_TLS_GD }, | 
|  | +  { BFD_RELOC_MIPS_TLS_LDM, R_RISCV_TLS_LDM }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_RISCV_TLS_DTPREL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_RISCV_TLS_DTPREL_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_GOTTPREL, R_RISCV_TLS_GOTTPREL }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL32, R_RISCV_TLS_TPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL64, R_RISCV_TLS_TPREL64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_RISCV_TLS_TPREL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_RISCV_TLS_TPREL_LO16 } | 
|  | +}; | 
|  | + | 
|  | +/* Given a BFD reloc type, return a howto structure.  */ | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +				 bfd_reloc_code_real_type code) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | +  /* FIXME: We default to RELA here instead of choosing the right | 
|  | +     relocation variant.  */ | 
|  | +  reloc_howto_type *howto_table = elf_mips_howto_table_rela; | 
|  | + | 
|  | +  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); | 
|  | +       i++) | 
|  | +    { | 
|  | +      if (mips_reloc_map[i].bfd_val == code) | 
|  | +	return &howto_table[(int) mips_reloc_map[i].elf_val]; | 
|  | +    } | 
|  | + | 
|  | +  switch (code) | 
|  | +    { | 
|  | +    case BFD_RELOC_VTABLE_INHERIT: | 
|  | +      return &elf_mips_gnu_vtinherit_howto; | 
|  | +    case BFD_RELOC_VTABLE_ENTRY: | 
|  | +      return &elf_mips_gnu_vtentry_howto; | 
|  | +    case BFD_RELOC_MIPS_COPY: | 
|  | +      return &elf_mips_copy_howto; | 
|  | +    case BFD_RELOC_MIPS_JUMP_SLOT: | 
|  | +      return &elf_mips_jump_slot_howto; | 
|  | +    default: | 
|  | +      bfd_set_error (bfd_error_bad_value); | 
|  | +      return NULL; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +				 const char *r_name) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  for (i = 0; | 
|  | +       i < (sizeof (elf_mips_howto_table_rela) | 
|  | +	    / sizeof (elf_mips_howto_table_rela[0])); | 
|  | +       i++) | 
|  | +    if (elf_mips_howto_table_rela[i].name != NULL | 
|  | +	&& strcasecmp (elf_mips_howto_table_rela[i].name, r_name) == 0) | 
|  | +      return &elf_mips_howto_table_rela[i]; | 
|  | + | 
|  | +  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_vtinherit_howto; | 
|  | +  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_vtentry_howto; | 
|  | +  if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_rel16_s2; | 
|  | +  if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_rela16_s2; | 
|  | +  if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_copy_howto; | 
|  | +  if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_jump_slot_howto; | 
|  | + | 
|  | +  return NULL; | 
|  | +} | 
|  | + | 
|  | +/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */ | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +mips_elf_n32_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p) | 
|  | +{ | 
|  | +  switch (r_type) | 
|  | +    { | 
|  | +    case R_RISCV_GNU_VTINHERIT: | 
|  | +      return &elf_mips_gnu_vtinherit_howto; | 
|  | +    case R_RISCV_GNU_VTENTRY: | 
|  | +      return &elf_mips_gnu_vtentry_howto; | 
|  | +    case R_RISCV_GNU_REL16_S2: | 
|  | +      if (rela_p) | 
|  | +	return &elf_mips_gnu_rela16_s2; | 
|  | +      else | 
|  | +	return &elf_mips_gnu_rel16_s2; | 
|  | +    case R_RISCV_COPY: | 
|  | +      return &elf_mips_copy_howto; | 
|  | +    case R_RISCV_JUMP_SLOT: | 
|  | +      return &elf_mips_jump_slot_howto; | 
|  | +    default: | 
|  | +      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max); | 
|  | +      if (rela_p) | 
|  | +	return &elf_mips_howto_table_rela[r_type]; | 
|  | +      else | 
|  | +	return &elf_mips_howto_table_rel[r_type]; | 
|  | +      break; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst) | 
|  | +{ | 
|  | +  unsigned int r_type; | 
|  | + | 
|  | +  r_type = ELF32_R_TYPE (dst->r_info); | 
|  | +  cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, FALSE); | 
|  | + | 
|  | +  /* The addend for a GPREL16 or LITERAL relocation comes from the GP | 
|  | +     value for the object file.  We get the addend now, rather than | 
|  | +     when we do the relocation, because the symbol manipulations done | 
|  | +     by the linker may cause us to lose track of the input BFD.  */ | 
|  | +  if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0 | 
|  | +      && (r_type == R_RISCV_GPREL16 || r_type == (unsigned int) R_RISCV_LITERAL)) | 
|  | +    cache_ptr->addend = elf_gp (abfd); | 
|  | +} | 
|  | + | 
|  | +/* Given a MIPS Elf_Internal_Rela, fill in an arelent structure.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +			 arelent *cache_ptr, Elf_Internal_Rela *dst) | 
|  | +{ | 
|  | +  unsigned int r_type; | 
|  | + | 
|  | +  r_type = ELF32_R_TYPE (dst->r_info); | 
|  | +  cache_ptr->howto = mips_elf_n32_rtype_to_howto (r_type, TRUE); | 
|  | +  cache_ptr->addend = dst->r_addend; | 
|  | +} | 
|  | + | 
|  | +/* Determine whether a symbol is global for the purposes of splitting | 
|  | +   the symbol table into global symbols and local symbols.  At least | 
|  | +   on Irix 5, this split must be between section symbols and all other | 
|  | +   symbols.  On most ELF targets the split is between static symbols | 
|  | +   and externally visible symbols.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym) | 
|  | +{ | 
|  | +  return ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0 | 
|  | +	  || bfd_is_und_section (bfd_get_section (sym)) | 
|  | +	  || bfd_is_com_section (bfd_get_section (sym))); | 
|  | +} | 
|  | + | 
|  | +/* Set the right machine number for a MIPS ELF file.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_n32_object_p (bfd *abfd) | 
|  | +{ | 
|  | +  unsigned long mach; | 
|  | + | 
|  | +  mach = _bfd_elf_riscv_mach (elf_elfheader (abfd)->e_flags); | 
|  | +  bfd_default_set_arch_mach (abfd, bfd_arch_riscv, mach); | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Support for core dump NOTE sections.  */ | 
|  | +static bfd_boolean | 
|  | +elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) | 
|  | +{ | 
|  | +  int offset; | 
|  | +  unsigned int size; | 
|  | + | 
|  | +  switch (note->descsz) | 
|  | +    { | 
|  | +      default: | 
|  | +	return FALSE; | 
|  | + | 
|  | +      case 440:		/* Linux/MIPS N32 */ | 
|  | +	/* pr_cursig */ | 
|  | +	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); | 
|  | + | 
|  | +	/* pr_pid */ | 
|  | +	elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 24); | 
|  | + | 
|  | +	/* pr_reg */ | 
|  | +	offset = 72; | 
|  | +	size = 360; | 
|  | + | 
|  | +	break; | 
|  | +    } | 
|  | + | 
|  | +  /* Make a ".reg/999" section.  */ | 
|  | +  return _bfd_elfcore_make_pseudosection (abfd, ".reg", size, | 
|  | +					  note->descpos + offset); | 
|  | +} | 
|  | + | 
|  | +static bfd_boolean | 
|  | +elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) | 
|  | +{ | 
|  | +  switch (note->descsz) | 
|  | +    { | 
|  | +      default: | 
|  | +	return FALSE; | 
|  | + | 
|  | +      case 128:		/* Linux/MIPS elf_prpsinfo */ | 
|  | +	elf_tdata (abfd)->core_program | 
|  | +	 = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); | 
|  | +	elf_tdata (abfd)->core_command | 
|  | +	 = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); | 
|  | +    } | 
|  | + | 
|  | +  /* Note that for some reason, a spurious space is tacked | 
|  | +     onto the end of the args in some (at least one anyway) | 
|  | +     implementations, so strip it off if it exists.  */ | 
|  | + | 
|  | +  { | 
|  | +    char *command = elf_tdata (abfd)->core_command; | 
|  | +    int n = strlen (command); | 
|  | + | 
|  | +    if (0 < n && command[n - 1] == ' ') | 
|  | +      command[n - 1] = '\0'; | 
|  | +  } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* ECOFF swapping routines.  These are used when dealing with the | 
|  | +   .mdebug section, which is in the ECOFF debugging format.  */ | 
|  | +static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { | 
|  | +  /* Symbol table magic number.  */ | 
|  | +  magicSym, | 
|  | +  /* Alignment of debugging information.  E.g., 4.  */ | 
|  | +  4, | 
|  | +  /* Sizes of external symbolic information.  */ | 
|  | +  sizeof (struct hdr_ext), | 
|  | +  sizeof (struct dnr_ext), | 
|  | +  sizeof (struct pdr_ext), | 
|  | +  sizeof (struct sym_ext), | 
|  | +  sizeof (struct opt_ext), | 
|  | +  sizeof (struct fdr_ext), | 
|  | +  sizeof (struct rfd_ext), | 
|  | +  sizeof (struct ext_ext), | 
|  | +  /* Functions to swap in external symbolic data.  */ | 
|  | +  ecoff_swap_hdr_in, | 
|  | +  ecoff_swap_dnr_in, | 
|  | +  ecoff_swap_pdr_in, | 
|  | +  ecoff_swap_sym_in, | 
|  | +  ecoff_swap_opt_in, | 
|  | +  ecoff_swap_fdr_in, | 
|  | +  ecoff_swap_rfd_in, | 
|  | +  ecoff_swap_ext_in, | 
|  | +  _bfd_ecoff_swap_tir_in, | 
|  | +  _bfd_ecoff_swap_rndx_in, | 
|  | +  /* Functions to swap out external symbolic data.  */ | 
|  | +  ecoff_swap_hdr_out, | 
|  | +  ecoff_swap_dnr_out, | 
|  | +  ecoff_swap_pdr_out, | 
|  | +  ecoff_swap_sym_out, | 
|  | +  ecoff_swap_opt_out, | 
|  | +  ecoff_swap_fdr_out, | 
|  | +  ecoff_swap_rfd_out, | 
|  | +  ecoff_swap_ext_out, | 
|  | +  _bfd_ecoff_swap_tir_out, | 
|  | +  _bfd_ecoff_swap_rndx_out, | 
|  | +  /* Function to read in symbolic data.  */ | 
|  | +  _bfd_riscv_elf_read_ecoff_info | 
|  | +}; | 
|  | + | 
|  | +#define ELF_ARCH			bfd_arch_riscv | 
|  | +#define ELF_TARGET_ID			MIPS_ELF_DATA | 
|  | +#define ELF_MACHINE_CODE		EM_RISCV | 
|  | + | 
|  | +#define elf_backend_collect		TRUE | 
|  | +#define elf_backend_type_change_ok	TRUE | 
|  | +#define elf_backend_can_gc_sections	TRUE | 
|  | +#define elf_info_to_howto		mips_info_to_howto_rela | 
|  | +#define elf_info_to_howto_rel		mips_info_to_howto_rel | 
|  | +#define elf_backend_sym_is_global	mips_elf_sym_is_global | 
|  | +#define elf_backend_object_p		mips_elf_n32_object_p | 
|  | +#define elf_backend_symbol_processing	_bfd_riscv_elf_symbol_processing | 
|  | +#define elf_backend_section_processing	_bfd_riscv_elf_section_processing | 
|  | +#define elf_backend_section_from_shdr	_bfd_riscv_elf_section_from_shdr | 
|  | +#define elf_backend_fake_sections	_bfd_riscv_elf_fake_sections | 
|  | +#define elf_backend_section_from_bfd_section \ | 
|  | +					_bfd_riscv_elf_section_from_bfd_section | 
|  | +#define elf_backend_add_symbol_hook	_bfd_riscv_elf_add_symbol_hook | 
|  | +#define elf_backend_link_output_symbol_hook \ | 
|  | +					_bfd_riscv_elf_link_output_symbol_hook | 
|  | +#define elf_backend_create_dynamic_sections \ | 
|  | +					_bfd_riscv_elf_create_dynamic_sections | 
|  | +#define elf_backend_check_relocs	_bfd_riscv_elf_check_relocs | 
|  | +#define elf_backend_merge_symbol_attribute \ | 
|  | +					_bfd_riscv_elf_merge_symbol_attribute | 
|  | +#define elf_backend_get_target_dtag	_bfd_riscv_elf_get_target_dtag | 
|  | +#define elf_backend_adjust_dynamic_symbol \ | 
|  | +					_bfd_riscv_elf_adjust_dynamic_symbol | 
|  | +#define elf_backend_always_size_sections \ | 
|  | +					_bfd_riscv_elf_always_size_sections | 
|  | +#define elf_backend_size_dynamic_sections \ | 
|  | +					_bfd_riscv_elf_size_dynamic_sections | 
|  | +#define elf_backend_init_index_section	_bfd_elf_init_1_index_section | 
|  | +#define elf_backend_relocate_section	_bfd_riscv_elf_relocate_section | 
|  | +#define elf_backend_finish_dynamic_symbol \ | 
|  | +					_bfd_riscv_elf_finish_dynamic_symbol | 
|  | +#define elf_backend_finish_dynamic_sections \ | 
|  | +					_bfd_riscv_elf_finish_dynamic_sections | 
|  | +#define elf_backend_final_write_processing \ | 
|  | +					_bfd_riscv_elf_final_write_processing | 
|  | +#define elf_backend_additional_program_headers \ | 
|  | +					_bfd_riscv_elf_additional_program_headers | 
|  | +#define elf_backend_modify_segment_map	_bfd_riscv_elf_modify_segment_map | 
|  | +#define elf_backend_gc_mark_hook	_bfd_riscv_elf_gc_mark_hook | 
|  | +#define elf_backend_gc_sweep_hook	_bfd_riscv_elf_gc_sweep_hook | 
|  | +#define elf_backend_copy_indirect_symbol \ | 
|  | +					_bfd_riscv_elf_copy_indirect_symbol | 
|  | +#define elf_backend_grok_prstatus	elf32_mips_grok_prstatus | 
|  | +#define elf_backend_grok_psinfo		elf32_mips_grok_psinfo | 
|  | +#define elf_backend_ecoff_debug_swap	&mips_elf32_ecoff_debug_swap | 
|  | + | 
|  | +#define elf_backend_got_header_size	(4 * MIPS_RESERVED_GOTNO) | 
|  | + | 
|  | +/* MIPS n32 ELF can use a mixture of REL and RELA, but some Relocations | 
|  | +   work better/work only in RELA, so we default to this.  */ | 
|  | +#define elf_backend_may_use_rel_p	1 | 
|  | +#define elf_backend_may_use_rela_p	1 | 
|  | +#define elf_backend_default_use_rela_p	1 | 
|  | +#define elf_backend_rela_plts_and_copies_p 0 | 
|  | +#define elf_backend_sign_extend_vma	TRUE | 
|  | +#define elf_backend_plt_readonly	1 | 
|  | +#define elf_backend_plt_sym_val		_bfd_riscv_elf_plt_sym_val | 
|  | + | 
|  | +#define elf_backend_discard_info	_bfd_riscv_elf_discard_info | 
|  | +#define elf_backend_ignore_discarded_relocs \ | 
|  | +					_bfd_riscv_elf_ignore_discarded_relocs | 
|  | +#define elf_backend_write_section	_bfd_riscv_elf_write_section | 
|  | +#define elf_backend_mips_rtype_to_howto	mips_elf_n32_rtype_to_howto | 
|  | +#define bfd_elf32_find_nearest_line	_bfd_riscv_elf_find_nearest_line | 
|  | +#define bfd_elf32_find_inliner_info	_bfd_riscv_elf_find_inliner_info | 
|  | +#define bfd_elf32_new_section_hook	_bfd_riscv_elf_new_section_hook | 
|  | +#define bfd_elf32_set_section_contents	_bfd_riscv_elf_set_section_contents | 
|  | +#define bfd_elf32_bfd_get_relocated_section_contents \ | 
|  | +				_bfd_elf_riscv_get_relocated_section_contents | 
|  | +#define bfd_elf32_bfd_link_hash_table_create \ | 
|  | +					_bfd_riscv_elf_link_hash_table_create | 
|  | +#define bfd_elf32_bfd_final_link	_bfd_riscv_elf_final_link | 
|  | +#define bfd_elf32_bfd_merge_private_bfd_data \ | 
|  | +					_bfd_riscv_elf_merge_private_bfd_data | 
|  | +#define bfd_elf32_bfd_set_private_flags	_bfd_riscv_elf_set_private_flags | 
|  | +#define bfd_elf32_bfd_print_private_bfd_data \ | 
|  | +					_bfd_riscv_elf_print_private_bfd_data | 
|  | +#define bfd_elf32_bfd_relax_section     _bfd_riscv_relax_section | 
|  | + | 
|  | +/* Support for SGI-ish mips targets using n32 ABI.  */ | 
|  | + | 
|  | +#define TARGET_LITTLE_SYM               bfd_elf32_littleriscv_vec | 
|  | +#define TARGET_LITTLE_NAME              "elf32-littleriscv" | 
|  | +#define TARGET_BIG_SYM                  bfd_elf32_bigriscv_vec | 
|  | +#define TARGET_BIG_NAME                 "elf32-bigriscv" | 
|  | + | 
|  | +#define ELF_MAXPAGESIZE			0x10000 | 
|  | +#define ELF_COMMONPAGESIZE		0x1000 | 
|  | + | 
|  | +#include "elf32-target.h" | 
|  | diff -ruN binutils-2.24/bfd/elf64-riscv.c binutils-2.24-riscv/bfd/elf64-riscv.c | 
|  | --- binutils-2.24/bfd/elf64-riscv.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/elf64-riscv.c	2014-12-02 16:05:44.905434919 -0800 | 
|  | @@ -0,0 +1,2999 @@ | 
|  | +/* MIPS-specific support for 64-bit ELF | 
|  | +   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, | 
|  | +   2006, 2007, 2008, 2009, 2010 | 
|  | +   Free Software Foundation, Inc. | 
|  | +   Ian Lance Taylor, Cygnus Support | 
|  | +   Linker support added by Mark Mitchell, CodeSourcery, LLC. | 
|  | +   <mark@codesourcery.com> | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | + | 
|  | +/* This file supports the 64-bit MIPS ELF ABI. | 
|  | + | 
|  | +   The MIPS 64-bit ELF ABI uses an unusual reloc format.  This file | 
|  | +   overrides the usual ELF reloc handling, and handles reading and | 
|  | +   writing the relocations here.  */ | 
|  | + | 
|  | +/* TODO: Many things are unsupported, even if there is some code for it | 
|  | + .       (which was mostly stolen from elf32-mips.c and slightly adapted). | 
|  | + . | 
|  | + .   - Relocation handling for REL relocs is wrong in many cases and | 
|  | + .     generally untested. | 
|  | + .   - Relocation handling for RELA relocs related to GOT support are | 
|  | + .     also likely to be wrong. | 
|  | + .   - Support for MIPS16 is untested. | 
|  | + .   - Combined relocs with RSS_* entries are unsupported. | 
|  | + .   - The whole GOT handling for NewABI is missing, some parts of | 
|  | + .     the OldABI version is still lying around and should be removed. | 
|  | + */ | 
|  | + | 
|  | +#include "sysdep.h" | 
|  | +#include "bfd.h" | 
|  | +#include "libbfd.h" | 
|  | +#include "aout/ar.h" | 
|  | +#include "bfdlink.h" | 
|  | +#include "genlink.h" | 
|  | +#include "elf-bfd.h" | 
|  | +#include "elfxx-riscv.h" | 
|  | +#include "elf/riscv.h" | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +/* Get the ECOFF swapping routines.  The 64-bit ABI is not supposed to | 
|  | +   use ECOFF.  However, we support it anyhow for an easier changeover.  */ | 
|  | +#include "coff/sym.h" | 
|  | +#include "coff/symconst.h" | 
|  | +#include "coff/internal.h" | 
|  | +#include "coff/ecoff.h" | 
|  | +/* The 64 bit versions of the mdebug data structures are in alpha.h.  */ | 
|  | +#include "coff/alpha.h" | 
|  | +#define ECOFF_SIGNED_64 | 
|  | +#include "ecoffswap.h" | 
|  | + | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +static void mips_elf64_swap_reloc_in | 
|  | +  (bfd *, const Elf64_Mips_External_Rel *, Elf64_Mips_Internal_Rela *); | 
|  | +static void mips_elf64_swap_reloca_in | 
|  | +  (bfd *, const Elf64_Mips_External_Rela *, Elf64_Mips_Internal_Rela *); | 
|  | +static void mips_elf64_swap_reloc_out | 
|  | +  (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rel *); | 
|  | +static void mips_elf64_swap_reloca_out | 
|  | +  (bfd *, const Elf64_Mips_Internal_Rela *, Elf64_Mips_External_Rela *); | 
|  | +static void mips_elf64_be_swap_reloc_in | 
|  | +  (bfd *, const bfd_byte *, Elf_Internal_Rela *); | 
|  | +static void mips_elf64_be_swap_reloc_out | 
|  | +  (bfd *, const Elf_Internal_Rela *, bfd_byte *); | 
|  | +static void mips_elf64_be_swap_reloca_in | 
|  | +  (bfd *, const bfd_byte *, Elf_Internal_Rela *); | 
|  | +static void mips_elf64_be_swap_reloca_out | 
|  | +  (bfd *, const Elf_Internal_Rela *, bfd_byte *); | 
|  | +static reloc_howto_type *bfd_elf64_bfd_reloc_type_lookup | 
|  | +  (bfd *, bfd_reloc_code_real_type); | 
|  | +static reloc_howto_type *mips_elf64_rtype_to_howto | 
|  | +  (unsigned int, bfd_boolean); | 
|  | +static void mips_elf64_info_to_howto_rel | 
|  | +  (bfd *, arelent *, Elf_Internal_Rela *); | 
|  | +static void mips_elf64_info_to_howto_rela | 
|  | +  (bfd *, arelent *, Elf_Internal_Rela *); | 
|  | +static long mips_elf64_get_reloc_upper_bound | 
|  | +  (bfd *, asection *); | 
|  | +static long mips_elf64_canonicalize_reloc | 
|  | +  (bfd *, asection *, arelent **, asymbol **); | 
|  | +static long mips_elf64_get_dynamic_reloc_upper_bound | 
|  | +  (bfd *); | 
|  | +static long mips_elf64_canonicalize_dynamic_reloc | 
|  | +  (bfd *, arelent **, asymbol **); | 
|  | +static bfd_boolean mips_elf64_slurp_one_reloc_table | 
|  | +  (bfd *, asection *, Elf_Internal_Shdr *, bfd_size_type, arelent *, | 
|  | +   asymbol **, bfd_boolean); | 
|  | +static bfd_boolean mips_elf64_slurp_reloc_table | 
|  | +  (bfd *, asection *, asymbol **, bfd_boolean); | 
|  | +static void mips_elf64_write_relocs | 
|  | +  (bfd *, asection *, void *); | 
|  | +static void mips_elf64_write_rel | 
|  | +  (bfd *, asection *, Elf_Internal_Shdr *, int *, void *); | 
|  | +static void mips_elf64_write_rela | 
|  | +  (bfd *, asection *, Elf_Internal_Shdr *, int *, void *); | 
|  | +static bfd_reloc_status_type mips_elf64_gprel16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_reloc_status_type mips_elf64_literal_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_reloc_status_type mips_elf64_gprel32_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +static bfd_boolean mips_elf64_assign_gp | 
|  | +  (bfd *, bfd_vma *); | 
|  | +static bfd_reloc_status_type mips_elf64_final_gp | 
|  | +  (bfd *, asymbol *, bfd_boolean, char **, bfd_vma *); | 
|  | +static bfd_boolean mips_elf64_object_p | 
|  | +  (bfd *); | 
|  | +static bfd_boolean elf64_mips_grok_prstatus | 
|  | +  (bfd *, Elf_Internal_Note *); | 
|  | +static bfd_boolean elf64_mips_grok_psinfo | 
|  | +  (bfd *, Elf_Internal_Note *); | 
|  | + | 
|  | +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value | 
|  | +   from smaller values.  Start with zero, widen, *then* decrement.  */ | 
|  | +#define MINUS_ONE	(((bfd_vma)0) - 1) | 
|  | + | 
|  | +/* The number of local .got entries we reserve.  */ | 
|  | +#define MIPS_RESERVED_GOTNO (2) | 
|  | + | 
|  | +/* The relocation table used for SHT_REL sections.  */ | 
|  | + | 
|  | +static reloc_howto_type mips_elf64_howto_table_rel[] = | 
|  | +{ | 
|  | +  /* No relocation.  */ | 
|  | +  HOWTO (R_RISCV_NONE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_NONE",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (1), | 
|  | + | 
|  | +  /* 32 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_32",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit symbol relative relocation.  */ | 
|  | +  HOWTO (R_RISCV_REL32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 26 bit jump address.  */ | 
|  | +  HOWTO (R_RISCV_26,		/* type */ | 
|  | +	 RISCV_JUMP_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_JUMP_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_TARGET,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +				/* This needs complex overflow | 
|  | +				   detection, because the upper 36 | 
|  | +				   bits must match the PC + 4.  */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_26",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* src_mask */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* dst_mask */ | 
|  | +	 TRUE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* R_RISCV_HI16 and R_RISCV_LO16 are unsupported for NewABI REL. | 
|  | +     However, the native IRIX6 tools use them, so we try our best. */ | 
|  | + | 
|  | +  /* High 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_HI16,		/* type */ | 
|  | +	 RISCV_IMM_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_hi16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_HI16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_LO16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_lo16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LO16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf64_gprel16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to literal section.  */ | 
|  | +  HOWTO (R_RISCV_LITERAL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf64_literal_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LITERAL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_got16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GOT16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit PC relative reference.  Note that the ABI document has a typo | 
|  | +     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless. | 
|  | +     We do the right thing here.  */ | 
|  | +  HOWTO (R_RISCV_PC16,		/* type */ | 
|  | +	 RISCV_BRANCH_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_PC16",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 TRUE),			/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit call through global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 mips_elf64_gprel32_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL32",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (13), | 
|  | +  EMPTY_HOWTO (14), | 
|  | +  EMPTY_HOWTO (15), | 
|  | +  EMPTY_HOWTO (16), | 
|  | +  EMPTY_HOWTO (17), | 
|  | + | 
|  | +  /* 64 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_64,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_64",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Displacement in the global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_DISP",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (20), | 
|  | +  EMPTY_HOWTO (21), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 64 bit subtraction.  */ | 
|  | +  HOWTO (R_RISCV_SUB,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SUB",		/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_A,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_A",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction, and change all relocations | 
|  | +     to refer to the old instruction at the address.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_B,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_B",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Delete a 32 bit instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_DELETE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_DELETE",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (28), | 
|  | +  EMPTY_HOWTO (29), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Section displacement, used by an associated event location section.  */ | 
|  | +  HOWTO (R_RISCV_SCN_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SCN_DISP",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_REL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 1,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* These two are obsolete.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE), | 
|  | +  EMPTY_HOWTO (R_RISCV_PJUMP), | 
|  | + | 
|  | +  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section. | 
|  | +     It must be used for multigot GOT's (and only there).  */ | 
|  | +  HOWTO (R_RISCV_RELGOT,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_RELGOT",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0xffffffff,		/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO(37), | 
|  | + | 
|  | +  /* TLS relocations.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD32), | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPREL32), | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPMOD64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPMOD64",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL64",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS general dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOTTPREL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOTTPREL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS IE dynamic relocations.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_TPREL32), | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_TPREL64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL64",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_HI16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_LO16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit relocation with no addend.  */ | 
|  | +  HOWTO (R_RISCV_GLOB_DAT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GLOB_DAT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | +}; | 
|  | + | 
|  | +/* The relocation table used for SHT_RELA sections.  */ | 
|  | + | 
|  | +static reloc_howto_type mips_elf64_howto_table_rela[] = | 
|  | +{ | 
|  | +  /* No relocation.  */ | 
|  | +  HOWTO (R_RISCV_NONE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_NONE",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (1), | 
|  | + | 
|  | +  /* 32 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_32",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit symbol relative relocation.  */ | 
|  | +  HOWTO (R_RISCV_REL32,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL32",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 26 bit jump address.  */ | 
|  | +  HOWTO (R_RISCV_26,		/* type */ | 
|  | +	 RISCV_JUMP_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_JUMP_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_TARGET,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +				/* This needs complex overflow | 
|  | +				   detection, because the upper 36 | 
|  | +				   bits must match the PC + 4.  */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_26",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_JUMP_BITS)-1) << OP_SH_TARGET,		/* dst_mask */ | 
|  | +	 TRUE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_HI16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_HI16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of symbol value.  */ | 
|  | +  HOWTO (R_RISCV_LO16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_LO16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf64_gprel16_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to literal section.  */ | 
|  | +  HOWTO (R_RISCV_LITERAL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 mips_elf64_literal_reloc, /* special_function */ | 
|  | +	 "R_RISCV_LITERAL",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Reference to global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GOT16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit PC relative reference.  Note that the ABI document has a typo | 
|  | +     and claims R_RISCV_PC16 to be not rightshifted, rendering it useless. | 
|  | +     We do the right thing here.  */ | 
|  | +  HOWTO (R_RISCV_PC16,		/* type */ | 
|  | +	 2,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_PC16",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 TRUE),			/* pcrel_offset */ | 
|  | + | 
|  | +  /* 16 bit call through global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit GP relative reference.  */ | 
|  | +  HOWTO (R_RISCV_GPREL32,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 mips_elf64_gprel32_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GPREL32",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (13), | 
|  | +  EMPTY_HOWTO (14), | 
|  | +  EMPTY_HOWTO (15), | 
|  | +  EMPTY_HOWTO (16), | 
|  | +  EMPTY_HOWTO (17), | 
|  | + | 
|  | +  /* 64 bit relocation.  */ | 
|  | +  HOWTO (R_RISCV_64,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_64",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Displacement in the global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_DISP",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (20), | 
|  | +  EMPTY_HOWTO (21), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GOT_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 64 bit subtraction.  */ | 
|  | +  HOWTO (R_RISCV_SUB,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SUB",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_A,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_A",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Insert the addend as an instruction, and change all relocations | 
|  | +     to refer to the old instruction at the address.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_INSERT_B,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_INSERT_B",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Delete a 32 bit instruction.  */ | 
|  | +  /* FIXME: Not handled correctly.  */ | 
|  | +  HOWTO (R_RISCV_DELETE,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_DELETE",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (28), | 
|  | +  EMPTY_HOWTO (29), | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_CALL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_CALL_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Section displacement, used by an associated event location section.  */ | 
|  | +  HOWTO (R_RISCV_SCN_DISP,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_SCN_DISP",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_REL16,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 1,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_REL16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* These two are obsolete.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_ADD_IMMEDIATE), | 
|  | +  EMPTY_HOWTO (R_RISCV_PJUMP), | 
|  | + | 
|  | +  /* Similiar to R_RISCV_REL32, but used for relocations in a GOT section. | 
|  | +     It must be used for multigot GOT's (and only there).  */ | 
|  | +  HOWTO (R_RISCV_RELGOT,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_RELGOT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO(37), | 
|  | + | 
|  | +  /* TLS relocations.  */ | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPMOD32), | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_DTPREL32), | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPMOD64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPMOD64", /* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL64",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS general dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GD",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic variable reference.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_HI16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS local dynamic offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_DTPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_DTPREL_LO16",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOTTPREL,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_GOTTPREL",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  EMPTY_HOWTO (R_RISCV_TLS_TPREL32), | 
|  | + | 
|  | +  HOWTO (R_RISCV_TLS_TPREL64,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL64",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 MINUS_ONE,		/* src_mask */ | 
|  | +	 MINUS_ONE,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_HI16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* TLS thread pointer offset.  */ | 
|  | +  HOWTO (R_RISCV_TLS_TPREL_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,	/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_TLS_TPREL_LO16", /* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GOT_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GOT_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_GD_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_GD_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* High 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_HI16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BIGIMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_BIGIMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_HI16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 ((1<<RISCV_BIGIMM_BITS)-1) << OP_SH_BIGIMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* Low 16 bits of displacement in global offset table.  */ | 
|  | +  HOWTO (R_RISCV_TLS_LDM_LO16,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_IMM_BITS,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 OP_SH_IMMEDIATE,	/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_TLS_LDM_LO16",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 (RISCV_IMM_REACH-1) << OP_SH_IMMEDIATE,	/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | + | 
|  | +  /* 32 bit relocation with no addend.  */ | 
|  | +  HOWTO (R_RISCV_GLOB_DAT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 32,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GLOB_DAT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,			/* src_mask */ | 
|  | +	 0xffffffff,		/* dst_mask */ | 
|  | +	 FALSE),		/* pcrel_offset */ | 
|  | +}; | 
|  | + | 
|  | +/* GNU extension to record C++ vtable hierarchy */ | 
|  | +static reloc_howto_type elf_mips_gnu_vtinherit_howto = | 
|  | +  HOWTO (R_RISCV_GNU_VTINHERIT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 NULL,			/* special_function */ | 
|  | +	 "R_RISCV_GNU_VTINHERIT", /* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* GNU extension to record C++ vtable member usage */ | 
|  | +static reloc_howto_type elf_mips_gnu_vtentry_howto = | 
|  | +  HOWTO (R_RISCV_GNU_VTENTRY,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_dont, /* complain_on_overflow */ | 
|  | +	 _bfd_elf_rel_vtable_reloc_fn, /* special_function */ | 
|  | +	 "R_RISCV_GNU_VTENTRY",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 0,			/* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* 16 bit offset for pc-relative branches.  */ | 
|  | +static reloc_howto_type elf_mips_gnu_rel16_s2 = | 
|  | +  HOWTO (R_RISCV_GNU_REL16_S2,	/* type */ | 
|  | +	 RISCV_BRANCH_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BRANCH_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc, /* special_function */ | 
|  | +	 "R_RISCV_GNU_REL16_S2",	/* name */ | 
|  | +	 TRUE,			/* partial_inplace */ | 
|  | +	 RISCV_BRANCH_REACH-1,		/* src_mask */ | 
|  | +	 RISCV_BRANCH_REACH-1,		/* dst_mask */ | 
|  | +	 TRUE);			/* pcrel_offset */ | 
|  | + | 
|  | +/* 16 bit offset for pc-relative branches.  */ | 
|  | +static reloc_howto_type elf_mips_gnu_rela16_s2 = | 
|  | +  HOWTO (R_RISCV_GNU_REL16_S2,	/* type */ | 
|  | +	 RISCV_BRANCH_ALIGN_BITS,			/* rightshift */ | 
|  | +	 2,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 RISCV_BRANCH_BITS,			/* bitsize */ | 
|  | +	 TRUE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_signed, /* complain_on_overflow */ | 
|  | +	 _bfd_riscv_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_GNU_REL16_S2",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0,			/* src_mask */ | 
|  | +	 RISCV_BRANCH_REACH-1,		/* dst_mask */ | 
|  | +	 TRUE);			/* pcrel_offset */ | 
|  | + | 
|  | +/* Originally a VxWorks extension, but now used for other systems too.  */ | 
|  | +static reloc_howto_type elf_mips_copy_howto = | 
|  | +  HOWTO (R_RISCV_COPY,		/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 0,			/* this one is variable size */ | 
|  | +	 0,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_bitfield, /* complain_on_overflow */ | 
|  | +	 bfd_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_COPY",		/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,         		/* src_mask */ | 
|  | +	 0x0,		        /* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* Originally a VxWorks extension, but now used for other systems too.  */ | 
|  | +static reloc_howto_type elf_mips_jump_slot_howto = | 
|  | +  HOWTO (R_RISCV_JUMP_SLOT,	/* type */ | 
|  | +	 0,			/* rightshift */ | 
|  | +	 4,			/* size (0 = byte, 1 = short, 2 = long) */ | 
|  | +	 64,			/* bitsize */ | 
|  | +	 FALSE,			/* pc_relative */ | 
|  | +	 0,			/* bitpos */ | 
|  | +	 complain_overflow_bitfield, /* complain_on_overflow */ | 
|  | +	 bfd_elf_generic_reloc,	/* special_function */ | 
|  | +	 "R_RISCV_JUMP_SLOT",	/* name */ | 
|  | +	 FALSE,			/* partial_inplace */ | 
|  | +	 0x0,         		/* src_mask */ | 
|  | +	 0x0,		        /* dst_mask */ | 
|  | +	 FALSE);		/* pcrel_offset */ | 
|  | + | 
|  | +/* Swap in a MIPS 64-bit Rel reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_swap_reloc_in (bfd *abfd, const Elf64_Mips_External_Rel *src, | 
|  | +			  Elf64_Mips_Internal_Rela *dst) | 
|  | +{ | 
|  | +  dst->r_offset = H_GET_64 (abfd, src->r_offset); | 
|  | +  dst->r_sym = H_GET_32 (abfd, src->r_sym); | 
|  | +  dst->r_ssym = H_GET_8 (abfd, src->r_ssym); | 
|  | +  dst->r_type3 = H_GET_8 (abfd, src->r_type3); | 
|  | +  dst->r_type2 = H_GET_8 (abfd, src->r_type2); | 
|  | +  dst->r_type = H_GET_8 (abfd, src->r_type); | 
|  | +  dst->r_addend = 0; | 
|  | +} | 
|  | + | 
|  | +/* Swap in a MIPS 64-bit Rela reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_swap_reloca_in (bfd *abfd, const Elf64_Mips_External_Rela *src, | 
|  | +			   Elf64_Mips_Internal_Rela *dst) | 
|  | +{ | 
|  | +  dst->r_offset = H_GET_64 (abfd, src->r_offset); | 
|  | +  dst->r_sym = H_GET_32 (abfd, src->r_sym); | 
|  | +  dst->r_ssym = H_GET_8 (abfd, src->r_ssym); | 
|  | +  dst->r_type3 = H_GET_8 (abfd, src->r_type3); | 
|  | +  dst->r_type2 = H_GET_8 (abfd, src->r_type2); | 
|  | +  dst->r_type = H_GET_8 (abfd, src->r_type); | 
|  | +  dst->r_addend = H_GET_S64 (abfd, src->r_addend); | 
|  | +} | 
|  | + | 
|  | +/* Swap out a MIPS 64-bit Rel reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_swap_reloc_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src, | 
|  | +			   Elf64_Mips_External_Rel *dst) | 
|  | +{ | 
|  | +  H_PUT_64 (abfd, src->r_offset, dst->r_offset); | 
|  | +  H_PUT_32 (abfd, src->r_sym, dst->r_sym); | 
|  | +  H_PUT_8 (abfd, src->r_ssym, dst->r_ssym); | 
|  | +  H_PUT_8 (abfd, src->r_type3, dst->r_type3); | 
|  | +  H_PUT_8 (abfd, src->r_type2, dst->r_type2); | 
|  | +  H_PUT_8 (abfd, src->r_type, dst->r_type); | 
|  | +} | 
|  | + | 
|  | +/* Swap out a MIPS 64-bit Rela reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_swap_reloca_out (bfd *abfd, const Elf64_Mips_Internal_Rela *src, | 
|  | +			    Elf64_Mips_External_Rela *dst) | 
|  | +{ | 
|  | +  H_PUT_64 (abfd, src->r_offset, dst->r_offset); | 
|  | +  H_PUT_32 (abfd, src->r_sym, dst->r_sym); | 
|  | +  H_PUT_8 (abfd, src->r_ssym, dst->r_ssym); | 
|  | +  H_PUT_8 (abfd, src->r_type3, dst->r_type3); | 
|  | +  H_PUT_8 (abfd, src->r_type2, dst->r_type2); | 
|  | +  H_PUT_8 (abfd, src->r_type, dst->r_type); | 
|  | +  H_PUT_S64 (abfd, src->r_addend, dst->r_addend); | 
|  | +} | 
|  | + | 
|  | +/* Swap in a MIPS 64-bit Rel reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_be_swap_reloc_in (bfd *abfd, const bfd_byte *src, | 
|  | +			     Elf_Internal_Rela *dst) | 
|  | +{ | 
|  | +  Elf64_Mips_Internal_Rela mirel; | 
|  | + | 
|  | +  mips_elf64_swap_reloc_in (abfd, | 
|  | +			    (const Elf64_Mips_External_Rel *) src, | 
|  | +			    &mirel); | 
|  | + | 
|  | +  dst[0].r_offset = mirel.r_offset; | 
|  | +  dst[0].r_info = ELF64_R_INFO (mirel.r_sym, mirel.r_type); | 
|  | +  dst[0].r_addend = 0; | 
|  | +  dst[1].r_offset = mirel.r_offset; | 
|  | +  dst[1].r_info = ELF64_R_INFO (mirel.r_ssym, mirel.r_type2); | 
|  | +  dst[1].r_addend = 0; | 
|  | +  dst[2].r_offset = mirel.r_offset; | 
|  | +  dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirel.r_type3); | 
|  | +  dst[2].r_addend = 0; | 
|  | +} | 
|  | + | 
|  | +/* Swap in a MIPS 64-bit Rela reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_be_swap_reloca_in (bfd *abfd, const bfd_byte *src, | 
|  | +			      Elf_Internal_Rela *dst) | 
|  | +{ | 
|  | +  Elf64_Mips_Internal_Rela mirela; | 
|  | + | 
|  | +  mips_elf64_swap_reloca_in (abfd, | 
|  | +			     (const Elf64_Mips_External_Rela *) src, | 
|  | +			     &mirela); | 
|  | + | 
|  | +  dst[0].r_offset = mirela.r_offset; | 
|  | +  dst[0].r_info = ELF64_R_INFO (mirela.r_sym, mirela.r_type); | 
|  | +  dst[0].r_addend = mirela.r_addend; | 
|  | +  dst[1].r_offset = mirela.r_offset; | 
|  | +  dst[1].r_info = ELF64_R_INFO (mirela.r_ssym, mirela.r_type2); | 
|  | +  dst[1].r_addend = 0; | 
|  | +  dst[2].r_offset = mirela.r_offset; | 
|  | +  dst[2].r_info = ELF64_R_INFO (STN_UNDEF, mirela.r_type3); | 
|  | +  dst[2].r_addend = 0; | 
|  | +} | 
|  | + | 
|  | +/* Swap out a MIPS 64-bit Rel reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_be_swap_reloc_out (bfd *abfd, const Elf_Internal_Rela *src, | 
|  | +			      bfd_byte *dst) | 
|  | +{ | 
|  | +  Elf64_Mips_Internal_Rela mirel; | 
|  | + | 
|  | +  mirel.r_offset = src[0].r_offset; | 
|  | +  BFD_ASSERT(src[0].r_offset == src[1].r_offset); | 
|  | + | 
|  | +  mirel.r_type = ELF64_MIPS_R_TYPE (src[0].r_info); | 
|  | +  mirel.r_sym = ELF64_R_SYM (src[0].r_info); | 
|  | +  mirel.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info); | 
|  | +  mirel.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info); | 
|  | +  mirel.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info); | 
|  | + | 
|  | +  mips_elf64_swap_reloc_out (abfd, &mirel, | 
|  | +			     (Elf64_Mips_External_Rel *) dst); | 
|  | +} | 
|  | + | 
|  | +/* Swap out a MIPS 64-bit Rela reloc.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_be_swap_reloca_out (bfd *abfd, const Elf_Internal_Rela *src, | 
|  | +			       bfd_byte *dst) | 
|  | +{ | 
|  | +  Elf64_Mips_Internal_Rela mirela; | 
|  | + | 
|  | +  mirela.r_offset = src[0].r_offset; | 
|  | +  BFD_ASSERT(src[0].r_offset == src[1].r_offset); | 
|  | +  BFD_ASSERT(src[0].r_offset == src[2].r_offset); | 
|  | + | 
|  | +  mirela.r_type = ELF64_MIPS_R_TYPE (src[0].r_info); | 
|  | +  mirela.r_sym = ELF64_R_SYM (src[0].r_info); | 
|  | +  mirela.r_addend = src[0].r_addend; | 
|  | +  BFD_ASSERT(src[1].r_addend == 0); | 
|  | +  BFD_ASSERT(src[2].r_addend == 0); | 
|  | + | 
|  | +  mirela.r_type2 = ELF64_MIPS_R_TYPE (src[1].r_info); | 
|  | +  mirela.r_ssym = ELF64_MIPS_R_SSYM (src[1].r_info); | 
|  | +  mirela.r_type3 = ELF64_MIPS_R_TYPE (src[2].r_info); | 
|  | + | 
|  | +  mips_elf64_swap_reloca_out (abfd, &mirela, | 
|  | +			      (Elf64_Mips_External_Rela *) dst); | 
|  | +} | 
|  | + | 
|  | +/* Set the GP value for OUTPUT_BFD.  Returns FALSE if this is a | 
|  | +   dangerous relocation.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf64_assign_gp (bfd *output_bfd, bfd_vma *pgp) | 
|  | +{ | 
|  | +  unsigned int count; | 
|  | +  asymbol **sym; | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  /* If we've already figured out what GP will be, just return it.  */ | 
|  | +  *pgp = _bfd_get_gp_value (output_bfd); | 
|  | +  if (*pgp) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  count = bfd_get_symcount (output_bfd); | 
|  | +  sym = bfd_get_outsymbols (output_bfd); | 
|  | + | 
|  | +  /* The linker script will have created a symbol named `_gp' with the | 
|  | +     appropriate value.  */ | 
|  | +  if (sym == NULL) | 
|  | +    i = count; | 
|  | +  else | 
|  | +    { | 
|  | +      for (i = 0; i < count; i++, sym++) | 
|  | +	{ | 
|  | +	  register const char *name; | 
|  | + | 
|  | +	  name = bfd_asymbol_name (*sym); | 
|  | +	  if (*name == '_' && strcmp (name, "_gp") == 0) | 
|  | +	    { | 
|  | +	      *pgp = bfd_asymbol_value (*sym); | 
|  | +	      _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +	      break; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if (i >= count) | 
|  | +    { | 
|  | +      /* Only get the error once.  */ | 
|  | +      *pgp = 4; | 
|  | +      _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* We have to figure out the gp value, so that we can adjust the | 
|  | +   symbol value correctly.  We look up the symbol _gp in the output | 
|  | +   BFD.  If we can't find it, we're stuck.  We cache it in the ELF | 
|  | +   target data.  We don't need to adjust the symbol value for an | 
|  | +   external symbol if we are producing relocatable output.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf64_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable, | 
|  | +		     char **error_message, bfd_vma *pgp) | 
|  | +{ | 
|  | +  if (bfd_is_und_section (symbol->section) | 
|  | +      && ! relocatable) | 
|  | +    { | 
|  | +      *pgp = 0; | 
|  | +      return bfd_reloc_undefined; | 
|  | +    } | 
|  | + | 
|  | +  *pgp = _bfd_get_gp_value (output_bfd); | 
|  | +  if (*pgp == 0 | 
|  | +      && (! relocatable | 
|  | +	  || (symbol->flags & BSF_SECTION_SYM) != 0)) | 
|  | +    { | 
|  | +      if (relocatable) | 
|  | +	{ | 
|  | +	  /* Make up a value.  */ | 
|  | +	  *pgp = symbol->section->output_section->vma /*+ 0x4000*/; | 
|  | +	  _bfd_set_gp_value (output_bfd, *pgp); | 
|  | +	} | 
|  | +      else if (!mips_elf64_assign_gp (output_bfd, pgp)) | 
|  | +	{ | 
|  | +	  *error_message = | 
|  | +	    (char *) _("GP relative relocation when _gp not defined"); | 
|  | +	  return bfd_reloc_dangerous; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_GPREL16 relocation.  This is a 16 bit value which must | 
|  | +   become the offset from the gp register.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf64_gprel16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			  void *data, asection *input_section, bfd *output_bfd, | 
|  | +			  char **error_message) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  /* If we're relocating, and this is an external symbol, we don't want | 
|  | +     to change anything.  */ | 
|  | +  if (output_bfd != NULL | 
|  | +      && (symbol->flags & BSF_SECTION_SYM) == 0 | 
|  | +      && (symbol->flags & BSF_LOCAL) != 0) | 
|  | +    { | 
|  | +      reloc_entry->address += input_section->output_offset; | 
|  | +      return bfd_reloc_ok; | 
|  | +    } | 
|  | + | 
|  | +  if (output_bfd != NULL) | 
|  | +    relocatable = TRUE; | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | +    } | 
|  | + | 
|  | +  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message, | 
|  | +			     &gp); | 
|  | +  if (ret != bfd_reloc_ok) | 
|  | +    return ret; | 
|  | + | 
|  | +  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry, | 
|  | +					input_section, relocatable, | 
|  | +					data, gp); | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_LITERAL relocation.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf64_literal_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			  void *data, asection *input_section, bfd *output_bfd, | 
|  | +			  char **error_message) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  /* R_RISCV_LITERAL relocations are defined for local symbols only.  */ | 
|  | +  if (output_bfd != NULL | 
|  | +      && (symbol->flags & BSF_SECTION_SYM) == 0 | 
|  | +      && (symbol->flags & BSF_LOCAL) != 0) | 
|  | +    { | 
|  | +      *error_message = (char *) | 
|  | +	_("literal relocation occurs for an external symbol"); | 
|  | +      return bfd_reloc_outofrange; | 
|  | +    } | 
|  | + | 
|  | +  /* FIXME: The entries in the .lit8 and .lit4 sections should be merged.  */ | 
|  | +  if (output_bfd != NULL) | 
|  | +    relocatable = TRUE; | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | +    } | 
|  | + | 
|  | +  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, error_message, | 
|  | +			     &gp); | 
|  | +  if (ret != bfd_reloc_ok) | 
|  | +    return ret; | 
|  | + | 
|  | +  return _bfd_riscv_elf_gprel16_with_gp (abfd, symbol, reloc_entry, | 
|  | +					input_section, relocatable, | 
|  | +					data, gp); | 
|  | +} | 
|  | + | 
|  | +/* Do a R_RISCV_GPREL32 relocation.  This is a 32 bit value which must | 
|  | +   become the offset from the gp register.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf64_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			  void *data, asection *input_section, bfd *output_bfd, | 
|  | +			  char **error_message) | 
|  | +{ | 
|  | +  bfd_boolean relocatable; | 
|  | +  bfd_reloc_status_type ret; | 
|  | +  bfd_vma gp; | 
|  | +  bfd_vma relocation; | 
|  | +  bfd_vma val; | 
|  | + | 
|  | +  /* R_RISCV_GPREL32 relocations are defined for local symbols only.  */ | 
|  | +  if (output_bfd != NULL | 
|  | +      && (symbol->flags & BSF_SECTION_SYM) == 0 | 
|  | +      && (symbol->flags & BSF_LOCAL) != 0) | 
|  | +    { | 
|  | +      *error_message = (char *) | 
|  | +	_("32bits gp relative relocation occurs for an external symbol"); | 
|  | +      return bfd_reloc_outofrange; | 
|  | +    } | 
|  | + | 
|  | +  if (output_bfd != NULL) | 
|  | +    relocatable = TRUE; | 
|  | +  else | 
|  | +    { | 
|  | +      relocatable = FALSE; | 
|  | +      output_bfd = symbol->section->output_section->owner; | 
|  | +    } | 
|  | + | 
|  | +  ret = mips_elf64_final_gp (output_bfd, symbol, relocatable, | 
|  | +			     error_message, &gp); | 
|  | +  if (ret != bfd_reloc_ok) | 
|  | +    return ret; | 
|  | + | 
|  | +  if (bfd_is_com_section (symbol->section)) | 
|  | +    relocation = 0; | 
|  | +  else | 
|  | +    relocation = symbol->value; | 
|  | + | 
|  | +  relocation += symbol->section->output_section->vma; | 
|  | +  relocation += symbol->section->output_offset; | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  /* Set val to the offset into the section or symbol.  */ | 
|  | +  val = reloc_entry->addend; | 
|  | + | 
|  | +  if (reloc_entry->howto->partial_inplace) | 
|  | +    val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); | 
|  | + | 
|  | +  /* Adjust val for the final section location and GP value.  If we | 
|  | +     are producing relocatable output, we don't want to do this for | 
|  | +     an external symbol.  */ | 
|  | +  if (! relocatable | 
|  | +      || (symbol->flags & BSF_SECTION_SYM) != 0) | 
|  | +    val += relocation - gp; | 
|  | + | 
|  | +  if (reloc_entry->howto->partial_inplace) | 
|  | +    bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address); | 
|  | +  else | 
|  | +    reloc_entry->addend = val; | 
|  | + | 
|  | +  if (relocatable) | 
|  | +    reloc_entry->address += input_section->output_offset; | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* A mapping from BFD reloc types to MIPS ELF reloc types.  */ | 
|  | + | 
|  | +struct elf_reloc_map { | 
|  | +  bfd_reloc_code_real_type bfd_val; | 
|  | +  enum elf_riscv_reloc_type elf_val; | 
|  | +}; | 
|  | + | 
|  | +static const struct elf_reloc_map mips_reloc_map[] = | 
|  | +{ | 
|  | +  { BFD_RELOC_NONE, R_RISCV_NONE }, | 
|  | +  { BFD_RELOC_32, R_RISCV_32 }, | 
|  | +  /* There is no BFD reloc for R_RISCV_REL32.  */ | 
|  | +  { BFD_RELOC_64, R_RISCV_64 }, | 
|  | +  { BFD_RELOC_CTOR, R_RISCV_64 }, | 
|  | +  { BFD_RELOC_16_PCREL_S2, R_RISCV_PC16 }, | 
|  | +  { BFD_RELOC_HI16_S, R_RISCV_HI16 }, | 
|  | +  { BFD_RELOC_LO16, R_RISCV_LO16 }, | 
|  | +  { BFD_RELOC_GPREL16, R_RISCV_GPREL16 }, | 
|  | +  { BFD_RELOC_GPREL32, R_RISCV_GPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_JMP, R_RISCV_26 }, | 
|  | +  { BFD_RELOC_MIPS_LITERAL, R_RISCV_LITERAL }, | 
|  | +  { BFD_RELOC_MIPS_GOT16, R_RISCV_GOT16 }, | 
|  | +  { BFD_RELOC_MIPS_CALL16, R_RISCV_CALL16 }, | 
|  | +  { BFD_RELOC_MIPS_GOT_DISP, R_RISCV_GOT_DISP }, | 
|  | +  { BFD_RELOC_MIPS_GOT_HI16, R_RISCV_GOT_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_GOT_LO16, R_RISCV_GOT_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_SUB, R_RISCV_SUB }, | 
|  | +  { BFD_RELOC_MIPS_INSERT_A, R_RISCV_INSERT_A }, | 
|  | +  { BFD_RELOC_MIPS_INSERT_B, R_RISCV_INSERT_B }, | 
|  | +  { BFD_RELOC_MIPS_DELETE, R_RISCV_DELETE }, | 
|  | +  { BFD_RELOC_MIPS_CALL_HI16, R_RISCV_CALL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_CALL_LO16, R_RISCV_CALL_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_SCN_DISP, R_RISCV_SCN_DISP }, | 
|  | +  { BFD_RELOC_MIPS_REL16, R_RISCV_REL16 }, | 
|  | +  /* Use of R_RISCV_ADD_IMMEDIATE and R_RISCV_PJUMP is deprecated.  */ | 
|  | +  { BFD_RELOC_MIPS_RELGOT, R_RISCV_RELGOT }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPMOD32, R_RISCV_TLS_DTPMOD32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL32, R_RISCV_TLS_DTPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPMOD64, R_RISCV_TLS_DTPMOD64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL64, R_RISCV_TLS_DTPREL64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_GD, R_RISCV_TLS_GD }, | 
|  | +  { BFD_RELOC_MIPS_TLS_LDM, R_RISCV_TLS_LDM }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_RISCV_TLS_DTPREL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_RISCV_TLS_DTPREL_LO16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_GOTTPREL, R_RISCV_TLS_GOTTPREL }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL32, R_RISCV_TLS_TPREL32 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL64, R_RISCV_TLS_TPREL64 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_RISCV_TLS_TPREL_HI16 }, | 
|  | +  { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_RISCV_TLS_TPREL_LO16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_GOT_HI16, R_RISCV_TLS_GOT_HI16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_GOT_LO16, R_RISCV_TLS_GOT_LO16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_GD_HI16, R_RISCV_TLS_GD_HI16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_GD_LO16, R_RISCV_TLS_GD_LO16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_LDM_HI16, R_RISCV_TLS_LDM_HI16 }, | 
|  | +  { BFD_RELOC_RISCV_TLS_LDM_LO16, R_RISCV_TLS_LDM_LO16 } | 
|  | +}; | 
|  | + | 
|  | +/* Given a BFD reloc type, return a howto structure.  */ | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +bfd_elf64_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +				 bfd_reloc_code_real_type code) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | +  /* FIXME: We default to RELA here instead of choosing the right | 
|  | +     relocation variant.  */ | 
|  | +  reloc_howto_type *howto_table = mips_elf64_howto_table_rela; | 
|  | + | 
|  | +  for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map); | 
|  | +       i++) | 
|  | +    { | 
|  | +      if (mips_reloc_map[i].bfd_val == code) | 
|  | +	return &howto_table[(int) mips_reloc_map[i].elf_val]; | 
|  | +    } | 
|  | + | 
|  | +  switch (code) | 
|  | +    { | 
|  | +    case BFD_RELOC_VTABLE_INHERIT: | 
|  | +      return &elf_mips_gnu_vtinherit_howto; | 
|  | +    case BFD_RELOC_VTABLE_ENTRY: | 
|  | +      return &elf_mips_gnu_vtentry_howto; | 
|  | +    case BFD_RELOC_MIPS_COPY: | 
|  | +      return &elf_mips_copy_howto; | 
|  | +    case BFD_RELOC_MIPS_JUMP_SLOT: | 
|  | +      return &elf_mips_jump_slot_howto; | 
|  | +    default: | 
|  | +      bfd_set_error (bfd_error_bad_value); | 
|  | +      return NULL; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +bfd_elf64_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +				 const char *r_name) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  for (i = 0; | 
|  | +       i < (sizeof (mips_elf64_howto_table_rela) | 
|  | +	    / sizeof (mips_elf64_howto_table_rela[0])); i++) | 
|  | +    if (mips_elf64_howto_table_rela[i].name != NULL | 
|  | +	&& strcasecmp (mips_elf64_howto_table_rela[i].name, r_name) == 0) | 
|  | +      return &mips_elf64_howto_table_rela[i]; | 
|  | + | 
|  | +  if (strcasecmp (elf_mips_gnu_vtinherit_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_vtinherit_howto; | 
|  | +  if (strcasecmp (elf_mips_gnu_vtentry_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_vtentry_howto; | 
|  | +  if (strcasecmp (elf_mips_gnu_rel16_s2.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_rel16_s2; | 
|  | +  if (strcasecmp (elf_mips_gnu_rela16_s2.name, r_name) == 0) | 
|  | +    return &elf_mips_gnu_rela16_s2; | 
|  | +  if (strcasecmp (elf_mips_copy_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_copy_howto; | 
|  | +  if (strcasecmp (elf_mips_jump_slot_howto.name, r_name) == 0) | 
|  | +    return &elf_mips_jump_slot_howto; | 
|  | + | 
|  | +  return NULL; | 
|  | +} | 
|  | + | 
|  | +/* Given a MIPS Elf_Internal_Rel, fill in an arelent structure.  */ | 
|  | + | 
|  | +static reloc_howto_type * | 
|  | +mips_elf64_rtype_to_howto (unsigned int r_type, bfd_boolean rela_p) | 
|  | +{ | 
|  | +  switch (r_type) | 
|  | +    { | 
|  | +    case R_RISCV_GNU_VTINHERIT: | 
|  | +      return &elf_mips_gnu_vtinherit_howto; | 
|  | +    case R_RISCV_GNU_VTENTRY: | 
|  | +      return &elf_mips_gnu_vtentry_howto; | 
|  | +    case R_RISCV_GNU_REL16_S2: | 
|  | +      if (rela_p) | 
|  | +	return &elf_mips_gnu_rela16_s2; | 
|  | +      else | 
|  | +	return &elf_mips_gnu_rel16_s2; | 
|  | +    case R_RISCV_COPY: | 
|  | +      return &elf_mips_copy_howto; | 
|  | +    case R_RISCV_JUMP_SLOT: | 
|  | +      return &elf_mips_jump_slot_howto; | 
|  | +    default: | 
|  | +      BFD_ASSERT (r_type < (unsigned int) R_RISCV_max); | 
|  | +      if (rela_p) | 
|  | +	return &mips_elf64_howto_table_rela[r_type]; | 
|  | +      else | 
|  | +	return &mips_elf64_howto_table_rel[r_type]; | 
|  | +      break; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Prevent relocation handling by bfd for MIPS ELF64.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +			      arelent *cache_ptr ATTRIBUTE_UNUSED, | 
|  | +			      Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  BFD_ASSERT (0); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +			       arelent *cache_ptr ATTRIBUTE_UNUSED, | 
|  | +			       Elf_Internal_Rela *dst ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  BFD_ASSERT (0); | 
|  | +} | 
|  | + | 
|  | +/* Since each entry in an SHT_REL or SHT_RELA section can represent up | 
|  | +   to three relocs, we must tell the user to allocate more space.  */ | 
|  | + | 
|  | +static long | 
|  | +mips_elf64_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) | 
|  | +{ | 
|  | +  return (sec->reloc_count * 3 + 1) * sizeof (arelent *); | 
|  | +} | 
|  | + | 
|  | +static long | 
|  | +mips_elf64_get_dynamic_reloc_upper_bound (bfd *abfd) | 
|  | +{ | 
|  | +  return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3; | 
|  | +} | 
|  | + | 
|  | +/* We must also copy more relocations than the corresponding functions | 
|  | +   in elf.c would, so the two following functions are slightly | 
|  | +   modified from elf.c, that multiply the external relocation count by | 
|  | +   3 to obtain the internal relocation count.  */ | 
|  | + | 
|  | +static long | 
|  | +mips_elf64_canonicalize_reloc (bfd *abfd, sec_ptr section, | 
|  | +			       arelent **relptr, asymbol **symbols) | 
|  | +{ | 
|  | +  arelent *tblptr; | 
|  | +  unsigned int i; | 
|  | +  const struct elf_backend_data *bed = get_elf_backend_data (abfd); | 
|  | + | 
|  | +  if (! bed->s->slurp_reloc_table (abfd, section, symbols, FALSE)) | 
|  | +    return -1; | 
|  | + | 
|  | +  tblptr = section->relocation; | 
|  | +  for (i = 0; i < section->reloc_count * 3; i++) | 
|  | +    *relptr++ = tblptr++; | 
|  | + | 
|  | +  *relptr = NULL; | 
|  | + | 
|  | +  return section->reloc_count * 3; | 
|  | +} | 
|  | + | 
|  | +static long | 
|  | +mips_elf64_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, | 
|  | +				       asymbol **syms) | 
|  | +{ | 
|  | +  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); | 
|  | +  asection *s; | 
|  | +  long ret; | 
|  | + | 
|  | +  if (elf_dynsymtab (abfd) == 0) | 
|  | +    { | 
|  | +      bfd_set_error (bfd_error_invalid_operation); | 
|  | +      return -1; | 
|  | +    } | 
|  | + | 
|  | +  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; | 
|  | +  ret = 0; | 
|  | +  for (s = abfd->sections; s != NULL; s = s->next) | 
|  | +    { | 
|  | +      if (elf_section_data (s)->this_hdr.sh_link == elf_dynsymtab (abfd) | 
|  | +	  && (elf_section_data (s)->this_hdr.sh_type == SHT_REL | 
|  | +	      || elf_section_data (s)->this_hdr.sh_type == SHT_RELA)) | 
|  | +	{ | 
|  | +	  arelent *p; | 
|  | +	  long count, i; | 
|  | + | 
|  | +	  if (! (*slurp_relocs) (abfd, s, syms, TRUE)) | 
|  | +	    return -1; | 
|  | +	  count = s->size / elf_section_data (s)->this_hdr.sh_entsize * 3; | 
|  | +	  p = s->relocation; | 
|  | +	  for (i = 0; i < count; i++) | 
|  | +	    *storage++ = p++; | 
|  | +	  ret += count; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  *storage = NULL; | 
|  | + | 
|  | +  return ret; | 
|  | +} | 
|  | + | 
|  | +/* Read the relocations from one reloc section.  This is mostly copied | 
|  | +   from elfcode.h, except for the changes to expand one external | 
|  | +   relocation to 3 internal ones.  We must unfortunately set | 
|  | +   reloc_count to the number of external relocations, because a lot of | 
|  | +   generic code seems to depend on this.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf64_slurp_one_reloc_table (bfd *abfd, asection *asect, | 
|  | +				  Elf_Internal_Shdr *rel_hdr, | 
|  | +				  bfd_size_type reloc_count, | 
|  | +				  arelent *relents, asymbol **symbols, | 
|  | +				  bfd_boolean dynamic) | 
|  | +{ | 
|  | +  void *allocated; | 
|  | +  bfd_byte *native_relocs; | 
|  | +  arelent *relent; | 
|  | +  bfd_vma i; | 
|  | +  int entsize; | 
|  | +  bfd_boolean rela_p; | 
|  | + | 
|  | +  allocated = bfd_malloc (rel_hdr->sh_size); | 
|  | +  if (allocated == NULL) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0 | 
|  | +      || (bfd_bread (allocated, rel_hdr->sh_size, abfd) | 
|  | +	  != rel_hdr->sh_size)) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  native_relocs = allocated; | 
|  | + | 
|  | +  entsize = rel_hdr->sh_entsize; | 
|  | +  BFD_ASSERT (entsize == sizeof (Elf64_Mips_External_Rel) | 
|  | +	      || entsize == sizeof (Elf64_Mips_External_Rela)); | 
|  | + | 
|  | +  if (entsize == sizeof (Elf64_Mips_External_Rel)) | 
|  | +    rela_p = FALSE; | 
|  | +  else | 
|  | +    rela_p = TRUE; | 
|  | + | 
|  | +  for (i = 0, relent = relents; | 
|  | +       i < reloc_count; | 
|  | +       i++, native_relocs += entsize) | 
|  | +    { | 
|  | +      Elf64_Mips_Internal_Rela rela; | 
|  | +      bfd_boolean used_sym, used_ssym; | 
|  | +      int ir; | 
|  | + | 
|  | +      if (entsize == sizeof (Elf64_Mips_External_Rela)) | 
|  | +	mips_elf64_swap_reloca_in (abfd, | 
|  | +				   (Elf64_Mips_External_Rela *) native_relocs, | 
|  | +				   &rela); | 
|  | +      else | 
|  | +	mips_elf64_swap_reloc_in (abfd, | 
|  | +				  (Elf64_Mips_External_Rel *) native_relocs, | 
|  | +				  &rela); | 
|  | + | 
|  | +      /* Each entry represents exactly three actual relocations.  */ | 
|  | + | 
|  | +      used_sym = FALSE; | 
|  | +      used_ssym = FALSE; | 
|  | +      for (ir = 0; ir < 3; ir++) | 
|  | +	{ | 
|  | +	  enum elf_riscv_reloc_type type; | 
|  | + | 
|  | +	  switch (ir) | 
|  | +	    { | 
|  | +	    default: | 
|  | +	      abort (); | 
|  | +	    case 0: | 
|  | +	      type = (enum elf_riscv_reloc_type) rela.r_type; | 
|  | +	      break; | 
|  | +	    case 1: | 
|  | +	      type = (enum elf_riscv_reloc_type) rela.r_type2; | 
|  | +	      break; | 
|  | +	    case 2: | 
|  | +	      type = (enum elf_riscv_reloc_type) rela.r_type3; | 
|  | +	      break; | 
|  | +	    } | 
|  | + | 
|  | +	  /* Some types require symbols, whereas some do not.  */ | 
|  | +	  switch (type) | 
|  | +	    { | 
|  | +	    case R_RISCV_NONE: | 
|  | +	    case R_RISCV_LITERAL: | 
|  | +	    case R_RISCV_INSERT_A: | 
|  | +	    case R_RISCV_INSERT_B: | 
|  | +	    case R_RISCV_DELETE: | 
|  | +	      relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; | 
|  | +	      break; | 
|  | + | 
|  | +	    default: | 
|  | +	      if (! used_sym) | 
|  | +		{ | 
|  | +		  if (rela.r_sym == STN_UNDEF) | 
|  | +		    relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; | 
|  | +		  else | 
|  | +		    { | 
|  | +		      asymbol **ps, *s; | 
|  | + | 
|  | +		      ps = symbols + rela.r_sym - 1; | 
|  | +		      s = *ps; | 
|  | +		      if ((s->flags & BSF_SECTION_SYM) == 0) | 
|  | +			relent->sym_ptr_ptr = ps; | 
|  | +		      else | 
|  | +			relent->sym_ptr_ptr = s->section->symbol_ptr_ptr; | 
|  | +		    } | 
|  | + | 
|  | +		  used_sym = TRUE; | 
|  | +		} | 
|  | +	      else if (! used_ssym) | 
|  | +		{ | 
|  | +		  switch (rela.r_ssym) | 
|  | +		    { | 
|  | +		    case RSS_UNDEF: | 
|  | +		      relent->sym_ptr_ptr = | 
|  | +			bfd_abs_section_ptr->symbol_ptr_ptr; | 
|  | +		      break; | 
|  | + | 
|  | +		    case RSS_GP: | 
|  | +		    case RSS_GP0: | 
|  | +		    case RSS_LOC: | 
|  | +		      /* FIXME: I think these need to be handled using | 
|  | +			 special howto structures.  */ | 
|  | +		      BFD_ASSERT (0); | 
|  | +		      break; | 
|  | + | 
|  | +		    default: | 
|  | +		      BFD_ASSERT (0); | 
|  | +		      break; | 
|  | +		    } | 
|  | + | 
|  | +		  used_ssym = TRUE; | 
|  | +		} | 
|  | +	      else | 
|  | +		relent->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; | 
|  | + | 
|  | +	      break; | 
|  | +	    } | 
|  | + | 
|  | +	  /* The address of an ELF reloc is section relative for an | 
|  | +	     object file, and absolute for an executable file or | 
|  | +	     shared library.  The address of a BFD reloc is always | 
|  | +	     section relative.  */ | 
|  | +	  if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0 || dynamic) | 
|  | +	    relent->address = rela.r_offset; | 
|  | +	  else | 
|  | +	    relent->address = rela.r_offset - asect->vma; | 
|  | + | 
|  | +	  relent->addend = rela.r_addend; | 
|  | + | 
|  | +	  relent->howto = mips_elf64_rtype_to_howto (type, rela_p); | 
|  | + | 
|  | +	  ++relent; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  asect->reloc_count += (relent - relents) / 3; | 
|  | + | 
|  | +  if (allocated != NULL) | 
|  | +    free (allocated); | 
|  | + | 
|  | +  return TRUE; | 
|  | + | 
|  | + error_return: | 
|  | +  if (allocated != NULL) | 
|  | +    free (allocated); | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +/* Read the relocations.  On Irix 6, there can be two reloc sections | 
|  | +   associated with a single data section.  This is copied from | 
|  | +   elfcode.h as well, with changes as small as accounting for 3 | 
|  | +   internal relocs per external reloc and resetting reloc_count to | 
|  | +   zero before processing the relocs of a section.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf64_slurp_reloc_table (bfd *abfd, asection *asect, | 
|  | +			      asymbol **symbols, bfd_boolean dynamic) | 
|  | +{ | 
|  | +  struct bfd_elf_section_data * const d = elf_section_data (asect); | 
|  | +  Elf_Internal_Shdr *rel_hdr; | 
|  | +  Elf_Internal_Shdr *rel_hdr2; | 
|  | +  bfd_size_type reloc_count; | 
|  | +  bfd_size_type reloc_count2; | 
|  | +  arelent *relents; | 
|  | +  bfd_size_type amt; | 
|  | + | 
|  | +  if (asect->relocation != NULL) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  if (! dynamic) | 
|  | +    { | 
|  | +      if ((asect->flags & SEC_RELOC) == 0 | 
|  | +	  || asect->reloc_count == 0) | 
|  | +	return TRUE; | 
|  | + | 
|  | +      rel_hdr = d->rel.hdr; | 
|  | +      reloc_count = rel_hdr ? NUM_SHDR_ENTRIES (rel_hdr) : 0; | 
|  | +      rel_hdr2 = d->rela.hdr; | 
|  | +      reloc_count2 = (rel_hdr2 ? NUM_SHDR_ENTRIES (rel_hdr2) : 0); | 
|  | + | 
|  | +      BFD_ASSERT (asect->reloc_count == reloc_count + reloc_count2); | 
|  | +      BFD_ASSERT ((rel_hdr && asect->rel_filepos == rel_hdr->sh_offset) | 
|  | +		  || (rel_hdr2 && asect->rel_filepos == rel_hdr2->sh_offset)); | 
|  | + | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      /* Note that ASECT->RELOC_COUNT tends not to be accurate in this | 
|  | +	 case because relocations against this section may use the | 
|  | +	 dynamic symbol table, and in that case bfd_section_from_shdr | 
|  | +	 in elf.c does not update the RELOC_COUNT.  */ | 
|  | +      if (asect->size == 0) | 
|  | +	return TRUE; | 
|  | + | 
|  | +      rel_hdr = &d->this_hdr; | 
|  | +      reloc_count = NUM_SHDR_ENTRIES (rel_hdr); | 
|  | +      rel_hdr2 = NULL; | 
|  | +      reloc_count2 = 0; | 
|  | +    } | 
|  | + | 
|  | +  /* Allocate space for 3 arelent structures for each Rel structure.  */ | 
|  | +  amt = (reloc_count + reloc_count2) * 3 * sizeof (arelent); | 
|  | +  relents = bfd_alloc (abfd, amt); | 
|  | +  if (relents == NULL) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* The slurp_one_reloc_table routine increments reloc_count.  */ | 
|  | +  asect->reloc_count = 0; | 
|  | + | 
|  | +  if (rel_hdr != NULL | 
|  | +      && ! mips_elf64_slurp_one_reloc_table (abfd, asect, | 
|  | +					     rel_hdr, reloc_count, | 
|  | +					     relents, | 
|  | +					     symbols, dynamic)) | 
|  | +    return FALSE; | 
|  | +  if (rel_hdr2 != NULL | 
|  | +      && ! mips_elf64_slurp_one_reloc_table (abfd, asect, | 
|  | +					     rel_hdr2, reloc_count2, | 
|  | +					     relents + reloc_count * 3, | 
|  | +					     symbols, dynamic)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  asect->relocation = relents; | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Write out the relocations.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_write_relocs (bfd *abfd, asection *sec, void *data) | 
|  | +{ | 
|  | +  bfd_boolean *failedp = data; | 
|  | +  int count; | 
|  | +  Elf_Internal_Shdr *rel_hdr; | 
|  | +  unsigned int idx; | 
|  | + | 
|  | +  /* If we have already failed, don't do anything.  */ | 
|  | +  if (*failedp) | 
|  | +    return; | 
|  | + | 
|  | +  if ((sec->flags & SEC_RELOC) == 0) | 
|  | +    return; | 
|  | + | 
|  | +  /* The linker backend writes the relocs out itself, and sets the | 
|  | +     reloc_count field to zero to inhibit writing them here.  Also, | 
|  | +     sometimes the SEC_RELOC flag gets set even when there aren't any | 
|  | +     relocs.  */ | 
|  | +  if (sec->reloc_count == 0) | 
|  | +    return; | 
|  | + | 
|  | +  /* We can combine up to three relocs that refer to the same address | 
|  | +     if the latter relocs have no associated symbol.  */ | 
|  | +  count = 0; | 
|  | +  for (idx = 0; idx < sec->reloc_count; idx++) | 
|  | +    { | 
|  | +      bfd_vma addr; | 
|  | +      unsigned int i; | 
|  | + | 
|  | +      ++count; | 
|  | + | 
|  | +      addr = sec->orelocation[idx]->address; | 
|  | +      for (i = 0; i < 2; i++) | 
|  | +	{ | 
|  | +	  arelent *r; | 
|  | + | 
|  | +	  if (idx + 1 >= sec->reloc_count) | 
|  | +	    break; | 
|  | +	  r = sec->orelocation[idx + 1]; | 
|  | +	  if (r->address != addr | 
|  | +	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) | 
|  | +	      || (*r->sym_ptr_ptr)->value != 0) | 
|  | +	    break; | 
|  | + | 
|  | +	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */ | 
|  | + | 
|  | +	  ++idx; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  rel_hdr = _bfd_elf_single_rel_hdr (sec); | 
|  | + | 
|  | +  /* Do the actual relocation.  */ | 
|  | + | 
|  | +  if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rel)) | 
|  | +    mips_elf64_write_rel (abfd, sec, rel_hdr, &count, data); | 
|  | +  else if (rel_hdr->sh_entsize == sizeof(Elf64_Mips_External_Rela)) | 
|  | +    mips_elf64_write_rela (abfd, sec, rel_hdr, &count, data); | 
|  | +  else | 
|  | +    BFD_ASSERT (0); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_write_rel (bfd *abfd, asection *sec, | 
|  | +		      Elf_Internal_Shdr *rel_hdr, | 
|  | +		      int *count, void *data) | 
|  | +{ | 
|  | +  bfd_boolean *failedp = data; | 
|  | +  Elf64_Mips_External_Rel *ext_rel; | 
|  | +  unsigned int idx; | 
|  | +  asymbol *last_sym = 0; | 
|  | +  int last_sym_idx = 0; | 
|  | + | 
|  | +  rel_hdr->sh_size = rel_hdr->sh_entsize * *count; | 
|  | +  rel_hdr->contents = bfd_alloc (abfd, rel_hdr->sh_size); | 
|  | +  if (rel_hdr->contents == NULL) | 
|  | +    { | 
|  | +      *failedp = TRUE; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  ext_rel = (Elf64_Mips_External_Rel *) rel_hdr->contents; | 
|  | +  for (idx = 0; idx < sec->reloc_count; idx++, ext_rel++) | 
|  | +    { | 
|  | +      arelent *ptr; | 
|  | +      Elf64_Mips_Internal_Rela int_rel; | 
|  | +      asymbol *sym; | 
|  | +      int n; | 
|  | +      unsigned int i; | 
|  | + | 
|  | +      ptr = sec->orelocation[idx]; | 
|  | + | 
|  | +      /* The address of an ELF reloc is section relative for an object | 
|  | +	 file, and absolute for an executable file or shared library. | 
|  | +	 The address of a BFD reloc is always section relative.  */ | 
|  | +      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) | 
|  | +	int_rel.r_offset = ptr->address; | 
|  | +      else | 
|  | +	int_rel.r_offset = ptr->address + sec->vma; | 
|  | + | 
|  | +      sym = *ptr->sym_ptr_ptr; | 
|  | +      if (sym == last_sym) | 
|  | +	n = last_sym_idx; | 
|  | +      else if (bfd_is_abs_section (sym->section) && sym->value == 0) | 
|  | +	n = STN_UNDEF; | 
|  | +      else | 
|  | +	{ | 
|  | +	  last_sym = sym; | 
|  | +	  n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); | 
|  | +	  if (n < 0) | 
|  | +	    { | 
|  | +	      *failedp = TRUE; | 
|  | +	      return; | 
|  | +	    } | 
|  | +	  last_sym_idx = n; | 
|  | +	} | 
|  | + | 
|  | +      int_rel.r_sym = n; | 
|  | +      int_rel.r_ssym = RSS_UNDEF; | 
|  | + | 
|  | +      if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec | 
|  | +	  && ! _bfd_elf_validate_reloc (abfd, ptr)) | 
|  | +	{ | 
|  | +	  *failedp = TRUE; | 
|  | +	  return; | 
|  | +	} | 
|  | + | 
|  | +      int_rel.r_type = ptr->howto->type; | 
|  | +      int_rel.r_type2 = (int) R_RISCV_NONE; | 
|  | +      int_rel.r_type3 = (int) R_RISCV_NONE; | 
|  | + | 
|  | +      for (i = 0; i < 2; i++) | 
|  | +	{ | 
|  | +	  arelent *r; | 
|  | + | 
|  | +	  if (idx + 1 >= sec->reloc_count) | 
|  | +	    break; | 
|  | +	  r = sec->orelocation[idx + 1]; | 
|  | +	  if (r->address != ptr->address | 
|  | +	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) | 
|  | +	      || (*r->sym_ptr_ptr)->value != 0) | 
|  | +	    break; | 
|  | + | 
|  | +	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */ | 
|  | + | 
|  | +	  if (i == 0) | 
|  | +	    int_rel.r_type2 = r->howto->type; | 
|  | +	  else | 
|  | +	    int_rel.r_type3 = r->howto->type; | 
|  | + | 
|  | +	  ++idx; | 
|  | +	} | 
|  | + | 
|  | +      mips_elf64_swap_reloc_out (abfd, &int_rel, ext_rel); | 
|  | +    } | 
|  | + | 
|  | +  BFD_ASSERT (ext_rel - (Elf64_Mips_External_Rel *) rel_hdr->contents | 
|  | +	      == *count); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +mips_elf64_write_rela (bfd *abfd, asection *sec, | 
|  | +		       Elf_Internal_Shdr *rela_hdr, | 
|  | +		       int *count, void *data) | 
|  | +{ | 
|  | +  bfd_boolean *failedp = data; | 
|  | +  Elf64_Mips_External_Rela *ext_rela; | 
|  | +  unsigned int idx; | 
|  | +  asymbol *last_sym = 0; | 
|  | +  int last_sym_idx = 0; | 
|  | + | 
|  | +  rela_hdr->sh_size = rela_hdr->sh_entsize * *count; | 
|  | +  rela_hdr->contents = bfd_alloc (abfd, rela_hdr->sh_size); | 
|  | +  if (rela_hdr->contents == NULL) | 
|  | +    { | 
|  | +      *failedp = TRUE; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  ext_rela = (Elf64_Mips_External_Rela *) rela_hdr->contents; | 
|  | +  for (idx = 0; idx < sec->reloc_count; idx++, ext_rela++) | 
|  | +    { | 
|  | +      arelent *ptr; | 
|  | +      Elf64_Mips_Internal_Rela int_rela; | 
|  | +      asymbol *sym; | 
|  | +      int n; | 
|  | +      unsigned int i; | 
|  | + | 
|  | +      ptr = sec->orelocation[idx]; | 
|  | + | 
|  | +      /* The address of an ELF reloc is section relative for an object | 
|  | +	 file, and absolute for an executable file or shared library. | 
|  | +	 The address of a BFD reloc is always section relative.  */ | 
|  | +      if ((abfd->flags & (EXEC_P | DYNAMIC)) == 0) | 
|  | +	int_rela.r_offset = ptr->address; | 
|  | +      else | 
|  | +	int_rela.r_offset = ptr->address + sec->vma; | 
|  | + | 
|  | +      sym = *ptr->sym_ptr_ptr; | 
|  | +      if (sym == last_sym) | 
|  | +	n = last_sym_idx; | 
|  | +      else if (bfd_is_abs_section (sym->section) && sym->value == 0) | 
|  | +	n = STN_UNDEF; | 
|  | +      else | 
|  | +	{ | 
|  | +	  last_sym = sym; | 
|  | +	  n = _bfd_elf_symbol_from_bfd_symbol (abfd, &sym); | 
|  | +	  if (n < 0) | 
|  | +	    { | 
|  | +	      *failedp = TRUE; | 
|  | +	      return; | 
|  | +	    } | 
|  | +	  last_sym_idx = n; | 
|  | +	} | 
|  | + | 
|  | +      int_rela.r_sym = n; | 
|  | +      int_rela.r_addend = ptr->addend; | 
|  | +      int_rela.r_ssym = RSS_UNDEF; | 
|  | + | 
|  | +      if ((*ptr->sym_ptr_ptr)->the_bfd->xvec != abfd->xvec | 
|  | +	  && ! _bfd_elf_validate_reloc (abfd, ptr)) | 
|  | +	{ | 
|  | +	  *failedp = TRUE; | 
|  | +	  return; | 
|  | +	} | 
|  | + | 
|  | +      int_rela.r_type = ptr->howto->type; | 
|  | +      int_rela.r_type2 = (int) R_RISCV_NONE; | 
|  | +      int_rela.r_type3 = (int) R_RISCV_NONE; | 
|  | + | 
|  | +      for (i = 0; i < 2; i++) | 
|  | +	{ | 
|  | +	  arelent *r; | 
|  | + | 
|  | +	  if (idx + 1 >= sec->reloc_count) | 
|  | +	    break; | 
|  | +	  r = sec->orelocation[idx + 1]; | 
|  | +	  if (r->address != ptr->address | 
|  | +	      || ! bfd_is_abs_section ((*r->sym_ptr_ptr)->section) | 
|  | +	      || (*r->sym_ptr_ptr)->value != 0) | 
|  | +	    break; | 
|  | + | 
|  | +	  /* We can merge the reloc at IDX + 1 with the reloc at IDX.  */ | 
|  | + | 
|  | +	  if (i == 0) | 
|  | +	    int_rela.r_type2 = r->howto->type; | 
|  | +	  else | 
|  | +	    int_rela.r_type3 = r->howto->type; | 
|  | + | 
|  | +	  ++idx; | 
|  | +	} | 
|  | + | 
|  | +      mips_elf64_swap_reloca_out (abfd, &int_rela, ext_rela); | 
|  | +    } | 
|  | + | 
|  | +  BFD_ASSERT (ext_rela - (Elf64_Mips_External_Rela *) rela_hdr->contents | 
|  | +	      == *count); | 
|  | +} | 
|  | + | 
|  | +/* Set the right machine number for a MIPS ELF file.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf64_object_p (bfd *abfd) | 
|  | +{ | 
|  | +  unsigned long mach; | 
|  | + | 
|  | +  mach = _bfd_elf_riscv_mach (elf_elfheader (abfd)->e_flags); | 
|  | +  bfd_default_set_arch_mach (abfd, bfd_arch_riscv, mach); | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Support for core dump NOTE sections.  */ | 
|  | +static bfd_boolean | 
|  | +elf64_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) | 
|  | +{ | 
|  | +  int offset; | 
|  | +  unsigned int size; | 
|  | + | 
|  | +  switch (note->descsz) | 
|  | +    { | 
|  | +      default: | 
|  | +	return FALSE; | 
|  | + | 
|  | +      case 480:		/* Linux/MIPS - N64 kernel */ | 
|  | +	/* pr_cursig */ | 
|  | +	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); | 
|  | + | 
|  | +	/* pr_pid */ | 
|  | +	elf_tdata (abfd)->core_lwpid = bfd_get_32 (abfd, note->descdata + 32); | 
|  | + | 
|  | +	/* pr_reg */ | 
|  | +	offset = 112; | 
|  | +	size = 360; | 
|  | + | 
|  | +	break; | 
|  | +    } | 
|  | + | 
|  | +  /* Make a ".reg/999" section.  */ | 
|  | +  return _bfd_elfcore_make_pseudosection (abfd, ".reg", | 
|  | +					  size, note->descpos + offset); | 
|  | +} | 
|  | + | 
|  | +static bfd_boolean | 
|  | +elf64_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) | 
|  | +{ | 
|  | +  switch (note->descsz) | 
|  | +    { | 
|  | +      default: | 
|  | +	return FALSE; | 
|  | + | 
|  | +      case 136:		/* Linux/MIPS - N64 kernel elf_prpsinfo */ | 
|  | +	elf_tdata (abfd)->core_program | 
|  | +	 = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); | 
|  | +	elf_tdata (abfd)->core_command | 
|  | +	 = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); | 
|  | +    } | 
|  | + | 
|  | +  /* Note that for some reason, a spurious space is tacked | 
|  | +     onto the end of the args in some (at least one anyway) | 
|  | +     implementations, so strip it off if it exists.  */ | 
|  | + | 
|  | +  { | 
|  | +    char *command = elf_tdata (abfd)->core_command; | 
|  | +    int n = strlen (command); | 
|  | + | 
|  | +    if (0 < n && command[n - 1] == ' ') | 
|  | +      command[n - 1] = '\0'; | 
|  | +  } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* ECOFF swapping routines.  These are used when dealing with the | 
|  | +   .mdebug section, which is in the ECOFF debugging format.  */ | 
|  | +static const struct ecoff_debug_swap mips_elf64_ecoff_debug_swap = | 
|  | +{ | 
|  | +  /* Symbol table magic number.  */ | 
|  | +  magicSym2, | 
|  | +  /* Alignment of debugging information.  E.g., 4.  */ | 
|  | +  8, | 
|  | +  /* Sizes of external symbolic information.  */ | 
|  | +  sizeof (struct hdr_ext), | 
|  | +  sizeof (struct dnr_ext), | 
|  | +  sizeof (struct pdr_ext), | 
|  | +  sizeof (struct sym_ext), | 
|  | +  sizeof (struct opt_ext), | 
|  | +  sizeof (struct fdr_ext), | 
|  | +  sizeof (struct rfd_ext), | 
|  | +  sizeof (struct ext_ext), | 
|  | +  /* Functions to swap in external symbolic data.  */ | 
|  | +  ecoff_swap_hdr_in, | 
|  | +  ecoff_swap_dnr_in, | 
|  | +  ecoff_swap_pdr_in, | 
|  | +  ecoff_swap_sym_in, | 
|  | +  ecoff_swap_opt_in, | 
|  | +  ecoff_swap_fdr_in, | 
|  | +  ecoff_swap_rfd_in, | 
|  | +  ecoff_swap_ext_in, | 
|  | +  _bfd_ecoff_swap_tir_in, | 
|  | +  _bfd_ecoff_swap_rndx_in, | 
|  | +  /* Functions to swap out external symbolic data.  */ | 
|  | +  ecoff_swap_hdr_out, | 
|  | +  ecoff_swap_dnr_out, | 
|  | +  ecoff_swap_pdr_out, | 
|  | +  ecoff_swap_sym_out, | 
|  | +  ecoff_swap_opt_out, | 
|  | +  ecoff_swap_fdr_out, | 
|  | +  ecoff_swap_rfd_out, | 
|  | +  ecoff_swap_ext_out, | 
|  | +  _bfd_ecoff_swap_tir_out, | 
|  | +  _bfd_ecoff_swap_rndx_out, | 
|  | +  /* Function to read in symbolic data.  */ | 
|  | +  _bfd_riscv_elf_read_ecoff_info | 
|  | +}; | 
|  | + | 
|  | +/* Relocations in the 64 bit MIPS ELF ABI are more complex than in | 
|  | +   standard ELF.  This structure is used to redirect the relocation | 
|  | +   handling routines.  */ | 
|  | + | 
|  | +const struct elf_size_info mips_elf64_size_info = | 
|  | +{ | 
|  | +  sizeof (Elf64_External_Ehdr), | 
|  | +  sizeof (Elf64_External_Phdr), | 
|  | +  sizeof (Elf64_External_Shdr), | 
|  | +  sizeof (Elf64_Mips_External_Rel), | 
|  | +  sizeof (Elf64_Mips_External_Rela), | 
|  | +  sizeof (Elf64_External_Sym), | 
|  | +  sizeof (Elf64_External_Dyn), | 
|  | +  sizeof (Elf_External_Note), | 
|  | +  4,		/* hash-table entry size */ | 
|  | +  3,		/* internal relocations per external relocations */ | 
|  | +  64,		/* arch_size */ | 
|  | +  3,		/* log_file_align */ | 
|  | +  ELFCLASS64, | 
|  | +  EV_CURRENT, | 
|  | +  bfd_elf64_write_out_phdrs, | 
|  | +  bfd_elf64_write_shdrs_and_ehdr, | 
|  | +  bfd_elf64_checksum_contents, | 
|  | +  mips_elf64_write_relocs, | 
|  | +  bfd_elf64_swap_symbol_in, | 
|  | +  bfd_elf64_swap_symbol_out, | 
|  | +  mips_elf64_slurp_reloc_table, | 
|  | +  bfd_elf64_slurp_symbol_table, | 
|  | +  bfd_elf64_swap_dyn_in, | 
|  | +  bfd_elf64_swap_dyn_out, | 
|  | +  mips_elf64_be_swap_reloc_in, | 
|  | +  mips_elf64_be_swap_reloc_out, | 
|  | +  mips_elf64_be_swap_reloca_in, | 
|  | +  mips_elf64_be_swap_reloca_out | 
|  | +}; | 
|  | + | 
|  | +#define ELF_ARCH			bfd_arch_riscv | 
|  | +#define ELF_TARGET_ID			MIPS_ELF_DATA | 
|  | +#define ELF_MACHINE_CODE		EM_RISCV | 
|  | + | 
|  | +#define elf_backend_collect		TRUE | 
|  | +#define elf_backend_type_change_ok	TRUE | 
|  | +#define elf_backend_can_gc_sections	TRUE | 
|  | +#define elf_info_to_howto		mips_elf64_info_to_howto_rela | 
|  | +#define elf_info_to_howto_rel		mips_elf64_info_to_howto_rel | 
|  | +#define elf_backend_object_p		mips_elf64_object_p | 
|  | +#define elf_backend_symbol_processing	_bfd_riscv_elf_symbol_processing | 
|  | +#define elf_backend_section_processing	_bfd_riscv_elf_section_processing | 
|  | +#define elf_backend_section_from_shdr	_bfd_riscv_elf_section_from_shdr | 
|  | +#define elf_backend_fake_sections	_bfd_riscv_elf_fake_sections | 
|  | +#define elf_backend_section_from_bfd_section \ | 
|  | +				_bfd_riscv_elf_section_from_bfd_section | 
|  | +#define elf_backend_add_symbol_hook	_bfd_riscv_elf_add_symbol_hook | 
|  | +#define elf_backend_link_output_symbol_hook \ | 
|  | +				_bfd_riscv_elf_link_output_symbol_hook | 
|  | +#define elf_backend_create_dynamic_sections \ | 
|  | +				_bfd_riscv_elf_create_dynamic_sections | 
|  | +#define elf_backend_check_relocs	_bfd_riscv_elf_check_relocs | 
|  | +#define elf_backend_merge_symbol_attribute \ | 
|  | +				_bfd_riscv_elf_merge_symbol_attribute | 
|  | +#define elf_backend_get_target_dtag	_bfd_riscv_elf_get_target_dtag | 
|  | +#define elf_backend_adjust_dynamic_symbol \ | 
|  | +				_bfd_riscv_elf_adjust_dynamic_symbol | 
|  | +#define elf_backend_always_size_sections \ | 
|  | +				_bfd_riscv_elf_always_size_sections | 
|  | +#define elf_backend_size_dynamic_sections \ | 
|  | +				_bfd_riscv_elf_size_dynamic_sections | 
|  | +#define elf_backend_init_index_section	_bfd_elf_init_1_index_section | 
|  | +#define elf_backend_relocate_section    _bfd_riscv_elf_relocate_section | 
|  | +#define elf_backend_finish_dynamic_symbol \ | 
|  | +				_bfd_riscv_elf_finish_dynamic_symbol | 
|  | +#define elf_backend_finish_dynamic_sections \ | 
|  | +				_bfd_riscv_elf_finish_dynamic_sections | 
|  | +#define elf_backend_final_write_processing \ | 
|  | +				_bfd_riscv_elf_final_write_processing | 
|  | +#define elf_backend_additional_program_headers \ | 
|  | +				_bfd_riscv_elf_additional_program_headers | 
|  | +#define elf_backend_modify_segment_map	_bfd_riscv_elf_modify_segment_map | 
|  | +#define elf_backend_gc_mark_hook	_bfd_riscv_elf_gc_mark_hook | 
|  | +#define elf_backend_gc_sweep_hook	_bfd_riscv_elf_gc_sweep_hook | 
|  | +#define elf_backend_copy_indirect_symbol \ | 
|  | +					_bfd_riscv_elf_copy_indirect_symbol | 
|  | +#define elf_backend_ignore_discarded_relocs \ | 
|  | +					_bfd_riscv_elf_ignore_discarded_relocs | 
|  | +#define elf_backend_mips_rtype_to_howto	mips_elf64_rtype_to_howto | 
|  | +#define elf_backend_ecoff_debug_swap	&mips_elf64_ecoff_debug_swap | 
|  | +#define elf_backend_size_info		mips_elf64_size_info | 
|  | + | 
|  | +#define elf_backend_grok_prstatus	elf64_mips_grok_prstatus | 
|  | +#define elf_backend_grok_psinfo		elf64_mips_grok_psinfo | 
|  | + | 
|  | +#define elf_backend_got_header_size	(4 * MIPS_RESERVED_GOTNO) | 
|  | + | 
|  | +/* MIPS ELF64 can use a mixture of REL and RELA, but some Relocations | 
|  | +   work better/work only in RELA, so we default to this.  */ | 
|  | +#define elf_backend_may_use_rel_p	1 | 
|  | +#define elf_backend_may_use_rela_p	1 | 
|  | +#define elf_backend_default_use_rela_p	1 | 
|  | +#define elf_backend_rela_plts_and_copies_p 0 | 
|  | +#define elf_backend_plt_readonly	1 | 
|  | +#define elf_backend_plt_sym_val		_bfd_riscv_elf_plt_sym_val | 
|  | + | 
|  | +#define elf_backend_sign_extend_vma	TRUE | 
|  | + | 
|  | +#define elf_backend_write_section	_bfd_riscv_elf_write_section | 
|  | + | 
|  | +/* We don't set bfd_elf64_bfd_is_local_label_name because the 32-bit | 
|  | +   MIPS-specific function only applies to IRIX5, which had no 64-bit | 
|  | +   ABI.  */ | 
|  | +#define bfd_elf64_find_nearest_line	_bfd_riscv_elf_find_nearest_line | 
|  | +#define bfd_elf64_find_inliner_info	_bfd_riscv_elf_find_inliner_info | 
|  | +#define bfd_elf64_new_section_hook	_bfd_riscv_elf_new_section_hook | 
|  | +#define bfd_elf64_set_section_contents	_bfd_riscv_elf_set_section_contents | 
|  | +#define bfd_elf64_bfd_get_relocated_section_contents \ | 
|  | +				_bfd_elf_riscv_get_relocated_section_contents | 
|  | +#define bfd_elf64_bfd_link_hash_table_create \ | 
|  | +				_bfd_riscv_elf_link_hash_table_create | 
|  | +#define bfd_elf64_bfd_final_link	_bfd_riscv_elf_final_link | 
|  | +#define bfd_elf64_bfd_merge_private_bfd_data \ | 
|  | +				_bfd_riscv_elf_merge_private_bfd_data | 
|  | +#define bfd_elf64_bfd_set_private_flags	_bfd_riscv_elf_set_private_flags | 
|  | +#define bfd_elf64_bfd_print_private_bfd_data \ | 
|  | +				_bfd_riscv_elf_print_private_bfd_data | 
|  | + | 
|  | +#define bfd_elf64_get_reloc_upper_bound mips_elf64_get_reloc_upper_bound | 
|  | +#define bfd_elf64_canonicalize_reloc mips_elf64_canonicalize_reloc | 
|  | +#define bfd_elf64_get_dynamic_reloc_upper_bound mips_elf64_get_dynamic_reloc_upper_bound | 
|  | +#define bfd_elf64_canonicalize_dynamic_reloc mips_elf64_canonicalize_dynamic_reloc | 
|  | +#define bfd_elf64_bfd_relax_section     _bfd_riscv_relax_section | 
|  | + | 
|  | +/* MIPS ELF64 archive functions.  */ | 
|  | +#define bfd_elf64_archive_functions | 
|  | +extern bfd_boolean bfd_elf64_archive_slurp_armap | 
|  | +  (bfd *); | 
|  | +extern bfd_boolean bfd_elf64_archive_write_armap | 
|  | +  (bfd *, unsigned int, struct orl *, unsigned int, int); | 
|  | +#define bfd_elf64_archive_slurp_extended_name_table \ | 
|  | +			_bfd_archive_coff_slurp_extended_name_table | 
|  | +#define bfd_elf64_archive_construct_extended_name_table \ | 
|  | +			_bfd_archive_coff_construct_extended_name_table | 
|  | +#define bfd_elf64_archive_truncate_arname \ | 
|  | +			_bfd_archive_coff_truncate_arname | 
|  | +#define bfd_elf64_archive_read_ar_hdr	_bfd_archive_coff_read_ar_hdr | 
|  | +#define bfd_elf64_archive_write_ar_hdr	_bfd_archive_coff_write_ar_hdr | 
|  | +#define bfd_elf64_archive_openr_next_archived_file \ | 
|  | +			_bfd_archive_coff_openr_next_archived_file | 
|  | +#define bfd_elf64_archive_get_elt_at_index \ | 
|  | +			_bfd_archive_coff_get_elt_at_index | 
|  | +#define bfd_elf64_archive_generic_stat_arch_elt \ | 
|  | +			_bfd_archive_coff_generic_stat_arch_elt | 
|  | +#define bfd_elf64_archive_update_armap_timestamp \ | 
|  | +			_bfd_archive_coff_update_armap_timestamp | 
|  | + | 
|  | +/* The SGI style (n)64 NewABI.  */ | 
|  | +#define TARGET_LITTLE_SYM		bfd_elf64_littleriscv_vec | 
|  | +#define TARGET_LITTLE_NAME		"elf64-littleriscv" | 
|  | +#define TARGET_BIG_SYM			bfd_elf64_bigriscv_vec | 
|  | +#define TARGET_BIG_NAME			"elf64-bigriscv" | 
|  | + | 
|  | +#define ELF_MAXPAGESIZE			0x10000 | 
|  | +#define ELF_COMMONPAGESIZE		0x1000 | 
|  | + | 
|  | +#include "elf64-target.h" | 
|  | diff -ruN binutils-2.24/bfd/elfxx-riscv.c binutils-2.24-riscv/bfd/elfxx-riscv.c | 
|  | --- binutils-2.24/bfd/elfxx-riscv.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/elfxx-riscv.c	2014-12-02 16:05:44.909434942 -0800 | 
|  | @@ -0,0 +1,7387 @@ | 
|  | +/* MIPS-specific support for ELF | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | 
|  | +   2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. | 
|  | + | 
|  | +   Most of the information added by Ian Lance Taylor, Cygnus Support, | 
|  | +   <ian@cygnus.com>. | 
|  | +   N32/64 ABI support added by Mark Mitchell, CodeSourcery, LLC. | 
|  | +   <mark@codesourcery.com> | 
|  | +   Traditional MIPS targets support added by Koundinya.K, Dansk Data | 
|  | +   Elektronik & Operations Research Group. <kk@ddeorg.soft.net> | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | + | 
|  | +/* This file handles functionality common to the different MIPS ABI's.  */ | 
|  | + | 
|  | +#include "sysdep.h" | 
|  | +#include "bfd.h" | 
|  | +#include "libbfd.h" | 
|  | +#include "libiberty.h" | 
|  | +#include "elf-bfd.h" | 
|  | +#include "elfxx-riscv.h" | 
|  | +#include "elf/riscv.h" | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +/* Get the ECOFF swapping routines.  */ | 
|  | +#include "coff/sym.h" | 
|  | +#include "coff/symconst.h" | 
|  | +#include "coff/ecoff.h" | 
|  | +#include "coff/mips.h" | 
|  | + | 
|  | +#include "hashtab.h" | 
|  | + | 
|  | +/* This structure is used to hold information about one GOT entry. | 
|  | +   There are three types of entry: | 
|  | + | 
|  | +      (1) absolute addresses | 
|  | +	    (abfd == NULL) | 
|  | +      (2) SYMBOL + OFFSET addresses, where SYMBOL is local to an input bfd | 
|  | +	    (abfd != NULL, symndx >= 0) | 
|  | +      (3) SYMBOL addresses, where SYMBOL is not local to an input bfd | 
|  | +	    (abfd != NULL, symndx == -1) | 
|  | + | 
|  | +   Type (3) entries are treated differently for different types of GOT. | 
|  | +   In the "master" GOT -- i.e.  the one that describes every GOT | 
|  | +   reference needed in the link -- the mips_got_entry is keyed on both | 
|  | +   the symbol and the input bfd that references it.  If it turns out | 
|  | +   that we need multiple GOTs, we can then use this information to | 
|  | +   create separate GOTs for each input bfd. | 
|  | + | 
|  | +   However, we want each of these separate GOTs to have at most one | 
|  | +   entry for a given symbol, so their type (3) entries are keyed only | 
|  | +   on the symbol.  The input bfd given by the "abfd" field is somewhat | 
|  | +   arbitrary in this case. | 
|  | + | 
|  | +   This means that when there are multiple GOTs, each GOT has a unique | 
|  | +   mips_got_entry for every symbol within it.  We can therefore use the | 
|  | +   mips_got_entry fields (tls_type and gotidx) to track the symbol's | 
|  | +   GOT index. | 
|  | + | 
|  | +   However, if it turns out that we need only a single GOT, we continue | 
|  | +   to use the master GOT to describe it.  There may therefore be several | 
|  | +   mips_got_entries for the same symbol, each with a different input bfd. | 
|  | +   We want to make sure that each symbol gets a unique GOT entry, so when | 
|  | +   there's a single GOT, we use the symbol's hash entry, not the | 
|  | +   mips_got_entry fields, to track a symbol's GOT index.  */ | 
|  | +struct mips_got_entry | 
|  | +{ | 
|  | +  /* The input bfd in which the symbol is defined.  */ | 
|  | +  bfd *abfd; | 
|  | +  /* The index of the symbol, as stored in the relocation r_info, if | 
|  | +     we have a local symbol; -1 otherwise.  */ | 
|  | +  long symndx; | 
|  | +  union | 
|  | +  { | 
|  | +    /* If abfd == NULL, an address that must be stored in the got.  */ | 
|  | +    bfd_vma address; | 
|  | +    /* If abfd != NULL && symndx != -1, the addend of the relocation | 
|  | +       that should be added to the symbol value.  */ | 
|  | +    bfd_vma addend; | 
|  | +    /* If abfd != NULL && symndx == -1, the hash table entry | 
|  | +       corresponding to symbol in the GOT.  The symbol's entry | 
|  | +       is in the local area if h->global_got_area is GGA_NONE, | 
|  | +       otherwise it is in the global area.  */ | 
|  | +    struct mips_elf_link_hash_entry *h; | 
|  | +  } d; | 
|  | + | 
|  | +  /* The TLS types included in this GOT entry (specifically, GD and | 
|  | +     IE).  The GD and IE flags can be added as we encounter new | 
|  | +     relocations.  LDM can also be set; it will always be alone, not | 
|  | +     combined with any GD or IE flags.  An LDM GOT entry will be | 
|  | +     a local symbol entry with r_symndx == 0.  */ | 
|  | +  unsigned char tls_type; | 
|  | + | 
|  | +  /* The offset from the beginning of the .got section to the entry | 
|  | +     corresponding to this symbol+addend.  If it's a global symbol | 
|  | +     whose offset is yet to be decided, it's going to be -1.  */ | 
|  | +  long gotidx; | 
|  | +}; | 
|  | + | 
|  | +/* This structure describes a range of addends: [MIN_ADDEND, MAX_ADDEND]. | 
|  | +   The structures form a non-overlapping list that is sorted by increasing | 
|  | +   MIN_ADDEND.  */ | 
|  | +struct mips_got_page_range | 
|  | +{ | 
|  | +  struct mips_got_page_range *next; | 
|  | +  bfd_signed_vma min_addend; | 
|  | +  bfd_signed_vma max_addend; | 
|  | +}; | 
|  | + | 
|  | +/* This structure describes the range of addends that are applied to page | 
|  | +   relocations against a given symbol.  */ | 
|  | +struct mips_got_page_entry | 
|  | +{ | 
|  | +  /* The input bfd in which the symbol is defined.  */ | 
|  | +  bfd *abfd; | 
|  | +  /* The index of the symbol, as stored in the relocation r_info.  */ | 
|  | +  long symndx; | 
|  | +  /* The ranges for this page entry.  */ | 
|  | +  struct mips_got_page_range *ranges; | 
|  | +  /* The maximum number of page entries needed for RANGES.  */ | 
|  | +  bfd_vma num_pages; | 
|  | +}; | 
|  | + | 
|  | +/* This structure is used to hold .got information when linking.  */ | 
|  | + | 
|  | +struct mips_got_info | 
|  | +{ | 
|  | +  /* The global symbol in the GOT with the lowest index in the dynamic | 
|  | +     symbol table.  */ | 
|  | +  struct elf_link_hash_entry *global_gotsym; | 
|  | +  /* The number of global .got entries.  */ | 
|  | +  unsigned int global_gotno; | 
|  | +  /* The number of global .got entries that are in the GGA_RELOC_ONLY area.  */ | 
|  | +  unsigned int reloc_only_gotno; | 
|  | +  /* The number of .got slots used for TLS.  */ | 
|  | +  unsigned int tls_gotno; | 
|  | +  /* The first unused TLS .got entry.  Used only during | 
|  | +     mips_elf_initialize_tls_index.  */ | 
|  | +  unsigned int tls_assigned_gotno; | 
|  | +  /* The number of local .got entries, eventually including page entries.  */ | 
|  | +  unsigned int local_gotno; | 
|  | +  /* The maximum number of page entries needed.  */ | 
|  | +  unsigned int page_gotno; | 
|  | +  /* The number of local .got entries we have used.  */ | 
|  | +  unsigned int assigned_gotno; | 
|  | +  /* A hash table holding members of the got.  */ | 
|  | +  struct htab *got_entries; | 
|  | +  /* A hash table of mips_got_page_entry structures.  */ | 
|  | +  struct htab *got_page_entries; | 
|  | +  /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE | 
|  | +     for none, or MINUS_TWO for not yet assigned.  This is needed | 
|  | +     because a single-GOT link may have multiple hash table entries | 
|  | +     for the LDM.  It does not get initialized in multi-GOT mode.  */ | 
|  | +  bfd_vma tls_ldm_offset; | 
|  | +}; | 
|  | + | 
|  | +/* Another structure used to pass arguments for got entries traversal.  */ | 
|  | + | 
|  | +struct mips_elf_set_global_got_offset_arg | 
|  | +{ | 
|  | +  struct mips_got_info *g; | 
|  | +  int value; | 
|  | +  unsigned int needed_relocs; | 
|  | +  struct bfd_link_info *info; | 
|  | +}; | 
|  | + | 
|  | +/* A structure used to count TLS relocations or GOT entries, for GOT | 
|  | +   entry or ELF symbol table traversal.  */ | 
|  | + | 
|  | +struct mips_elf_count_tls_arg | 
|  | +{ | 
|  | +  struct bfd_link_info *info; | 
|  | +  unsigned int needed; | 
|  | +}; | 
|  | + | 
|  | +struct _mips_elf_section_data | 
|  | +{ | 
|  | +  struct bfd_elf_section_data elf; | 
|  | +  union | 
|  | +  { | 
|  | +    bfd_byte *tdata; | 
|  | +  } u; | 
|  | +}; | 
|  | + | 
|  | +#define mips_elf_section_data(sec) \ | 
|  | +  ((struct _mips_elf_section_data *) elf_section_data (sec)) | 
|  | + | 
|  | +#define is_mips_elf(bfd)				\ | 
|  | +  (bfd_get_flavour (bfd) == bfd_target_elf_flavour	\ | 
|  | +   && elf_tdata (bfd) != NULL				\ | 
|  | +   && elf_object_id (bfd) == MIPS_ELF_DATA) | 
|  | + | 
|  | +/* The ABI says that every symbol used by dynamic relocations must have | 
|  | +   a global GOT entry.  Among other things, this provides the dynamic | 
|  | +   linker with a free, directly-indexed cache.  The GOT can therefore | 
|  | +   contain symbols that are not referenced by GOT relocations themselves | 
|  | +   (in other words, it may have symbols that are not referenced by things | 
|  | +   like R_RISCV_GOT16). | 
|  | + | 
|  | +   GOT relocations are less likely to overflow if we put the associated | 
|  | +   GOT entries towards the beginning.  We therefore divide the global | 
|  | +   GOT entries into two areas: "normal" and "reloc-only".  Entries in | 
|  | +   the first area can be used for both dynamic relocations and GP-relative | 
|  | +   accesses, while those in the "reloc-only" area are for dynamic | 
|  | +   relocations only. | 
|  | + | 
|  | +   These GGA_* ("Global GOT Area") values are organised so that lower | 
|  | +   values are more general than higher values.  Also, non-GGA_NONE | 
|  | +   values are ordered by the position of the area in the GOT.  */ | 
|  | +#define GGA_NORMAL 0 | 
|  | +#define GGA_RELOC_ONLY 1 | 
|  | +#define GGA_NONE 2 | 
|  | + | 
|  | +/* This structure is passed to mips_elf_sort_hash_table_f when sorting | 
|  | +   the dynamic symbols.  */ | 
|  | + | 
|  | +struct mips_elf_hash_sort_data | 
|  | +{ | 
|  | +  /* The symbol in the global GOT with the lowest dynamic symbol table | 
|  | +     index.  */ | 
|  | +  struct elf_link_hash_entry *low; | 
|  | +  /* The least dynamic symbol table index corresponding to a non-TLS | 
|  | +     symbol with a GOT entry.  */ | 
|  | +  long min_got_dynindx; | 
|  | +  /* The greatest dynamic symbol table index corresponding to a symbol | 
|  | +     with a GOT entry that is not referenced (e.g., a dynamic symbol | 
|  | +     with dynamic relocations pointing to it from non-primary GOTs).  */ | 
|  | +  long max_unref_got_dynindx; | 
|  | +  /* The greatest dynamic symbol table index not corresponding to a | 
|  | +     symbol without a GOT entry.  */ | 
|  | +  long max_non_got_dynindx; | 
|  | +}; | 
|  | + | 
|  | +/* The MIPS ELF linker needs additional information for each symbol in | 
|  | +   the global hash table.  */ | 
|  | + | 
|  | +struct mips_elf_link_hash_entry | 
|  | +{ | 
|  | +  struct elf_link_hash_entry root; | 
|  | + | 
|  | +  /* External symbol information.  */ | 
|  | +  EXTR esym; | 
|  | + | 
|  | +  /* Number of R_RISCV_32, R_RISCV_REL32, or R_RISCV_64 relocs against | 
|  | +     this symbol.  */ | 
|  | +  unsigned int possibly_dynamic_relocs; | 
|  | + | 
|  | +#define GOT_NORMAL	0 | 
|  | +#define GOT_TLS_GD	1 | 
|  | +#define GOT_TLS_LDM	2 | 
|  | +#define GOT_TLS_IE	4 | 
|  | +#define GOT_TLS_OFFSET_DONE    0x40 | 
|  | +#define GOT_TLS_DONE    0x80 | 
|  | +  unsigned char tls_type; | 
|  | + | 
|  | +  /* This is only used in single-GOT mode; in multi-GOT mode there | 
|  | +     is one mips_got_entry per GOT entry, so the offset is stored | 
|  | +     there.  In single-GOT mode there may be many mips_got_entry | 
|  | +     structures all referring to the same GOT slot.  It might be | 
|  | +     possible to use root.got.offset instead, but that field is | 
|  | +     overloaded already.  */ | 
|  | +  bfd_vma tls_got_offset; | 
|  | + | 
|  | +  /* The highest GGA_* value that satisfies all references to this symbol.  */ | 
|  | +  unsigned int global_got_area : 2; | 
|  | + | 
|  | +  /* True if one of the relocations described by possibly_dynamic_relocs | 
|  | +     is against a readonly section.  */ | 
|  | +  unsigned int readonly_reloc : 1; | 
|  | + | 
|  | +  /* True if there is a relocation against this symbol that must be | 
|  | +     resolved by the static linker (in other words, if the relocation | 
|  | +     cannot possibly be made dynamic).  */ | 
|  | +  unsigned int has_static_relocs : 1; | 
|  | +}; | 
|  | + | 
|  | +/* MIPS ELF linker hash table.  */ | 
|  | + | 
|  | +struct mips_elf_link_hash_table | 
|  | +{ | 
|  | +  struct elf_link_hash_table root; | 
|  | +#if 0 | 
|  | +  /* We no longer use this.  */ | 
|  | +  /* String section indices for the dynamic section symbols.  */ | 
|  | +  bfd_size_type dynsym_sec_strindex[SIZEOF_MIPS_DYNSYM_SECNAMES]; | 
|  | +#endif | 
|  | + | 
|  | +  /* Shortcuts to some dynamic sections, or NULL if they are not | 
|  | +     being used.  */ | 
|  | +  asection *srelbss; | 
|  | +  asection *sdynbss; | 
|  | +  asection *srelplt; | 
|  | +  asection *srelplt2; | 
|  | +  asection *sgotplt; | 
|  | +  asection *splt; | 
|  | +  asection *sgot; | 
|  | + | 
|  | +  /* The master GOT information.  */ | 
|  | +  struct mips_got_info *got_info; | 
|  | + | 
|  | +  /* The size of the PLT header in bytes.  */ | 
|  | +  bfd_vma plt_header_size; | 
|  | + | 
|  | +  /* The size of a PLT entry in bytes.  */ | 
|  | +  bfd_vma plt_entry_size; | 
|  | + | 
|  | +  /* The number of reserved entries at the beginning of the GOT.  */ | 
|  | +  unsigned int reserved_gotno; | 
|  | +}; | 
|  | + | 
|  | +/* Get the MIPS ELF linker hash table from a link_info structure.  */ | 
|  | + | 
|  | +#define mips_elf_hash_table(p) \ | 
|  | +  (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ | 
|  | +  == MIPS_ELF_DATA ? ((struct mips_elf_link_hash_table *) ((p)->hash)) : NULL) | 
|  | + | 
|  | +/* A structure used to communicate with htab_traverse callbacks.  */ | 
|  | +struct mips_htab_traverse_info | 
|  | +{ | 
|  | +  /* The usual link-wide information.  */ | 
|  | +  struct bfd_link_info *info; | 
|  | +  bfd *output_bfd; | 
|  | + | 
|  | +  /* Starts off FALSE and is set to TRUE if the link should be aborted.  */ | 
|  | +  bfd_boolean error; | 
|  | +}; | 
|  | + | 
|  | +#define TLS_RELOC_P(r_type) \ | 
|  | +  (r_type == R_RISCV_TLS_DTPMOD32		\ | 
|  | +   || r_type == R_RISCV_TLS_DTPMOD64		\ | 
|  | +   || r_type == R_RISCV_TLS_DTPREL32		\ | 
|  | +   || r_type == R_RISCV_TLS_DTPREL64		\ | 
|  | +   || TLS_GD_RELOC_P(r_type)			\ | 
|  | +   || TLS_LDM_RELOC_P(r_type)			\ | 
|  | +   || r_type == R_RISCV_TLS_LDM			\ | 
|  | +   || r_type == R_RISCV_TLS_DTPREL_HI16		\ | 
|  | +   || r_type == R_RISCV_TLS_DTPREL_LO16		\ | 
|  | +   || TLS_GOTTPREL_RELOC_P(r_type)		\ | 
|  | +   || r_type == R_RISCV_TLS_TPREL32		\ | 
|  | +   || r_type == R_RISCV_TLS_TPREL64		\ | 
|  | +   || r_type == R_RISCV_TLS_TPREL_HI16		\ | 
|  | +   || r_type == R_RISCV_TLS_TPREL_LO16) | 
|  | + | 
|  | +#define TLS_GOTTPREL_RELOC_P(r_type) \ | 
|  | +  ((r_type) == R_RISCV_TLS_GOTTPREL		\ | 
|  | +   || (r_type) == R_RISCV_TLS_GOT_HI16		\ | 
|  | +   || (r_type) == R_RISCV_TLS_GOT_LO16) | 
|  | + | 
|  | +#define TLS_GD_RELOC_P(r_type) \ | 
|  | +  ((r_type) == R_RISCV_TLS_GD			\ | 
|  | +   || (r_type) == R_RISCV_TLS_GD_HI16		\ | 
|  | +   || (r_type) == R_RISCV_TLS_GD_LO16) | 
|  | + | 
|  | +#define TLS_LDM_RELOC_P(r_type) \ | 
|  | +  ((r_type) == R_RISCV_TLS_LDM			\ | 
|  | +   || (r_type) == R_RISCV_TLS_LDM_HI16		\ | 
|  | +   || (r_type) == R_RISCV_TLS_LDM_LO16) | 
|  | + | 
|  | +/* Structure used to pass information to mips_elf_output_extsym.  */ | 
|  | + | 
|  | +struct extsym_info | 
|  | +{ | 
|  | +  bfd *abfd; | 
|  | +  struct bfd_link_info *info; | 
|  | +  struct ecoff_debug_info *debug; | 
|  | +  const struct ecoff_debug_swap *swap; | 
|  | +  bfd_boolean failed; | 
|  | +}; | 
|  | + | 
|  | +/* The structure of the runtime procedure descriptor created by the | 
|  | +   loader for use by the static exception system.  */ | 
|  | + | 
|  | +typedef struct runtime_pdr { | 
|  | +	bfd_vma	adr;		/* Memory address of start of procedure.  */ | 
|  | +	long	regmask;	/* Save register mask.  */ | 
|  | +	long	regoffset;	/* Save register offset.  */ | 
|  | +	long	fregmask;	/* Save floating point register mask.  */ | 
|  | +	long	fregoffset;	/* Save floating point register offset.  */ | 
|  | +	long	frameoffset;	/* Frame size.  */ | 
|  | +	short	framereg;	/* Frame pointer register.  */ | 
|  | +	short	pcreg;		/* Offset or reg of return pc.  */ | 
|  | +	long	irpss;		/* Index into the runtime string table.  */ | 
|  | +	long	reserved; | 
|  | +	struct exception_info *exception_info;/* Pointer to exception array.  */ | 
|  | +} RPDR, *pRPDR; | 
|  | +#define cbRPDR sizeof (RPDR) | 
|  | +#define rpdNil ((pRPDR) 0) | 
|  | + | 
|  | +static struct mips_got_entry *mips_elf_create_local_got_entry | 
|  | +  (bfd *, struct bfd_link_info *, bfd *, bfd_vma, unsigned long, | 
|  | +   struct mips_elf_link_hash_entry *, int); | 
|  | +static bfd_boolean mips_elf_sort_hash_table_f | 
|  | +  (struct mips_elf_link_hash_entry *, void *); | 
|  | +static bfd_boolean mips_elf_create_dynamic_relocation | 
|  | +  (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *, | 
|  | +   struct mips_elf_link_hash_entry *, asection *, bfd_vma, | 
|  | +   bfd_vma *, asection *); | 
|  | +static hashval_t mips_elf_got_entry_hash | 
|  | +  (const void *); | 
|  | + | 
|  | +/* This will be used when we sort the dynamic relocation records.  */ | 
|  | +static bfd *reldyn_sorting_bfd; | 
|  | + | 
|  | +/* True if ABFD is a PIC object.  */ | 
|  | +#define PIC_OBJECT_P(abfd) \ | 
|  | +  ((elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) != 0) | 
|  | + | 
|  | +/* Nonzero if ABFD is using the RV64 ABI.  */ | 
|  | +#define ABI_64_P(abfd) \ | 
|  | +  (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS64) | 
|  | + | 
|  | +/* Nonzero if ABFD is using the RV32 ABI.  */ | 
|  | +#define ABI_32_P(abfd) (!ABI_64_P(abfd)) | 
|  | + | 
|  | +/* The name of the options section.  */ | 
|  | +#define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) ".MIPS.options" | 
|  | + | 
|  | +/* True if NAME is the recognized name of any SHT_MIPS_OPTIONS section. | 
|  | +   Some IRIX system files do not use MIPS_ELF_OPTIONS_SECTION_NAME.  */ | 
|  | +#define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \ | 
|  | +  (strcmp (NAME, ".MIPS.options") == 0) | 
|  | + | 
|  | +/* Whether the section is readonly.  */ | 
|  | +#define MIPS_ELF_READONLY_SECTION(sec) \ | 
|  | +  ((sec->flags & (SEC_ALLOC | SEC_LOAD | SEC_READONLY))		\ | 
|  | +   == (SEC_ALLOC | SEC_LOAD | SEC_READONLY)) | 
|  | + | 
|  | +/* The size of an external REL relocation.  */ | 
|  | +#define MIPS_ELF_REL_SIZE(abfd) \ | 
|  | +  (get_elf_backend_data (abfd)->s->sizeof_rel) | 
|  | + | 
|  | +/* The size of an external dynamic table entry.  */ | 
|  | +#define MIPS_ELF_DYN_SIZE(abfd) \ | 
|  | +  (get_elf_backend_data (abfd)->s->sizeof_dyn) | 
|  | + | 
|  | +/* The size of a GOT entry.  */ | 
|  | +#define MIPS_ELF_GOT_SIZE(abfd) \ | 
|  | +  (get_elf_backend_data (abfd)->s->arch_size / 8) | 
|  | + | 
|  | +/* The size of a symbol-table entry.  */ | 
|  | +#define MIPS_ELF_SYM_SIZE(abfd) \ | 
|  | +  (get_elf_backend_data (abfd)->s->sizeof_sym) | 
|  | + | 
|  | +/* The default alignment for sections, as a power of two.  */ | 
|  | +#define MIPS_ELF_LOG_FILE_ALIGN(abfd)				\ | 
|  | +  (get_elf_backend_data (abfd)->s->log_file_align) | 
|  | + | 
|  | +/* Get word-sized data.  */ | 
|  | +#define MIPS_ELF_GET_WORD(abfd, ptr) \ | 
|  | +  (ABI_64_P (abfd) ? bfd_get_64 (abfd, ptr) : bfd_get_32 (abfd, ptr)) | 
|  | + | 
|  | +/* Put out word-sized data.  */ | 
|  | +#define MIPS_ELF_PUT_WORD(abfd, val, ptr)	\ | 
|  | +  (ABI_64_P (abfd) 				\ | 
|  | +   ? bfd_put_64 (abfd, val, ptr) 		\ | 
|  | +   : bfd_put_32 (abfd, val, ptr)) | 
|  | + | 
|  | +/* Add a dynamic symbol table-entry.  */ | 
|  | +#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val)	\ | 
|  | +  _bfd_elf_add_dynamic_entry (info, tag, val) | 
|  | + | 
|  | +#define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela)			\ | 
|  | +  (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela)) | 
|  | + | 
|  | +/* The name of the dynamic relocation section.  */ | 
|  | +#define MIPS_ELF_REL_DYN_NAME(INFO) ".rel.dyn" | 
|  | + | 
|  | +/* In case we're on a 32-bit machine, construct a 64-bit "-1" value | 
|  | +   from smaller values.  Start with zero, widen, *then* decrement.  */ | 
|  | +#define MINUS_ONE	(((bfd_vma)0) - 1) | 
|  | +#define MINUS_TWO	(((bfd_vma)0) - 2) | 
|  | + | 
|  | +/* The value to write into got[1] for SVR4 targets, to identify it is | 
|  | +   a GNU object.  The dynamic linker can then use got[1] to store the | 
|  | +   module pointer.  */ | 
|  | +#define MIPS_ELF_GNU_GOT1_MASK(abfd) \ | 
|  | +  ((bfd_vma) 1 << (ABI_64_P (abfd) ? 63 : 31)) | 
|  | + | 
|  | +#define MIPS_FUNCTION_STUB_NORMAL_SIZE 16 | 
|  | +#define MIPS_FUNCTION_STUB_BIG_SIZE 20 | 
|  | + | 
|  | +/* The name of the dynamic interpreter.  This is put in the .interp | 
|  | +   section.  */ | 
|  | + | 
|  | +#define ELF_DYNAMIC_INTERPRETER(abfd) 		\ | 
|  | +   (ABI_64_P (abfd) ? "/lib/ld.so.1" 	\ | 
|  | +    : "/lib32/ld.so.1") | 
|  | + | 
|  | +#ifdef BFD64 | 
|  | +#define MNAME(bfd,pre,pos) \ | 
|  | +  (ABI_64_P (bfd) ? CONCAT4 (pre,64,_,pos) : CONCAT4 (pre,32,_,pos)) | 
|  | +#define ELF_R_SYM(bfd, i)					\ | 
|  | +  (ABI_64_P (bfd) ? ELF64_R_SYM (i) : ELF32_R_SYM (i)) | 
|  | +#define ELF_R_TYPE(bfd, i)					\ | 
|  | +  (ABI_64_P (bfd) ? ELF64_MIPS_R_TYPE (i) : ELF32_R_TYPE (i)) | 
|  | +#define ELF_R_INFO(bfd, s, t)					\ | 
|  | +  (ABI_64_P (bfd) ? ELF64_R_INFO (s, t) : ELF32_R_INFO (s, t)) | 
|  | +#else | 
|  | +#define MNAME(bfd,pre,pos) CONCAT4 (pre,32,_,pos) | 
|  | +#define ELF_R_SYM(bfd, i)					\ | 
|  | +  (ELF32_R_SYM (i)) | 
|  | +#define ELF_R_TYPE(bfd, i)					\ | 
|  | +  (ELF32_R_TYPE (i)) | 
|  | +#define ELF_R_INFO(bfd, s, t)					\ | 
|  | +  (ELF32_R_INFO (s, t)) | 
|  | +#endif | 
|  | + | 
|  | +#define IS_STORE_RELOC(bfd, reloc, opcode) \ | 
|  | +  ((ELF_R_TYPE (bfd, reloc) == R_RISCV_LO16		\ | 
|  | +    || ELF_R_TYPE (bfd, reloc) == R_RISCV_TLS_TPREL_LO16	\ | 
|  | +    || ELF_R_TYPE (bfd, reloc) == R_RISCV_TLS_DTPREL_LO16)	\ | 
|  | +   && OPCODE_IS_STORE(opcode)) | 
|  | + | 
|  | +#define MATCH_LREG(abfd) (ABI_64_P(abfd) ? MATCH_LD : MATCH_LW) | 
|  | +#define MATCH_SREG(abfd) (ABI_64_P(abfd) ? MATCH_SD : MATCH_SW) | 
|  | + | 
|  | +#define OPCODE_MATCHES(OPCODE, OP) \ | 
|  | +  (((OPCODE) & MASK_##OP) == MATCH_##OP) | 
|  | + | 
|  | +#define OPCODE_IS_STORE(OPCODE) \ | 
|  | +  (OPCODE_MATCHES(OPCODE, SD)  || OPCODE_MATCHES(OPCODE, SW) || \ | 
|  | +   OPCODE_MATCHES(OPCODE, SH)  || OPCODE_MATCHES(OPCODE, SB) || \ | 
|  | +   OPCODE_MATCHES(OPCODE, FSW) || OPCODE_MATCHES(OPCODE, FSD)) | 
|  | + | 
|  | +/* The format of the first PLT entry.  */ | 
|  | + | 
|  | +#define RISCV_PLT0_ENTRY_INSNS 44 | 
|  | +static void | 
|  | +riscv_make_plt0_entry(bfd* abfd, bfd_vma gotplt_value, bfd_vma addr, | 
|  | +                      bfd_vma entry[RISCV_PLT0_ENTRY_INSNS]) | 
|  | +{ | 
|  | +  /* save ra and arg registers to stack | 
|  | +     auipc  v0, %hi(GOTPLT) | 
|  | +     addi   v0, v0, %lo(GOTPLT) | 
|  | +     sub    a1, v1, v0 | 
|  | +     ld     a0, PTRSIZE(v0) | 
|  | +     ld     v0, 0(v0) | 
|  | +     slli   a1, a1, 1 | 
|  | +     addi   a1, a1, -4*PTRSIZE | 
|  | +     jalr   v0 | 
|  | +     restore ra and arg registers from stack | 
|  | +     jr     v0 | 
|  | +  */ | 
|  | + | 
|  | +  int i = 0, j, regbytes = ABI_64_P(abfd) ? 8 : 4; | 
|  | +  entry[i++] = RISCV_ITYPE(ADDI, 14, 14, -16*regbytes); | 
|  | +  entry[i++] = RISCV_BTYPE(SREG(abfd), 14, LINK_REG, 0); | 
|  | +  for (j = 0; j < 14; j++) | 
|  | +    entry[i++] = RISCV_BTYPE(SREG(abfd), 14, 18+j, (j+1)*regbytes); | 
|  | +  gotplt_value -= addr + i*4; | 
|  | +  entry[i++] = RISCV_LTYPE(AUIPC, 16, RISCV_LUI_HIGH_PART(gotplt_value)); | 
|  | +  entry[i++] = RISCV_ITYPE(ADDI, 16, 16, RISCV_CONST_LOW_PART(gotplt_value)); | 
|  | +  entry[i++] = RISCV_RTYPE(SUB, 19, 17, 16); | 
|  | +  entry[i++] = RISCV_ITYPE(LREG(abfd), 18, 16, regbytes); | 
|  | +  entry[i++] = RISCV_ITYPE(LREG(abfd), 16, 16, 0); | 
|  | +  entry[i++] = RISCV_ITYPE(SLLI, 19, 19, 1); | 
|  | +  entry[i++] = RISCV_ITYPE(ADDI, 19, 19, -4*regbytes); | 
|  | +  entry[i++] = RISCV_ITYPE(JALR_C, LINK_REG, 16, 0); | 
|  | +  entry[i++] = RISCV_ITYPE(LREG(abfd), LINK_REG, 14, 0); | 
|  | +  for (j = 0; j < 14; j++) | 
|  | +    entry[i++] = RISCV_ITYPE(LREG(abfd), 18+j, 14, (j+1)*regbytes); | 
|  | +  entry[i++] = RISCV_ITYPE(ADDI, 14, 14, 16*regbytes); | 
|  | +  entry[i++] = RISCV_ITYPE(JALR_J, 0, 16, 0); | 
|  | + | 
|  | +  BFD_ASSERT(i <= RISCV_PLT0_ENTRY_INSNS); | 
|  | +  while (i < RISCV_PLT0_ENTRY_INSNS) | 
|  | +    entry[i++] = RISCV_ITYPE(ADDI, 0, 0, 0); | 
|  | +} | 
|  | + | 
|  | +/* The format of subsequent PLT entries.  */ | 
|  | + | 
|  | +#define RISCV_PLT_ENTRY_INSNS 4 | 
|  | +static void | 
|  | +riscv_make_plt_entry(bfd* abfd, bfd_vma got_address, bfd_vma addr, | 
|  | +                     bfd_vma entry[RISCV_PLT_ENTRY_INSNS]) | 
|  | +{ | 
|  | +  /* auipc  v1, %hi(.got.plt entry) | 
|  | +     l[w|d] v0, %lo(.got.plt entry)(t6) | 
|  | +     addi   v1, v1, %lo(.got.plt entry) | 
|  | +     jr     v0 | 
|  | +  */ | 
|  | + | 
|  | +  got_address -= addr; | 
|  | +  entry[0] = RISCV_LTYPE(AUIPC, 17, RISCV_LUI_HIGH_PART(got_address)); | 
|  | +  entry[1] = RISCV_ITYPE(LREG(abfd),  16, 17, RISCV_CONST_LOW_PART(got_address)); | 
|  | +  entry[2] = RISCV_ITYPE(ADDI, 17, 17, RISCV_CONST_LOW_PART(got_address)); | 
|  | +  entry[3] = RISCV_ITYPE(JALR_J, 0, 16, 0); | 
|  | +} | 
|  | + | 
|  | +/* Look up an entry in a MIPS ELF linker hash table.  */ | 
|  | + | 
|  | +#define mips_elf_link_hash_lookup(table, string, create, copy, follow)	\ | 
|  | +  ((struct mips_elf_link_hash_entry *)					\ | 
|  | +   elf_link_hash_lookup (&(table)->root, (string), (create),		\ | 
|  | +			 (copy), (follow))) | 
|  | + | 
|  | +/* Traverse a MIPS ELF linker hash table.  */ | 
|  | + | 
|  | +#define mips_elf_link_hash_traverse(table, func, info)			\ | 
|  | +  (elf_link_hash_traverse						\ | 
|  | +   (&(table)->root,							\ | 
|  | +    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),	\ | 
|  | +    (info))) | 
|  | + | 
|  | +/* Find the base offsets for thread-local storage in this object, | 
|  | +   for GD/LD and IE/LE respectively.  */ | 
|  | + | 
|  | +#define TP_OFFSET 0x7000 | 
|  | +#define DTP_OFFSET 0x8000 | 
|  | + | 
|  | +static bfd_vma | 
|  | +dtprel_base (struct bfd_link_info *info) | 
|  | +{ | 
|  | +  /* If tls_sec is NULL, we should have signalled an error already.  */ | 
|  | +  if (elf_hash_table (info)->tls_sec == NULL) | 
|  | +    return 0; | 
|  | +  return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET; | 
|  | +} | 
|  | + | 
|  | +static bfd_vma | 
|  | +tprel_base (struct bfd_link_info *info) | 
|  | +{ | 
|  | +  /* If tls_sec is NULL, we should have signalled an error already.  */ | 
|  | +  if (elf_hash_table (info)->tls_sec == NULL) | 
|  | +    return 0; | 
|  | +  return elf_hash_table (info)->tls_sec->vma + TP_OFFSET; | 
|  | +} | 
|  | + | 
|  | +/* Create an entry in a MIPS ELF linker hash table.  */ | 
|  | + | 
|  | +static struct bfd_hash_entry * | 
|  | +mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, | 
|  | +			    struct bfd_hash_table *table, const char *string) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_entry *ret = | 
|  | +    (struct mips_elf_link_hash_entry *) entry; | 
|  | + | 
|  | +  /* Allocate the structure if it has not already been allocated by a | 
|  | +     subclass.  */ | 
|  | +  if (ret == NULL) | 
|  | +    ret = bfd_hash_allocate (table, sizeof (struct mips_elf_link_hash_entry)); | 
|  | +  if (ret == NULL) | 
|  | +    return (struct bfd_hash_entry *) ret; | 
|  | + | 
|  | +  /* Call the allocation method of the superclass.  */ | 
|  | +  ret = ((struct mips_elf_link_hash_entry *) | 
|  | +	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, | 
|  | +				     table, string)); | 
|  | +  if (ret != NULL) | 
|  | +    { | 
|  | +      /* Set local fields.  */ | 
|  | +      memset (&ret->esym, 0, sizeof (EXTR)); | 
|  | +      /* We use -2 as a marker to indicate that the information has | 
|  | +	 not been set.  -1 means there is no associated ifd.  */ | 
|  | +      ret->esym.ifd = -2; | 
|  | +      ret->possibly_dynamic_relocs = 0; | 
|  | +      ret->tls_type = GOT_NORMAL; | 
|  | +      ret->global_got_area = GGA_NONE; | 
|  | +      ret->readonly_reloc = FALSE; | 
|  | +      ret->has_static_relocs = FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return (struct bfd_hash_entry *) ret; | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_new_section_hook (bfd *abfd, asection *sec) | 
|  | +{ | 
|  | +  if (!sec->used_by_bfd) | 
|  | +    { | 
|  | +      struct _mips_elf_section_data *sdata; | 
|  | +      bfd_size_type amt = sizeof (*sdata); | 
|  | + | 
|  | +      sdata = bfd_zalloc (abfd, amt); | 
|  | +      if (sdata == NULL) | 
|  | +	return FALSE; | 
|  | +      sec->used_by_bfd = sdata; | 
|  | +    } | 
|  | + | 
|  | +  return _bfd_elf_new_section_hook (abfd, sec); | 
|  | +} | 
|  | + | 
|  | +/* Read ECOFF debugging information from a .mdebug section into a | 
|  | +   ecoff_debug_info structure.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_read_ecoff_info (bfd *abfd, asection *section, | 
|  | +			       struct ecoff_debug_info *debug) | 
|  | +{ | 
|  | +  HDRR *symhdr; | 
|  | +  const struct ecoff_debug_swap *swap; | 
|  | +  char *ext_hdr; | 
|  | + | 
|  | +  swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; | 
|  | +  memset (debug, 0, sizeof (*debug)); | 
|  | + | 
|  | +  ext_hdr = bfd_malloc (swap->external_hdr_size); | 
|  | +  if (ext_hdr == NULL && swap->external_hdr_size != 0) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  if (! bfd_get_section_contents (abfd, section, ext_hdr, 0, | 
|  | +				  swap->external_hdr_size)) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  symhdr = &debug->symbolic_header; | 
|  | +  (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr); | 
|  | + | 
|  | +  /* The symbolic header contains absolute file offsets and sizes to | 
|  | +     read.  */ | 
|  | +#define READ(ptr, offset, count, size, type)				\ | 
|  | +  if (symhdr->count == 0)						\ | 
|  | +    debug->ptr = NULL;							\ | 
|  | +  else									\ | 
|  | +    {									\ | 
|  | +      bfd_size_type amt = (bfd_size_type) size * symhdr->count;		\ | 
|  | +      debug->ptr = bfd_malloc (amt);					\ | 
|  | +      if (debug->ptr == NULL)						\ | 
|  | +	goto error_return;						\ | 
|  | +      if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0		\ | 
|  | +	  || bfd_bread (debug->ptr, amt, abfd) != amt)			\ | 
|  | +	goto error_return;						\ | 
|  | +    } | 
|  | + | 
|  | +  READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); | 
|  | +  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *); | 
|  | +  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *); | 
|  | +  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *); | 
|  | +  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *); | 
|  | +  READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), | 
|  | +	union aux_ext *); | 
|  | +  READ (ss, cbSsOffset, issMax, sizeof (char), char *); | 
|  | +  READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *); | 
|  | +  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *); | 
|  | +  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *); | 
|  | +  READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *); | 
|  | +#undef READ | 
|  | + | 
|  | +  debug->fdr = NULL; | 
|  | + | 
|  | +  return TRUE; | 
|  | + | 
|  | + error_return: | 
|  | +  if (ext_hdr != NULL) | 
|  | +    free (ext_hdr); | 
|  | +  if (debug->line != NULL) | 
|  | +    free (debug->line); | 
|  | +  if (debug->external_dnr != NULL) | 
|  | +    free (debug->external_dnr); | 
|  | +  if (debug->external_pdr != NULL) | 
|  | +    free (debug->external_pdr); | 
|  | +  if (debug->external_sym != NULL) | 
|  | +    free (debug->external_sym); | 
|  | +  if (debug->external_opt != NULL) | 
|  | +    free (debug->external_opt); | 
|  | +  if (debug->external_aux != NULL) | 
|  | +    free (debug->external_aux); | 
|  | +  if (debug->ss != NULL) | 
|  | +    free (debug->ss); | 
|  | +  if (debug->ssext != NULL) | 
|  | +    free (debug->ssext); | 
|  | +  if (debug->external_fdr != NULL) | 
|  | +    free (debug->external_fdr); | 
|  | +  if (debug->external_rfd != NULL) | 
|  | +    free (debug->external_rfd); | 
|  | +  if (debug->external_ext != NULL) | 
|  | +    free (debug->external_ext); | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +got16_reloc_p (int r_type) | 
|  | +{ | 
|  | +  return r_type == R_RISCV_GOT16; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +call16_reloc_p (int r_type) | 
|  | +{ | 
|  | +  return r_type == R_RISCV_CALL16; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +hi16_reloc_p (int r_type) | 
|  | +{ | 
|  | +  return r_type == R_RISCV_HI16; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +lo16_reloc_p (int r_type) | 
|  | +{ | 
|  | +  return r_type == R_RISCV_LO16; | 
|  | +} | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_high (bfd_vma value) | 
|  | +{ | 
|  | +  return RISCV_LUI_HIGH_PART (value) & ((1<<RISCV_BIGIMM_BITS)-1); | 
|  | +} | 
|  | + | 
|  | +bfd_reloc_status_type | 
|  | +_bfd_riscv_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol, | 
|  | +			       arelent *reloc_entry, asection *input_section, | 
|  | +			       bfd_boolean relocatable, void *data, bfd_vma gp) | 
|  | +{ | 
|  | +  bfd_vma relocation; | 
|  | +  bfd_signed_vma val; | 
|  | +  bfd_reloc_status_type status; | 
|  | + | 
|  | +  if (bfd_is_com_section (symbol->section)) | 
|  | +    relocation = 0; | 
|  | +  else | 
|  | +    relocation = symbol->value; | 
|  | + | 
|  | +  relocation += symbol->section->output_section->vma; | 
|  | +  relocation += symbol->section->output_offset; | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  /* Set val to the offset into the section or symbol.  */ | 
|  | +  val = reloc_entry->addend; | 
|  | + | 
|  | +  _bfd_riscv_elf_sign_extend (val, RISCV_IMM_BITS); | 
|  | + | 
|  | +  /* Adjust val for the final section location and GP value.  If we | 
|  | +     are producing relocatable output, we don't want to do this for | 
|  | +     an external symbol.  */ | 
|  | +  if (! relocatable | 
|  | +      || (symbol->flags & BSF_SECTION_SYM) != 0) | 
|  | +    val += relocation - gp; | 
|  | + | 
|  | +  if (reloc_entry->howto->partial_inplace) | 
|  | +    { | 
|  | +      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val, | 
|  | +				       (bfd_byte *) data | 
|  | +				       + reloc_entry->address); | 
|  | +      if (status != bfd_reloc_ok) | 
|  | +	return status; | 
|  | +    } | 
|  | +  else | 
|  | +    reloc_entry->addend = val; | 
|  | + | 
|  | +  if (relocatable) | 
|  | +    reloc_entry->address += input_section->output_offset; | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* Used to store a REL high-part relocation such as R_RISCV_HI16 or | 
|  | +   R_RISCV_GOT16.  REL is the relocation, INPUT_SECTION is the section | 
|  | +   that contains the relocation field and DATA points to the start of | 
|  | +   INPUT_SECTION.  */ | 
|  | + | 
|  | +struct mips_hi16 | 
|  | +{ | 
|  | +  struct mips_hi16 *next; | 
|  | +  bfd_byte *data; | 
|  | +  asection *input_section; | 
|  | +  arelent rel; | 
|  | +}; | 
|  | + | 
|  | +/* FIXME: This should not be a static variable.  */ | 
|  | + | 
|  | +static struct mips_hi16 *mips_hi16_list; | 
|  | + | 
|  | +/* A howto special_function for REL *HI16 relocations.  We can only | 
|  | +   calculate the correct value once we've seen the partnering | 
|  | +   *LO16 relocation, so just save the information for later. | 
|  | + | 
|  | +   The ABI requires that the *LO16 immediately follow the *HI16. | 
|  | +   However, as a GNU extension, we permit an arbitrary number of | 
|  | +   *HI16s to be associated with a single *LO16.  This significantly | 
|  | +   simplies the relocation handling in gcc.  */ | 
|  | + | 
|  | +bfd_reloc_status_type | 
|  | +_bfd_riscv_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, | 
|  | +			  asymbol *symbol ATTRIBUTE_UNUSED, void *data, | 
|  | +			  asection *input_section, bfd *output_bfd, | 
|  | +			  char **error_message ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  struct mips_hi16 *n; | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  n = bfd_malloc (sizeof *n); | 
|  | +  if (n == NULL) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  n->next = mips_hi16_list; | 
|  | +  n->data = data; | 
|  | +  n->input_section = input_section; | 
|  | +  n->rel = *reloc_entry; | 
|  | +  mips_hi16_list = n; | 
|  | + | 
|  | +  if (output_bfd != NULL) | 
|  | +    reloc_entry->address += input_section->output_offset; | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* A howto special_function for REL R_MIPS*_GOT16 relocations.  This is just | 
|  | +   like any other 16-bit relocation when applied to global symbols, but is | 
|  | +   treated in the same as R_RISCV_HI16 when applied to local symbols.  */ | 
|  | + | 
|  | +bfd_reloc_status_type | 
|  | +_bfd_riscv_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			   void *data, asection *input_section, | 
|  | +			   bfd *output_bfd, char **error_message) | 
|  | +{ | 
|  | +  if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 | 
|  | +      || bfd_is_und_section (bfd_get_section (symbol)) | 
|  | +      || bfd_is_com_section (bfd_get_section (symbol))) | 
|  | +    /* The relocation is against a global symbol.  */ | 
|  | +    return _bfd_riscv_elf_generic_reloc (abfd, reloc_entry, symbol, data, | 
|  | +					input_section, output_bfd, | 
|  | +					error_message); | 
|  | + | 
|  | +  return _bfd_riscv_elf_hi16_reloc (abfd, reloc_entry, symbol, data, | 
|  | +				   input_section, output_bfd, error_message); | 
|  | +} | 
|  | + | 
|  | +/* A howto special_function for REL *LO16 relocations.  The *LO16 itself | 
|  | +   is a straightforward 16 bit inplace relocation, but we must deal with | 
|  | +   any partnering high-part relocations as well.  */ | 
|  | + | 
|  | +bfd_reloc_status_type | 
|  | +_bfd_riscv_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, | 
|  | +			  void *data, asection *input_section, | 
|  | +			  bfd *output_bfd, char **error_message) | 
|  | +{ | 
|  | +  bfd_vma vallo; | 
|  | +  bfd_byte *location = (bfd_byte *) data + reloc_entry->address; | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  vallo = bfd_get_32 (abfd, location); | 
|  | + | 
|  | +  while (mips_hi16_list != NULL) | 
|  | +    { | 
|  | +      bfd_reloc_status_type ret; | 
|  | +      struct mips_hi16 *hi; | 
|  | + | 
|  | +      hi = mips_hi16_list; | 
|  | + | 
|  | +      /* R_MIPS*_GOT16 relocations are something of a special case.  We | 
|  | +	 want to install the addend in the same way as for a R_MIPS*_HI16 | 
|  | +	 relocation (with a rightshift of 16).  However, since GOT16 | 
|  | +	 relocations can also be used with global symbols, their howto | 
|  | +	 has a rightshift of 0.  */ | 
|  | +      if (hi->rel.howto->type == R_RISCV_GOT16) | 
|  | +	hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_RISCV_HI16, FALSE); | 
|  | + | 
|  | +      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any | 
|  | +	 carry or borrow will induce a change of +1 or -1 in the high part.  */ | 
|  | +      hi->rel.addend += (vallo + RISCV_IMM_REACH/2) & (RISCV_IMM_REACH-1); | 
|  | + | 
|  | +      ret = _bfd_riscv_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data, | 
|  | +					 hi->input_section, output_bfd, | 
|  | +					 error_message); | 
|  | +      if (ret != bfd_reloc_ok) | 
|  | +	return ret; | 
|  | + | 
|  | +      mips_hi16_list = hi->next; | 
|  | +      free (hi); | 
|  | +    } | 
|  | + | 
|  | +  return _bfd_riscv_elf_generic_reloc (abfd, reloc_entry, symbol, data, | 
|  | +				      input_section, output_bfd, | 
|  | +				      error_message); | 
|  | +} | 
|  | + | 
|  | +/* A generic howto special_function.  This calculates and installs the | 
|  | +   relocation itself, thus avoiding the oft-discussed problems in | 
|  | +   bfd_perform_relocation and bfd_install_relocation.  */ | 
|  | + | 
|  | +bfd_reloc_status_type | 
|  | +_bfd_riscv_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, | 
|  | +			     asymbol *symbol, void *data ATTRIBUTE_UNUSED, | 
|  | +			     asection *input_section, bfd *output_bfd, | 
|  | +			     char **error_message ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  bfd_signed_vma val; | 
|  | +  bfd_reloc_status_type status; | 
|  | +  bfd_boolean relocatable; | 
|  | + | 
|  | +  relocatable = (output_bfd != NULL); | 
|  | + | 
|  | +  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) | 
|  | +    return bfd_reloc_outofrange; | 
|  | + | 
|  | +  /* Build up the field adjustment in VAL.  */ | 
|  | +  val = 0; | 
|  | +  if (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0) | 
|  | +    { | 
|  | +      /* Either we're calculating the final field value or we have a | 
|  | +	 relocation against a section symbol.  Add in the section's | 
|  | +	 offset or address.  */ | 
|  | +      val += symbol->section->output_section->vma; | 
|  | +      val += symbol->section->output_offset; | 
|  | +    } | 
|  | + | 
|  | +  if (!relocatable) | 
|  | +    { | 
|  | +      /* We're calculating the final field value.  Add in the symbol's value | 
|  | +	 and, if pc-relative, subtract the address of the field itself.  */ | 
|  | +      val += symbol->value; | 
|  | +      if (reloc_entry->howto->pc_relative) | 
|  | +	{ | 
|  | +	  val -= input_section->output_section->vma; | 
|  | +	  val -= input_section->output_offset; | 
|  | +	  val -= reloc_entry->address; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* VAL is now the final adjustment.  If we're keeping this relocation | 
|  | +     in the output file, and if the relocation uses a separate addend, | 
|  | +     we just need to add VAL to that addend.  Otherwise we need to add | 
|  | +     VAL to the relocation field itself.  */ | 
|  | +  if (relocatable && !reloc_entry->howto->partial_inplace) | 
|  | +    reloc_entry->addend += val; | 
|  | +  else | 
|  | +    { | 
|  | +      bfd_byte *loc = (bfd_byte *) data + reloc_entry->address; | 
|  | +      struct reloc_howto_struct howto = *reloc_entry->howto; | 
|  | + | 
|  | +      /* Add in the separate addend, if any.  */ | 
|  | +      val += reloc_entry->addend; | 
|  | + | 
|  | +      /* Fix up dst_mask and value for R_RISCV_LO16 relocs on stores. */ | 
|  | +      if (IS_STORE_RELOC (abfd, howto.type, | 
|  | +		bfd_big_endian(abfd) ? bfd_getb32(loc) : bfd_getl32(loc))) | 
|  | +	{ | 
|  | +	  val >>= OP_SH_IMMEDIATE; | 
|  | +	  val = ((val >> RISCV_IMMLO_BITS) << OP_SH_IMMHI) | | 
|  | +		((val & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO); | 
|  | +	  howto.dst_mask = (OP_MASK_IMMHI << OP_SH_IMMHI) | | 
|  | +			   (OP_MASK_IMMLO << OP_SH_IMMLO); | 
|  | +	} | 
|  | + | 
|  | +      /* Add VAL to the reloc field.  */ | 
|  | +      status = _bfd_relocate_contents (&howto, abfd, val, loc); | 
|  | + | 
|  | +      if (status != bfd_reloc_ok) | 
|  | +	return status; | 
|  | +    } | 
|  | + | 
|  | +  if (relocatable) | 
|  | +    reloc_entry->address += input_section->output_offset; | 
|  | + | 
|  | +  return bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* A .reginfo section holds a single Elf32_RegInfo structure.  These | 
|  | +   routines swap this structure in and out.  They are used outside of | 
|  | +   BFD, so they are globally visible.  */ | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf32_swap_reginfo_in (bfd *abfd, const Elf32_External_RegInfo *ex, | 
|  | +				Elf32_RegInfo *in) | 
|  | +{ | 
|  | +  in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask); | 
|  | +  in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]); | 
|  | +  in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]); | 
|  | +  in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]); | 
|  | +  in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]); | 
|  | +  in->ri_gp_value = H_GET_32 (abfd, ex->ri_gp_value); | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf32_swap_reginfo_out (bfd *abfd, const Elf32_RegInfo *in, | 
|  | +				 Elf32_External_RegInfo *ex) | 
|  | +{ | 
|  | +  H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]); | 
|  | +  H_PUT_32 (abfd, in->ri_gp_value, ex->ri_gp_value); | 
|  | +} | 
|  | + | 
|  | +/* In the 64 bit ABI, the .MIPS.options section holds register | 
|  | +   information in an Elf64_Reginfo structure.  These routines swap | 
|  | +   them in and out.  They are globally visible because they are used | 
|  | +   outside of BFD.  These routines are here so that gas can call them | 
|  | +   without worrying about whether the 64 bit ABI has been included.  */ | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf64_swap_reginfo_in (bfd *abfd, const Elf64_External_RegInfo *ex, | 
|  | +				Elf64_Internal_RegInfo *in) | 
|  | +{ | 
|  | +  in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask); | 
|  | +  in->ri_pad = H_GET_32 (abfd, ex->ri_pad); | 
|  | +  in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]); | 
|  | +  in->ri_cprmask[1] = H_GET_32 (abfd, ex->ri_cprmask[1]); | 
|  | +  in->ri_cprmask[2] = H_GET_32 (abfd, ex->ri_cprmask[2]); | 
|  | +  in->ri_cprmask[3] = H_GET_32 (abfd, ex->ri_cprmask[3]); | 
|  | +  in->ri_gp_value = H_GET_64 (abfd, ex->ri_gp_value); | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf64_swap_reginfo_out (bfd *abfd, const Elf64_Internal_RegInfo *in, | 
|  | +				 Elf64_External_RegInfo *ex) | 
|  | +{ | 
|  | +  H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask); | 
|  | +  H_PUT_32 (abfd, in->ri_pad, ex->ri_pad); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[1], ex->ri_cprmask[1]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[2], ex->ri_cprmask[2]); | 
|  | +  H_PUT_32 (abfd, in->ri_cprmask[3], ex->ri_cprmask[3]); | 
|  | +  H_PUT_64 (abfd, in->ri_gp_value, ex->ri_gp_value); | 
|  | +} | 
|  | + | 
|  | +/* Swap in an options header.  */ | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf_swap_options_in (bfd *abfd, const Elf_External_Options *ex, | 
|  | +			      Elf_Internal_Options *in) | 
|  | +{ | 
|  | +  in->kind = H_GET_8 (abfd, ex->kind); | 
|  | +  in->size = H_GET_8 (abfd, ex->size); | 
|  | +  in->section = H_GET_16 (abfd, ex->section); | 
|  | +  in->info = H_GET_32 (abfd, ex->info); | 
|  | +} | 
|  | + | 
|  | +/* Swap out an options header.  */ | 
|  | + | 
|  | +void | 
|  | +bfd_riscv_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in, | 
|  | +			       Elf_External_Options *ex) | 
|  | +{ | 
|  | +  H_PUT_8 (abfd, in->kind, ex->kind); | 
|  | +  H_PUT_8 (abfd, in->size, ex->size); | 
|  | +  H_PUT_16 (abfd, in->section, ex->section); | 
|  | +  H_PUT_32 (abfd, in->info, ex->info); | 
|  | +} | 
|  | + | 
|  | +/* This function is called via qsort() to sort the dynamic relocation | 
|  | +   entries by increasing r_symndx value.  */ | 
|  | + | 
|  | +static int | 
|  | +sort_dynamic_relocs (const void *arg1, const void *arg2) | 
|  | +{ | 
|  | +  Elf_Internal_Rela int_reloc1; | 
|  | +  Elf_Internal_Rela int_reloc2; | 
|  | +  int diff; | 
|  | + | 
|  | +  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg1, &int_reloc1); | 
|  | +  bfd_elf32_swap_reloc_in (reldyn_sorting_bfd, arg2, &int_reloc2); | 
|  | + | 
|  | +  diff = ELF32_R_SYM (int_reloc1.r_info) - ELF32_R_SYM (int_reloc2.r_info); | 
|  | +  if (diff != 0) | 
|  | +    return diff; | 
|  | + | 
|  | +  if (int_reloc1.r_offset < int_reloc2.r_offset) | 
|  | +    return -1; | 
|  | +  if (int_reloc1.r_offset > int_reloc2.r_offset) | 
|  | +    return 1; | 
|  | +  return 0; | 
|  | +} | 
|  | + | 
|  | +/* Like sort_dynamic_relocs, but used for elf64 relocations.  */ | 
|  | + | 
|  | +static int | 
|  | +sort_dynamic_relocs_64 (const void *arg1 ATTRIBUTE_UNUSED, | 
|  | +			const void *arg2 ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +#ifdef BFD64 | 
|  | +  Elf_Internal_Rela int_reloc1[3]; | 
|  | +  Elf_Internal_Rela int_reloc2[3]; | 
|  | + | 
|  | +  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in) | 
|  | +    (reldyn_sorting_bfd, arg1, int_reloc1); | 
|  | +  (*get_elf_backend_data (reldyn_sorting_bfd)->s->swap_reloc_in) | 
|  | +    (reldyn_sorting_bfd, arg2, int_reloc2); | 
|  | + | 
|  | +  if (ELF64_R_SYM (int_reloc1[0].r_info) < ELF64_R_SYM (int_reloc2[0].r_info)) | 
|  | +    return -1; | 
|  | +  if (ELF64_R_SYM (int_reloc1[0].r_info) > ELF64_R_SYM (int_reloc2[0].r_info)) | 
|  | +    return 1; | 
|  | + | 
|  | +  if (int_reloc1[0].r_offset < int_reloc2[0].r_offset) | 
|  | +    return -1; | 
|  | +  if (int_reloc1[0].r_offset > int_reloc2[0].r_offset) | 
|  | +    return 1; | 
|  | +  return 0; | 
|  | +#else | 
|  | +  abort (); | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* This routine is used to write out ECOFF debugging external symbol | 
|  | +   information.  It is called via mips_elf_link_hash_traverse.  The | 
|  | +   ECOFF external symbol information must match the ELF external | 
|  | +   symbol information.  Unfortunately, at this point we don't know | 
|  | +   whether a symbol is required by reloc information, so the two | 
|  | +   tables may wind up being different.  We must sort out the external | 
|  | +   symbol information before we can set the final size of the .mdebug | 
|  | +   section, and we must set the size of the .mdebug section before we | 
|  | +   can relocate any sections, and we can't know which symbols are | 
|  | +   required by relocation until we relocate the sections. | 
|  | +   Fortunately, it is relatively unlikely that any symbol will be | 
|  | +   stripped but required by a reloc.  In particular, it can not happen | 
|  | +   when generating a final executable.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) | 
|  | +{ | 
|  | +  struct extsym_info *einfo = data; | 
|  | +  bfd_boolean strip; | 
|  | +  asection *sec, *output_section; | 
|  | + | 
|  | +  if (h->root.root.type == bfd_link_hash_warning) | 
|  | +    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; | 
|  | + | 
|  | +  if (h->root.indx == -2) | 
|  | +    strip = FALSE; | 
|  | +  else if ((h->root.def_dynamic | 
|  | +	    || h->root.ref_dynamic | 
|  | +	    || h->root.type == bfd_link_hash_new) | 
|  | +	   && !h->root.def_regular | 
|  | +	   && !h->root.ref_regular) | 
|  | +    strip = TRUE; | 
|  | +  else if (einfo->info->strip == strip_all | 
|  | +	   || (einfo->info->strip == strip_some | 
|  | +	       && bfd_hash_lookup (einfo->info->keep_hash, | 
|  | +				   h->root.root.root.string, | 
|  | +				   FALSE, FALSE) == NULL)) | 
|  | +    strip = TRUE; | 
|  | +  else | 
|  | +    strip = FALSE; | 
|  | + | 
|  | +  if (strip) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  if (h->esym.ifd == -2) | 
|  | +    { | 
|  | +      h->esym.jmptbl = 0; | 
|  | +      h->esym.cobol_main = 0; | 
|  | +      h->esym.weakext = 0; | 
|  | +      h->esym.reserved = 0; | 
|  | +      h->esym.ifd = ifdNil; | 
|  | +      h->esym.asym.value = 0; | 
|  | +      h->esym.asym.st = stGlobal; | 
|  | + | 
|  | +      if (h->root.root.type == bfd_link_hash_undefined | 
|  | +	  || h->root.root.type == bfd_link_hash_undefweak) | 
|  | +	h->esym.asym.sc = scUndefined; | 
|  | +      else if (h->root.root.type != bfd_link_hash_defined | 
|  | +	  && h->root.root.type != bfd_link_hash_defweak) | 
|  | +	h->esym.asym.sc = scAbs; | 
|  | +      else | 
|  | +	{ | 
|  | +	  const char *name; | 
|  | + | 
|  | +	  sec = h->root.root.u.def.section; | 
|  | +	  output_section = sec->output_section; | 
|  | + | 
|  | +	  /* When making a shared library and symbol h is the one from | 
|  | +	     the another shared library, OUTPUT_SECTION may be null.  */ | 
|  | +	  if (output_section == NULL) | 
|  | +	    h->esym.asym.sc = scUndefined; | 
|  | +	  else | 
|  | +	    { | 
|  | +	      name = bfd_section_name (output_section->owner, output_section); | 
|  | + | 
|  | +	      if (strcmp (name, ".text") == 0) | 
|  | +		h->esym.asym.sc = scText; | 
|  | +	      else if (strcmp (name, ".data") == 0) | 
|  | +		h->esym.asym.sc = scData; | 
|  | +	      else if (strcmp (name, ".rodata") == 0 | 
|  | +		       || strcmp (name, ".rdata") == 0) | 
|  | +		h->esym.asym.sc = scRData; | 
|  | +	      else if (strcmp (name, ".bss") == 0) | 
|  | +		h->esym.asym.sc = scBss; | 
|  | +	      else if (strcmp (name, ".init") == 0) | 
|  | +		h->esym.asym.sc = scInit; | 
|  | +	      else if (strcmp (name, ".fini") == 0) | 
|  | +		h->esym.asym.sc = scFini; | 
|  | +	      else | 
|  | +		h->esym.asym.sc = scAbs; | 
|  | +	    } | 
|  | +	} | 
|  | + | 
|  | +      h->esym.asym.reserved = 0; | 
|  | +      h->esym.asym.index = indexNil; | 
|  | +    } | 
|  | + | 
|  | +  if (h->root.root.type == bfd_link_hash_common) | 
|  | +    h->esym.asym.value = h->root.root.u.c.size; | 
|  | +  else if (h->root.root.type == bfd_link_hash_defined | 
|  | +	   || h->root.root.type == bfd_link_hash_defweak) | 
|  | +    { | 
|  | +      if (h->esym.asym.sc == scCommon || h->esym.asym.sc == scSCommon) | 
|  | +	h->esym.asym.sc = scBss; | 
|  | + | 
|  | +      sec = h->root.root.u.def.section; | 
|  | +      output_section = sec->output_section; | 
|  | +      if (output_section != NULL) | 
|  | +	h->esym.asym.value = (h->root.root.u.def.value | 
|  | +			      + sec->output_offset | 
|  | +			      + output_section->vma); | 
|  | +      else | 
|  | +	h->esym.asym.value = 0; | 
|  | +    } | 
|  | + | 
|  | +  if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, | 
|  | +				      h->root.root.root.string, | 
|  | +				      &h->esym)) | 
|  | +    { | 
|  | +      einfo->failed = TRUE; | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Functions to manage the got entry hash table.  */ | 
|  | + | 
|  | +/* Use all 64 bits of a bfd_vma for the computation of a 32-bit | 
|  | +   hash number.  */ | 
|  | + | 
|  | +static INLINE hashval_t | 
|  | +mips_elf_hash_bfd_vma (bfd_vma addr) | 
|  | +{ | 
|  | +#ifdef BFD64 | 
|  | +  return addr + (addr >> 32); | 
|  | +#else | 
|  | +  return addr; | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | +/* got_entries only match if they're identical, except for gotidx, so | 
|  | +   use all fields to compute the hash, and compare the appropriate | 
|  | +   union members.  */ | 
|  | + | 
|  | +static hashval_t | 
|  | +mips_elf_got_entry_hash (const void *entry_) | 
|  | +{ | 
|  | +  const struct mips_got_entry *entry = (struct mips_got_entry *)entry_; | 
|  | + | 
|  | +  return entry->symndx | 
|  | +    + ((entry->tls_type & GOT_TLS_LDM) << 17) | 
|  | +    + (! entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address) | 
|  | +       : entry->abfd->id | 
|  | +         + (entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend) | 
|  | +	    : entry->d.h->root.root.root.hash)); | 
|  | +} | 
|  | + | 
|  | +static int | 
|  | +mips_elf_got_entry_eq (const void *entry1, const void *entry2) | 
|  | +{ | 
|  | +  const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1; | 
|  | +  const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2; | 
|  | + | 
|  | +  /* An LDM entry can only match another LDM entry.  */ | 
|  | +  if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM) | 
|  | +    return 0; | 
|  | + | 
|  | +  return e1->abfd == e2->abfd && e1->symndx == e2->symndx | 
|  | +    && (! e1->abfd ? e1->d.address == e2->d.address | 
|  | +	: e1->symndx >= 0 ? e1->d.addend == e2->d.addend | 
|  | +	: e1->d.h == e2->d.h); | 
|  | +} | 
|  | + | 
|  | +static hashval_t | 
|  | +mips_got_page_entry_hash (const void *entry_) | 
|  | +{ | 
|  | +  const struct mips_got_page_entry *entry; | 
|  | + | 
|  | +  entry = (const struct mips_got_page_entry *) entry_; | 
|  | +  return entry->abfd->id + entry->symndx; | 
|  | +} | 
|  | + | 
|  | +static int | 
|  | +mips_got_page_entry_eq (const void *entry1_, const void *entry2_) | 
|  | +{ | 
|  | +  const struct mips_got_page_entry *entry1, *entry2; | 
|  | + | 
|  | +  entry1 = (const struct mips_got_page_entry *) entry1_; | 
|  | +  entry2 = (const struct mips_got_page_entry *) entry2_; | 
|  | +  return entry1->abfd == entry2->abfd && entry1->symndx == entry2->symndx; | 
|  | +} | 
|  | + | 
|  | +/* Return the dynamic relocation section.  If it doesn't exist, try to | 
|  | +   create a new it if CREATE_P, otherwise return NULL.  Also return NULL | 
|  | +   if creation fails.  */ | 
|  | + | 
|  | +static asection * | 
|  | +mips_elf_rel_dyn_section (struct bfd_link_info *info, bfd_boolean create_p) | 
|  | +{ | 
|  | +  const char *dname; | 
|  | +  asection *sreloc; | 
|  | +  bfd *dynobj; | 
|  | + | 
|  | +  dname = MIPS_ELF_REL_DYN_NAME (info); | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  sreloc = bfd_get_section_by_name (dynobj, dname); | 
|  | +  if (sreloc == NULL && create_p) | 
|  | +    { | 
|  | +      sreloc = bfd_make_section_with_flags (dynobj, dname, | 
|  | +					    (SEC_ALLOC | 
|  | +					     | SEC_LOAD | 
|  | +					     | SEC_HAS_CONTENTS | 
|  | +					     | SEC_IN_MEMORY | 
|  | +					     | SEC_LINKER_CREATED | 
|  | +					     | SEC_READONLY)); | 
|  | +      if (sreloc == NULL | 
|  | +	  || ! bfd_set_section_alignment (dynobj, sreloc, | 
|  | +					  MIPS_ELF_LOG_FILE_ALIGN (dynobj))) | 
|  | +	return NULL; | 
|  | +    } | 
|  | +  return sreloc; | 
|  | +} | 
|  | + | 
|  | +/* Count the number of relocations needed for a TLS GOT entry, with | 
|  | +   access types from TLS_TYPE, and symbol H (or a local symbol if H | 
|  | +   is NULL).  */ | 
|  | + | 
|  | +static int | 
|  | +mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type, | 
|  | +		     struct elf_link_hash_entry *h) | 
|  | +{ | 
|  | +  int indx = 0; | 
|  | +  int ret = 0; | 
|  | +  bfd_boolean need_relocs = FALSE; | 
|  | +  bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; | 
|  | + | 
|  | +  if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) | 
|  | +      && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h))) | 
|  | +    indx = h->dynindx; | 
|  | + | 
|  | +  if ((info->shared || indx != 0) | 
|  | +      && (h == NULL | 
|  | +	  || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT | 
|  | +	  || h->root.type != bfd_link_hash_undefweak)) | 
|  | +    need_relocs = TRUE; | 
|  | + | 
|  | +  if (!need_relocs) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (tls_type & GOT_TLS_GD) | 
|  | +    { | 
|  | +      ret++; | 
|  | +      if (indx != 0) | 
|  | +	ret++; | 
|  | +    } | 
|  | + | 
|  | +  if (tls_type & GOT_TLS_IE) | 
|  | +    ret++; | 
|  | + | 
|  | +  if ((tls_type & GOT_TLS_LDM) && info->shared) | 
|  | +    ret++; | 
|  | + | 
|  | +  return ret; | 
|  | +} | 
|  | + | 
|  | +/* Count the number of TLS relocations required for the GOT entry in | 
|  | +   ARG1, if it describes a local symbol.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_count_local_tls_relocs (void **arg1, void *arg2) | 
|  | +{ | 
|  | +  struct mips_got_entry *entry = * (struct mips_got_entry **) arg1; | 
|  | +  struct mips_elf_count_tls_arg *arg = arg2; | 
|  | + | 
|  | +  if (entry->abfd != NULL && entry->symndx != -1) | 
|  | +    arg->needed += mips_tls_got_relocs (arg->info, entry->tls_type, NULL); | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Count the number of TLS GOT entries required for the global (or | 
|  | +   forced-local) symbol in ARG1.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_count_global_tls_entries (void *arg1, void *arg2) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_entry *hm | 
|  | +    = (struct mips_elf_link_hash_entry *) arg1; | 
|  | +  struct mips_elf_count_tls_arg *arg = arg2; | 
|  | + | 
|  | +  if (hm->tls_type & GOT_TLS_GD) | 
|  | +    arg->needed += 2; | 
|  | +  if (hm->tls_type & GOT_TLS_IE) | 
|  | +    arg->needed += 1; | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Count the number of TLS relocations required for the global (or | 
|  | +   forced-local) symbol in ARG1.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_count_global_tls_relocs (void *arg1, void *arg2) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_entry *hm | 
|  | +    = (struct mips_elf_link_hash_entry *) arg1; | 
|  | +  struct mips_elf_count_tls_arg *arg = arg2; | 
|  | + | 
|  | +  arg->needed += mips_tls_got_relocs (arg->info, hm->tls_type, &hm->root); | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Output a simple dynamic relocation into SRELOC.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf_output_dynamic_relocation (bfd *output_bfd, | 
|  | +				    asection *sreloc, | 
|  | +				    unsigned long reloc_index, | 
|  | +				    unsigned long indx, | 
|  | +				    int r_type, | 
|  | +				    bfd_vma offset) | 
|  | +{ | 
|  | +  Elf_Internal_Rela rel[3]; | 
|  | + | 
|  | +  memset (rel, 0, sizeof (rel)); | 
|  | + | 
|  | +  rel[0].r_info = ELF_R_INFO (output_bfd, indx, r_type); | 
|  | +  rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset; | 
|  | + | 
|  | +  if (ABI_64_P (output_bfd)) | 
|  | +    { | 
|  | +      (*get_elf_backend_data (output_bfd)->s->swap_reloc_out) | 
|  | +	(output_bfd, &rel[0], | 
|  | +	 (sreloc->contents | 
|  | +	  + reloc_index * sizeof (Elf64_RISCV_External_Rel))); | 
|  | +    } | 
|  | +  else | 
|  | +    bfd_elf32_swap_reloc_out | 
|  | +      (output_bfd, &rel[0], | 
|  | +       (sreloc->contents | 
|  | +	+ reloc_index * sizeof (Elf32_External_Rel))); | 
|  | +} | 
|  | + | 
|  | +/* Initialize a set of TLS GOT entries for one symbol.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset, | 
|  | +			       unsigned char *tls_type_p, | 
|  | +			       struct bfd_link_info *info, | 
|  | +			       struct mips_elf_link_hash_entry *h, | 
|  | +			       bfd_vma value) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  int indx; | 
|  | +  asection *sreloc, *sgot; | 
|  | +  bfd_vma offset, offset2; | 
|  | +  bfd_boolean need_relocs = FALSE; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  if (htab == NULL) | 
|  | +    return; | 
|  | + | 
|  | +  sgot = htab->sgot; | 
|  | + | 
|  | +  indx = 0; | 
|  | +  if (h != NULL) | 
|  | +    { | 
|  | +      bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; | 
|  | + | 
|  | +      if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root) | 
|  | +	  && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root))) | 
|  | +	indx = h->root.dynindx; | 
|  | +    } | 
|  | + | 
|  | +  if (*tls_type_p & GOT_TLS_DONE) | 
|  | +    return; | 
|  | + | 
|  | +  if ((info->shared || indx != 0) | 
|  | +      && (h == NULL | 
|  | +	  || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT | 
|  | +	  || h->root.type != bfd_link_hash_undefweak)) | 
|  | +    need_relocs = TRUE; | 
|  | + | 
|  | +  /* MINUS_ONE means the symbol is not defined in this object.  It may not | 
|  | +     be defined at all; assume that the value doesn't matter in that | 
|  | +     case.  Otherwise complain if we would use the value.  */ | 
|  | +  BFD_ASSERT (value != MINUS_ONE || (indx != 0 && need_relocs) | 
|  | +	      || h->root.root.type == bfd_link_hash_undefweak); | 
|  | + | 
|  | +  /* Emit necessary relocations.  */ | 
|  | +  sreloc = mips_elf_rel_dyn_section (info, FALSE); | 
|  | + | 
|  | +  /* General Dynamic.  */ | 
|  | +  if (*tls_type_p & GOT_TLS_GD) | 
|  | +    { | 
|  | +      offset = got_offset; | 
|  | +      offset2 = offset + MIPS_ELF_GOT_SIZE (abfd); | 
|  | + | 
|  | +      if (need_relocs) | 
|  | +	{ | 
|  | +	  mips_elf_output_dynamic_relocation | 
|  | +	    (abfd, sreloc, sreloc->reloc_count++, indx, | 
|  | +	     ABI_64_P (abfd) ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32, | 
|  | +	     sgot->output_offset + sgot->output_section->vma + offset); | 
|  | + | 
|  | +	  if (indx) | 
|  | +	    mips_elf_output_dynamic_relocation | 
|  | +	      (abfd, sreloc, sreloc->reloc_count++, indx, | 
|  | +	       ABI_64_P (abfd) ? R_RISCV_TLS_DTPREL64 : R_RISCV_TLS_DTPREL32, | 
|  | +	       sgot->output_offset + sgot->output_section->vma + offset2); | 
|  | +	  else | 
|  | +	    MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info), | 
|  | +			       sgot->contents + offset2); | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  MIPS_ELF_PUT_WORD (abfd, 1, | 
|  | +			     sgot->contents + offset); | 
|  | +	  MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info), | 
|  | +			     sgot->contents + offset2); | 
|  | +	} | 
|  | + | 
|  | +      got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd); | 
|  | +    } | 
|  | + | 
|  | +  /* Initial Exec model.  */ | 
|  | +  if (*tls_type_p & GOT_TLS_IE) | 
|  | +    { | 
|  | +      offset = got_offset; | 
|  | + | 
|  | +      if (need_relocs) | 
|  | +	{ | 
|  | +	  if (indx == 0) | 
|  | +	    MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma, | 
|  | +			       sgot->contents + offset); | 
|  | +	  else | 
|  | +	    MIPS_ELF_PUT_WORD (abfd, 0, | 
|  | +			       sgot->contents + offset); | 
|  | + | 
|  | +	  mips_elf_output_dynamic_relocation | 
|  | +	    (abfd, sreloc, sreloc->reloc_count++, indx, | 
|  | +	     ABI_64_P (abfd) ? R_RISCV_TLS_TPREL64 : R_RISCV_TLS_TPREL32, | 
|  | +	     sgot->output_offset + sgot->output_section->vma + offset); | 
|  | +	} | 
|  | +      else | 
|  | +	MIPS_ELF_PUT_WORD (abfd, value - tprel_base (info), | 
|  | +			   sgot->contents + offset); | 
|  | +    } | 
|  | + | 
|  | +  if (*tls_type_p & GOT_TLS_LDM) | 
|  | +    { | 
|  | +      /* The initial offset is zero, and the LD offsets will include the | 
|  | +	 bias by DTP_OFFSET.  */ | 
|  | +      MIPS_ELF_PUT_WORD (abfd, 0, | 
|  | +			 sgot->contents + got_offset | 
|  | +			 + MIPS_ELF_GOT_SIZE (abfd)); | 
|  | + | 
|  | +      if (!info->shared) | 
|  | +	MIPS_ELF_PUT_WORD (abfd, 1, | 
|  | +			   sgot->contents + got_offset); | 
|  | +      else | 
|  | +	mips_elf_output_dynamic_relocation | 
|  | +	  (abfd, sreloc, sreloc->reloc_count++, indx, | 
|  | +	   ABI_64_P (abfd) ? R_RISCV_TLS_DTPMOD64 : R_RISCV_TLS_DTPMOD32, | 
|  | +	   sgot->output_offset + sgot->output_section->vma + got_offset); | 
|  | +    } | 
|  | + | 
|  | +  *tls_type_p |= GOT_TLS_DONE; | 
|  | +} | 
|  | + | 
|  | +/* Return the GOT index to use for a relocation of type R_TYPE against | 
|  | +   a symbol accessed using TLS_TYPE models.  The GOT entries for this | 
|  | +   symbol in this GOT start at GOT_INDEX.  This function initializes the | 
|  | +   GOT entries and corresponding relocations.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type, | 
|  | +		    int r_type, struct bfd_link_info *info, | 
|  | +		    struct mips_elf_link_hash_entry *h, bfd_vma symbol) | 
|  | +{ | 
|  | +  BFD_ASSERT (TLS_GOTTPREL_RELOC_P(r_type) || TLS_GD_RELOC_P(r_type) | 
|  | +	      || TLS_LDM_RELOC_P(r_type)); | 
|  | + | 
|  | +  mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol); | 
|  | + | 
|  | +  if (TLS_GOTTPREL_RELOC_P(r_type)) | 
|  | +    { | 
|  | +      BFD_ASSERT (*tls_type & GOT_TLS_IE); | 
|  | +      if (*tls_type & GOT_TLS_GD) | 
|  | +	return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd); | 
|  | +      else | 
|  | +	return got_index; | 
|  | +    } | 
|  | + | 
|  | +  if (TLS_GD_RELOC_P(r_type)) | 
|  | +    { | 
|  | +      BFD_ASSERT (*tls_type & GOT_TLS_GD); | 
|  | +      return got_index; | 
|  | +    } | 
|  | + | 
|  | +  if (TLS_LDM_RELOC_P(r_type)) | 
|  | +    { | 
|  | +      BFD_ASSERT (*tls_type & GOT_TLS_LDM); | 
|  | +      return got_index; | 
|  | +    } | 
|  | + | 
|  | +  return got_index; | 
|  | +} | 
|  | + | 
|  | +/* Return the GOT offset for address VALUE.   If there is not yet a GOT | 
|  | +   entry for this value, create one.  If R_SYMNDX refers to a TLS symbol, | 
|  | +   create a TLS GOT entry instead.  Return -1 if no satisfactory GOT | 
|  | +   offset can be found.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, | 
|  | +			  bfd_vma value, unsigned long r_symndx, | 
|  | +			  struct mips_elf_link_hash_entry *h, int r_type) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_got_entry *entry; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value, | 
|  | +					   r_symndx, h, r_type); | 
|  | +  if (!entry) | 
|  | +    return MINUS_ONE; | 
|  | + | 
|  | +  if (TLS_RELOC_P (r_type)) | 
|  | +    { | 
|  | +      if (entry->symndx == -1) | 
|  | +	/* A type (3) entry in the single-GOT case.  We use the symbol's | 
|  | +	   hash table entry to track the index.  */ | 
|  | +	return mips_tls_got_index (abfd, h->tls_got_offset, &h->tls_type, | 
|  | +				   r_type, info, h, value); | 
|  | +      else | 
|  | +	return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, | 
|  | +				   r_type, info, h, value); | 
|  | +    } | 
|  | +  else | 
|  | +    return entry->gotidx; | 
|  | +} | 
|  | + | 
|  | +/* Returns the GOT index for the global symbol indicated by H.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_global_got_index (bfd *abfd, struct elf_link_hash_entry *h, | 
|  | +			   int r_type, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  bfd_vma got_index; | 
|  | +  struct mips_got_info *g; | 
|  | +  long global_got_dynindx = 0; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  g = htab->got_info; | 
|  | + | 
|  | +  if (g->global_gotsym != NULL) | 
|  | +    global_got_dynindx = g->global_gotsym->dynindx; | 
|  | + | 
|  | +  if (TLS_RELOC_P (r_type)) | 
|  | +    { | 
|  | +      struct mips_elf_link_hash_entry *hm | 
|  | +	= (struct mips_elf_link_hash_entry *) h; | 
|  | +      bfd_vma value = MINUS_ONE; | 
|  | + | 
|  | +      if ((h->root.type == bfd_link_hash_defined | 
|  | +	   || h->root.type == bfd_link_hash_defweak) | 
|  | +	  && h->root.u.def.section->output_section) | 
|  | +	value = (h->root.u.def.value | 
|  | +		 + h->root.u.def.section->output_offset | 
|  | +		 + h->root.u.def.section->output_section->vma); | 
|  | + | 
|  | +      got_index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type, | 
|  | +				      r_type, info, hm, value); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      /* Once we determine the global GOT entry with the lowest dynamic | 
|  | +	 symbol table index, we must put all dynamic symbols with greater | 
|  | +	 indices into the GOT.  That makes it easy to calculate the GOT | 
|  | +	 offset.  */ | 
|  | +      BFD_ASSERT (h->dynindx >= global_got_dynindx); | 
|  | +      got_index = ((h->dynindx - global_got_dynindx + g->local_gotno) | 
|  | +		   * MIPS_ELF_GOT_SIZE (abfd)); | 
|  | +    } | 
|  | +  BFD_ASSERT (got_index < htab->sgot->size); | 
|  | + | 
|  | +  return got_index; | 
|  | +} | 
|  | + | 
|  | +/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE. | 
|  | +   EXTERNAL is true if the relocation was originally against a global | 
|  | +   symbol that binds locally.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, | 
|  | +		      bfd_vma value, bfd_boolean external) | 
|  | +{ | 
|  | +  struct mips_got_entry *entry; | 
|  | + | 
|  | +  /* GOT16 relocations against local symbols are followed by a LO16 | 
|  | +     relocation; those against global symbols are not.  Thus if the | 
|  | +     symbol was originally local, the GOT16 relocation should load the | 
|  | +     equivalent of %hi(VALUE), otherwise it should load VALUE itself.  */ | 
|  | +  if (! external) | 
|  | +    value = mips_elf_high (value) << RISCV_IMM_BITS; | 
|  | + | 
|  | +  /* It doesn't matter whether the original relocation was R_RISCV_GOT16, | 
|  | +     R_MIPS16_GOT16, R_RISCV_CALL16, etc.  The format of the entry is the | 
|  | +     same in all cases.  */ | 
|  | +  entry = mips_elf_create_local_got_entry (abfd, info, ibfd, value, 0, | 
|  | +					   NULL, R_RISCV_GOT16); | 
|  | +  if (entry) | 
|  | +    return entry->gotidx; | 
|  | +  else | 
|  | +    return MINUS_ONE; | 
|  | +} | 
|  | + | 
|  | +/* Returns the offset for the entry at the INDEXth position | 
|  | +   in the GOT.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_got_offset_from_index (struct bfd_link_info *info, bfd *output_bfd, | 
|  | +				bfd_vma got_index) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  asection *sgot; | 
|  | +  bfd_vma gp; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  sgot = htab->sgot; | 
|  | +  gp = _bfd_get_gp_value (output_bfd); | 
|  | + | 
|  | +  return sgot->output_section->vma + sgot->output_offset + got_index - gp; | 
|  | +} | 
|  | + | 
|  | +/* Create and return a local GOT entry for VALUE, which was calculated | 
|  | +   from a symbol belonging to INPUT_SECTON.  Return NULL if it could not | 
|  | +   be created.  If R_SYMNDX refers to a TLS symbol, create a TLS entry | 
|  | +   instead.  */ | 
|  | + | 
|  | +static struct mips_got_entry * | 
|  | +mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info, | 
|  | +				 bfd *ibfd, bfd_vma value, | 
|  | +				 unsigned long r_symndx, | 
|  | +				 struct mips_elf_link_hash_entry *h, | 
|  | +				 int r_type) | 
|  | +{ | 
|  | +  struct mips_got_entry entry, **loc; | 
|  | +  struct mips_got_info *g; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  entry.abfd = NULL; | 
|  | +  entry.symndx = -1; | 
|  | +  entry.d.address = value; | 
|  | +  entry.tls_type = 0; | 
|  | + | 
|  | +  g = htab->got_info; | 
|  | + | 
|  | +  /* This function shouldn't be called for symbols that live in the global | 
|  | +     area of the GOT.  */ | 
|  | +  BFD_ASSERT (h == NULL || h->global_got_area == GGA_NONE); | 
|  | +  if (TLS_RELOC_P (r_type)) | 
|  | +    { | 
|  | +      struct mips_got_entry *p; | 
|  | + | 
|  | +      entry.abfd = ibfd; | 
|  | +      if (TLS_LDM_RELOC_P(r_type)) | 
|  | +	{ | 
|  | +	  entry.tls_type = GOT_TLS_LDM; | 
|  | +	  entry.symndx = 0; | 
|  | +	  entry.d.addend = 0; | 
|  | +	} | 
|  | +      else if (h == NULL) | 
|  | +	{ | 
|  | +	  entry.symndx = r_symndx; | 
|  | +	  entry.d.addend = 0; | 
|  | +	} | 
|  | +      else | 
|  | +	entry.d.h = h; | 
|  | + | 
|  | +      p = (struct mips_got_entry *) | 
|  | +	htab_find (g->got_entries, &entry); | 
|  | + | 
|  | +      BFD_ASSERT (p); | 
|  | +      return p; | 
|  | +    } | 
|  | + | 
|  | +  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry, | 
|  | +						   INSERT); | 
|  | +  if (*loc) | 
|  | +    return *loc; | 
|  | + | 
|  | +  entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; | 
|  | +  entry.tls_type = 0; | 
|  | + | 
|  | +  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); | 
|  | + | 
|  | +  if (! *loc) | 
|  | +    return NULL; | 
|  | + | 
|  | +  memcpy (*loc, &entry, sizeof entry); | 
|  | + | 
|  | +  if (g->assigned_gotno > g->local_gotno) | 
|  | +    { | 
|  | +      (*loc)->gotidx = -1; | 
|  | +      /* We didn't allocate enough space in the GOT.  */ | 
|  | +      (*_bfd_error_handler) | 
|  | +	(_("not enough GOT space for local GOT entries")); | 
|  | +      bfd_set_error (bfd_error_bad_value); | 
|  | +      return NULL; | 
|  | +    } | 
|  | + | 
|  | +  MIPS_ELF_PUT_WORD (abfd, value, | 
|  | +		     (htab->sgot->contents + entry.gotidx)); | 
|  | + | 
|  | +  return *loc; | 
|  | +} | 
|  | + | 
|  | +/* Return the number of dynamic section symbols required by OUTPUT_BFD. | 
|  | +   The number might be exact or a worst-case estimate, depending on how | 
|  | +   much information is available to elf_backend_omit_section_dynsym at | 
|  | +   the current linking stage.  */ | 
|  | + | 
|  | +static bfd_size_type | 
|  | +count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  bfd_size_type count; | 
|  | + | 
|  | +  count = 0; | 
|  | +  if (info->shared || elf_hash_table (info)->is_relocatable_executable) | 
|  | +    { | 
|  | +      asection *p; | 
|  | +      const struct elf_backend_data *bed; | 
|  | + | 
|  | +      bed = get_elf_backend_data (output_bfd); | 
|  | +      for (p = output_bfd->sections; p ; p = p->next) | 
|  | +	if ((p->flags & SEC_EXCLUDE) == 0 | 
|  | +	    && (p->flags & SEC_ALLOC) != 0 | 
|  | +	    && !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p)) | 
|  | +	  ++count; | 
|  | +    } | 
|  | +  return count; | 
|  | +} | 
|  | + | 
|  | +/* Sort the dynamic symbol table so that symbols that need GOT entries | 
|  | +   appear towards the end.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_elf_hash_sort_data hsd; | 
|  | +  struct mips_got_info *g; | 
|  | + | 
|  | +  if (elf_hash_table (info)->dynsymcount == 0) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  g = htab->got_info; | 
|  | +  if (g == NULL) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  hsd.low = NULL; | 
|  | +  hsd.max_unref_got_dynindx | 
|  | +    = hsd.min_got_dynindx | 
|  | +    = (elf_hash_table (info)->dynsymcount - g->reloc_only_gotno); | 
|  | +  hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1; | 
|  | +  mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *) | 
|  | +				elf_hash_table (info)), | 
|  | +			       mips_elf_sort_hash_table_f, | 
|  | +			       &hsd); | 
|  | + | 
|  | +  /* There should have been enough room in the symbol table to | 
|  | +     accommodate both the GOT and non-GOT symbols.  */ | 
|  | +  BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx); | 
|  | +  BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx | 
|  | +	      == elf_hash_table (info)->dynsymcount); | 
|  | +  BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx | 
|  | +	      == g->global_gotno); | 
|  | + | 
|  | +  /* Now we know which dynamic symbol has the lowest dynamic symbol | 
|  | +     table index in the GOT.  */ | 
|  | +  g->global_gotsym = hsd.low; | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* If H needs a GOT entry, assign it the highest available dynamic | 
|  | +   index.  Otherwise, assign it the lowest available dynamic | 
|  | +   index.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data) | 
|  | +{ | 
|  | +  struct mips_elf_hash_sort_data *hsd = data; | 
|  | + | 
|  | +  if (h->root.root.type == bfd_link_hash_warning) | 
|  | +    h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; | 
|  | + | 
|  | +  /* Symbols without dynamic symbol table entries aren't interesting | 
|  | +     at all.  */ | 
|  | +  if (h->root.dynindx == -1) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  switch (h->global_got_area) | 
|  | +    { | 
|  | +    case GGA_NONE: | 
|  | +      h->root.dynindx = hsd->max_non_got_dynindx++; | 
|  | +      break; | 
|  | + | 
|  | +    case GGA_NORMAL: | 
|  | +      BFD_ASSERT (h->tls_type == GOT_NORMAL); | 
|  | + | 
|  | +      h->root.dynindx = --hsd->min_got_dynindx; | 
|  | +      hsd->low = (struct elf_link_hash_entry *) h; | 
|  | +      break; | 
|  | + | 
|  | +    case GGA_RELOC_ONLY: | 
|  | +      BFD_ASSERT (h->tls_type == GOT_NORMAL); | 
|  | + | 
|  | +      if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx) | 
|  | +	hsd->low = (struct elf_link_hash_entry *) h; | 
|  | +      h->root.dynindx = hsd->max_unref_got_dynindx++; | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* If H is a symbol that needs a global GOT entry, but has a dynamic | 
|  | +   symbol table index lower than any we've seen to date, record it for | 
|  | +   posterity.  FOR_CALL is true if the caller is only interested in | 
|  | +   using the GOT entry for calls.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, | 
|  | +				   bfd *abfd, struct bfd_link_info *info, | 
|  | +				   unsigned char tls_flag) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_elf_link_hash_entry *hmips; | 
|  | +  struct mips_got_entry entry, **loc; | 
|  | +  struct mips_got_info *g; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | + | 
|  | +  /* A global symbol in the GOT must also be in the dynamic symbol | 
|  | +     table.  */ | 
|  | +  if (h->dynindx == -1) | 
|  | +    { | 
|  | +      switch (ELF_ST_VISIBILITY (h->other)) | 
|  | +	{ | 
|  | +	case STV_INTERNAL: | 
|  | +	case STV_HIDDEN: | 
|  | +	  _bfd_elf_link_hash_hide_symbol (info, h, TRUE); | 
|  | +	  break; | 
|  | +	} | 
|  | +      if (!bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  /* Make sure we have a GOT to put this entry into.  */ | 
|  | +  g = htab->got_info; | 
|  | +  BFD_ASSERT (g != NULL); | 
|  | + | 
|  | +  entry.abfd = abfd; | 
|  | +  entry.symndx = -1; | 
|  | +  entry.d.h = (struct mips_elf_link_hash_entry *) h; | 
|  | +  entry.tls_type = 0; | 
|  | + | 
|  | +  loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry, | 
|  | +						   INSERT); | 
|  | + | 
|  | +  /* If we've already marked this entry as needing GOT space, we don't | 
|  | +     need to do it again.  */ | 
|  | +  if (*loc) | 
|  | +    { | 
|  | +      (*loc)->tls_type |= tls_flag; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); | 
|  | + | 
|  | +  if (! *loc) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  entry.gotidx = -1; | 
|  | +  entry.tls_type = tls_flag; | 
|  | + | 
|  | +  memcpy (*loc, &entry, sizeof entry); | 
|  | + | 
|  | +  if (tls_flag == 0) | 
|  | +    hmips->global_got_area = GGA_NORMAL; | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Reserve space in G for a GOT entry containing the value of symbol | 
|  | +   SYMNDX in input bfd ABDF, plus ADDEND.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend, | 
|  | +				  struct bfd_link_info *info, | 
|  | +				  unsigned char tls_flag) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_got_info *g; | 
|  | +  struct mips_got_entry entry, **loc; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  g = htab->got_info; | 
|  | +  BFD_ASSERT (g != NULL); | 
|  | + | 
|  | +  entry.abfd = abfd; | 
|  | +  entry.symndx = symndx; | 
|  | +  entry.d.addend = addend; | 
|  | +  entry.tls_type = tls_flag; | 
|  | +  loc = (struct mips_got_entry **) | 
|  | +    htab_find_slot (g->got_entries, &entry, INSERT); | 
|  | + | 
|  | +  if (*loc) | 
|  | +    { | 
|  | +      if (tls_flag == GOT_TLS_GD && !((*loc)->tls_type & GOT_TLS_GD)) | 
|  | +	{ | 
|  | +	  g->tls_gotno += 2; | 
|  | +	  (*loc)->tls_type |= tls_flag; | 
|  | +	} | 
|  | +      else if (tls_flag == GOT_TLS_IE && !((*loc)->tls_type & GOT_TLS_IE)) | 
|  | +	{ | 
|  | +	  g->tls_gotno += 1; | 
|  | +	  (*loc)->tls_type |= tls_flag; | 
|  | +	} | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  if (tls_flag != 0) | 
|  | +    { | 
|  | +      entry.gotidx = -1; | 
|  | +      entry.tls_type = tls_flag; | 
|  | +      if (tls_flag == GOT_TLS_IE) | 
|  | +	g->tls_gotno += 1; | 
|  | +      else if (tls_flag == GOT_TLS_GD) | 
|  | +	g->tls_gotno += 2; | 
|  | +      else if (g->tls_ldm_offset == MINUS_ONE) | 
|  | +	{ | 
|  | +	  g->tls_ldm_offset = MINUS_TWO; | 
|  | +	  g->tls_gotno += 2; | 
|  | +	} | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      entry.gotidx = g->local_gotno++; | 
|  | +      entry.tls_type = 0; | 
|  | +    } | 
|  | + | 
|  | +  *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); | 
|  | + | 
|  | +  if (! *loc) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  memcpy (*loc, &entry, sizeof entry); | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Return the maximum number of GOT page entries required for RANGE.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_pages_for_range (const struct mips_got_page_range *range) | 
|  | +{ | 
|  | +  return (range->max_addend - range->min_addend + RISCV_IMM_REACH-1) >> RISCV_IMM_BITS; | 
|  | +} | 
|  | + | 
|  | +/* Record that ABFD has a page relocation against symbol SYMNDX and | 
|  | +   that ADDEND is the addend for that relocation. | 
|  | + | 
|  | +   This function creates an upper bound on the number of GOT slots | 
|  | +   required; no attempt is made to combine references to non-overridable | 
|  | +   global symbols across multiple input files.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_record_got_page_entry (struct bfd_link_info *info, bfd *abfd, | 
|  | +				long symndx, bfd_signed_vma addend) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_got_info *g; | 
|  | +  struct mips_got_page_entry lookup, *entry; | 
|  | +  struct mips_got_page_range **range_ptr, *range; | 
|  | +  bfd_vma old_pages, new_pages; | 
|  | +  void **loc; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  g = htab->got_info; | 
|  | +  BFD_ASSERT (g != NULL); | 
|  | + | 
|  | +  /* Find the mips_got_page_entry hash table entry for this symbol.  */ | 
|  | +  lookup.abfd = abfd; | 
|  | +  lookup.symndx = symndx; | 
|  | +  loc = htab_find_slot (g->got_page_entries, &lookup, INSERT); | 
|  | +  if (loc == NULL) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Create a mips_got_page_entry if this is the first time we've | 
|  | +     seen the symbol.  */ | 
|  | +  entry = (struct mips_got_page_entry *) *loc; | 
|  | +  if (!entry) | 
|  | +    { | 
|  | +      entry = bfd_alloc (abfd, sizeof (*entry)); | 
|  | +      if (!entry) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      entry->abfd = abfd; | 
|  | +      entry->symndx = symndx; | 
|  | +      entry->ranges = NULL; | 
|  | +      entry->num_pages = 0; | 
|  | +      *loc = entry; | 
|  | +    } | 
|  | + | 
|  | +  /* Skip over ranges whose maximum extent cannot share a page entry | 
|  | +     with ADDEND.  */ | 
|  | +  range_ptr = &entry->ranges; | 
|  | +  while (*range_ptr && addend > (*range_ptr)->max_addend + RISCV_IMM_REACH/2-1) | 
|  | +    range_ptr = &(*range_ptr)->next; | 
|  | + | 
|  | +  /* If we scanned to the end of the list, or found a range whose | 
|  | +     minimum extent cannot share a page entry with ADDEND, create | 
|  | +     a new singleton range.  */ | 
|  | +  range = *range_ptr; | 
|  | +  if (!range || addend < range->min_addend - (RISCV_IMM_REACH/2-1)) | 
|  | +    { | 
|  | +      range = bfd_alloc (abfd, sizeof (*range)); | 
|  | +      if (!range) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      range->next = *range_ptr; | 
|  | +      range->min_addend = addend; | 
|  | +      range->max_addend = addend; | 
|  | + | 
|  | +      *range_ptr = range; | 
|  | +      entry->num_pages++; | 
|  | +      g->page_gotno++; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* Remember how many pages the old range contributed.  */ | 
|  | +  old_pages = mips_elf_pages_for_range (range); | 
|  | + | 
|  | +  /* Update the ranges.  */ | 
|  | +  if (addend < range->min_addend) | 
|  | +    range->min_addend = addend; | 
|  | +  else if (addend > range->max_addend) | 
|  | +    { | 
|  | +      if (range->next && addend >= range->next->min_addend - (RISCV_IMM_REACH/2-1)) | 
|  | +	{ | 
|  | +	  old_pages += mips_elf_pages_for_range (range->next); | 
|  | +	  range->max_addend = range->next->max_addend; | 
|  | +	  range->next = range->next->next; | 
|  | +	} | 
|  | +      else | 
|  | +	range->max_addend = addend; | 
|  | +    } | 
|  | + | 
|  | +  /* Record any change in the total estimate.  */ | 
|  | +  new_pages = mips_elf_pages_for_range (range); | 
|  | +  if (old_pages != new_pages) | 
|  | +    { | 
|  | +      entry->num_pages += new_pages - old_pages; | 
|  | +      g->page_gotno += new_pages - old_pages; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Add room for N relocations to the .rel(a).dyn section in ABFD.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf_allocate_dynamic_relocations (bfd *abfd, struct bfd_link_info *info, | 
|  | +				       unsigned int n) | 
|  | +{ | 
|  | +  asection *s; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  s = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +  BFD_ASSERT (s != NULL); | 
|  | + | 
|  | +  if (s->size == 0) | 
|  | +    { | 
|  | +      /* Make room for a null element.  */ | 
|  | +      s->size += MIPS_ELF_REL_SIZE (abfd); | 
|  | +      ++s->reloc_count; | 
|  | +    } | 
|  | +  s->size += n * MIPS_ELF_REL_SIZE (abfd); | 
|  | +} | 
|  | + | 
|  | +/* A htab_traverse callback for GOT entries.  Set boolean *DATA to true | 
|  | +   if the GOT entry is for an indirect or warning symbol.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_check_recreate_got (void **entryp, void *data) | 
|  | +{ | 
|  | +  struct mips_got_entry *entry; | 
|  | +  bfd_boolean *must_recreate; | 
|  | + | 
|  | +  entry = (struct mips_got_entry *) *entryp; | 
|  | +  must_recreate = (bfd_boolean *) data; | 
|  | +  if (entry->abfd != NULL && entry->symndx == -1) | 
|  | +    { | 
|  | +      struct mips_elf_link_hash_entry *h; | 
|  | + | 
|  | +      h = entry->d.h; | 
|  | +      if (h->root.root.type == bfd_link_hash_indirect | 
|  | +	  || h->root.root.type == bfd_link_hash_warning) | 
|  | +	{ | 
|  | +	  *must_recreate = TRUE; | 
|  | +	  return 0; | 
|  | +	} | 
|  | +    } | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* A htab_traverse callback for GOT entries.  Add all entries to | 
|  | +   hash table *DATA, converting entries for indirect and warning | 
|  | +   symbols into entries for the target symbol.  Set *DATA to null | 
|  | +   on error.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_recreate_got (void **entryp, void *data) | 
|  | +{ | 
|  | +  htab_t *new_got; | 
|  | +  struct mips_got_entry *entry; | 
|  | +  void **slot; | 
|  | + | 
|  | +  new_got = (htab_t *) data; | 
|  | +  entry = (struct mips_got_entry *) *entryp; | 
|  | +  if (entry->abfd != NULL && entry->symndx == -1) | 
|  | +    { | 
|  | +      struct mips_elf_link_hash_entry *h; | 
|  | + | 
|  | +      h = entry->d.h; | 
|  | +      while (h->root.root.type == bfd_link_hash_indirect | 
|  | +	     || h->root.root.type == bfd_link_hash_warning) | 
|  | +	{ | 
|  | +	  BFD_ASSERT (h->global_got_area == GGA_NONE); | 
|  | +	  h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; | 
|  | +	} | 
|  | +      entry->d.h = h; | 
|  | +    } | 
|  | +  slot = htab_find_slot (*new_got, entry, INSERT); | 
|  | +  if (slot == NULL) | 
|  | +    { | 
|  | +      *new_got = NULL; | 
|  | +      return 0; | 
|  | +    } | 
|  | +  if (*slot == NULL) | 
|  | +    *slot = entry; | 
|  | +  else | 
|  | +    free (entry); | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* If any entries in G->got_entries are for indirect or warning symbols, | 
|  | +   replace them with entries for the target symbol.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_resolve_final_got_entries (struct mips_got_info *g) | 
|  | +{ | 
|  | +  bfd_boolean must_recreate; | 
|  | +  htab_t new_got; | 
|  | + | 
|  | +  must_recreate = FALSE; | 
|  | +  htab_traverse (g->got_entries, mips_elf_check_recreate_got, &must_recreate); | 
|  | +  if (must_recreate) | 
|  | +    { | 
|  | +      new_got = htab_create (htab_size (g->got_entries), | 
|  | +			     mips_elf_got_entry_hash, | 
|  | +			     mips_elf_got_entry_eq, NULL); | 
|  | +      htab_traverse (g->got_entries, mips_elf_recreate_got, &new_got); | 
|  | +      if (new_got == NULL) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      /* Each entry in g->got_entries has either been copied to new_got | 
|  | +	 or freed.  Now delete the hash table itself.  */ | 
|  | +      htab_delete (g->got_entries); | 
|  | +      g->got_entries = new_got; | 
|  | +    } | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* A mips_elf_link_hash_traverse callback for which DATA points | 
|  | +   to the link_info structure.  Count the number of type (3) entries | 
|  | +   in the master GOT.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data) | 
|  | +{ | 
|  | +  struct bfd_link_info *info; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_got_info *g; | 
|  | + | 
|  | +  info = (struct bfd_link_info *) data; | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  g = htab->got_info; | 
|  | +  if (h->global_got_area != GGA_NONE) | 
|  | +    { | 
|  | +      /* Make a final decision about whether the symbol belongs in the | 
|  | +	 local or global GOT.  Symbols that bind locally can (and in the | 
|  | +	 case of forced-local symbols, must) live in the local GOT. | 
|  | +	 Those that are aren't in the dynamic symbol table must also | 
|  | +	 live in the local GOT. | 
|  | + | 
|  | +	 Note that the former condition does not always imply the | 
|  | +	 latter: symbols do not bind locally if they are completely | 
|  | +	 undefined.  We'll report undefined symbols later if appropriate.  */ | 
|  | +      if (h->root.dynindx == -1 || SYMBOL_REFERENCES_LOCAL (info, &h->root)) | 
|  | +	{ | 
|  | +	  /* The symbol belongs in the local GOT.  We no longer need this | 
|  | +	     entry if it was only used for relocations; those relocations | 
|  | +	     will be against the null or section symbol instead of H.  */ | 
|  | +	  if (h->global_got_area != GGA_RELOC_ONLY) | 
|  | +	    g->local_gotno++; | 
|  | +	  h->global_got_area = GGA_NONE; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  g->global_gotno++; | 
|  | +	  if (h->global_got_area == GGA_RELOC_ONLY) | 
|  | +	    g->reloc_only_gotno++; | 
|  | +	} | 
|  | +    } | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Set the TLS GOT index for the GOT entry in ENTRYP.  ENTRYP's NEXT field | 
|  | +   is null iff there is just a single GOT.  */ | 
|  | + | 
|  | +static int | 
|  | +mips_elf_initialize_tls_index (void **entryp, void *p) | 
|  | +{ | 
|  | +  struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; | 
|  | +  struct mips_got_info *g = p; | 
|  | +  bfd_vma next_index; | 
|  | +  unsigned char tls_type; | 
|  | + | 
|  | +  /* We're only interested in TLS symbols.  */ | 
|  | +  if (entry->tls_type == 0) | 
|  | +    return 1; | 
|  | + | 
|  | +  next_index = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno; | 
|  | + | 
|  | +  if (entry->symndx == -1) | 
|  | +    { | 
|  | +      /* A type (3) got entry in the single-GOT case.  We use the symbol's | 
|  | +	 hash table entry to track its index.  */ | 
|  | +      if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE) | 
|  | +	return 1; | 
|  | +      entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE; | 
|  | +      entry->d.h->tls_got_offset = next_index; | 
|  | +      tls_type = entry->d.h->tls_type; | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      if (entry->tls_type & GOT_TLS_LDM) | 
|  | +	{ | 
|  | +	  /* There are separate mips_got_entry objects for each input bfd | 
|  | +	     that requires an LDM entry.  Make sure that all LDM entries in | 
|  | +	     a GOT resolve to the same index.  */ | 
|  | +	  if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE) | 
|  | +	    { | 
|  | +	      entry->gotidx = g->tls_ldm_offset; | 
|  | +	      return 1; | 
|  | +	    } | 
|  | +	  g->tls_ldm_offset = next_index; | 
|  | +	} | 
|  | +      entry->gotidx = next_index; | 
|  | +      tls_type = entry->tls_type; | 
|  | +    } | 
|  | + | 
|  | +  /* Account for the entries we've just allocated.  */ | 
|  | +  if (tls_type & (GOT_TLS_GD | GOT_TLS_LDM)) | 
|  | +    g->tls_assigned_gotno += 2; | 
|  | +  if (tls_type & GOT_TLS_IE) | 
|  | +    g->tls_assigned_gotno += 1; | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Returns the first relocation of type r_type found, beginning with | 
|  | +   RELOCATION.  RELEND is one-past-the-end of the relocation table.  */ | 
|  | + | 
|  | +static const Elf_Internal_Rela * | 
|  | +mips_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, | 
|  | +			  const Elf_Internal_Rela *relocation, | 
|  | +			  const Elf_Internal_Rela *relend) | 
|  | +{ | 
|  | +  unsigned long r_symndx = ELF_R_SYM (abfd, relocation->r_info); | 
|  | + | 
|  | +  while (relocation < relend) | 
|  | +    { | 
|  | +      if (ELF_R_TYPE (abfd, relocation->r_info) == r_type | 
|  | +	  && ELF_R_SYM (abfd, relocation->r_info) == r_symndx) | 
|  | +	return relocation; | 
|  | + | 
|  | +      ++relocation; | 
|  | +    } | 
|  | + | 
|  | +  /* We didn't find it.  */ | 
|  | +  return NULL; | 
|  | +} | 
|  | + | 
|  | +/* Return whether an input relocation is against a local symbol.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_local_relocation_p (bfd *input_bfd, | 
|  | +			     const Elf_Internal_Rela *relocation, | 
|  | +			     asection **local_sections) | 
|  | +{ | 
|  | +  unsigned long r_symndx; | 
|  | +  Elf_Internal_Shdr *symtab_hdr; | 
|  | +  size_t extsymoff; | 
|  | + | 
|  | +  r_symndx = ELF_R_SYM (input_bfd, relocation->r_info); | 
|  | +  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; | 
|  | +  extsymoff = (elf_bad_symtab (input_bfd)) ? 0 : symtab_hdr->sh_info; | 
|  | + | 
|  | +  if (r_symndx < extsymoff) | 
|  | +    return TRUE; | 
|  | +  if (elf_bad_symtab (input_bfd) && local_sections[r_symndx] != NULL) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +/* Sign-extend VALUE, which has the indicated number of BITS.  */ | 
|  | + | 
|  | +bfd_vma | 
|  | +_bfd_riscv_elf_sign_extend (bfd_vma value, int bits) | 
|  | +{ | 
|  | +  if (value & ((bfd_vma) 1 << (bits - 1))) | 
|  | +    /* VALUE is negative.  */ | 
|  | +    value |= ((bfd_vma) - 1) << bits; | 
|  | + | 
|  | +  return value; | 
|  | +} | 
|  | + | 
|  | +/* Return non-zero if the indicated VALUE has overflowed the maximum | 
|  | +   range expressible by a signed number with the indicated number of | 
|  | +   BITS.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_overflow_p (bfd_vma value, int bits) | 
|  | +{ | 
|  | +  bfd_signed_vma svalue = (bfd_signed_vma) value; | 
|  | + | 
|  | +  if (svalue > (1 << (bits - 1)) - 1) | 
|  | +    /* The value is too big.  */ | 
|  | +    return TRUE; | 
|  | +  else if (svalue < -(1 << (bits - 1))) | 
|  | +    /* The value is too small.  */ | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* All is well.  */ | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +/* Create the .got section to hold the global offset table.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  flagword flags; | 
|  | +  register asection *s; | 
|  | +  struct elf_link_hash_entry *h; | 
|  | +  struct bfd_link_hash_entry *bh; | 
|  | +  struct mips_got_info *g; | 
|  | +  bfd_size_type amt; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  /* This function may be called more than once.  */ | 
|  | +  if (htab->sgot) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | 
|  | +	   | SEC_LINKER_CREATED); | 
|  | + | 
|  | +  /* We have to use an alignment of 2**4 here because this is hardcoded | 
|  | +     in the function stub generation and in the linker script.  */ | 
|  | +  s = bfd_make_section_with_flags (abfd, ".got", flags); | 
|  | +  if (s == NULL | 
|  | +      || ! bfd_set_section_alignment (abfd, s, 4)) | 
|  | +    return FALSE; | 
|  | +  htab->sgot = s; | 
|  | + | 
|  | +  /* Define the symbol _GLOBAL_OFFSET_TABLE_.  We don't do this in the | 
|  | +     linker script because we don't want to define the symbol if we | 
|  | +     are not creating a global offset table.  */ | 
|  | +  bh = NULL; | 
|  | +  if (! (_bfd_generic_link_add_one_symbol | 
|  | +	 (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, | 
|  | +	  0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  h = (struct elf_link_hash_entry *) bh; | 
|  | +  h->non_elf = 0; | 
|  | +  h->def_regular = 1; | 
|  | +  h->type = STT_OBJECT; | 
|  | +  elf_hash_table (info)->hgot = h; | 
|  | + | 
|  | +  if (info->shared | 
|  | +      && ! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  amt = sizeof (struct mips_got_info); | 
|  | +  g = bfd_alloc (abfd, amt); | 
|  | +  if (g == NULL) | 
|  | +    return FALSE; | 
|  | +  g->global_gotsym = NULL; | 
|  | +  g->global_gotno = 0; | 
|  | +  g->reloc_only_gotno = 0; | 
|  | +  g->tls_gotno = 0; | 
|  | +  g->local_gotno = 0; | 
|  | +  g->page_gotno = 0; | 
|  | +  g->assigned_gotno = 0; | 
|  | +  g->tls_ldm_offset = MINUS_ONE; | 
|  | +  g->got_entries = htab_try_create (1, mips_elf_got_entry_hash, | 
|  | +				    mips_elf_got_entry_eq, NULL); | 
|  | +  if (g->got_entries == NULL) | 
|  | +    return FALSE; | 
|  | +  g->got_page_entries = htab_try_create (1, mips_got_page_entry_hash, | 
|  | +					 mips_got_page_entry_eq, NULL); | 
|  | +  if (g->got_page_entries == NULL) | 
|  | +    return FALSE; | 
|  | +  htab->got_info = g; | 
|  | +  mips_elf_section_data (s)->elf.this_hdr.sh_flags |= SHF_ALLOC | SHF_WRITE; | 
|  | + | 
|  | +  /* We also need a .got.plt section when generating PLTs.  */ | 
|  | +  s = bfd_make_section_with_flags (abfd, ".got.plt", | 
|  | +				   SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | 
|  | +				   | SEC_IN_MEMORY | SEC_LINKER_CREATED); | 
|  | +  if (s == NULL) | 
|  | +    return FALSE; | 
|  | +  htab->sgotplt = s; | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Calculate the value produced by the RELOCATION (which comes from | 
|  | +   the INPUT_BFD).  The ADDEND is the addend to use for this | 
|  | +   RELOCATION; RELOCATION->R_ADDEND is ignored. | 
|  | + | 
|  | +   The result of the relocation calculation is stored in VALUEP. | 
|  | +   On exit, set *CROSS_MODE_JUMP_P to true if the relocation field | 
|  | +   is a MIPS16 jump to non-MIPS16 code, or vice versa. | 
|  | + | 
|  | +   This function returns bfd_reloc_continue if the caller need take no | 
|  | +   further action regarding this relocation, bfd_reloc_notsupported if | 
|  | +   something goes dramatically wrong, bfd_reloc_overflow if an | 
|  | +   overflow occurs, and bfd_reloc_ok to indicate success.  */ | 
|  | + | 
|  | +static bfd_reloc_status_type | 
|  | +mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, | 
|  | +			       asection *input_section, | 
|  | +			       struct bfd_link_info *info, | 
|  | +			       const Elf_Internal_Rela *relocation, | 
|  | +			       bfd_vma addend, reloc_howto_type *howto, | 
|  | +			       Elf_Internal_Sym *local_syms, | 
|  | +			       asection **local_sections, bfd_vma *valuep, | 
|  | +			       const char **namep, | 
|  | +			       bfd_boolean save_addend) | 
|  | +{ | 
|  | +  /* The eventual value we will return.  */ | 
|  | +  bfd_vma value; | 
|  | +  /* The address of the symbol against which the relocation is | 
|  | +     occurring.  */ | 
|  | +  bfd_vma symbol = 0; | 
|  | +  /* The final GP value to be used for the relocatable, executable, or | 
|  | +     shared object file being produced.  */ | 
|  | +  bfd_vma gp; | 
|  | +  /* The place (section offset or address) of the storage unit being | 
|  | +     relocated.  */ | 
|  | +  bfd_vma p; | 
|  | +  /* The value of GP used to create the relocatable object.  */ | 
|  | +  bfd_vma gp0; | 
|  | +  /* The offset into the global offset table at which the address of | 
|  | +     the relocation entry symbol, adjusted by the addend, resides | 
|  | +     during execution.  */ | 
|  | +  bfd_vma g = MINUS_ONE; | 
|  | +  /* The section in which the symbol referenced by the relocation is | 
|  | +     located.  */ | 
|  | +  asection *sec = NULL; | 
|  | +  struct mips_elf_link_hash_entry *h = NULL; | 
|  | +  /* TRUE if the symbol referred to by this relocation is a local | 
|  | +     symbol.  */ | 
|  | +  bfd_boolean local_p, was_local_p; | 
|  | +  Elf_Internal_Shdr *symtab_hdr; | 
|  | +  size_t extsymoff; | 
|  | +  unsigned long r_symndx; | 
|  | +  int r_type; | 
|  | +  /* TRUE if overflow occurred during the calculation of the | 
|  | +     relocation value.  */ | 
|  | +  bfd_boolean overflowed_p; | 
|  | +  /* TRUE if this relocation refers to a MIPS16 function.  */ | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  bfd *dynobj; | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  /* Parse the relocation.  */ | 
|  | +  r_symndx = ELF_R_SYM (input_bfd, relocation->r_info); | 
|  | +  r_type = ELF_R_TYPE (input_bfd, relocation->r_info); | 
|  | +  p = (input_section->output_section->vma | 
|  | +       + input_section->output_offset | 
|  | +       + relocation->r_offset); | 
|  | + | 
|  | +  /* Assume that there will be no overflow.  */ | 
|  | +  overflowed_p = FALSE; | 
|  | + | 
|  | +  /* Figure out whether or not the symbol is local, and get the offset | 
|  | +     used in the array of hash table entries.  */ | 
|  | +  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; | 
|  | +  local_p = mips_elf_local_relocation_p (input_bfd, relocation, | 
|  | +					 local_sections); | 
|  | +  was_local_p = local_p; | 
|  | +  if (! elf_bad_symtab (input_bfd)) | 
|  | +    extsymoff = symtab_hdr->sh_info; | 
|  | +  else | 
|  | +    { | 
|  | +      /* The symbol table does not follow the rule that local symbols | 
|  | +	 must come before globals.  */ | 
|  | +      extsymoff = 0; | 
|  | +    } | 
|  | + | 
|  | +  /* Figure out the value of the symbol.  */ | 
|  | +  if (local_p) | 
|  | +    { | 
|  | +      Elf_Internal_Sym *sym; | 
|  | + | 
|  | +      sym = local_syms + r_symndx; | 
|  | +      sec = local_sections[r_symndx]; | 
|  | + | 
|  | +      symbol = sec->output_section->vma + sec->output_offset; | 
|  | +      if (ELF_ST_TYPE (sym->st_info) != STT_SECTION | 
|  | +	  || (sec->flags & SEC_MERGE)) | 
|  | +	symbol += sym->st_value; | 
|  | +      if ((sec->flags & SEC_MERGE) | 
|  | +	  && ELF_ST_TYPE (sym->st_info) == STT_SECTION) | 
|  | +	{ | 
|  | +	  addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend); | 
|  | +	  addend -= symbol; | 
|  | +	  addend += sec->output_section->vma + sec->output_offset; | 
|  | +	} | 
|  | + | 
|  | +      /* Record the name of this symbol, for our caller.  */ | 
|  | +      *namep = bfd_elf_string_from_elf_section (input_bfd, | 
|  | +						symtab_hdr->sh_link, | 
|  | +						sym->st_name); | 
|  | +      if (*namep == '\0') | 
|  | +	*namep = bfd_section_name (input_bfd, sec); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ?  */ | 
|  | + | 
|  | +      /* For global symbols we look up the symbol in the hash-table.  */ | 
|  | +      h = ((struct mips_elf_link_hash_entry *) | 
|  | +	   elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); | 
|  | +      /* Find the real hash-table entry for this symbol.  */ | 
|  | +      while (h->root.root.type == bfd_link_hash_indirect | 
|  | +	     || h->root.root.type == bfd_link_hash_warning) | 
|  | +	h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; | 
|  | + | 
|  | +      /* Record the name of this symbol, for our caller.  */ | 
|  | +      *namep = h->root.root.root.string; | 
|  | + | 
|  | +      /* If this symbol is defined, calculate its address.  Note that | 
|  | +	 _gp_disp is a magic symbol, always implicitly defined by the | 
|  | +	 linker, so it's inappropriate to check to see whether or not | 
|  | +	 its defined.  */ | 
|  | +      if ((h->root.root.type == bfd_link_hash_defined | 
|  | +		|| h->root.root.type == bfd_link_hash_defweak) | 
|  | +	       && h->root.root.u.def.section) | 
|  | +	{ | 
|  | +	  sec = h->root.root.u.def.section; | 
|  | +	  if (sec->output_section) | 
|  | +	    symbol = (h->root.root.u.def.value | 
|  | +		      + sec->output_section->vma | 
|  | +		      + sec->output_offset); | 
|  | +	  else | 
|  | +	    symbol = h->root.root.u.def.value; | 
|  | +	} | 
|  | +      else if (h->root.root.type == bfd_link_hash_undefweak) | 
|  | +	/* We allow relocations against undefined weak symbols, giving | 
|  | +	   it the value zero, so that you can undefined weak functions | 
|  | +	   and check to see if they exist by looking at their | 
|  | +	   addresses.  */ | 
|  | +	symbol = 0; | 
|  | +      else if (info->unresolved_syms_in_objects == RM_IGNORE | 
|  | +	       && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) | 
|  | +	symbol = 0; | 
|  | +      else if (strcmp (*namep, "_DYNAMIC_LINKING") == 0) | 
|  | +	{ | 
|  | +	  /* If this is a dynamic link, we should have created a | 
|  | +	     _DYNAMIC_LINKING symbol | 
|  | +	     in in _bfd_riscv_elf_create_dynamic_sections. | 
|  | +	     Otherwise, we should define the symbol with a value of 0. | 
|  | +	     FIXME: It should probably get into the symbol table | 
|  | +	     somehow as well.  */ | 
|  | +	  BFD_ASSERT (! info->shared); | 
|  | +	  BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL); | 
|  | +	  symbol = 0; | 
|  | +	} | 
|  | +      else if ((*info->callbacks->undefined_symbol) | 
|  | +	       (info, h->root.root.root.string, input_bfd, | 
|  | +		input_section, relocation->r_offset, | 
|  | +		(info->unresolved_syms_in_objects == RM_GENERATE_ERROR) | 
|  | +		 || ELF_ST_VISIBILITY (h->root.other))) | 
|  | +	{ | 
|  | +	  return bfd_reloc_undefined; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  return bfd_reloc_notsupported; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root); | 
|  | + | 
|  | +  gp0 = _bfd_get_gp_value (input_bfd); | 
|  | +  gp = _bfd_get_gp_value (abfd); | 
|  | + | 
|  | +  /* If we haven't already determined the GOT offset, and we're going | 
|  | +     to need it, get it now.  */ | 
|  | +  switch (r_type) | 
|  | +    { | 
|  | +    case R_MIPS16_CALL16: | 
|  | +    case R_MIPS16_GOT16: | 
|  | +    case R_RISCV_CALL16: | 
|  | +    case R_RISCV_GOT16: | 
|  | +    case R_RISCV_GOT_DISP: | 
|  | +    case R_RISCV_GOT_HI16: | 
|  | +    case R_RISCV_CALL_HI16: | 
|  | +    case R_RISCV_GOT_LO16: | 
|  | +    case R_RISCV_CALL_LO16: | 
|  | +    case R_RISCV_TLS_GD: | 
|  | +    case R_RISCV_TLS_GD_HI16: | 
|  | +    case R_RISCV_TLS_GD_LO16: | 
|  | +    case R_RISCV_TLS_GOTTPREL: | 
|  | +    case R_RISCV_TLS_GOT_HI16: | 
|  | +    case R_RISCV_TLS_GOT_LO16: | 
|  | +    case R_RISCV_TLS_LDM: | 
|  | +    case R_RISCV_TLS_LDM_HI16: | 
|  | +    case R_RISCV_TLS_LDM_LO16: | 
|  | +      /* Find the index into the GOT where this value is located.  */ | 
|  | +      if (TLS_LDM_RELOC_P(r_type)) | 
|  | +	{ | 
|  | +	  g = mips_elf_local_got_index (abfd, input_bfd, info, | 
|  | +					0, 0, NULL, r_type); | 
|  | +	  if (g == MINUS_ONE) | 
|  | +	    return bfd_reloc_outofrange; | 
|  | +	} | 
|  | +      else if (!local_p) | 
|  | +	{ | 
|  | +	      BFD_ASSERT (addend == 0); | 
|  | +	      g = mips_elf_global_got_index (dynobj, &h->root, r_type, info); | 
|  | +	      if (h->tls_type == GOT_NORMAL | 
|  | +		  && !elf_hash_table (info)->dynamic_sections_created) | 
|  | +		/* This is a static link.  We must initialize the GOT entry.  */ | 
|  | +		MIPS_ELF_PUT_WORD (dynobj, symbol, htab->sgot->contents + g); | 
|  | +	} | 
|  | +      else if (call16_reloc_p (r_type) || got16_reloc_p (r_type)) | 
|  | +	/* The calculation below does not involve "g".  */ | 
|  | +	break; | 
|  | +      else | 
|  | +	{ | 
|  | +	  g = mips_elf_local_got_index (abfd, input_bfd, info, | 
|  | +					symbol + addend, r_symndx, h, r_type); | 
|  | +	  if (g == MINUS_ONE) | 
|  | +	    return bfd_reloc_outofrange; | 
|  | +	} | 
|  | + | 
|  | +      /* Convert GOT indices to actual offsets.  */ | 
|  | +      g = mips_elf_got_offset_from_index (info, abfd, g); | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  /* Figure out what kind of relocation is being performed.  */ | 
|  | +  switch (r_type) | 
|  | +    { | 
|  | +    case R_RISCV_NONE: | 
|  | +      return bfd_reloc_continue; | 
|  | + | 
|  | +    case R_RISCV_32: | 
|  | +    case R_RISCV_REL32: | 
|  | +    case R_RISCV_64: | 
|  | +      if ((info->shared | 
|  | +	   || (htab->root.dynamic_sections_created | 
|  | +	       && h != NULL | 
|  | +	       && h->root.def_dynamic | 
|  | +	       && !h->root.def_regular | 
|  | +	       && !h->has_static_relocs)) | 
|  | +	  && r_symndx != STN_UNDEF | 
|  | +	  && (h == NULL | 
|  | +	      || h->root.root.type != bfd_link_hash_undefweak | 
|  | +	      || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) | 
|  | +	  && (input_section->flags & SEC_ALLOC) != 0) | 
|  | +	{ | 
|  | +	  /* If we're creating a shared library, then we can't know | 
|  | +	     where the symbol will end up.  So, we create a relocation | 
|  | +	     record in the output, and leave the job up to the dynamic | 
|  | +	     linker.  We must do the same for executable references to | 
|  | +	     shared library symbols, unless we've decided to use copy | 
|  | +	     relocs or PLTs instead.  */ | 
|  | +	  value = addend; | 
|  | +	  if (!mips_elf_create_dynamic_relocation (abfd, | 
|  | +						   info, | 
|  | +						   relocation, | 
|  | +						   h, | 
|  | +						   sec, | 
|  | +						   symbol, | 
|  | +						   &value, | 
|  | +						   input_section)) | 
|  | +	    return bfd_reloc_undefined; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  if (r_type != R_RISCV_REL32) | 
|  | +	    value = symbol + addend; | 
|  | +	  else | 
|  | +	    value = addend; | 
|  | +	} | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_PC32: | 
|  | +      value = symbol + addend - p; | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_26: | 
|  | +      if (symbol == 0) | 
|  | +	{ | 
|  | +	  /* Need to support JAL to address 0 to statically link against libc. | 
|  | +	     For now, implement as an infinite loop, "1: JAL 1b", but this is | 
|  | +	     incorrect and we should relax it to JALR ra, x0. */ | 
|  | +	  value = 0; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  value = symbol + _bfd_riscv_elf_sign_extend (addend, RISCV_JUMP_BITS+RISCV_JUMP_ALIGN_BITS) - p; | 
|  | +	  overflowed_p = mips_elf_overflow_p (value, RISCV_JUMP_BITS+RISCV_JUMP_ALIGN_BITS); | 
|  | +	} | 
|  | +      value >>= howto->rightshift; | 
|  | +      value <<= OP_SH_TARGET; | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_DTPREL_HI16: | 
|  | +      value = ((mips_elf_high (addend + symbol - dtprel_base (info)) | 
|  | +		<< OP_SH_BIGIMMEDIATE) & howto->dst_mask); | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_DTPREL_LO16: | 
|  | +    case R_RISCV_TLS_DTPREL32: | 
|  | +    case R_RISCV_TLS_DTPREL64: | 
|  | +      value = ((addend + symbol - dtprel_base (info)) | 
|  | +		<< OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_TPREL_HI16: | 
|  | +      value = (mips_elf_high (addend + symbol - tprel_base (info)) | 
|  | +	       << OP_SH_BIGIMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_TPREL_LO16: | 
|  | +      value = ((symbol + addend - tprel_base (info)) | 
|  | +	        << OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_HI16: | 
|  | +    case R_MIPS16_HI16: | 
|  | +      value = mips_elf_high (addend + symbol) << OP_SH_BIGIMMEDIATE; | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_LO16: | 
|  | +    case R_MIPS16_LO16: | 
|  | +      value = ((symbol + addend) << OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_LITERAL: | 
|  | +      /* Because we don't merge literal sections, we can handle this | 
|  | +	 just like R_RISCV_GPREL16.  In the long run, we should merge | 
|  | +	 shared literals, and then we will need to additional work | 
|  | +	 here.  */ | 
|  | + | 
|  | +      /* Fall through.  */ | 
|  | + | 
|  | +    case R_MIPS16_GPREL: | 
|  | +      /* The R_MIPS16_GPREL performs the same calculation as | 
|  | +	 R_RISCV_GPREL16, but stores the relocated bits in a different | 
|  | +	 order.  We don't need to do anything special here; the | 
|  | +	 differences are handled in mips_elf_perform_relocation.  */ | 
|  | +    case R_RISCV_GPREL16: | 
|  | +      /* Only sign-extend the addend if it was extracted from the | 
|  | +	 instruction.  If the addend was separate, leave it alone, | 
|  | +	 otherwise we may lose significant bits.  */ | 
|  | +      if (howto->partial_inplace) | 
|  | +	addend = _bfd_riscv_elf_sign_extend (addend, RISCV_IMM_BITS); | 
|  | +      value = symbol + addend - gp; | 
|  | +      /* If the symbol was local, any earlier relocatable links will | 
|  | +	 have adjusted its addend with the gp offset, so compensate | 
|  | +	 for that now.  Don't do it for symbols forced local in this | 
|  | +	 link, though, since they won't have had the gp offset applied | 
|  | +	 to them before.  */ | 
|  | +      if (was_local_p) | 
|  | +	value += gp0; | 
|  | +      overflowed_p = mips_elf_overflow_p (value, RISCV_IMM_BITS); | 
|  | +      break; | 
|  | + | 
|  | +    case R_MIPS16_GOT16: | 
|  | +    case R_MIPS16_CALL16: | 
|  | +    case R_RISCV_GOT16: | 
|  | +    case R_RISCV_CALL16: | 
|  | +      if (local_p) | 
|  | +	{ | 
|  | +	  value = mips_elf_got16_entry (abfd, input_bfd, info, | 
|  | +					symbol + addend, !was_local_p); | 
|  | +	  if (value == MINUS_ONE) | 
|  | +	    return bfd_reloc_outofrange; | 
|  | +	  value | 
|  | +	    = mips_elf_got_offset_from_index (info, abfd, value); | 
|  | +	  overflowed_p = mips_elf_overflow_p (value, RISCV_IMM_BITS); | 
|  | +	  value = (value << OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +	  break; | 
|  | +	} | 
|  | + | 
|  | +      /* Fall through.  */ | 
|  | + | 
|  | +    case R_RISCV_TLS_GD: | 
|  | +    case R_RISCV_TLS_GOTTPREL: | 
|  | +    case R_RISCV_TLS_LDM: | 
|  | +    case R_RISCV_GOT_DISP: | 
|  | +      value = g; | 
|  | +      overflowed_p = mips_elf_overflow_p (value, RISCV_IMM_BITS); | 
|  | +      value = (value << OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_GPREL32: | 
|  | +      value = (addend + symbol + gp0 - gp); | 
|  | +      if (!save_addend) | 
|  | +	value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_GOT_HI16: | 
|  | +    case R_RISCV_TLS_GD_HI16: | 
|  | +    case R_RISCV_TLS_LDM_HI16: | 
|  | +    case R_RISCV_GOT_HI16: | 
|  | +    case R_RISCV_CALL_HI16: | 
|  | +      /* We're allowed to handle these two relocations identically. | 
|  | +	 The dynamic linker is allowed to handle the CALL relocations | 
|  | +	 differently by creating a lazy evaluation stub.  */ | 
|  | +      value = (mips_elf_high (g - p + gp) << OP_SH_BIGIMMEDIATE); | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_TLS_GOT_LO16: | 
|  | +    case R_RISCV_TLS_GD_LO16: | 
|  | +    case R_RISCV_TLS_LDM_LO16: | 
|  | +    case R_RISCV_GOT_LO16: | 
|  | +    case R_RISCV_CALL_LO16: | 
|  | +      value = ((g - p + gp) << OP_SH_IMMEDIATE) & howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_SUB: | 
|  | +      value = symbol - addend; | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_SCN_DISP: | 
|  | +      value = symbol + addend - sec->output_offset; | 
|  | +      value &= howto->dst_mask; | 
|  | +      break; | 
|  | + | 
|  | +    case R_RISCV_PJUMP: | 
|  | +    case R_RISCV_GNU_VTINHERIT: | 
|  | +    case R_RISCV_GNU_VTENTRY: | 
|  | +      /* We don't do anything with these at present.  */ | 
|  | +      return bfd_reloc_continue; | 
|  | + | 
|  | +    default: | 
|  | +      /* An unrecognized relocation type.  */ | 
|  | +      return bfd_reloc_notsupported; | 
|  | +    } | 
|  | + | 
|  | +  /* Store the VALUE for our caller.  */ | 
|  | +  *valuep = value; | 
|  | +  return overflowed_p ? bfd_reloc_overflow : bfd_reloc_ok; | 
|  | +} | 
|  | + | 
|  | +/* Obtain the field relocated by RELOCATION.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_obtain_contents (reloc_howto_type *howto, | 
|  | +			  const Elf_Internal_Rela *relocation, | 
|  | +			  bfd *input_bfd, bfd_byte *contents) | 
|  | +{ | 
|  | +  bfd_vma x; | 
|  | +  bfd_byte *location = contents + relocation->r_offset; | 
|  | + | 
|  | +  /* Obtain the bytes.  */ | 
|  | +  x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location); | 
|  | + | 
|  | +  return x; | 
|  | +} | 
|  | + | 
|  | +/* It has been determined that the result of the RELOCATION is the | 
|  | +   VALUE.  Use HOWTO to place VALUE into the output file at the | 
|  | +   appropriate position.  The SECTION is the section to which the | 
|  | +   relocation applies. | 
|  | +   CROSS_MODE_JUMP_P is true if the relocation field | 
|  | +   is a MIPS16 jump to non-MIPS16 code, or vice versa. | 
|  | + | 
|  | +   Returns FALSE if anything goes wrong.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_perform_relocation (struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
|  | +			     reloc_howto_type *howto, | 
|  | +			     const Elf_Internal_Rela *relocation, | 
|  | +			     bfd_vma value, bfd *input_bfd, | 
|  | +			     asection *input_section ATTRIBUTE_UNUSED, bfd_byte *contents) | 
|  | +{ | 
|  | +  bfd_vma x; | 
|  | +  bfd_byte *location; | 
|  | +  bfd_vma dst_mask = howto->dst_mask; | 
|  | + | 
|  | +  /* Figure out where the relocation is occurring.  */ | 
|  | +  location = contents + relocation->r_offset; | 
|  | + | 
|  | +  /* Obtain the current value.  */ | 
|  | +  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents); | 
|  | + | 
|  | +  /* Fix up dst_mask and value for R_RISCV_LO16 relocs on stores. */ | 
|  | +  if (IS_STORE_RELOC (input_bfd, relocation->r_info, x)) | 
|  | +    { | 
|  | +      value >>= OP_SH_IMMEDIATE; | 
|  | +      value = ((value >> RISCV_IMMLO_BITS) << OP_SH_IMMHI) | | 
|  | +	      ((value & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO); | 
|  | +      dst_mask = (OP_MASK_IMMHI << OP_SH_IMMHI) | (OP_MASK_IMMLO << OP_SH_IMMLO); | 
|  | +    } | 
|  | + | 
|  | +  /* Update the field, adding in any nonzero bits in the original. */ | 
|  | +  x = (x &~ dst_mask) | (((x & dst_mask) + value) & dst_mask); | 
|  | + | 
|  | +  /* Put the value into the output.  */ | 
|  | +  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location); | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Create a rel.dyn relocation for the dynamic linker to resolve.  REL | 
|  | +   is the original relocation, which is now being transformed into a | 
|  | +   dynamic relocation.  The ADDENDP is adjusted if necessary; the | 
|  | +   caller should store the result in place of the original addend.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_create_dynamic_relocation (bfd *output_bfd, | 
|  | +				    struct bfd_link_info *info, | 
|  | +				    const Elf_Internal_Rela *rel, | 
|  | +				    struct mips_elf_link_hash_entry *h, | 
|  | +				    asection *sec, bfd_vma symbol, | 
|  | +				    bfd_vma *addendp, asection *input_section) | 
|  | +{ | 
|  | +  Elf_Internal_Rela outrel[3]; | 
|  | +  asection *sreloc; | 
|  | +  int r_type; | 
|  | +  long indx; | 
|  | +  bfd_boolean defined_p; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  r_type = ELF_R_TYPE (output_bfd, rel->r_info); | 
|  | +  sreloc = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +  BFD_ASSERT (sreloc != NULL); | 
|  | +  BFD_ASSERT (sreloc->contents != NULL); | 
|  | +  BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd) | 
|  | +	      < sreloc->size); | 
|  | + | 
|  | +  outrel[0].r_offset = | 
|  | +    _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); | 
|  | +  if (ABI_64_P (output_bfd)) | 
|  | +    { | 
|  | +      outrel[1].r_offset = | 
|  | +	_bfd_elf_section_offset (output_bfd, info, input_section, rel[1].r_offset); | 
|  | +      outrel[2].r_offset = | 
|  | +	_bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); | 
|  | +    } | 
|  | + | 
|  | +  if (outrel[0].r_offset == MINUS_ONE) | 
|  | +    /* The relocation field has been deleted.  */ | 
|  | +    return TRUE; | 
|  | + | 
|  | +  if (outrel[0].r_offset == MINUS_TWO) | 
|  | +    { | 
|  | +      /* The relocation field has been converted into a relative value of | 
|  | +	 some sort.  Functions like _bfd_elf_write_section_eh_frame expect | 
|  | +	 the field to be fully relocated, so add in the symbol's value.  */ | 
|  | +      *addendp += symbol; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* We must now calculate the dynamic symbol table index to use | 
|  | +     in the relocation.  */ | 
|  | +  if (h != NULL && ! SYMBOL_REFERENCES_LOCAL (info, &h->root)) | 
|  | +    { | 
|  | +      BFD_ASSERT (h->global_got_area != GGA_NONE); | 
|  | +      indx = h->root.dynindx; | 
|  | +      /* ??? glibc's ld.so just adds the final GOT entry to the | 
|  | +         relocation field.  It therefore treats relocs against | 
|  | +         defined symbols in the same way as relocs against | 
|  | +         undefined symbols.  */ | 
|  | +      defined_p = FALSE; | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      if (sec != NULL && bfd_is_abs_section (sec)) | 
|  | +	indx = 0; | 
|  | +      else if (sec == NULL || sec->owner == NULL) | 
|  | +	{ | 
|  | +	  bfd_set_error (bfd_error_bad_value); | 
|  | +	  return FALSE; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  indx = elf_section_data (sec->output_section)->dynindx; | 
|  | +	  if (indx == 0) | 
|  | +	    { | 
|  | +	      asection *osec = htab->root.text_index_section; | 
|  | +	      indx = elf_section_data (osec)->dynindx; | 
|  | +	    } | 
|  | +	  if (indx == 0) | 
|  | +	    abort (); | 
|  | +	} | 
|  | + | 
|  | +      /* Instead of generating a relocation using the section | 
|  | +	 symbol, we may as well make it a fully relative | 
|  | +	 relocation.  We want to avoid generating relocations to | 
|  | +	 local symbols because we used to generate them | 
|  | +	 incorrectly, without adding the original symbol value, | 
|  | +	 which is mandated by the ABI for section symbols.  In | 
|  | +	 order to give dynamic loaders and applications time to | 
|  | +	 phase out the incorrect use, we refrain from emitting | 
|  | +	 section-relative relocations.  It's not like they're | 
|  | +	 useful, after all.  This should be a bit more efficient | 
|  | +	 as well.  */ | 
|  | +      /* ??? Although this behavior is compatible with glibc's ld.so, | 
|  | +	 the ABI says that relocations against STN_UNDEF should have | 
|  | +	 a symbol value of 0.  Irix rld honors this, so relocations | 
|  | +	 against STN_UNDEF have no effect.  */ | 
|  | +      indx = 0; | 
|  | +      defined_p = TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* If the relocation was previously an absolute relocation and | 
|  | +     this symbol will not be referred to by the relocation, we must | 
|  | +     adjust it by the value we give it in the dynamic symbol table. | 
|  | +     Otherwise leave the job up to the dynamic linker.  */ | 
|  | +  if (defined_p && r_type != R_RISCV_REL32) | 
|  | +    *addendp += symbol; | 
|  | + | 
|  | +  /* The relocation is always an REL32 relocation because we don't | 
|  | +     know where the shared library will wind up at load-time.  */ | 
|  | +  outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, | 
|  | +				 R_RISCV_REL32); | 
|  | + | 
|  | +  /* For strict adherence to the ABI specification, we should | 
|  | +     generate a R_RISCV_64 relocation record by itself before the | 
|  | +     _REL32/_64 record as well, such that the addend is read in as | 
|  | +     a 64-bit value (REL32 is a 32-bit relocation, after all). | 
|  | +     However, since none of the existing ELF64 MIPS dynamic | 
|  | +     loaders seems to care, we don't waste space with these | 
|  | +     artificial relocations.  If this turns out to not be true, | 
|  | +     mips_elf_allocate_dynamic_relocation() should be tweaked so | 
|  | +     as to make room for a pair of dynamic relocations per | 
|  | +     invocation if ABI_64_P, and here we should generate an | 
|  | +     additional relocation record with R_RISCV_64 by itself for a | 
|  | +     NULL symbol before this relocation record.  */ | 
|  | +  outrel[1].r_info = ELF_R_INFO (output_bfd, 0, | 
|  | +				 ABI_64_P (output_bfd) | 
|  | +				 ? R_RISCV_64 | 
|  | +				 : R_RISCV_NONE); | 
|  | +  outrel[2].r_info = ELF_R_INFO (output_bfd, 0, R_RISCV_NONE); | 
|  | + | 
|  | +  /* Adjust the output offset of the relocation to reference the | 
|  | +     correct location in the output file.  */ | 
|  | +  outrel[0].r_offset += (input_section->output_section->vma | 
|  | +			 + input_section->output_offset); | 
|  | +  outrel[1].r_offset += (input_section->output_section->vma | 
|  | +			 + input_section->output_offset); | 
|  | +  outrel[2].r_offset += (input_section->output_section->vma | 
|  | +			 + input_section->output_offset); | 
|  | + | 
|  | +  /* Put the relocation back out.  We have to use the special | 
|  | +     relocation outputter in the 64-bit case since the 64-bit | 
|  | +     relocation format is non-standard.  */ | 
|  | +  if (ABI_64_P (output_bfd)) | 
|  | +    { | 
|  | +      (*get_elf_backend_data (output_bfd)->s->swap_reloc_out) | 
|  | +	(output_bfd, &outrel[0], | 
|  | +	 (sreloc->contents | 
|  | +	  + sreloc->reloc_count * sizeof (Elf64_RISCV_External_Rel))); | 
|  | +    } | 
|  | +  else | 
|  | +    bfd_elf32_swap_reloc_out | 
|  | +      (output_bfd, &outrel[0], | 
|  | +       (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel))); | 
|  | + | 
|  | +  /* We've now added another relocation.  */ | 
|  | +  ++sreloc->reloc_count; | 
|  | + | 
|  | +  /* Make sure the output section is writable.  The dynamic linker | 
|  | +     will be writing to it.  */ | 
|  | +  elf_section_data (input_section->output_section)->this_hdr.sh_flags | 
|  | +    |= SHF_WRITE; | 
|  | + | 
|  | +  /* If we've written this relocation for a readonly section, | 
|  | +     we need to set DF_TEXTREL again, so that we do not delete the | 
|  | +     DT_TEXTREL tag.  */ | 
|  | +  if (MIPS_ELF_READONLY_SECTION (input_section)) | 
|  | +    info->flags |= DF_TEXTREL; | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Return the MACH for a MIPS e_flags value.  */ | 
|  | + | 
|  | +unsigned long | 
|  | +_bfd_elf_riscv_mach (flagword flags) | 
|  | +{ | 
|  | +  switch (flags & EF_MIPS_MACH) | 
|  | +    { | 
|  | +    case E_RISCV_MACH_ROCKET32: | 
|  | +      return bfd_mach_riscv_rocket32; | 
|  | + | 
|  | +    case E_RISCV_MACH_ROCKET64: | 
|  | +      return bfd_mach_riscv_rocket64; | 
|  | + | 
|  | +    default: | 
|  | +      switch (flags & EF_MIPS_ARCH) | 
|  | +	{ | 
|  | +	case E_RISCV_ARCH_RV32: | 
|  | +	  return bfd_mach_riscv_rocket32; | 
|  | + | 
|  | +	default: | 
|  | +	case E_RISCV_ARCH_RV64: | 
|  | +	  return bfd_mach_riscv_rocket64; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return 0; | 
|  | +} | 
|  | + | 
|  | +/* Return printable name for ABI.  */ | 
|  | + | 
|  | +static INLINE char * | 
|  | +elf_mips_abi_name (bfd *abfd) | 
|  | +{ | 
|  | +  flagword flags; | 
|  | + | 
|  | +  flags = elf_elfheader (abfd)->e_flags; | 
|  | +  switch (flags & EF_MIPS_ABI) | 
|  | +    { | 
|  | +    case 0: | 
|  | +      if (ABI_32_P (abfd)) | 
|  | +	return "32"; | 
|  | +      else if (ABI_64_P (abfd)) | 
|  | +	return "64"; | 
|  | +      else | 
|  | +	return "none"; | 
|  | +    default: | 
|  | +      return "unknown abi"; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* MIPS ELF uses two common sections.  One is the usual one, and the | 
|  | +   other is for small objects.  All the small objects are kept | 
|  | +   together, and then referenced via the gp pointer, which yields | 
|  | +   faster assembler code.  This is what we use for the small common | 
|  | +   section.  This approach is copied from ecoff.c.  */ | 
|  | +static asection mips_elf_scom_section; | 
|  | +static asymbol mips_elf_scom_symbol; | 
|  | +static asymbol *mips_elf_scom_symbol_ptr; | 
|  | + | 
|  | +/* MIPS ELF also uses an acommon section, which represents an | 
|  | +   allocated common symbol which may be overridden by a | 
|  | +   definition in a shared library.  */ | 
|  | +static asection mips_elf_acom_section; | 
|  | +static asymbol mips_elf_acom_symbol; | 
|  | +static asymbol *mips_elf_acom_symbol_ptr; | 
|  | + | 
|  | +/* This is used for both the 32-bit and the 64-bit ABI.  */ | 
|  | + | 
|  | +void | 
|  | +_bfd_riscv_elf_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, asymbol *asym) | 
|  | +{ | 
|  | +  elf_symbol_type *elfsym; | 
|  | + | 
|  | +  /* Handle the special MIPS section numbers that a symbol may use.  */ | 
|  | +  elfsym = (elf_symbol_type *) asym; | 
|  | +  switch (elfsym->internal_elf_sym.st_shndx) | 
|  | +    { | 
|  | +    case SHN_MIPS_ACOMMON: | 
|  | +      /* This section is used in a dynamically linked executable file. | 
|  | +	 It is an allocated common section.  The dynamic linker can | 
|  | +	 either resolve these symbols to something in a shared | 
|  | +	 library, or it can just leave them here.  For our purposes, | 
|  | +	 we can consider these symbols to be in a new section.  */ | 
|  | +      if (mips_elf_acom_section.name == NULL) | 
|  | +	{ | 
|  | +	  /* Initialize the acommon section.  */ | 
|  | +	  mips_elf_acom_section.name = ".acommon"; | 
|  | +	  mips_elf_acom_section.flags = SEC_ALLOC; | 
|  | +	  mips_elf_acom_section.output_section = &mips_elf_acom_section; | 
|  | +	  mips_elf_acom_section.symbol = &mips_elf_acom_symbol; | 
|  | +	  mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr; | 
|  | +	  mips_elf_acom_symbol.name = ".acommon"; | 
|  | +	  mips_elf_acom_symbol.flags = BSF_SECTION_SYM; | 
|  | +	  mips_elf_acom_symbol.section = &mips_elf_acom_section; | 
|  | +	  mips_elf_acom_symbol_ptr = &mips_elf_acom_symbol; | 
|  | +	} | 
|  | +      asym->section = &mips_elf_acom_section; | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_COMMON: | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_SCOMMON: | 
|  | +      if (mips_elf_scom_section.name == NULL) | 
|  | +	{ | 
|  | +	  /* Initialize the small common section.  */ | 
|  | +	  mips_elf_scom_section.name = ".scommon"; | 
|  | +	  mips_elf_scom_section.flags = SEC_IS_COMMON; | 
|  | +	  mips_elf_scom_section.output_section = &mips_elf_scom_section; | 
|  | +	  mips_elf_scom_section.symbol = &mips_elf_scom_symbol; | 
|  | +	  mips_elf_scom_section.symbol_ptr_ptr = &mips_elf_scom_symbol_ptr; | 
|  | +	  mips_elf_scom_symbol.name = ".scommon"; | 
|  | +	  mips_elf_scom_symbol.flags = BSF_SECTION_SYM; | 
|  | +	  mips_elf_scom_symbol.section = &mips_elf_scom_section; | 
|  | +	  mips_elf_scom_symbol_ptr = &mips_elf_scom_symbol; | 
|  | +	} | 
|  | +      asym->section = &mips_elf_scom_section; | 
|  | +      asym->value = elfsym->internal_elf_sym.st_size; | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_SUNDEFINED: | 
|  | +      asym->section = bfd_und_section_ptr; | 
|  | +      break; | 
|  | +  } | 
|  | + | 
|  | +  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */ | 
|  | +  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC | 
|  | +      && (asym->value & 1) != 0) | 
|  | +    { | 
|  | +      asym->value--; | 
|  | +      elfsym->internal_elf_sym.st_other | 
|  | +	= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other); | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Implement elf_backend_eh_frame_address_size. */ | 
|  | + | 
|  | +unsigned int | 
|  | +_bfd_riscv_elf_eh_frame_address_size (bfd *abfd, asection *sec ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) | 
|  | +    return 8; | 
|  | +  return 4; | 
|  | +} | 
|  | + | 
|  | +/* There appears to be a bug in the MIPSpro linker that causes GOT_DISP | 
|  | +   relocations against two unnamed section symbols to resolve to the | 
|  | +   same address.  For example, if we have code like: | 
|  | + | 
|  | +	lw	$4,%got_disp(.data)($gp) | 
|  | +	lw	$25,%got_disp(.text)($gp) | 
|  | +	jalr	$25 | 
|  | + | 
|  | +   then the linker will resolve both relocations to .data and the program | 
|  | +   will jump there rather than to .text. | 
|  | + | 
|  | +   We can work around this problem by giving names to local section symbols. | 
|  | +   This is also what the MIPSpro tools do.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_name_local_section_symbols (bfd *abfd ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +/* Work over a section just before writing it out.  This routine is | 
|  | +   used by both the 32-bit and the 64-bit ABI.  FIXME: We recognize | 
|  | +   sections that need the SHF_MIPS_GPREL flag by name; there has to be | 
|  | +   a better way.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) | 
|  | +{ | 
|  | +  if (hdr->sh_type == SHT_MIPS_REGINFO | 
|  | +      && hdr->sh_size > 0) | 
|  | +    { | 
|  | +      bfd_byte buf[4]; | 
|  | + | 
|  | +      BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo)); | 
|  | +      BFD_ASSERT (hdr->contents == NULL); | 
|  | + | 
|  | +      if (bfd_seek (abfd, | 
|  | +		    hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4, | 
|  | +		    SEEK_SET) != 0) | 
|  | +	return FALSE; | 
|  | +      H_PUT_32 (abfd, elf_gp (abfd), buf); | 
|  | +      if (bfd_bwrite (buf, 4, abfd) != 4) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  if (hdr->sh_type == SHT_MIPS_OPTIONS | 
|  | +      && hdr->bfd_section != NULL | 
|  | +      && mips_elf_section_data (hdr->bfd_section) != NULL | 
|  | +      && mips_elf_section_data (hdr->bfd_section)->u.tdata != NULL) | 
|  | +    { | 
|  | +      bfd_byte *contents, *l, *lend; | 
|  | + | 
|  | +      /* We stored the section contents in the tdata field in the | 
|  | +	 set_section_contents routine.  We save the section contents | 
|  | +	 so that we don't have to read them again. | 
|  | +	 At this point we know that elf_gp is set, so we can look | 
|  | +	 through the section contents to see if there is an | 
|  | +	 ODK_REGINFO structure.  */ | 
|  | + | 
|  | +      contents = mips_elf_section_data (hdr->bfd_section)->u.tdata; | 
|  | +      l = contents; | 
|  | +      lend = contents + hdr->sh_size; | 
|  | +      while (l + sizeof (Elf_External_Options) <= lend) | 
|  | +	{ | 
|  | +	  Elf_Internal_Options intopt; | 
|  | + | 
|  | +	  bfd_riscv_elf_swap_options_in (abfd, (Elf_External_Options *) l, | 
|  | +					&intopt); | 
|  | +	  if (intopt.size < sizeof (Elf_External_Options)) | 
|  | +	    { | 
|  | +	      (*_bfd_error_handler) | 
|  | +		(_("%B: Warning: bad `%s' option size %u smaller than its header"), | 
|  | +		abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size); | 
|  | +	      break; | 
|  | +	    } | 
|  | +	  if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO) | 
|  | +	    { | 
|  | +	      bfd_byte buf[8]; | 
|  | + | 
|  | +	      if (bfd_seek (abfd, | 
|  | +			    (hdr->sh_offset | 
|  | +			     + (l - contents) | 
|  | +			     + sizeof (Elf_External_Options) | 
|  | +			     + (sizeof (Elf64_External_RegInfo) - 8)), | 
|  | +			     SEEK_SET) != 0) | 
|  | +		return FALSE; | 
|  | +	      H_PUT_64 (abfd, elf_gp (abfd), buf); | 
|  | +	      if (bfd_bwrite (buf, 8, abfd) != 8) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | +	  else if (intopt.kind == ODK_REGINFO) | 
|  | +	    { | 
|  | +	      bfd_byte buf[4]; | 
|  | + | 
|  | +	      if (bfd_seek (abfd, | 
|  | +			    (hdr->sh_offset | 
|  | +			     + (l - contents) | 
|  | +			     + sizeof (Elf_External_Options) | 
|  | +			     + (sizeof (Elf32_External_RegInfo) - 4)), | 
|  | +			    SEEK_SET) != 0) | 
|  | +		return FALSE; | 
|  | +	      H_PUT_32 (abfd, elf_gp (abfd), buf); | 
|  | +	      if (bfd_bwrite (buf, 4, abfd) != 4) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | +	  l += intopt.size; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if (hdr->bfd_section != NULL) | 
|  | +    { | 
|  | +      const char *name = bfd_get_section_name (abfd, hdr->bfd_section); | 
|  | + | 
|  | +      if (strcmp (name, ".rtproc") == 0) | 
|  | +	{ | 
|  | +	  if (hdr->sh_addralign != 0 && hdr->sh_entsize == 0) | 
|  | +	    { | 
|  | +	      unsigned int adjust; | 
|  | + | 
|  | +	      adjust = hdr->sh_size % hdr->sh_addralign; | 
|  | +	      if (adjust != 0) | 
|  | +		hdr->sh_size += hdr->sh_addralign - adjust; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Handle a MIPS specific section when reading an object file.  This | 
|  | +   is called when elfcode.h finds a section with an unknown type. | 
|  | +   This routine supports both the 32-bit and 64-bit ELF ABI. | 
|  | + | 
|  | +   FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure | 
|  | +   how to.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_section_from_shdr (bfd *abfd, | 
|  | +				 Elf_Internal_Shdr *hdr, | 
|  | +				 const char *name, | 
|  | +				 int shindex) | 
|  | +{ | 
|  | +  flagword flags = 0; | 
|  | + | 
|  | +  /* There ought to be a place to keep ELF backend specific flags, but | 
|  | +     at the moment there isn't one.  We just keep track of the | 
|  | +     sections by their name, instead.  Fortunately, the ABI gives | 
|  | +     suggested names for all the MIPS specific sections, so we will | 
|  | +     probably get away with this.  */ | 
|  | +  switch (hdr->sh_type) | 
|  | +    { | 
|  | +    case SHT_MIPS_LIBLIST: | 
|  | +      if (strcmp (name, ".liblist") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_MSYM: | 
|  | +      if (strcmp (name, ".msym") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_CONFLICT: | 
|  | +      if (strcmp (name, ".conflict") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_GPTAB: | 
|  | +      BFD_ASSERT (FALSE); | 
|  | +    case SHT_MIPS_UCODE: | 
|  | +      if (strcmp (name, ".ucode") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_DEBUG: | 
|  | +      if (strcmp (name, ".mdebug") != 0) | 
|  | +	return FALSE; | 
|  | +      flags = SEC_DEBUGGING; | 
|  | +      break; | 
|  | +    case SHT_MIPS_REGINFO: | 
|  | +      if (strcmp (name, ".reginfo") != 0 | 
|  | +	  || hdr->sh_size != sizeof (Elf32_External_RegInfo)) | 
|  | +	return FALSE; | 
|  | +      flags = (SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_SIZE); | 
|  | +      break; | 
|  | +    case SHT_MIPS_IFACE: | 
|  | +      if (strcmp (name, ".MIPS.interfaces") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_CONTENT: | 
|  | +      if (! CONST_STRNEQ (name, ".MIPS.content")) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_OPTIONS: | 
|  | +      if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_DWARF: | 
|  | +      if (! CONST_STRNEQ (name, ".debug_") | 
|  | +          && ! CONST_STRNEQ (name, ".zdebug_")) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_SYMBOL_LIB: | 
|  | +      if (strcmp (name, ".MIPS.symlib") != 0) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    case SHT_MIPS_EVENTS: | 
|  | +      if (! CONST_STRNEQ (name, ".MIPS.events") | 
|  | +	  && ! CONST_STRNEQ (name, ".MIPS.post_rel")) | 
|  | +	return FALSE; | 
|  | +      break; | 
|  | +    default: | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (flags) | 
|  | +    { | 
|  | +      if (! bfd_set_section_flags (abfd, hdr->bfd_section, | 
|  | +				   (bfd_get_section_flags (abfd, | 
|  | +							   hdr->bfd_section) | 
|  | +				    | flags))) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  /* FIXME: We should record sh_info for a .gptab section.  */ | 
|  | + | 
|  | +  /* For a .reginfo section, set the gp value in the tdata information | 
|  | +     from the contents of this section.  We need the gp value while | 
|  | +     processing relocs, so we just get it now.  The .reginfo section | 
|  | +     is not used in the 64-bit MIPS ELF ABI.  */ | 
|  | +  if (hdr->sh_type == SHT_MIPS_REGINFO) | 
|  | +    { | 
|  | +      Elf32_External_RegInfo ext; | 
|  | +      Elf32_RegInfo s; | 
|  | + | 
|  | +      if (! bfd_get_section_contents (abfd, hdr->bfd_section, | 
|  | +				      &ext, 0, sizeof ext)) | 
|  | +	return FALSE; | 
|  | +      bfd_riscv_elf32_swap_reginfo_in (abfd, &ext, &s); | 
|  | +      elf_gp (abfd) = s.ri_gp_value; | 
|  | +    } | 
|  | + | 
|  | +  /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and | 
|  | +     set the gp value based on what we find.  We may see both | 
|  | +     SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case, | 
|  | +     they should agree.  */ | 
|  | +  if (hdr->sh_type == SHT_MIPS_OPTIONS) | 
|  | +    { | 
|  | +      bfd_byte *contents, *l, *lend; | 
|  | + | 
|  | +      contents = bfd_malloc (hdr->sh_size); | 
|  | +      if (contents == NULL) | 
|  | +	return FALSE; | 
|  | +      if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents, | 
|  | +				      0, hdr->sh_size)) | 
|  | +	{ | 
|  | +	  free (contents); | 
|  | +	  return FALSE; | 
|  | +	} | 
|  | +      l = contents; | 
|  | +      lend = contents + hdr->sh_size; | 
|  | +      while (l + sizeof (Elf_External_Options) <= lend) | 
|  | +	{ | 
|  | +	  Elf_Internal_Options intopt; | 
|  | + | 
|  | +	  bfd_riscv_elf_swap_options_in (abfd, (Elf_External_Options *) l, | 
|  | +					&intopt); | 
|  | +	  if (intopt.size < sizeof (Elf_External_Options)) | 
|  | +	    { | 
|  | +	      (*_bfd_error_handler) | 
|  | +		(_("%B: Warning: bad `%s' option size %u smaller than its header"), | 
|  | +		abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size); | 
|  | +	      break; | 
|  | +	    } | 
|  | +	  if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO) | 
|  | +	    { | 
|  | +	      Elf64_Internal_RegInfo intreg; | 
|  | + | 
|  | +	      bfd_riscv_elf64_swap_reginfo_in | 
|  | +		(abfd, | 
|  | +		 ((Elf64_External_RegInfo *) | 
|  | +		  (l + sizeof (Elf_External_Options))), | 
|  | +		 &intreg); | 
|  | +	      elf_gp (abfd) = intreg.ri_gp_value; | 
|  | +	    } | 
|  | +	  else if (intopt.kind == ODK_REGINFO) | 
|  | +	    { | 
|  | +	      Elf32_RegInfo intreg; | 
|  | + | 
|  | +	      bfd_riscv_elf32_swap_reginfo_in | 
|  | +		(abfd, | 
|  | +		 ((Elf32_External_RegInfo *) | 
|  | +		  (l + sizeof (Elf_External_Options))), | 
|  | +		 &intreg); | 
|  | +	      elf_gp (abfd) = intreg.ri_gp_value; | 
|  | +	    } | 
|  | +	  l += intopt.size; | 
|  | +	} | 
|  | +      free (contents); | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Set the correct type for a MIPS ELF section.  We do this by the | 
|  | +   section name, which is a hack, but ought to work.  This routine is | 
|  | +   used by both the 32-bit and the 64-bit ABI.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +                              Elf_Internal_Shdr *hdr, asection *sec) | 
|  | +{ | 
|  | +  const char *name = bfd_get_section_name (abfd, sec); | 
|  | + | 
|  | +  if (strcmp (name, ".liblist") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_LIBLIST; | 
|  | +      hdr->sh_info = sec->size / sizeof (Elf32_Lib); | 
|  | +      /* The sh_link field is set in final_write_processing.  */ | 
|  | +    } | 
|  | +  else if (strcmp (name, ".conflict") == 0) | 
|  | +    hdr->sh_type = SHT_MIPS_CONFLICT; | 
|  | +  else if (CONST_STRNEQ (name, ".gptab.")) | 
|  | +    BFD_ASSERT (FALSE); | 
|  | +  else if (strcmp (name, ".ucode") == 0) | 
|  | +    hdr->sh_type = SHT_MIPS_UCODE; | 
|  | +  else if (strcmp (name, ".mdebug") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_DEBUG; | 
|  | +      hdr->sh_entsize = 1; | 
|  | +    } | 
|  | +  else if (strcmp (name, ".reginfo") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_REGINFO; | 
|  | +      /* In a shared object on IRIX 5.3, the .reginfo section has an | 
|  | +         entsize of 0x18.  FIXME: Does this matter?  */ | 
|  | +      hdr->sh_entsize = sizeof (Elf32_External_RegInfo); | 
|  | +    } | 
|  | +  else if (strcmp (name, ".got") == 0 | 
|  | +	   || strcmp (name, ".srdata") == 0 | 
|  | +	   || strcmp (name, ".sdata") == 0 | 
|  | +	   || strcmp (name, ".sbss") == 0 | 
|  | +	   || strcmp (name, ".lit4") == 0 | 
|  | +	   || strcmp (name, ".lit8") == 0) | 
|  | +    hdr->sh_flags |= SHF_MIPS_GPREL; | 
|  | +  else if (strcmp (name, ".MIPS.interfaces") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_IFACE; | 
|  | +      hdr->sh_flags |= SHF_MIPS_NOSTRIP; | 
|  | +    } | 
|  | +  else if (CONST_STRNEQ (name, ".MIPS.content")) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_CONTENT; | 
|  | +      hdr->sh_flags |= SHF_MIPS_NOSTRIP; | 
|  | +      /* The sh_info field is set in final_write_processing.  */ | 
|  | +    } | 
|  | +  else if (MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_OPTIONS; | 
|  | +      hdr->sh_entsize = 1; | 
|  | +      hdr->sh_flags |= SHF_MIPS_NOSTRIP; | 
|  | +    } | 
|  | +  else if (CONST_STRNEQ (name, ".debug_") | 
|  | +           || CONST_STRNEQ (name, ".zdebug_")) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_DWARF; | 
|  | +    } | 
|  | +  else if (strcmp (name, ".MIPS.symlib") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_SYMBOL_LIB; | 
|  | +      /* The sh_link and sh_info fields are set in | 
|  | +         final_write_processing.  */ | 
|  | +    } | 
|  | +  else if (CONST_STRNEQ (name, ".MIPS.events") | 
|  | +	   || CONST_STRNEQ (name, ".MIPS.post_rel")) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_EVENTS; | 
|  | +      hdr->sh_flags |= SHF_MIPS_NOSTRIP; | 
|  | +      /* The sh_link field is set in final_write_processing.  */ | 
|  | +    } | 
|  | +  else if (strcmp (name, ".msym") == 0) | 
|  | +    { | 
|  | +      hdr->sh_type = SHT_MIPS_MSYM; | 
|  | +      hdr->sh_flags |= SHF_ALLOC; | 
|  | +      hdr->sh_entsize = 8; | 
|  | +    } | 
|  | + | 
|  | +  /* The generic elf_fake_sections will set up REL_HDR using the default | 
|  | +   kind of relocations.  We used to set up a second header for the | 
|  | +   non-default kind of relocations here, but only NewABI would use | 
|  | +   these, and the IRIX ld doesn't like resulting empty RELA sections. | 
|  | +   Thus we create those header only on demand now.  */ | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Given a BFD section, try to locate the corresponding ELF section | 
|  | +   index.  This is used by both the 32-bit and the 64-bit ABI. | 
|  | +   Actually, it's not clear to me that the 64-bit ABI supports these, | 
|  | +   but for non-PIC objects we will certainly want support for at least | 
|  | +   the .scommon section.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +					asection *sec, int *retval) | 
|  | +{ | 
|  | +  if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) | 
|  | +    { | 
|  | +      *retval = SHN_MIPS_SCOMMON; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | +  if (strcmp (bfd_get_section_name (abfd, sec), ".acommon") == 0) | 
|  | +    { | 
|  | +      *retval = SHN_MIPS_ACOMMON; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +/* Hook called by the linker routine which adds symbols from an object | 
|  | +   file.  We must handle the special MIPS section numbers here.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_add_symbol_hook (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +             struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
|  | +			       Elf_Internal_Sym *sym, const char **namep ATTRIBUTE_UNUSED, | 
|  | +			       flagword *flagsp ATTRIBUTE_UNUSED, | 
|  | +			       asection **secp, bfd_vma *valp) | 
|  | +{ | 
|  | +  switch (sym->st_shndx) | 
|  | +    { | 
|  | +    case SHN_COMMON: | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_SCOMMON: | 
|  | +      *secp = bfd_make_section_old_way (abfd, ".scommon"); | 
|  | +      (*secp)->flags |= SEC_IS_COMMON; | 
|  | +      *valp = sym->st_size; | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_TEXT: | 
|  | +      /* This section is used in a shared object.  */ | 
|  | +      if (elf_tdata (abfd)->elf_text_section == NULL) | 
|  | +	{ | 
|  | +	  asymbol *elf_text_symbol; | 
|  | +	  asection *elf_text_section; | 
|  | +	  bfd_size_type amt = sizeof (asection); | 
|  | + | 
|  | +	  elf_text_section = bfd_zalloc (abfd, amt); | 
|  | +	  if (elf_text_section == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  amt = sizeof (asymbol); | 
|  | +	  elf_text_symbol = bfd_zalloc (abfd, amt); | 
|  | +	  if (elf_text_symbol == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  /* Initialize the section.  */ | 
|  | + | 
|  | +	  elf_tdata (abfd)->elf_text_section = elf_text_section; | 
|  | +	  elf_tdata (abfd)->elf_text_symbol = elf_text_symbol; | 
|  | + | 
|  | +	  elf_text_section->symbol = elf_text_symbol; | 
|  | +	  elf_text_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_text_symbol; | 
|  | + | 
|  | +	  elf_text_section->name = ".text"; | 
|  | +	  elf_text_section->flags = SEC_NO_FLAGS; | 
|  | +	  elf_text_section->output_section = NULL; | 
|  | +	  elf_text_section->owner = abfd; | 
|  | +	  elf_text_symbol->name = ".text"; | 
|  | +	  elf_text_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC; | 
|  | +	  elf_text_symbol->section = elf_text_section; | 
|  | +	} | 
|  | +      /* This code used to do *secp = bfd_und_section_ptr if | 
|  | +         info->shared.  I don't know why, and that doesn't make sense, | 
|  | +         so I took it out.  */ | 
|  | +      *secp = elf_tdata (abfd)->elf_text_section; | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_ACOMMON: | 
|  | +      /* Fall through. XXX Can we treat this as allocated data?  */ | 
|  | +    case SHN_MIPS_DATA: | 
|  | +      /* This section is used in a shared object.  */ | 
|  | +      if (elf_tdata (abfd)->elf_data_section == NULL) | 
|  | +	{ | 
|  | +	  asymbol *elf_data_symbol; | 
|  | +	  asection *elf_data_section; | 
|  | +	  bfd_size_type amt = sizeof (asection); | 
|  | + | 
|  | +	  elf_data_section = bfd_zalloc (abfd, amt); | 
|  | +	  if (elf_data_section == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  amt = sizeof (asymbol); | 
|  | +	  elf_data_symbol = bfd_zalloc (abfd, amt); | 
|  | +	  if (elf_data_symbol == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  /* Initialize the section.  */ | 
|  | + | 
|  | +	  elf_tdata (abfd)->elf_data_section = elf_data_section; | 
|  | +	  elf_tdata (abfd)->elf_data_symbol = elf_data_symbol; | 
|  | + | 
|  | +	  elf_data_section->symbol = elf_data_symbol; | 
|  | +	  elf_data_section->symbol_ptr_ptr = &elf_tdata (abfd)->elf_data_symbol; | 
|  | + | 
|  | +	  elf_data_section->name = ".data"; | 
|  | +	  elf_data_section->flags = SEC_NO_FLAGS; | 
|  | +	  elf_data_section->output_section = NULL; | 
|  | +	  elf_data_section->owner = abfd; | 
|  | +	  elf_data_symbol->name = ".data"; | 
|  | +	  elf_data_symbol->flags = BSF_SECTION_SYM | BSF_DYNAMIC; | 
|  | +	  elf_data_symbol->section = elf_data_section; | 
|  | +	} | 
|  | +      /* This code used to do *secp = bfd_und_section_ptr if | 
|  | +         info->shared.  I don't know why, and that doesn't make sense, | 
|  | +         so I took it out.  */ | 
|  | +      *secp = elf_tdata (abfd)->elf_data_section; | 
|  | +      break; | 
|  | + | 
|  | +    case SHN_MIPS_SUNDEFINED: | 
|  | +      *secp = bfd_und_section_ptr; | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* This hook function is called before the linker writes out a global | 
|  | +   symbol.  We mark symbols as small common if appropriate.  This is | 
|  | +   also where we undo the increment of the value for a mips16 symbol.  */ | 
|  | + | 
|  | +int | 
|  | +_bfd_riscv_elf_link_output_symbol_hook | 
|  | +  (struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
|  | +   const char *name ATTRIBUTE_UNUSED, Elf_Internal_Sym *sym, | 
|  | +   asection *input_sec, struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  /* If we see a common symbol, which implies a relocatable link, then | 
|  | +     if a symbol was small common in an input file, mark it as small | 
|  | +     common in the output file.  */ | 
|  | +  if (sym->st_shndx == SHN_COMMON | 
|  | +      && strcmp (input_sec->name, ".scommon") == 0) | 
|  | +    sym->st_shndx = SHN_MIPS_SCOMMON; | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Functions for the dynamic linker.  */ | 
|  | + | 
|  | +/* Create dynamic sections when linking against a dynamic object.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  struct elf_link_hash_entry *h; | 
|  | +  struct bfd_link_hash_entry *bh; | 
|  | +  flagword flags; | 
|  | +  register asection *s; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY | 
|  | +	   | SEC_LINKER_CREATED | SEC_READONLY); | 
|  | + | 
|  | +  /* The psABI requires a read-only .dynamic section. */ | 
|  | +  s = bfd_get_section_by_name (abfd, ".dynamic"); | 
|  | +  if (s != NULL) | 
|  | +    { | 
|  | +      if (! bfd_set_section_flags (abfd, s, flags)) | 
|  | +        return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  /* We need to create .got section.  */ | 
|  | +  if (!mips_elf_create_got_section (abfd, info)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (! mips_elf_rel_dyn_section (info, TRUE)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (!info->shared) | 
|  | +    { | 
|  | +      const char *name; | 
|  | + | 
|  | +      name = "_DYNAMIC_LINKING"; | 
|  | +      bh = NULL; | 
|  | +      if (!(_bfd_generic_link_add_one_symbol | 
|  | +	    (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0, | 
|  | +	     NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      h = (struct elf_link_hash_entry *) bh; | 
|  | +      h->non_elf = 0; | 
|  | +      h->def_regular = 1; | 
|  | +      h->type = STT_SECTION; | 
|  | + | 
|  | +      if (! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  /* Create the .plt, .rel(a).plt, .dynbss and .rel(a).bss sections. | 
|  | +     Also create the _PROCEDURE_LINKAGE_TABLE symbol.  */ | 
|  | +  if (!_bfd_elf_create_dynamic_sections (abfd, info)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Cache the sections created above.  */ | 
|  | +  htab->splt = bfd_get_section_by_name (abfd, ".plt"); | 
|  | +  htab->sdynbss = bfd_get_section_by_name (abfd, ".dynbss"); | 
|  | +  htab->srelplt = bfd_get_section_by_name (abfd, ".rel.plt"); | 
|  | +  if (!htab->sdynbss | 
|  | +      || !htab->srelplt | 
|  | +      || !htab->splt) | 
|  | +    abort (); | 
|  | + | 
|  | +  htab->plt_header_size = RISCV_PLT0_ENTRY_INSNS * 4; | 
|  | +  htab->plt_entry_size = RISCV_PLT_ENTRY_INSNS * 4; | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Return true if relocation REL against section SEC is a REL rather than | 
|  | +   RELA relocation.  RELOCS is the first relocation in the section and | 
|  | +   ABFD is the bfd that contains SEC.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_rel_relocation_p (bfd *abfd, asection *sec, | 
|  | +			   const Elf_Internal_Rela *relocs, | 
|  | +			   const Elf_Internal_Rela *rel) | 
|  | +{ | 
|  | +  Elf_Internal_Shdr *rel_hdr; | 
|  | +  const struct elf_backend_data *bed; | 
|  | + | 
|  | +  /* To determine which flavor of relocation this is, we depend on the | 
|  | +     fact that the INPUT_SECTION's REL_HDR is read before RELA_HDR.  */ | 
|  | +  rel_hdr = elf_section_data (sec)->rel.hdr; | 
|  | +  if (rel_hdr == NULL) | 
|  | +    return FALSE; | 
|  | +  bed = get_elf_backend_data (abfd); | 
|  | +  return ((size_t) (rel - relocs) | 
|  | +	  < NUM_SHDR_ENTRIES (rel_hdr) * bed->s->int_rels_per_ext_rel); | 
|  | +} | 
|  | + | 
|  | +/* Read the addend for REL relocation REL, which belongs to bfd ABFD. | 
|  | +   HOWTO is the relocation's howto and CONTENTS points to the contents | 
|  | +   of the section that REL is against.  */ | 
|  | + | 
|  | +static bfd_vma | 
|  | +mips_elf_read_rel_addend (bfd *abfd, const Elf_Internal_Rela *rel, | 
|  | +			  reloc_howto_type *howto, bfd_byte *contents) | 
|  | +{ | 
|  | +  bfd_vma addend; | 
|  | + | 
|  | +  /* Get the addend, which is stored in the input file.  */ | 
|  | +  addend = mips_elf_obtain_contents (howto, rel, abfd, contents); | 
|  | + | 
|  | +  return addend & howto->src_mask; | 
|  | +} | 
|  | + | 
|  | +/* REL is a relocation in ABFD that needs a partnering LO16 relocation | 
|  | +   and *ADDEND is the addend for REL itself.  Look for the LO16 relocation | 
|  | +   and update *ADDEND with the final addend.  Return true on success | 
|  | +   or false if the LO16 could not be found.  RELEND is the exclusive | 
|  | +   upper bound on the relocations for REL's section.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_add_lo16_rel_addend (bfd *abfd, | 
|  | +			      const Elf_Internal_Rela *rel, | 
|  | +			      const Elf_Internal_Rela *relend, | 
|  | +			      bfd_byte *contents, bfd_vma *addend) | 
|  | +{ | 
|  | +  unsigned int lo16_type; | 
|  | +  const Elf_Internal_Rela *lo16_relocation; | 
|  | +  reloc_howto_type *lo16_howto; | 
|  | +  bfd_vma l; | 
|  | + | 
|  | +  lo16_type = R_RISCV_LO16; | 
|  | + | 
|  | +  /* The combined value is the sum of the HI16 addend, left-shifted by | 
|  | +     sixteen bits, and the LO16 addend, sign extended.  (Usually, the | 
|  | +     code does a `lui' of the HI16 value, and then an `addiu' of the | 
|  | +     LO16 value.) | 
|  | + | 
|  | +     Scan ahead to find a matching LO16 relocation. | 
|  | + | 
|  | +     According to the MIPS ELF ABI, the R_RISCV_LO16 relocation must | 
|  | +     be immediately following.  However, for the IRIX6 ABI, the next | 
|  | +     relocation may be a composed relocation consisting of several | 
|  | +     relocations for the same address.  In that case, the R_RISCV_LO16 | 
|  | +     relocation may occur as one of these.  We permit a similar | 
|  | +     extension in general, as that is useful for GCC. | 
|  | + | 
|  | +     In some cases GCC dead code elimination removes the LO16 but keeps | 
|  | +     the corresponding HI16.  This is strictly speaking a violation of | 
|  | +     the ABI but not immediately harmful.  */ | 
|  | +  lo16_relocation = mips_elf_next_relocation (abfd, lo16_type, rel, relend); | 
|  | +  if (lo16_relocation == NULL) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Obtain the addend kept there.  */ | 
|  | +  lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, lo16_type, FALSE); | 
|  | +  l = mips_elf_read_rel_addend (abfd, lo16_relocation, lo16_howto, contents); | 
|  | + | 
|  | +  l <<= lo16_howto->rightshift; | 
|  | +  l = _bfd_riscv_elf_sign_extend (l, RISCV_IMM_BITS); | 
|  | + | 
|  | +  *addend <<= RISCV_IMM_BITS; | 
|  | +  *addend += l; | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Try to read the contents of section SEC in bfd ABFD.  Return true and | 
|  | +   store the contents in *CONTENTS on success.  Assume that *CONTENTS | 
|  | +   already holds the contents if it is nonull on entry.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_get_section_contents (bfd *abfd, asection *sec, bfd_byte **contents) | 
|  | +{ | 
|  | +  if (*contents) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* Get cached copy if it exists.  */ | 
|  | +  if (elf_section_data (sec)->this_hdr.contents != NULL) | 
|  | +    { | 
|  | +      *contents = elf_section_data (sec)->this_hdr.contents; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  return bfd_malloc_and_get_section (abfd, sec, contents); | 
|  | +} | 
|  | + | 
|  | +/* Look through the relocs for a section during the first phase, and | 
|  | +   allocate space in the global offset table.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, | 
|  | +			    asection *sec, const Elf_Internal_Rela *relocs) | 
|  | +{ | 
|  | +  const char *name; | 
|  | +  bfd *dynobj; | 
|  | +  Elf_Internal_Shdr *symtab_hdr; | 
|  | +  struct elf_link_hash_entry **sym_hashes; | 
|  | +  size_t extsymoff; | 
|  | +  const Elf_Internal_Rela *rel; | 
|  | +  const Elf_Internal_Rela *rel_end; | 
|  | +  asection *sreloc; | 
|  | +  const struct elf_backend_data *bed; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  bfd_byte *contents; | 
|  | +  bfd_vma addend; | 
|  | +  reloc_howto_type *howto; | 
|  | + | 
|  | +  if (info->relocatable) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  symtab_hdr = &elf_tdata (abfd)->symtab_hdr; | 
|  | +  sym_hashes = elf_sym_hashes (abfd); | 
|  | +  extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; | 
|  | + | 
|  | +  bed = get_elf_backend_data (abfd); | 
|  | +  rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel; | 
|  | + | 
|  | +  name = bfd_get_section_name (abfd, sec); | 
|  | + | 
|  | +  sreloc = NULL; | 
|  | +  contents = NULL; | 
|  | +  for (rel = relocs; rel < rel_end; ++rel) | 
|  | +    { | 
|  | +      unsigned long r_symndx; | 
|  | +      unsigned int r_type; | 
|  | +      struct elf_link_hash_entry *h; | 
|  | +      bfd_boolean can_make_dynamic_p; | 
|  | + | 
|  | +      r_symndx = ELF_R_SYM (abfd, rel->r_info); | 
|  | +      r_type = ELF_R_TYPE (abfd, rel->r_info); | 
|  | + | 
|  | +      if (r_symndx < extsymoff) | 
|  | +	h = NULL; | 
|  | +      else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) | 
|  | +	{ | 
|  | +	  (*_bfd_error_handler) | 
|  | +	    (_("%B: Malformed reloc detected for section %s"), | 
|  | +	     abfd, name); | 
|  | +	  bfd_set_error (bfd_error_bad_value); | 
|  | +	  return FALSE; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  h = sym_hashes[r_symndx - extsymoff]; | 
|  | +	  while (h != NULL | 
|  | +		 && (h->root.type == bfd_link_hash_indirect | 
|  | +		     || h->root.type == bfd_link_hash_warning)) | 
|  | +	    h = (struct elf_link_hash_entry *) h->root.u.i.link; | 
|  | +	} | 
|  | + | 
|  | +      /* Set CAN_MAKE_DYNAMIC_P to true if we can convert this | 
|  | +	 relocation into a dynamic one.  */ | 
|  | +      can_make_dynamic_p = FALSE; | 
|  | +      switch (r_type) | 
|  | +	{ | 
|  | +	case R_MIPS16_GOT16: | 
|  | +	case R_MIPS16_CALL16: | 
|  | +	case R_RISCV_GOT16: | 
|  | +	case R_RISCV_CALL16: | 
|  | +	case R_RISCV_CALL_HI16: | 
|  | +	case R_RISCV_CALL_LO16: | 
|  | +	case R_RISCV_GOT_HI16: | 
|  | +	case R_RISCV_GOT_LO16: | 
|  | +	case R_RISCV_GOT_DISP: | 
|  | +	case R_RISCV_TLS_GOTTPREL: | 
|  | +	case R_RISCV_TLS_GOT_HI16: | 
|  | +	case R_RISCV_TLS_GOT_LO16: | 
|  | +	case R_RISCV_TLS_GD: | 
|  | +	case R_RISCV_TLS_GD_HI16: | 
|  | +	case R_RISCV_TLS_GD_LO16: | 
|  | +	case R_RISCV_TLS_LDM: | 
|  | +	case R_RISCV_TLS_LDM_HI16: | 
|  | +	case R_RISCV_TLS_LDM_LO16: | 
|  | +	  if (dynobj == NULL) | 
|  | +	    elf_hash_table (info)->dynobj = dynobj = abfd; | 
|  | +	  if (!mips_elf_create_got_section (dynobj, info)) | 
|  | +	    return FALSE; | 
|  | +	  break; | 
|  | + | 
|  | +	case R_RISCV_32: | 
|  | +	case R_RISCV_REL32: | 
|  | +	case R_RISCV_64: | 
|  | +	  /* For executables that use PLTs and copy-relocs, we have a | 
|  | +	     choice between converting the relocation into a dynamic | 
|  | +	     one or using copy relocations or PLT entries.  It is | 
|  | +	     usually better to do the former, unless the relocation is | 
|  | +	     against a read-only section.  */ | 
|  | +	  if ((info->shared | 
|  | +	       || (h != NULL | 
|  | +		   && !(!info->nocopyreloc | 
|  | +			&& !PIC_OBJECT_P (abfd) | 
|  | +			&& MIPS_ELF_READONLY_SECTION (sec)))) | 
|  | +	      && (sec->flags & SEC_ALLOC) != 0) | 
|  | +	    { | 
|  | +	      can_make_dynamic_p = TRUE; | 
|  | +	      if (dynobj == NULL) | 
|  | +		elf_hash_table (info)->dynobj = dynobj = abfd; | 
|  | +	      break; | 
|  | +	    } | 
|  | +	  /* For sections that are not SEC_ALLOC a copy reloc would be | 
|  | +	     output if possible (implying questionable semantics for | 
|  | +	     read-only data objects) or otherwise the final link would | 
|  | +	     fail as ld.so will not process them and could not therefore | 
|  | +	     handle any outstanding dynamic relocations. | 
|  | + | 
|  | +	     For such sections that are also SEC_DEBUGGING, we can avoid | 
|  | +	     these problems by simply ignoring any relocs as these | 
|  | +	     sections have a predefined use and we know it is safe to do | 
|  | +	     so. | 
|  | + | 
|  | +	     This is needed in cases such as a global symbol definition | 
|  | +	     in a shared library causing a common symbol from an object | 
|  | +	     file to be converted to an undefined reference.  If that | 
|  | +	     happens, then all the relocations against this symbol from | 
|  | +	     SEC_DEBUGGING sections in the object file will resolve to | 
|  | +	     nil.  */ | 
|  | +	  if ((sec->flags & SEC_DEBUGGING) != 0) | 
|  | +	    break; | 
|  | +	  /* Fall through.  */ | 
|  | + | 
|  | +	default: | 
|  | +	  /* Most static relocations require pointer equality, except | 
|  | +	     for branches.  */ | 
|  | +	  if (h) | 
|  | +	    h->pointer_equality_needed = TRUE; | 
|  | +	  /* Fall through.  */ | 
|  | + | 
|  | +	case R_RISCV_26: | 
|  | +	case R_RISCV_PC16: | 
|  | +	case R_MIPS16_26: | 
|  | +	  if (h) | 
|  | +	    ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE; | 
|  | +	  break; | 
|  | +	} | 
|  | + | 
|  | +      if ((h == NULL && r_type == R_RISCV_CALL_LO16) | 
|  | +	       || r_type == R_RISCV_GOT_LO16 | 
|  | +	       || r_type == R_RISCV_GOT_DISP) | 
|  | +	{ | 
|  | +	  /* We may need a local GOT entry for this relocation.  We | 
|  | +	     don't count R_RISCV_GOT_PAGE because we can estimate the | 
|  | +	     maximum number of pages needed by looking at the size of | 
|  | +	     the segment.  Similar comments apply to R_MIPS*_GOT16 and | 
|  | +	     R_MIPS*_CALL16, except on VxWorks, where GOT relocations | 
|  | +	     always evaluate to "G".  We don't count R_RISCV_GOT_HI16, or | 
|  | +	     R_RISCV_CALL_HI16 because these are always followed by an | 
|  | +	     R_RISCV_GOT_LO16 or R_RISCV_CALL_LO16.  */ | 
|  | +	  if (!mips_elf_record_local_got_symbol (abfd, r_symndx, | 
|  | +						 rel->r_addend, info, 0)) | 
|  | +	    return FALSE; | 
|  | +	} | 
|  | + | 
|  | +      switch (r_type) | 
|  | +	{ | 
|  | +	case R_RISCV_CALL16: | 
|  | +	case R_MIPS16_CALL16: | 
|  | +	  if (h == NULL) | 
|  | +	    { | 
|  | +	      (*_bfd_error_handler) | 
|  | +		(_("%B: CALL16 reloc at 0x%lx not against global symbol"), | 
|  | +		 abfd, (unsigned long) rel->r_offset); | 
|  | +	      bfd_set_error (bfd_error_bad_value); | 
|  | +	      return FALSE; | 
|  | +	    } | 
|  | +	  /* Fall through.  */ | 
|  | + | 
|  | +	case R_MIPS16_GOT16: | 
|  | +	case R_RISCV_GOT16: | 
|  | +	case R_RISCV_GOT_HI16: | 
|  | +	case R_RISCV_GOT_LO16: | 
|  | +	  if (!h) | 
|  | +	    { | 
|  | +	      /* This relocation needs a page entry in the GOT. */ | 
|  | +	      if (mips_elf_rel_relocation_p (abfd, sec, relocs, rel)) | 
|  | +		{ | 
|  | +		  if (!mips_elf_get_section_contents (abfd, sec, &contents)) | 
|  | +		    return FALSE; | 
|  | +		  howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE); | 
|  | +		  addend = mips_elf_read_rel_addend (abfd, rel, | 
|  | +						     howto, contents); | 
|  | +		  if (got16_reloc_p (r_type)) | 
|  | +		    mips_elf_add_lo16_rel_addend (abfd, rel, rel_end, | 
|  | +						  contents, &addend); | 
|  | +		  else | 
|  | +		    addend <<= howto->rightshift; | 
|  | +		} | 
|  | +	      else | 
|  | +		addend = rel->r_addend; | 
|  | +	      if (!mips_elf_record_got_page_entry (info, abfd, r_symndx, | 
|  | +						   addend)) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | +	  /* Fall through.  */ | 
|  | + | 
|  | +	case R_RISCV_GOT_DISP: | 
|  | +	  if (h && !mips_elf_record_global_got_symbol (h, abfd, info, 0)) | 
|  | +	    return FALSE; | 
|  | +	  break; | 
|  | + | 
|  | +	case R_RISCV_TLS_GOTTPREL: | 
|  | +	case R_RISCV_TLS_GOT_HI16: | 
|  | +	case R_RISCV_TLS_GOT_LO16: | 
|  | +	  if (info->shared) | 
|  | +	    info->flags |= DF_STATIC_TLS; | 
|  | +	  /* Fall through */ | 
|  | + | 
|  | +	case R_RISCV_TLS_LDM: | 
|  | +	case R_RISCV_TLS_LDM_HI16: | 
|  | +	case R_RISCV_TLS_LDM_LO16: | 
|  | +	  if (TLS_LDM_RELOC_P(r_type)) | 
|  | +	    { | 
|  | +	      r_symndx = STN_UNDEF; | 
|  | +	      h = NULL; | 
|  | +	    } | 
|  | +	  /* Fall through */ | 
|  | + | 
|  | +	case R_RISCV_TLS_GD: | 
|  | +	case R_RISCV_TLS_GD_HI16: | 
|  | +	case R_RISCV_TLS_GD_LO16: | 
|  | +	  /* This symbol requires a global offset table entry, or two | 
|  | +	     for TLS GD relocations.  */ | 
|  | +	  { | 
|  | +	    unsigned char flag = (TLS_GD_RELOC_P(r_type) | 
|  | +				  ? GOT_TLS_GD | 
|  | +				  : TLS_LDM_RELOC_P(r_type) | 
|  | +				  ? GOT_TLS_LDM | 
|  | +				  : GOT_TLS_IE); | 
|  | +	    if (h != NULL) | 
|  | +	      { | 
|  | +		struct mips_elf_link_hash_entry *hmips = | 
|  | +		  (struct mips_elf_link_hash_entry *) h; | 
|  | +		hmips->tls_type |= flag; | 
|  | + | 
|  | +		if (h && !mips_elf_record_global_got_symbol (h, abfd, info, flag)) | 
|  | +		  return FALSE; | 
|  | +	      } | 
|  | +	    else | 
|  | +	      { | 
|  | +		BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != STN_UNDEF); | 
|  | + | 
|  | +		if (!mips_elf_record_local_got_symbol (abfd, r_symndx, | 
|  | +						       rel->r_addend, | 
|  | +						       info, flag)) | 
|  | +		  return FALSE; | 
|  | +	      } | 
|  | +	  } | 
|  | +	  break; | 
|  | + | 
|  | +	case R_RISCV_32: | 
|  | +	case R_RISCV_REL32: | 
|  | +	case R_RISCV_64: | 
|  | +	  /* In VxWorks executables, references to external symbols | 
|  | +	     are handled using copy relocs or PLT stubs, so there's | 
|  | +	     no need to add a .rela.dyn entry for this relocation.  */ | 
|  | +	  if (can_make_dynamic_p) | 
|  | +	    { | 
|  | +	      if (sreloc == NULL) | 
|  | +		{ | 
|  | +		  sreloc = mips_elf_rel_dyn_section (info, TRUE); | 
|  | +		  if (sreloc == NULL) | 
|  | +		    return FALSE; | 
|  | +		} | 
|  | +	      if (info->shared && h == NULL) | 
|  | +		{ | 
|  | +		  /* When creating a shared object, we must copy these | 
|  | +		     reloc types into the output file as R_RISCV_REL32 | 
|  | +		     relocs.  Make room for this reloc in .rel(a).dyn.  */ | 
|  | +		  mips_elf_allocate_dynamic_relocations (dynobj, info, 1); | 
|  | +		  if (MIPS_ELF_READONLY_SECTION (sec)) | 
|  | +		    /* We tell the dynamic linker that there are | 
|  | +		       relocations against the text segment.  */ | 
|  | +		    info->flags |= DF_TEXTREL; | 
|  | +		} | 
|  | +	      else | 
|  | +		{ | 
|  | +		  struct mips_elf_link_hash_entry *hmips; | 
|  | + | 
|  | +		  /* For a shared object, we must copy this relocation | 
|  | +		     unless the symbol turns out to be undefined and | 
|  | +		     weak with non-default visibility, in which case | 
|  | +		     it will be left as zero. | 
|  | + | 
|  | +		     We could elide R_RISCV_REL32 for locally binding symbols | 
|  | +		     in shared libraries, but do not yet do so. | 
|  | + | 
|  | +		     For an executable, we only need to copy this | 
|  | +		     reloc if the symbol is defined in a dynamic | 
|  | +		     object.  */ | 
|  | +		  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | +		  ++hmips->possibly_dynamic_relocs; | 
|  | +		  if (MIPS_ELF_READONLY_SECTION (sec)) | 
|  | +		    /* We need it to tell the dynamic linker if there | 
|  | +		       are relocations against the text segment.  */ | 
|  | +		    hmips->readonly_reloc = TRUE; | 
|  | +		} | 
|  | +	    } | 
|  | + | 
|  | +	  break; | 
|  | + | 
|  | +	case R_RISCV_26: | 
|  | +	case R_RISCV_GPREL16: | 
|  | +	case R_RISCV_LITERAL: | 
|  | +	case R_RISCV_GPREL32: | 
|  | +	  break; | 
|  | + | 
|  | +	  /* This relocation describes the C++ object vtable hierarchy. | 
|  | +	     Reconstruct it for later use during GC.  */ | 
|  | +	case R_RISCV_GNU_VTINHERIT: | 
|  | +	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) | 
|  | +	    return FALSE; | 
|  | +	  break; | 
|  | + | 
|  | +	  /* This relocation describes which C++ vtable entries are actually | 
|  | +	     used.  Record for later use during GC.  */ | 
|  | +	case R_RISCV_GNU_VTENTRY: | 
|  | +	  BFD_ASSERT (h != NULL); | 
|  | +	  if (h != NULL | 
|  | +	      && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) | 
|  | +	    return FALSE; | 
|  | +	  break; | 
|  | + | 
|  | +	default: | 
|  | +	  break; | 
|  | +	} | 
|  | + | 
|  | +      /* Refuse some position-dependent relocations when creating a | 
|  | +	 shared library.  Do not refuse R_RISCV_32 / R_RISCV_64; they're | 
|  | +	 not PIC, but we can create dynamic relocations and the result | 
|  | +	 will be fine.  Also do not refuse R_RISCV_LO16, which can be | 
|  | +	 combined with R_RISCV_GOT16.  */ | 
|  | +      if (info->shared) | 
|  | +	{ | 
|  | +	  switch (r_type) | 
|  | +	    { | 
|  | +	    case R_MIPS16_HI16: | 
|  | +	    case R_RISCV_HI16: | 
|  | +	      /* Don't refuse a high part relocation if it's against | 
|  | +		 no symbol (e.g. part of a compound relocation).  */ | 
|  | +	      if (r_symndx == STN_UNDEF) | 
|  | +		break; | 
|  | + | 
|  | +	      howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE); | 
|  | +	      (*_bfd_error_handler) | 
|  | +		(_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), | 
|  | +		 abfd, howto->name, | 
|  | +		 (h) ? h->root.root.string : "a local symbol"); | 
|  | +	      bfd_set_error (bfd_error_bad_value); | 
|  | +	      return FALSE; | 
|  | +	    default: | 
|  | +	      break; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_relax_section (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +			 asection *sec ATTRIBUTE_UNUSED, | 
|  | +			 struct bfd_link_info *link_info ATTRIBUTE_UNUSED, | 
|  | +			 bfd_boolean *again) | 
|  | +{ | 
|  | +  *again = FALSE; | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Allocate space for global sym dynamic relocs.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) | 
|  | +{ | 
|  | +  struct bfd_link_info *info = inf; | 
|  | +  bfd *dynobj; | 
|  | +  struct mips_elf_link_hash_entry *hmips; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | + | 
|  | +  /* Ignore indirect and warning symbols.  All relocations against | 
|  | +     such symbols will be redirected to the target symbol.  */ | 
|  | +  if (h->root.type == bfd_link_hash_indirect | 
|  | +      || h->root.type == bfd_link_hash_warning) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* If this symbol is defined in a dynamic object, or we are creating | 
|  | +     a shared library, we will need to copy any R_RISCV_32 or | 
|  | +     R_RISCV_REL32 relocs against it into the output file.  */ | 
|  | +  if (! info->relocatable | 
|  | +      && hmips->possibly_dynamic_relocs != 0 | 
|  | +      && (h->root.type == bfd_link_hash_defweak | 
|  | +	  || !h->def_regular | 
|  | +	  || info->shared)) | 
|  | +    { | 
|  | +      bfd_boolean do_copy = TRUE; | 
|  | + | 
|  | +      if (h->root.type == bfd_link_hash_undefweak) | 
|  | +	{ | 
|  | +	  /* Do not copy relocations for undefined weak symbols with | 
|  | +	     non-default visibility.  */ | 
|  | +	  if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) | 
|  | +	    do_copy = FALSE; | 
|  | + | 
|  | +	  /* Make sure undefined weak symbols are output as a dynamic | 
|  | +	     symbol in PIEs.  */ | 
|  | +	  else if (h->dynindx == -1 && !h->forced_local) | 
|  | +	    { | 
|  | +	      if (! bfd_elf_link_record_dynamic_symbol (info, h)) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | +	} | 
|  | + | 
|  | +      if (do_copy) | 
|  | +	{ | 
|  | +	  /* Even though we don't directly need a GOT entry for this symbol, | 
|  | +	     the SVR4 psABI requires it to have a dynamic symbol table | 
|  | +	     index greater that DT_MIPS_GOTSYM if there are dynamic | 
|  | +	     relocations against it. */ | 
|  | +	  if (hmips->global_got_area > GGA_RELOC_ONLY) | 
|  | +	    hmips->global_got_area = GGA_RELOC_ONLY; | 
|  | + | 
|  | +	  mips_elf_allocate_dynamic_relocations | 
|  | +	    (dynobj, info, hmips->possibly_dynamic_relocs); | 
|  | +	  if (hmips->readonly_reloc) | 
|  | +	    /* We tell the dynamic linker that there are relocations | 
|  | +	       against the text segment.  */ | 
|  | +	    info->flags |= DF_TEXTREL; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Adjust a symbol defined by a dynamic object and referenced by a | 
|  | +   regular object.  The current definition is in some section of the | 
|  | +   dynamic object, but we're not including those sections.  We have to | 
|  | +   change the definition to something the rest of the link can | 
|  | +   understand.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_adjust_dynamic_symbol (struct bfd_link_info *info, | 
|  | +				     struct elf_link_hash_entry *h) | 
|  | +{ | 
|  | +  bfd *dynobj; | 
|  | +  struct mips_elf_link_hash_entry *hmips; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | + | 
|  | +  /* Make sure we know what is going on here.  */ | 
|  | +  BFD_ASSERT (dynobj != NULL | 
|  | +	      && (h->needs_plt | 
|  | +		  || h->u.weakdef != NULL | 
|  | +		  || (h->def_dynamic | 
|  | +		      && h->ref_regular | 
|  | +		      && !h->def_regular))); | 
|  | + | 
|  | +  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | + | 
|  | +  /* As above, VxWorks requires PLT entries for externally-defined | 
|  | +     functions that are only accessed through call relocations. | 
|  | + | 
|  | +     Both VxWorks and non-VxWorks targets also need PLT entries if there | 
|  | +     are static-only relocations against an externally-defined function. | 
|  | +     This can technically occur for shared libraries if there are | 
|  | +     branches to the symbol, although it is unlikely that this will be | 
|  | +     used in practice due to the short ranges involved.  It can occur | 
|  | +     for any relative or absolute relocation in executables; in that | 
|  | +     case, the PLT entry becomes the function's canonical address.  */ | 
|  | +  if (h->type == STT_FUNC && hmips->has_static_relocs | 
|  | +	   && !SYMBOL_CALLS_LOCAL (info, h) | 
|  | +	   && !(ELF_ST_VISIBILITY (h->other) != STV_DEFAULT | 
|  | +		&& h->root.type == bfd_link_hash_undefweak)) | 
|  | +    { | 
|  | +      /* If this is the first symbol to need a PLT entry, allocate room | 
|  | +	 for the header.  */ | 
|  | +      if (htab->splt->size == 0) | 
|  | +	{ | 
|  | +	  BFD_ASSERT (htab->sgotplt->size == 0); | 
|  | + | 
|  | +	  /* If we're using the PLT additions to the psABI, each PLT | 
|  | +	     entry is 16 bytes and the PLT0 entry is 32 bytes. | 
|  | +	     Encourage better cache usage by aligning.  We do this | 
|  | +	     lazily to avoid pessimizing traditional objects.  */ | 
|  | +	  if (!bfd_set_section_alignment (dynobj, htab->splt, 4)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  /* Make sure that .got.plt is word-aligned.  We do this lazily | 
|  | +	     for the same reason as above.  */ | 
|  | +	  if (!bfd_set_section_alignment (dynobj, htab->sgotplt, | 
|  | +					  MIPS_ELF_LOG_FILE_ALIGN (dynobj))) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  htab->splt->size += htab->plt_header_size; | 
|  | + | 
|  | +	  /* The last and first two entries in .got.plt are reserved.  */ | 
|  | +	  htab->sgotplt->size += 3 * MIPS_ELF_GOT_SIZE (dynobj); | 
|  | +	} | 
|  | + | 
|  | +      /* Assign the next .plt entry to this symbol.  */ | 
|  | +      h->plt.offset = htab->splt->size; | 
|  | +      htab->splt->size += htab->plt_entry_size; | 
|  | + | 
|  | +      /* If the output file has no definition of the symbol, set the | 
|  | +	 symbol's value to the address of the stub.  */ | 
|  | +      if (!h->def_regular) | 
|  | +	{ | 
|  | +	  h->root.u.def.section = htab->splt; | 
|  | +	  h->root.u.def.value = h->plt.offset; | 
|  | +	} | 
|  | + | 
|  | +      /* Make room for the .got.plt entry and the R_RISCV_JUMP_SLOT | 
|  | +	 relocation.  */ | 
|  | +      htab->sgotplt->size += MIPS_ELF_GOT_SIZE (dynobj); | 
|  | +      htab->srelplt->size += MIPS_ELF_REL_SIZE (dynobj); | 
|  | + | 
|  | +      /* All relocations against this symbol that could have been made | 
|  | +	 dynamic will now refer to the PLT entry instead.  */ | 
|  | +      hmips->possibly_dynamic_relocs = 0; | 
|  | + | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* If this is a weak symbol, and there is a real definition, the | 
|  | +     processor independent code will have arranged for us to see the | 
|  | +     real definition first, and we can just use the same value.  */ | 
|  | +  if (h->u.weakdef != NULL) | 
|  | +    { | 
|  | +      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined | 
|  | +		  || h->u.weakdef->root.type == bfd_link_hash_defweak); | 
|  | +      h->root.u.def.section = h->u.weakdef->root.u.def.section; | 
|  | +      h->root.u.def.value = h->u.weakdef->root.u.def.value; | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* Otherwise, there is nothing further to do for symbols defined | 
|  | +     in regular objects.  */ | 
|  | +  if (h->def_regular) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* There's also nothing more to do if we'll convert all relocations | 
|  | +     against this symbol into dynamic relocations.  */ | 
|  | +  if (!hmips->has_static_relocs) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* We must allocate the symbol in our .dynbss section, which will | 
|  | +     become part of the .bss section of the executable.  There will be | 
|  | +     an entry for this symbol in the .dynsym section.  The dynamic | 
|  | +     object will contain position independent code, so all references | 
|  | +     from the dynamic object to this symbol will go through the global | 
|  | +     offset table.  The dynamic linker will use the .dynsym entry to | 
|  | +     determine the address it must put in the global offset table, so | 
|  | +     both the dynamic object and the regular object will refer to the | 
|  | +     same memory location for the variable.  */ | 
|  | + | 
|  | +  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) | 
|  | +    { | 
|  | +      mips_elf_allocate_dynamic_relocations (dynobj, info, 1); | 
|  | +      h->needs_copy = 1; | 
|  | +    } | 
|  | + | 
|  | +  /* All relocations against this symbol that could have been made | 
|  | +     dynamic will now refer to the local copy instead.  */ | 
|  | +  hmips->possibly_dynamic_relocs = 0; | 
|  | + | 
|  | +  return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss); | 
|  | +} | 
|  | + | 
|  | +/* This function is called after all the input files have been read, | 
|  | +   and the input sections have been assigned to output sections.  We | 
|  | +   check for any mips16 stub sections that we can discard.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_always_size_sections (bfd *output_bfd, | 
|  | +				    struct bfd_link_info *info ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  /* The .reginfo section has a fixed size.  */ | 
|  | +  asection *ri = bfd_get_section_by_name (output_bfd, ".reginfo"); | 
|  | +  if (ri != NULL) | 
|  | +    bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo)); | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* If the link uses a GOT, lay it out and work out its size.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  bfd *dynobj; | 
|  | +  asection *s; | 
|  | +  struct mips_got_info *g; | 
|  | +  bfd_size_type loadable_size = 0; | 
|  | +  bfd_size_type page_gotno; | 
|  | +  bfd *sub; | 
|  | +  struct mips_elf_count_tls_arg count_tls_arg; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_elf_count_tls_arg arg; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  s = htab->sgot; | 
|  | +  if (s == NULL) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  g = htab->got_info; | 
|  | + | 
|  | +  /* Allocate room for the reserved entries. */ | 
|  | +  BFD_ASSERT (g->assigned_gotno == 0); | 
|  | +  htab->reserved_gotno = 2; | 
|  | +  g->local_gotno += htab->reserved_gotno; | 
|  | +  g->assigned_gotno = htab->reserved_gotno; | 
|  | + | 
|  | +  /* Replace entries for indirect and warning symbols with entries for | 
|  | +     the target symbol.  */ | 
|  | +  if (!mips_elf_resolve_final_got_entries (g)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Count the number of GOT symbols.  */ | 
|  | +  mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, info); | 
|  | + | 
|  | +  /* Calculate the total loadable size of the output.  That | 
|  | +     will give us the maximum number of GOT_PAGE entries | 
|  | +     required.  */ | 
|  | +  for (sub = info->input_bfds; sub; sub = sub->link_next) | 
|  | +    { | 
|  | +      asection *subsection; | 
|  | + | 
|  | +      for (subsection = sub->sections; | 
|  | +	   subsection; | 
|  | +	   subsection = subsection->next) | 
|  | +	{ | 
|  | +	  if ((subsection->flags & SEC_ALLOC) == 0) | 
|  | +	    continue; | 
|  | +	  loadable_size += ((subsection->size + 0xf) | 
|  | +			    &~ (bfd_size_type) 0xf); | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Assume there are two loadable segments consisting of contiguous | 
|  | +     sections.  Is 5 enough?  */ | 
|  | +  page_gotno = (loadable_size >> 16) + 5; | 
|  | + | 
|  | +  /* Choose the smaller of the two estimates; both are intended to be | 
|  | +     conservative.  */ | 
|  | +  if (page_gotno > g->page_gotno) | 
|  | +    page_gotno = g->page_gotno; | 
|  | + | 
|  | +  g->local_gotno += page_gotno; | 
|  | +  s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); | 
|  | +  s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd); | 
|  | + | 
|  | +  /* We need to calculate tls_gotno for global symbols at this point | 
|  | +     instead of building it up earlier, to avoid doublecounting | 
|  | +     entries for one global symbol from multiple input files.  */ | 
|  | +  count_tls_arg.info = info; | 
|  | +  count_tls_arg.needed = 0; | 
|  | +  elf_link_hash_traverse (elf_hash_table (info), | 
|  | +			  mips_elf_count_global_tls_entries, | 
|  | +			  &count_tls_arg); | 
|  | +  g->tls_gotno += count_tls_arg.needed; | 
|  | +  s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd); | 
|  | + | 
|  | +  /* Set up TLS entries.  */ | 
|  | +  g->tls_assigned_gotno = g->global_gotno + g->local_gotno; | 
|  | +  htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g); | 
|  | + | 
|  | +  /* Allocate room for the TLS relocations.  */ | 
|  | +  arg.info = info; | 
|  | +  arg.needed = 0; | 
|  | +  htab_traverse (g->got_entries, mips_elf_count_local_tls_relocs, &arg); | 
|  | +  elf_link_hash_traverse (elf_hash_table (info), | 
|  | +			mips_elf_count_global_tls_relocs, &arg); | 
|  | +  if (arg.needed) | 
|  | +    mips_elf_allocate_dynamic_relocations (dynobj, info, arg.needed); | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Set the sizes of the dynamic sections.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_size_dynamic_sections (bfd *output_bfd, | 
|  | +				     struct bfd_link_info *info) | 
|  | +{ | 
|  | +  bfd *dynobj; | 
|  | +  asection *s, *sreldyn; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  BFD_ASSERT (dynobj != NULL); | 
|  | + | 
|  | +  if (elf_hash_table (info)->dynamic_sections_created) | 
|  | +    { | 
|  | +      /* Set the contents of the .interp section to the interpreter.  */ | 
|  | +      if (info->executable) | 
|  | +	{ | 
|  | +	  s = bfd_get_section_by_name (dynobj, ".interp"); | 
|  | +	  BFD_ASSERT (s != NULL); | 
|  | +	  s->size | 
|  | +	    = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1; | 
|  | +	  s->contents | 
|  | +	    = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd); | 
|  | +	} | 
|  | + | 
|  | +      /* Create a symbol for the PLT, if we know that we are using it.  */ | 
|  | +      if (htab->splt && htab->splt->size > 0 && htab->root.hplt == NULL) | 
|  | +	{ | 
|  | +	  struct elf_link_hash_entry *h; | 
|  | + | 
|  | +	  h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt, | 
|  | +					   "_PROCEDURE_LINKAGE_TABLE_"); | 
|  | +	  htab->root.hplt = h; | 
|  | +	  if (h == NULL) | 
|  | +	    return FALSE; | 
|  | +	  h->type = STT_FUNC; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Allocate space for global sym dynamic relocs.  */ | 
|  | +  elf_link_hash_traverse (&htab->root, allocate_dynrelocs, (PTR) info); | 
|  | + | 
|  | +  if (!mips_elf_lay_out_got (output_bfd, info)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* The check_relocs and adjust_dynamic_symbol entry points have | 
|  | +     determined the sizes of the various dynamic sections.  Allocate | 
|  | +     memory for them.  */ | 
|  | +  for (s = dynobj->sections; s != NULL; s = s->next) | 
|  | +    { | 
|  | +      const char *name; | 
|  | + | 
|  | +      /* It's OK to base decisions on the section name, because none | 
|  | +	 of the dynobj section names depend upon the input files.  */ | 
|  | +      name = bfd_get_section_name (dynobj, s); | 
|  | + | 
|  | +      if ((s->flags & SEC_LINKER_CREATED) == 0) | 
|  | +	continue; | 
|  | + | 
|  | +      if (CONST_STRNEQ (name, ".rel")) | 
|  | +	{ | 
|  | +	  if (s->size != 0) | 
|  | +	    { | 
|  | +	      /* We use the reloc_count field as a counter if we need | 
|  | +		 to copy relocs into the output file.  */ | 
|  | +	      if (strcmp (name, MIPS_ELF_REL_DYN_NAME (info)) != 0) | 
|  | +		s->reloc_count = 0; | 
|  | + | 
|  | +	      /* If combreloc is enabled, elf_link_sort_relocs() will | 
|  | +		 sort relocations, but in a different way than we do, | 
|  | +		 and before we're done creating relocations.  Also, it | 
|  | +		 will move them around between input sections' | 
|  | +		 relocation's contents, so our sorting would be | 
|  | +		 broken, so don't let it run.  */ | 
|  | +	      info->combreloc = 0; | 
|  | +	    } | 
|  | +	} | 
|  | +      else if (s == htab->splt) | 
|  | +	{ | 
|  | +	} | 
|  | +      else if (! CONST_STRNEQ (name, ".init") | 
|  | +	       && s != htab->sgot | 
|  | +	       && s != htab->sgotplt | 
|  | +	       && s != htab->sdynbss) | 
|  | +	{ | 
|  | +	  /* It's not one of our sections, so don't allocate space.  */ | 
|  | +	  continue; | 
|  | +	} | 
|  | + | 
|  | +      if (s->size == 0) | 
|  | +	{ | 
|  | +	  s->flags |= SEC_EXCLUDE; | 
|  | +	  continue; | 
|  | +	} | 
|  | + | 
|  | +      if ((s->flags & SEC_HAS_CONTENTS) == 0) | 
|  | +	continue; | 
|  | + | 
|  | +      /* Allocate memory for the section contents.  */ | 
|  | +      s->contents = bfd_zalloc (dynobj, s->size); | 
|  | +      if (s->contents == NULL) | 
|  | +	{ | 
|  | +	  bfd_set_error (bfd_error_no_memory); | 
|  | +	  return FALSE; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if (elf_hash_table (info)->dynamic_sections_created) | 
|  | +    { | 
|  | +      /* Add some entries to the .dynamic section.  We fill in the | 
|  | +	 values later, in _bfd_riscv_elf_finish_dynamic_sections, but we | 
|  | +	 must add the entries now so that we get the correct size for | 
|  | +	 the .dynamic section.  */ | 
|  | + | 
|  | +      /* The DT_DEBUG entry may be filled in by the dynamic linker and | 
|  | +	 used by the debugger.  */ | 
|  | +      if (info->executable | 
|  | +	  && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_DEBUG, 0)) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      if ((info->flags & DF_TEXTREL) != 0) | 
|  | +	{ | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_TEXTREL, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  /* Clear the DF_TEXTREL flag.  It will be set again if we | 
|  | +	     write out an actual text relocation; we may not, because | 
|  | +	     at this point we do not know whether e.g. any .eh_frame | 
|  | +	     absolute relocations have been converted to PC-relative.  */ | 
|  | +	  info->flags &= ~DF_TEXTREL; | 
|  | +	} | 
|  | + | 
|  | +      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTGOT, 0)) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      sreldyn = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +	{ | 
|  | +	  if (sreldyn && sreldyn->size > 0) | 
|  | +	    { | 
|  | +	      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_REL, 0)) | 
|  | +		return FALSE; | 
|  | + | 
|  | +	      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELSZ, 0)) | 
|  | +		return FALSE; | 
|  | + | 
|  | +	      if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_RELENT, 0)) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_VERSION, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_FLAGS, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_BASE_ADDRESS, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LOCAL_GOTNO, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_SYMTABNO, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_UNREFEXTNO, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_GOTSYM, 0)) | 
|  | +	    return FALSE; | 
|  | +	} | 
|  | +      if (htab->splt->size > 0) | 
|  | +	{ | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTREL, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_JMPREL, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_PLTRELSZ, 0)) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_PLTGOT, 0)) | 
|  | +	    return FALSE; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* REL is a relocation in INPUT_BFD that is being copied to OUTPUT_BFD. | 
|  | +   Adjust its R_ADDEND field so that it is correct for the output file. | 
|  | +   LOCAL_SYMS and LOCAL_SECTIONS are arrays of INPUT_BFD's local symbols | 
|  | +   and sections respectively; both use symbol indexes.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info, | 
|  | +			bfd *input_bfd, Elf_Internal_Sym *local_syms, | 
|  | +			asection **local_sections, Elf_Internal_Rela *rel) | 
|  | +{ | 
|  | +  unsigned int r_type, r_symndx; | 
|  | +  Elf_Internal_Sym *sym; | 
|  | +  asection *sec; | 
|  | + | 
|  | +  if (mips_elf_local_relocation_p (input_bfd, rel, local_sections)) | 
|  | +    { | 
|  | +      r_type = ELF_R_TYPE (output_bfd, rel->r_info); | 
|  | +      if (r_type == R_MIPS16_GPREL | 
|  | +	  || r_type == R_RISCV_GPREL16 | 
|  | +	  || r_type == R_RISCV_GPREL32 | 
|  | +	  || r_type == R_RISCV_LITERAL) | 
|  | +	{ | 
|  | +	  rel->r_addend += _bfd_get_gp_value (input_bfd); | 
|  | +	  rel->r_addend -= _bfd_get_gp_value (output_bfd); | 
|  | +	} | 
|  | + | 
|  | +      r_symndx = ELF_R_SYM (output_bfd, rel->r_info); | 
|  | +      sym = local_syms + r_symndx; | 
|  | + | 
|  | +      /* Adjust REL's addend to account for section merging.  */ | 
|  | +      if (!info->relocatable) | 
|  | +	{ | 
|  | +	  sec = local_sections[r_symndx]; | 
|  | +	  _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); | 
|  | +	} | 
|  | + | 
|  | +      /* This would normally be done by the rela_normal code in elflink.c.  */ | 
|  | +      if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) | 
|  | +	rel->r_addend += local_sections[r_symndx]->output_offset; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Relocate a MIPS ELF section.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, | 
|  | +				bfd *input_bfd, asection *input_section, | 
|  | +				bfd_byte *contents, Elf_Internal_Rela *relocs, | 
|  | +				Elf_Internal_Sym *local_syms, | 
|  | +				asection **local_sections) | 
|  | +{ | 
|  | +  Elf_Internal_Rela *rel; | 
|  | +  const Elf_Internal_Rela *relend; | 
|  | +  bfd_vma addend = 0; | 
|  | +  bfd_boolean use_saved_addend_p = FALSE; | 
|  | +  const struct elf_backend_data *bed; | 
|  | + | 
|  | +  bed = get_elf_backend_data (output_bfd); | 
|  | +  relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; | 
|  | +  for (rel = relocs; rel < relend; ++rel) | 
|  | +    { | 
|  | +      const char *name; | 
|  | +      bfd_vma value = 0; | 
|  | +      reloc_howto_type *howto; | 
|  | +      /* TRUE if the relocation is a RELA relocation, rather than a | 
|  | +         REL relocation.  */ | 
|  | +      bfd_boolean rela_relocation_p = TRUE; | 
|  | +      unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info); | 
|  | +      const char *msg; | 
|  | +      unsigned long r_symndx; | 
|  | +      asection *sec; | 
|  | +      Elf_Internal_Shdr *symtab_hdr; | 
|  | +      struct elf_link_hash_entry *h; | 
|  | +      bfd_boolean rel_reloc; | 
|  | + | 
|  | +      rel_reloc = mips_elf_rel_relocation_p (input_bfd, input_section, | 
|  | +					     relocs, rel); | 
|  | +      /* Find the relocation howto for this relocation.  */ | 
|  | +      howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc); | 
|  | + | 
|  | +      r_symndx = ELF_R_SYM (input_bfd, rel->r_info); | 
|  | +      symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; | 
|  | +      if (mips_elf_local_relocation_p (input_bfd, rel, local_sections)) | 
|  | +	{ | 
|  | +	  sec = local_sections[r_symndx]; | 
|  | +	  h = NULL; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  unsigned long extsymoff; | 
|  | + | 
|  | +	  extsymoff = 0; | 
|  | +	  if (!elf_bad_symtab (input_bfd)) | 
|  | +	    extsymoff = symtab_hdr->sh_info; | 
|  | +	  h = elf_sym_hashes (input_bfd) [r_symndx - extsymoff]; | 
|  | +	  while (h->root.type == bfd_link_hash_indirect | 
|  | +		 || h->root.type == bfd_link_hash_warning) | 
|  | +	    h = (struct elf_link_hash_entry *) h->root.u.i.link; | 
|  | + | 
|  | +	  sec = NULL; | 
|  | +	  if (h->root.type == bfd_link_hash_defined | 
|  | +	      || h->root.type == bfd_link_hash_defweak) | 
|  | +	    sec = h->root.u.def.section; | 
|  | +	} | 
|  | + | 
|  | +      if (sec != NULL && elf_discarded_section (sec)) | 
|  | +	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, | 
|  | +					 rel, relend, howto, contents); | 
|  | + | 
|  | +      if (!use_saved_addend_p) | 
|  | +	{ | 
|  | +	  /* If these relocations were originally of the REL variety, | 
|  | +	     we must pull the addend out of the field that will be | 
|  | +	     relocated.  Otherwise, we simply use the contents of the | 
|  | +	     RELA relocation.  */ | 
|  | +	  if (mips_elf_rel_relocation_p (input_bfd, input_section, | 
|  | +					 relocs, rel)) | 
|  | +	    { | 
|  | +	      rela_relocation_p = FALSE; | 
|  | +	      addend = mips_elf_read_rel_addend (input_bfd, rel, | 
|  | +						 howto, contents); | 
|  | +	      if (hi16_reloc_p (r_type) | 
|  | +		  || (got16_reloc_p (r_type) | 
|  | +		      && mips_elf_local_relocation_p (input_bfd, rel, | 
|  | +						      local_sections))) | 
|  | +		{ | 
|  | +		  if (!mips_elf_add_lo16_rel_addend (input_bfd, rel, relend, | 
|  | +						     contents, &addend)) | 
|  | +		    { | 
|  | +		      if (h) | 
|  | +			name = h->root.root.string; | 
|  | +		      else | 
|  | +			name = bfd_elf_sym_name (input_bfd, symtab_hdr, | 
|  | +						 local_syms + r_symndx, | 
|  | +						 sec); | 
|  | +		      (*_bfd_error_handler) | 
|  | +			(_("%B: Can't find matching LO16 reloc against `%s' for %s at 0x%lx in section `%A'"), | 
|  | +			 input_bfd, input_section, name, howto->name, | 
|  | +			 rel->r_offset); | 
|  | +		    } | 
|  | +		} | 
|  | +	      else | 
|  | +		addend <<= howto->rightshift; | 
|  | +	    } | 
|  | +	  else | 
|  | +	    addend = rel->r_addend; | 
|  | +	  mips_elf_adjust_addend (output_bfd, info, input_bfd, | 
|  | +				  local_syms, local_sections, rel); | 
|  | +	} | 
|  | + | 
|  | +      if (info->relocatable) | 
|  | +	{ | 
|  | +	  if (!rela_relocation_p && rel->r_addend) | 
|  | +	    { | 
|  | +	      addend += rel->r_addend; | 
|  | +	      if (hi16_reloc_p (r_type) || got16_reloc_p (r_type)) | 
|  | +		addend = mips_elf_high (addend); | 
|  | +	      else | 
|  | +		addend >>= howto->rightshift; | 
|  | + | 
|  | +	      /* We use the source mask, rather than the destination | 
|  | +		 mask because the place to which we are writing will be | 
|  | +		 source of the addend in the final link.  */ | 
|  | +	      addend &= howto->src_mask; | 
|  | + | 
|  | +	      if (! mips_elf_perform_relocation (info, howto, rel, addend, | 
|  | +						 input_bfd, input_section, | 
|  | +						 contents)) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | + | 
|  | +	  /* Go on to the next relocation.  */ | 
|  | +	  continue; | 
|  | +	} | 
|  | + | 
|  | +      /* In the N32 and 64-bit ABIs there may be multiple consecutive | 
|  | +	 relocations for the same offset.  In that case we are | 
|  | +	 supposed to treat the output of each relocation as the addend | 
|  | +	 for the next.  */ | 
|  | +      if (rel + 1 < relend | 
|  | +	  && rel->r_offset == rel[1].r_offset | 
|  | +	  && ELF_R_TYPE (input_bfd, rel[1].r_info) != R_RISCV_NONE) | 
|  | +	use_saved_addend_p = TRUE; | 
|  | +      else | 
|  | +	use_saved_addend_p = FALSE; | 
|  | + | 
|  | +      /* Figure out what value we are supposed to relocate.  */ | 
|  | +      switch (mips_elf_calculate_relocation (output_bfd, input_bfd, | 
|  | +					     input_section, info, rel, | 
|  | +					     addend, howto, local_syms, | 
|  | +					     local_sections, &value, | 
|  | +					     &name, use_saved_addend_p)) | 
|  | +	{ | 
|  | +	case bfd_reloc_continue: | 
|  | +	  /* There's nothing to do.  */ | 
|  | +	  continue; | 
|  | + | 
|  | +	case bfd_reloc_undefined: | 
|  | +	  /* mips_elf_calculate_relocation already called the | 
|  | +	     undefined_symbol callback.  There's no real point in | 
|  | +	     trying to perform the relocation at this point, so we | 
|  | +	     just skip ahead to the next relocation.  */ | 
|  | +	  continue; | 
|  | + | 
|  | +	case bfd_reloc_notsupported: | 
|  | +	  msg = _("internal error: unsupported relocation error"); | 
|  | +	  info->callbacks->warning | 
|  | +	    (info, msg, name, input_bfd, input_section, rel->r_offset); | 
|  | +	  return FALSE; | 
|  | + | 
|  | +	case bfd_reloc_overflow: | 
|  | +	  if (use_saved_addend_p) | 
|  | +	    /* Ignore overflow until we reach the last relocation for | 
|  | +	       a given location.  */ | 
|  | +	    ; | 
|  | +	  else | 
|  | +	    { | 
|  | +	      struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +	      htab = mips_elf_hash_table (info); | 
|  | +	      BFD_ASSERT (htab != NULL); | 
|  | +	      BFD_ASSERT (name != NULL); | 
|  | +	      if (! ((*info->callbacks->reloc_overflow) | 
|  | +		     (info, NULL, name, howto->name, (bfd_vma) 0, | 
|  | +		      input_bfd, input_section, rel->r_offset))) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | +	  break; | 
|  | + | 
|  | +	case bfd_reloc_ok: | 
|  | +	  break; | 
|  | + | 
|  | +	default: | 
|  | +	  abort (); | 
|  | +	  break; | 
|  | +	} | 
|  | + | 
|  | +      /* If we've got another relocation for the address, keep going | 
|  | +	 until we reach the last one.  */ | 
|  | +      if (use_saved_addend_p) | 
|  | +	{ | 
|  | +	  addend = value; | 
|  | +	  continue; | 
|  | +	} | 
|  | + | 
|  | +      /* Actually perform the relocation.  */ | 
|  | +      if (! mips_elf_perform_relocation (info, howto, rel, value, | 
|  | +					 input_bfd, input_section, | 
|  | +					 contents)) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Finish up dynamic symbol handling.  We set the contents of various | 
|  | +   dynamic sections here.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_finish_dynamic_symbol (bfd *output_bfd, | 
|  | +				     struct bfd_link_info *info, | 
|  | +				     struct elf_link_hash_entry *h, | 
|  | +				     Elf_Internal_Sym *sym) | 
|  | +{ | 
|  | +  bfd *dynobj; | 
|  | +  asection *sgot; | 
|  | +  struct mips_got_info *g; | 
|  | +  const char *name; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  struct mips_elf_link_hash_entry *hmips; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | +  hmips = (struct mips_elf_link_hash_entry *) h; | 
|  | + | 
|  | +  if (h->plt.offset != MINUS_ONE) | 
|  | +    { | 
|  | +      /* We've decided to create a PLT entry for this symbol.  */ | 
|  | +      bfd_byte *loc; | 
|  | +      bfd_vma header_address, plt_index, got_address; | 
|  | +      bfd_vma plt_entry[RISCV_PLT_ENTRY_INSNS]; | 
|  | +      int i; | 
|  | + | 
|  | +      BFD_ASSERT (h->dynindx != -1); | 
|  | +      BFD_ASSERT (htab->splt != NULL); | 
|  | +      BFD_ASSERT (h->plt.offset <= htab->splt->size); | 
|  | +      BFD_ASSERT (!h->def_regular); | 
|  | + | 
|  | +      /* Calculate the address of the PLT header.  */ | 
|  | +      header_address = (htab->splt->output_section->vma | 
|  | +			+ htab->splt->output_offset); | 
|  | + | 
|  | +      /* Calculate the index of the entry.  */ | 
|  | +      plt_index = ((h->plt.offset - htab->plt_header_size) | 
|  | +		   / htab->plt_entry_size); | 
|  | + | 
|  | +      /* Calculate the address of the .got.plt entry.  */ | 
|  | +      got_address = (htab->sgotplt->output_section->vma | 
|  | +		     + htab->sgotplt->output_offset | 
|  | +		     + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj)); | 
|  | + | 
|  | +      /* Initially point the .got.plt entry at the PLT header.  */ | 
|  | +      loc = (htab->sgotplt->contents | 
|  | +	     + (2 + plt_index) * MIPS_ELF_GOT_SIZE (dynobj)); | 
|  | +      if (ABI_64_P (output_bfd)) | 
|  | +	bfd_put_64 (output_bfd, header_address, loc); | 
|  | +      else | 
|  | +	bfd_put_32 (output_bfd, header_address, loc); | 
|  | + | 
|  | +      /* Find out where the .plt entry should go.  */ | 
|  | +      loc = htab->splt->contents + h->plt.offset; | 
|  | + | 
|  | +      /* Fill in the PLT entry itself.  */ | 
|  | +      riscv_make_plt_entry (output_bfd, got_address, | 
|  | +                            header_address + h->plt.offset, plt_entry); | 
|  | +      for (i = 0; i < RISCV_PLT_ENTRY_INSNS; i++) | 
|  | +        bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i); | 
|  | + | 
|  | +      /* Emit an R_RISCV_JUMP_SLOT relocation against the .got.plt entry.  */ | 
|  | +      mips_elf_output_dynamic_relocation (output_bfd, htab->srelplt, | 
|  | +					  plt_index, h->dynindx, | 
|  | +					  R_RISCV_JUMP_SLOT, got_address); | 
|  | + | 
|  | +      /* We distinguish between PLT entries and lazy-binding stubs by | 
|  | +	 giving the former an st_other value of STO_MIPS_PLT.  Set the | 
|  | +	 flag and leave the value if there are any relocations in the | 
|  | +	 binary where pointer equality matters.  */ | 
|  | +      sym->st_shndx = SHN_UNDEF; | 
|  | +      if (h->pointer_equality_needed) | 
|  | +	sym->st_other = STO_MIPS_PLT; | 
|  | +      else | 
|  | +	sym->st_value = 0; | 
|  | +    } | 
|  | + | 
|  | +  BFD_ASSERT (h->dynindx != -1 | 
|  | +	      || h->forced_local); | 
|  | + | 
|  | +  sgot = htab->sgot; | 
|  | +  g = htab->got_info; | 
|  | +  BFD_ASSERT (g != NULL); | 
|  | + | 
|  | +  /* Run through the global symbol table, creating GOT entries for all | 
|  | +     the symbols that need them.  */ | 
|  | +  if (hmips->global_got_area != GGA_NONE) | 
|  | +    { | 
|  | +      bfd_vma offset; | 
|  | +      bfd_vma value; | 
|  | + | 
|  | +      value = sym->st_value; | 
|  | +      offset = mips_elf_global_got_index (dynobj, h, R_RISCV_GOT16, info); | 
|  | +      MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset); | 
|  | +    } | 
|  | + | 
|  | +  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  */ | 
|  | +  name = h->root.root.string; | 
|  | +  if (strcmp (name, "_DYNAMIC") == 0 | 
|  | +      || h == elf_hash_table (info)->hgot) | 
|  | +    sym->st_shndx = SHN_ABS; | 
|  | +  else if (strcmp (name, "_DYNAMIC_LINKING") == 0) | 
|  | +    { | 
|  | +      sym->st_shndx = SHN_ABS; | 
|  | +      sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); | 
|  | +      sym->st_value = 1; | 
|  | +    } | 
|  | + | 
|  | +  /* Emit a copy reloc, if needed.  */ | 
|  | +  if (h->needs_copy) | 
|  | +    { | 
|  | +      asection *s; | 
|  | +      bfd_vma symval; | 
|  | + | 
|  | +      BFD_ASSERT (h->dynindx != -1); | 
|  | + | 
|  | +      s = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +      symval = (h->root.u.def.section->output_section->vma | 
|  | +		+ h->root.u.def.section->output_offset | 
|  | +		+ h->root.u.def.value); | 
|  | +      mips_elf_output_dynamic_relocation (output_bfd, s, s->reloc_count++, | 
|  | +					  h->dynindx, R_RISCV_COPY, symval); | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Write out a plt0 entry to the beginning of .plt.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_finish_exec_plt (bfd *output_bfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  bfd_byte *loc; | 
|  | +  bfd_vma gotplt_value, plt_address; | 
|  | +  bfd_vma plt_entry[RISCV_PLT0_ENTRY_INSNS]; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | +  int i; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  plt_address = htab->splt->output_section->vma + htab->splt->output_offset; | 
|  | +  /* Calculate the value of .got.plt.  */ | 
|  | +  gotplt_value = (htab->sgotplt->output_section->vma | 
|  | +		  + htab->sgotplt->output_offset); | 
|  | + | 
|  | +  /* Install the PLT header.  */ | 
|  | +  loc = htab->splt->contents; | 
|  | +  riscv_make_plt0_entry (output_bfd, gotplt_value, plt_address, plt_entry); | 
|  | +  for (i = 0; i < RISCV_PLT0_ENTRY_INSNS; i++) | 
|  | +    bfd_put_32 (output_bfd, plt_entry[i], loc + 4*i); | 
|  | +} | 
|  | + | 
|  | +/* Finish up the dynamic sections.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_finish_dynamic_sections (bfd *output_bfd, | 
|  | +				       struct bfd_link_info *info) | 
|  | +{ | 
|  | +  bfd *dynobj; | 
|  | +  asection *sdyn; | 
|  | +  asection *sgot; | 
|  | +  struct mips_got_info *gg, *g; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  dynobj = elf_hash_table (info)->dynobj; | 
|  | + | 
|  | +  sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); | 
|  | + | 
|  | +  sgot = htab->sgot; | 
|  | +  g = gg = htab->got_info; | 
|  | + | 
|  | +  if (elf_hash_table (info)->dynamic_sections_created) | 
|  | +    { | 
|  | +      bfd_byte *b; | 
|  | +      int dyn_to_skip = 0, dyn_skipped = 0; | 
|  | + | 
|  | +      BFD_ASSERT (sdyn != NULL); | 
|  | +      BFD_ASSERT (gg != NULL); | 
|  | + | 
|  | +      for (b = sdyn->contents; | 
|  | +	   b < sdyn->contents + sdyn->size; | 
|  | +	   b += MIPS_ELF_DYN_SIZE (dynobj)) | 
|  | +	{ | 
|  | +	  Elf_Internal_Dyn dyn; | 
|  | +	  const char *name; | 
|  | +	  size_t elemsize; | 
|  | +	  asection *s; | 
|  | +	  bfd_boolean swap_out_p; | 
|  | + | 
|  | +	  /* Read in the current dynamic entry.  */ | 
|  | +	  (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); | 
|  | + | 
|  | +	  /* Assume that we're going to modify it and write it out.  */ | 
|  | +	  swap_out_p = TRUE; | 
|  | + | 
|  | +	  switch (dyn.d_tag) | 
|  | +	    { | 
|  | +	    case DT_RELENT: | 
|  | +	      dyn.d_un.d_val = MIPS_ELF_REL_SIZE (dynobj); | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_STRSZ: | 
|  | +	      /* Rewrite DT_STRSZ.  */ | 
|  | +	      dyn.d_un.d_val = | 
|  | +		_bfd_elf_strtab_size (elf_hash_table (info)->dynstr); | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_PLTGOT: | 
|  | +	      s = htab->sgot; | 
|  | +	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_PLTGOT: | 
|  | +	      s = htab->sgotplt; | 
|  | +	      dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_RLD_VERSION: | 
|  | +	      dyn.d_un.d_val = 1; /* XXX */ | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_FLAGS: | 
|  | +	      dyn.d_un.d_val = RHF_NOTPOT; /* XXX */ | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_TIME_STAMP: | 
|  | +	      { | 
|  | +		time_t t; | 
|  | +		time (&t); | 
|  | +		dyn.d_un.d_val = t; | 
|  | +	      } | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_ICHECKSUM: | 
|  | +	      /* XXX FIXME: */ | 
|  | +	      swap_out_p = FALSE; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_IVERSION: | 
|  | +	      /* XXX FIXME: */ | 
|  | +	      swap_out_p = FALSE; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_BASE_ADDRESS: | 
|  | +	      s = output_bfd->sections; | 
|  | +	      BFD_ASSERT (s != NULL); | 
|  | +	      dyn.d_un.d_ptr = s->vma & ~(bfd_vma) (RISCV_IMM_REACH-1); | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_LOCAL_GOTNO: | 
|  | +	      dyn.d_un.d_val = g->local_gotno; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_UNREFEXTNO: | 
|  | +	      /* The index into the dynamic symbol table which is the | 
|  | +		 entry of the first external symbol that is not | 
|  | +		 referenced within the same object.  */ | 
|  | +	      dyn.d_un.d_val = bfd_count_sections (output_bfd) + 1; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_GOTSYM: | 
|  | +	      if (gg->global_gotsym) | 
|  | +		{ | 
|  | +		  dyn.d_un.d_val = gg->global_gotsym->dynindx; | 
|  | +		  break; | 
|  | +		} | 
|  | +	      /* In case if we don't have global got symbols we default | 
|  | +		 to setting DT_MIPS_GOTSYM to the same value as | 
|  | +		 DT_MIPS_SYMTABNO, so we just fall through.  */ | 
|  | + | 
|  | +	    case DT_MIPS_SYMTABNO: | 
|  | +	      name = ".dynsym"; | 
|  | +	      elemsize = MIPS_ELF_SYM_SIZE (output_bfd); | 
|  | +	      s = bfd_get_section_by_name (output_bfd, name); | 
|  | +	      BFD_ASSERT (s != NULL); | 
|  | + | 
|  | +	      dyn.d_un.d_val = s->size / elemsize; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_HIPAGENO: | 
|  | +	      dyn.d_un.d_val = g->local_gotno - htab->reserved_gotno; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_MIPS_OPTIONS: | 
|  | +	      s = (bfd_get_section_by_name | 
|  | +		   (output_bfd, MIPS_ELF_OPTIONS_SECTION_NAME (output_bfd))); | 
|  | +	      dyn.d_un.d_ptr = s->vma; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_PLTREL: | 
|  | +	      dyn.d_un.d_val = DT_REL; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_PLTRELSZ: | 
|  | +	      dyn.d_un.d_val = htab->srelplt->size; | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_JMPREL: | 
|  | +	      dyn.d_un.d_ptr = (htab->srelplt->output_section->vma | 
|  | +				+ htab->srelplt->output_offset); | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_TEXTREL: | 
|  | +	      /* If we didn't need any text relocations after all, delete | 
|  | +		 the dynamic tag.  */ | 
|  | +	      if (!(info->flags & DF_TEXTREL)) | 
|  | +		{ | 
|  | +		  dyn_to_skip = MIPS_ELF_DYN_SIZE (dynobj); | 
|  | +		  swap_out_p = FALSE; | 
|  | +		} | 
|  | +	      break; | 
|  | + | 
|  | +	    case DT_FLAGS: | 
|  | +	      /* If we didn't need any text relocations after all, clear | 
|  | +		 DF_TEXTREL from DT_FLAGS.  */ | 
|  | +	      if (!(info->flags & DF_TEXTREL)) | 
|  | +		dyn.d_un.d_val &= ~DF_TEXTREL; | 
|  | +	      else | 
|  | +		swap_out_p = FALSE; | 
|  | +	      break; | 
|  | + | 
|  | +	    default: | 
|  | +	      swap_out_p = FALSE; | 
|  | +	      break; | 
|  | +	    } | 
|  | + | 
|  | +	  if (swap_out_p || dyn_skipped) | 
|  | +	    (*get_elf_backend_data (dynobj)->s->swap_dyn_out) | 
|  | +	      (dynobj, &dyn, b - dyn_skipped); | 
|  | + | 
|  | +	  if (dyn_to_skip) | 
|  | +	    { | 
|  | +	      dyn_skipped += dyn_to_skip; | 
|  | +	      dyn_to_skip = 0; | 
|  | +	    } | 
|  | +	} | 
|  | + | 
|  | +      /* Wipe out any trailing entries if we shifted down a dynamic tag.  */ | 
|  | +      if (dyn_skipped > 0) | 
|  | +	memset (b - dyn_skipped, 0, dyn_skipped); | 
|  | +    } | 
|  | + | 
|  | +  if (sgot != NULL && sgot->size > 0 | 
|  | +      && !bfd_is_abs_section (sgot->output_section)) | 
|  | +    { | 
|  | +      /* The first entry of the global offset table will be filled at | 
|  | +         runtime. The second entry will be used by some runtime loaders. | 
|  | +         This isn't the case of IRIX rld.  */ | 
|  | +      MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents); | 
|  | +      MIPS_ELF_PUT_WORD (output_bfd, MIPS_ELF_GNU_GOT1_MASK (output_bfd), | 
|  | +	                 sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd)); | 
|  | + | 
|  | +      elf_section_data (sgot->output_section)->this_hdr.sh_entsize | 
|  | +	 = MIPS_ELF_GOT_SIZE (output_bfd); | 
|  | +    } | 
|  | + | 
|  | +  /* The generation of dynamic relocations for the non-primary gots | 
|  | +     adds more dynamic relocations.  We cannot count them until | 
|  | +     here.  */ | 
|  | + | 
|  | +  if (elf_hash_table (info)->dynamic_sections_created) | 
|  | +    { | 
|  | +      bfd_byte *b; | 
|  | +      bfd_boolean swap_out_p; | 
|  | + | 
|  | +      BFD_ASSERT (sdyn != NULL); | 
|  | + | 
|  | +      for (b = sdyn->contents; | 
|  | +	   b < sdyn->contents + sdyn->size; | 
|  | +	   b += MIPS_ELF_DYN_SIZE (dynobj)) | 
|  | +	{ | 
|  | +	  Elf_Internal_Dyn dyn; | 
|  | +	  asection *s; | 
|  | + | 
|  | +	  /* Read in the current dynamic entry.  */ | 
|  | +	  (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); | 
|  | + | 
|  | +	  /* Assume that we're going to modify it and write it out.  */ | 
|  | +	  swap_out_p = TRUE; | 
|  | + | 
|  | +	  switch (dyn.d_tag) | 
|  | +	    { | 
|  | +	    case DT_RELSZ: | 
|  | +	      /* Reduce DT_RELSZ to account for any relocations we | 
|  | +		 decided not to make.  This is for the n64 irix rld, | 
|  | +		 which doesn't seem to apply any relocations if there | 
|  | +		 are trailing null entries.  */ | 
|  | +	      s = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +	      dyn.d_un.d_val = (s->reloc_count | 
|  | +				* (ABI_64_P (output_bfd) | 
|  | +				   ? sizeof (Elf64_RISCV_External_Rel) | 
|  | +				   : sizeof (Elf32_External_Rel))); | 
|  | +	      /* Adjust the section size too.  Tools like the prelinker | 
|  | +		 can reasonably expect the values to the same.  */ | 
|  | +	      elf_section_data (s->output_section)->this_hdr.sh_size | 
|  | +		= dyn.d_un.d_val; | 
|  | +	      break; | 
|  | + | 
|  | +	    default: | 
|  | +	      swap_out_p = FALSE; | 
|  | +	      break; | 
|  | +	    } | 
|  | + | 
|  | +	  if (swap_out_p) | 
|  | +	    (*get_elf_backend_data (dynobj)->s->swap_dyn_out) | 
|  | +	      (dynobj, &dyn, b); | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  { | 
|  | +    asection *s; | 
|  | + | 
|  | +    /* The psABI says that the dynamic relocations must be sorted in | 
|  | +       increasing order of r_symndx. */ | 
|  | +    s = mips_elf_rel_dyn_section (info, FALSE); | 
|  | +    if (s != NULL && s->size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd)) | 
|  | +      { | 
|  | +        reldyn_sorting_bfd = output_bfd; | 
|  | + | 
|  | +        if (ABI_64_P (output_bfd)) | 
|  | +          qsort ((Elf64_External_Rel *) s->contents + 1, | 
|  | +	         s->reloc_count - 1, sizeof (Elf64_RISCV_External_Rel), | 
|  | +	         sort_dynamic_relocs_64); | 
|  | +        else | 
|  | +          qsort ((Elf32_External_Rel *) s->contents + 1, | 
|  | +	         s->reloc_count - 1, sizeof (Elf32_External_Rel), | 
|  | +	         sort_dynamic_relocs); | 
|  | +      } | 
|  | +  } | 
|  | + | 
|  | +  if (htab->splt && htab->splt->size > 0) | 
|  | +    mips_finish_exec_plt (output_bfd, info); | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_set_isa_flags (bfd *abfd) | 
|  | +{ | 
|  | +  flagword val; | 
|  | + | 
|  | +  switch (bfd_get_mach (abfd)) | 
|  | +    { | 
|  | +    default: | 
|  | +    case bfd_mach_riscv_rocket64: | 
|  | +      val = E_RISCV_ARCH_RV64 | E_RISCV_MACH_ROCKET64; | 
|  | +      break; | 
|  | + | 
|  | +    case bfd_mach_riscv_rocket32: | 
|  | +      val = E_RISCV_ARCH_RV32 | E_RISCV_MACH_ROCKET32; | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); | 
|  | +  elf_elfheader (abfd)->e_flags |= val; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* The final processing done just before writing out a MIPS ELF object | 
|  | +   file.  This gets the MIPS architecture right based on the machine | 
|  | +   number.  This is used by both the 32-bit and the 64-bit ABI.  */ | 
|  | + | 
|  | +void | 
|  | +_bfd_riscv_elf_final_write_processing (bfd *abfd, | 
|  | +				      bfd_boolean linker ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | +  Elf_Internal_Shdr **hdrpp; | 
|  | +  const char *name; | 
|  | +  asection *sec; | 
|  | + | 
|  | +  /* Keep the existing EF_MIPS_MACH and EF_MIPS_ARCH flags if the former | 
|  | +     is nonzero.  This is for compatibility with old objects, which used | 
|  | +     a combination of a 32-bit EF_MIPS_ARCH and a 64-bit EF_MIPS_MACH.  */ | 
|  | +  if ((elf_elfheader (abfd)->e_flags & EF_MIPS_MACH) == 0) | 
|  | +    mips_set_isa_flags (abfd); | 
|  | + | 
|  | +  /* Set the sh_info field for .gptab sections and other appropriate | 
|  | +     info for each special section.  */ | 
|  | +  for (i = 1, hdrpp = elf_elfsections (abfd) + 1; | 
|  | +       i < elf_numsections (abfd); | 
|  | +       i++, hdrpp++) | 
|  | +    { | 
|  | +      switch ((*hdrpp)->sh_type) | 
|  | +	{ | 
|  | +	case SHT_MIPS_MSYM: | 
|  | +	case SHT_MIPS_LIBLIST: | 
|  | +	  sec = bfd_get_section_by_name (abfd, ".dynstr"); | 
|  | +	  if (sec != NULL) | 
|  | +	    (*hdrpp)->sh_link = elf_section_data (sec)->this_idx; | 
|  | +	  break; | 
|  | + | 
|  | +	case SHT_MIPS_GPTAB: | 
|  | +          BFD_ASSERT (FALSE); | 
|  | + | 
|  | +	case SHT_MIPS_CONTENT: | 
|  | +	  BFD_ASSERT ((*hdrpp)->bfd_section != NULL); | 
|  | +	  name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section); | 
|  | +	  BFD_ASSERT (name != NULL | 
|  | +		      && CONST_STRNEQ (name, ".MIPS.content")); | 
|  | +	  sec = bfd_get_section_by_name (abfd, | 
|  | +					 name + sizeof ".MIPS.content" - 1); | 
|  | +	  BFD_ASSERT (sec != NULL); | 
|  | +	  (*hdrpp)->sh_link = elf_section_data (sec)->this_idx; | 
|  | +	  break; | 
|  | + | 
|  | +	case SHT_MIPS_SYMBOL_LIB: | 
|  | +	  sec = bfd_get_section_by_name (abfd, ".dynsym"); | 
|  | +	  if (sec != NULL) | 
|  | +	    (*hdrpp)->sh_link = elf_section_data (sec)->this_idx; | 
|  | +	  sec = bfd_get_section_by_name (abfd, ".liblist"); | 
|  | +	  if (sec != NULL) | 
|  | +	    (*hdrpp)->sh_info = elf_section_data (sec)->this_idx; | 
|  | +	  break; | 
|  | + | 
|  | +	case SHT_MIPS_EVENTS: | 
|  | +	  BFD_ASSERT ((*hdrpp)->bfd_section != NULL); | 
|  | +	  name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section); | 
|  | +	  BFD_ASSERT (name != NULL); | 
|  | +	  if (CONST_STRNEQ (name, ".MIPS.events")) | 
|  | +	    sec = bfd_get_section_by_name (abfd, | 
|  | +					   name + sizeof ".MIPS.events" - 1); | 
|  | +	  else | 
|  | +	    { | 
|  | +	      BFD_ASSERT (CONST_STRNEQ (name, ".MIPS.post_rel")); | 
|  | +	      sec = bfd_get_section_by_name (abfd, | 
|  | +					     (name | 
|  | +					      + sizeof ".MIPS.post_rel" - 1)); | 
|  | +	    } | 
|  | +	  BFD_ASSERT (sec != NULL); | 
|  | +	  (*hdrpp)->sh_link = elf_section_data (sec)->this_idx; | 
|  | +	  break; | 
|  | + | 
|  | +	} | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* When creating an IRIX5 executable, we need REGINFO and RTPROC | 
|  | +   segments.  */ | 
|  | + | 
|  | +int | 
|  | +_bfd_riscv_elf_additional_program_headers (bfd *abfd, | 
|  | +					  struct bfd_link_info *info ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  asection *s; | 
|  | +  int ret = 0; | 
|  | + | 
|  | +  /* See if we need a PT_MIPS_REGINFO segment.  */ | 
|  | +  s = bfd_get_section_by_name (abfd, ".reginfo"); | 
|  | +  if (s && (s->flags & SEC_LOAD)) | 
|  | +    ++ret; | 
|  | + | 
|  | +  /* Allocate a PT_NULL header in dynamic objects.  See | 
|  | +     _bfd_riscv_elf_modify_segment_map for details.  */ | 
|  | +  if (bfd_get_section_by_name (abfd, ".dynamic")) | 
|  | +    ++ret; | 
|  | + | 
|  | +  return ret; | 
|  | +} | 
|  | + | 
|  | +/* Modify the segment map for an IRIX5 executable.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_modify_segment_map (bfd *abfd, | 
|  | +				  struct bfd_link_info *info) | 
|  | +{ | 
|  | +  asection *s; | 
|  | +  struct elf_segment_map *m, **pm; | 
|  | +  bfd_size_type amt; | 
|  | + | 
|  | +  /* If there is a .reginfo section, we need a PT_MIPS_REGINFO | 
|  | +     segment.  */ | 
|  | +  s = bfd_get_section_by_name (abfd, ".reginfo"); | 
|  | +  if (s != NULL && (s->flags & SEC_LOAD) != 0) | 
|  | +    { | 
|  | +      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) | 
|  | +	if (m->p_type == PT_MIPS_REGINFO) | 
|  | +	  break; | 
|  | +      if (m == NULL) | 
|  | +	{ | 
|  | +	  amt = sizeof *m; | 
|  | +	  m = bfd_zalloc (abfd, amt); | 
|  | +	  if (m == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  m->p_type = PT_MIPS_REGINFO; | 
|  | +	  m->count = 1; | 
|  | +	  m->sections[0] = s; | 
|  | + | 
|  | +	  /* We want to put it after the PHDR and INTERP segments.  */ | 
|  | +	  pm = &elf_tdata (abfd)->segment_map; | 
|  | +	  while (*pm != NULL | 
|  | +		 && ((*pm)->p_type == PT_PHDR | 
|  | +		     || (*pm)->p_type == PT_INTERP)) | 
|  | +	    pm = &(*pm)->next; | 
|  | + | 
|  | +	  m->next = *pm; | 
|  | +	  *pm = m; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +    { | 
|  | +      /* On IRIX5, the PT_DYNAMIC segment includes the .dynamic, | 
|  | +	 .dynstr, .dynsym, and .hash sections, and everything in | 
|  | +	 between.  */ | 
|  | +      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; | 
|  | +	   pm = &(*pm)->next) | 
|  | +	if ((*pm)->p_type == PT_DYNAMIC) | 
|  | +	  break; | 
|  | +      m = *pm; | 
|  | +      if (m != NULL) | 
|  | +	{ | 
|  | +	  /* For a normal mips executable the permissions for the PT_DYNAMIC | 
|  | +	     segment are read, write and execute. We do that here since | 
|  | +	     the code in elf.c sets only the read permission. This matters | 
|  | +	     sometimes for the dynamic linker.  */ | 
|  | +	  if (bfd_get_section_by_name (abfd, ".dynamic") != NULL) | 
|  | +	    { | 
|  | +	      m->p_flags = PF_R | PF_W | PF_X; | 
|  | +	      m->p_flags_valid = 1; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Allocate a spare program header in dynamic objects so that tools | 
|  | +     like the prelinker can add an extra PT_LOAD entry. | 
|  | + | 
|  | +     If the prelinker needs to make room for a new PT_LOAD entry, its | 
|  | +     standard procedure is to move the first (read-only) sections into | 
|  | +     the new (writable) segment.  However, the MIPS ABI requires | 
|  | +     .dynamic to be in a read-only segment, and the section will often | 
|  | +     start within sizeof (ElfNN_Phdr) bytes of the last program header. | 
|  | + | 
|  | +     Although the prelinker could in principle move .dynamic to a | 
|  | +     writable segment, it seems better to allocate a spare program | 
|  | +     header instead, and avoid the need to move any sections. | 
|  | +     There is a long tradition of allocating spare dynamic tags, | 
|  | +     so allocating a spare program header seems like a natural | 
|  | +     extension. | 
|  | + | 
|  | +     If INFO is NULL, we may be copying an already prelinked binary | 
|  | +     with objcopy or strip, so do not add this header.  */ | 
|  | +  if (info != NULL | 
|  | +      && bfd_get_section_by_name (abfd, ".dynamic")) | 
|  | +    { | 
|  | +      for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next) | 
|  | +	if ((*pm)->p_type == PT_NULL) | 
|  | +	  break; | 
|  | +      if (*pm == NULL) | 
|  | +	{ | 
|  | +	  m = bfd_zalloc (abfd, sizeof (*m)); | 
|  | +	  if (m == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  m->p_type = PT_NULL; | 
|  | +	  *pm = m; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Return the section that should be marked against GC for a given | 
|  | +   relocation.  */ | 
|  | + | 
|  | +asection * | 
|  | +_bfd_riscv_elf_gc_mark_hook (asection *sec, | 
|  | +			    struct bfd_link_info *info, | 
|  | +			    Elf_Internal_Rela *rel, | 
|  | +			    struct elf_link_hash_entry *h, | 
|  | +			    Elf_Internal_Sym *sym) | 
|  | +{ | 
|  | +  /* ??? Do mips16 stub sections need to be handled special?  */ | 
|  | + | 
|  | +  if (h != NULL) | 
|  | +    switch (ELF_R_TYPE (sec->owner, rel->r_info)) | 
|  | +      { | 
|  | +      case R_RISCV_GNU_VTINHERIT: | 
|  | +      case R_RISCV_GNU_VTENTRY: | 
|  | +	return NULL; | 
|  | +      } | 
|  | + | 
|  | +  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); | 
|  | +} | 
|  | + | 
|  | +/* Update the got entry reference counts for the section being removed.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, | 
|  | +			     struct bfd_link_info *info ATTRIBUTE_UNUSED, | 
|  | +			     asection *sec ATTRIBUTE_UNUSED, | 
|  | +			     const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Copy data from a MIPS ELF indirect symbol to its direct symbol, | 
|  | +   hiding the old indirect symbol.  Process additional relocation | 
|  | +   information.  Also called for weakdefs, in which case we just let | 
|  | +   _bfd_elf_link_hash_copy_indirect copy the flags for us.  */ | 
|  | + | 
|  | +void | 
|  | +_bfd_riscv_elf_copy_indirect_symbol (struct bfd_link_info *info, | 
|  | +				    struct elf_link_hash_entry *dir, | 
|  | +				    struct elf_link_hash_entry *ind) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_entry *dirmips, *indmips; | 
|  | + | 
|  | +  _bfd_elf_link_hash_copy_indirect (info, dir, ind); | 
|  | + | 
|  | +  dirmips = (struct mips_elf_link_hash_entry *) dir; | 
|  | +  indmips = (struct mips_elf_link_hash_entry *) ind; | 
|  | +  /* Any absolute non-dynamic relocations against an indirect or weak | 
|  | +     definition will be against the target symbol.  */ | 
|  | +  if (indmips->has_static_relocs) | 
|  | +    dirmips->has_static_relocs = TRUE; | 
|  | + | 
|  | +  if (ind->root.type != bfd_link_hash_indirect) | 
|  | +    return; | 
|  | + | 
|  | +  dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs; | 
|  | +  if (indmips->readonly_reloc) | 
|  | +    dirmips->readonly_reloc = TRUE; | 
|  | +  if (indmips->global_got_area < dirmips->global_got_area) | 
|  | +    dirmips->global_got_area = indmips->global_got_area; | 
|  | +  if (indmips->global_got_area < GGA_NONE) | 
|  | +    indmips->global_got_area = GGA_NONE; | 
|  | + | 
|  | +  if (dirmips->tls_type == 0) | 
|  | +    dirmips->tls_type = indmips->tls_type; | 
|  | +} | 
|  | + | 
|  | +#define PDR_SIZE 32 | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, | 
|  | +			    struct bfd_link_info *info) | 
|  | +{ | 
|  | +  asection *o; | 
|  | +  bfd_boolean ret = FALSE; | 
|  | +  unsigned char *tdata; | 
|  | +  size_t i, skip; | 
|  | + | 
|  | +  o = bfd_get_section_by_name (abfd, ".pdr"); | 
|  | +  if (! o) | 
|  | +    return FALSE; | 
|  | +  if (o->size == 0) | 
|  | +    return FALSE; | 
|  | +  if (o->size % PDR_SIZE != 0) | 
|  | +    return FALSE; | 
|  | +  if (o->output_section != NULL | 
|  | +      && bfd_is_abs_section (o->output_section)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  tdata = bfd_zmalloc (o->size / PDR_SIZE); | 
|  | +  if (! tdata) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, | 
|  | +					    info->keep_memory); | 
|  | +  if (!cookie->rels) | 
|  | +    { | 
|  | +      free (tdata); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  cookie->rel = cookie->rels; | 
|  | +  cookie->relend = cookie->rels + o->reloc_count; | 
|  | + | 
|  | +  for (i = 0, skip = 0; i < o->size / PDR_SIZE; i ++) | 
|  | +    { | 
|  | +      if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie)) | 
|  | +	{ | 
|  | +	  tdata[i] = 1; | 
|  | +	  skip ++; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if (skip != 0) | 
|  | +    { | 
|  | +      mips_elf_section_data (o)->u.tdata = tdata; | 
|  | +      o->size -= skip * PDR_SIZE; | 
|  | +      ret = TRUE; | 
|  | +    } | 
|  | +  else | 
|  | +    free (tdata); | 
|  | + | 
|  | +  if (! info->keep_memory) | 
|  | +    free (cookie->rels); | 
|  | + | 
|  | +  return ret; | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_ignore_discarded_relocs (asection *sec) | 
|  | +{ | 
|  | +  if (strcmp (sec->name, ".pdr") == 0) | 
|  | +    return TRUE; | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_write_section (bfd *output_bfd, | 
|  | +			     struct bfd_link_info *link_info ATTRIBUTE_UNUSED, | 
|  | +                             asection *sec, bfd_byte *contents) | 
|  | +{ | 
|  | +  bfd_byte *to, *from, *end; | 
|  | +  int i; | 
|  | + | 
|  | +  if (strcmp (sec->name, ".pdr") != 0) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  if (mips_elf_section_data (sec)->u.tdata == NULL) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  to = contents; | 
|  | +  end = contents + sec->size; | 
|  | +  for (from = contents, i = 0; | 
|  | +       from < end; | 
|  | +       from += PDR_SIZE, i++) | 
|  | +    { | 
|  | +      if ((mips_elf_section_data (sec)->u.tdata)[i] == 1) | 
|  | +	continue; | 
|  | +      if (to != from) | 
|  | +	memcpy (to, from, PDR_SIZE); | 
|  | +      to += PDR_SIZE; | 
|  | +    } | 
|  | +  bfd_set_section_contents (output_bfd, sec->output_section, contents, | 
|  | +			    sec->output_offset, sec->size); | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* MIPS ELF uses a special find_nearest_line routine in order the | 
|  | +   handle the ECOFF debugging information.  */ | 
|  | + | 
|  | +struct mips_elf_find_line | 
|  | +{ | 
|  | +  struct ecoff_debug_info d; | 
|  | +  struct ecoff_find_line i; | 
|  | +}; | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_find_nearest_line (bfd *abfd, asection *section, | 
|  | +				 asymbol **symbols, bfd_vma offset, | 
|  | +				 const char **filename_ptr, | 
|  | +				 const char **functionname_ptr, | 
|  | +				 unsigned int *line_ptr) | 
|  | +{ | 
|  | +  asection *msec; | 
|  | + | 
|  | +  if (_bfd_dwarf1_find_nearest_line (abfd, section, symbols, offset, | 
|  | +				     filename_ptr, functionname_ptr, | 
|  | +				     line_ptr)) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, | 
|  | +				     filename_ptr, functionname_ptr, | 
|  | +				     line_ptr, ABI_64_P (abfd) ? 8 : 0, | 
|  | +				     &elf_tdata (abfd)->dwarf2_find_line_info)) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  msec = bfd_get_section_by_name (abfd, ".mdebug"); | 
|  | +  if (msec != NULL) | 
|  | +    { | 
|  | +      flagword origflags; | 
|  | +      struct mips_elf_find_line *fi; | 
|  | +      const struct ecoff_debug_swap * const swap = | 
|  | +	get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; | 
|  | + | 
|  | +      /* If we are called during a link, mips_elf_final_link may have | 
|  | +	 cleared the SEC_HAS_CONTENTS field.  We force it back on here | 
|  | +	 if appropriate (which it normally will be).  */ | 
|  | +      origflags = msec->flags; | 
|  | +      if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS) | 
|  | +	msec->flags |= SEC_HAS_CONTENTS; | 
|  | + | 
|  | +      fi = elf_tdata (abfd)->find_line_info; | 
|  | +      if (fi == NULL) | 
|  | +	{ | 
|  | +	  bfd_size_type external_fdr_size; | 
|  | +	  char *fraw_src; | 
|  | +	  char *fraw_end; | 
|  | +	  struct fdr *fdr_ptr; | 
|  | +	  bfd_size_type amt = sizeof (struct mips_elf_find_line); | 
|  | + | 
|  | +	  fi = bfd_zalloc (abfd, amt); | 
|  | +	  if (fi == NULL) | 
|  | +	    { | 
|  | +	      msec->flags = origflags; | 
|  | +	      return FALSE; | 
|  | +	    } | 
|  | + | 
|  | +	  if (! _bfd_riscv_elf_read_ecoff_info (abfd, msec, &fi->d)) | 
|  | +	    { | 
|  | +	      msec->flags = origflags; | 
|  | +	      return FALSE; | 
|  | +	    } | 
|  | + | 
|  | +	  /* Swap in the FDR information.  */ | 
|  | +	  amt = fi->d.symbolic_header.ifdMax * sizeof (struct fdr); | 
|  | +	  fi->d.fdr = bfd_alloc (abfd, amt); | 
|  | +	  if (fi->d.fdr == NULL) | 
|  | +	    { | 
|  | +	      msec->flags = origflags; | 
|  | +	      return FALSE; | 
|  | +	    } | 
|  | +	  external_fdr_size = swap->external_fdr_size; | 
|  | +	  fdr_ptr = fi->d.fdr; | 
|  | +	  fraw_src = (char *) fi->d.external_fdr; | 
|  | +	  fraw_end = (fraw_src | 
|  | +		      + fi->d.symbolic_header.ifdMax * external_fdr_size); | 
|  | +	  for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) | 
|  | +	    (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr); | 
|  | + | 
|  | +	  elf_tdata (abfd)->find_line_info = fi; | 
|  | + | 
|  | +	  /* Note that we don't bother to ever free this information. | 
|  | +             find_nearest_line is either called all the time, as in | 
|  | +             objdump -l, so the information should be saved, or it is | 
|  | +             rarely called, as in ld error messages, so the memory | 
|  | +             wasted is unimportant.  Still, it would probably be a | 
|  | +             good idea for free_cached_info to throw it away.  */ | 
|  | +	} | 
|  | + | 
|  | +      if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap, | 
|  | +				  &fi->i, filename_ptr, functionname_ptr, | 
|  | +				  line_ptr)) | 
|  | +	{ | 
|  | +	  msec->flags = origflags; | 
|  | +	  return TRUE; | 
|  | +	} | 
|  | + | 
|  | +      msec->flags = origflags; | 
|  | +    } | 
|  | + | 
|  | +  /* Fall back on the generic ELF find_nearest_line routine.  */ | 
|  | + | 
|  | +  return _bfd_elf_find_nearest_line (abfd, section, symbols, offset, | 
|  | +				     filename_ptr, functionname_ptr, | 
|  | +				     line_ptr); | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_find_inliner_info (bfd *abfd, | 
|  | +				 const char **filename_ptr, | 
|  | +				 const char **functionname_ptr, | 
|  | +				 unsigned int *line_ptr) | 
|  | +{ | 
|  | +  bfd_boolean found; | 
|  | +  found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, | 
|  | +					 functionname_ptr, line_ptr, | 
|  | +					 & elf_tdata (abfd)->dwarf2_find_line_info); | 
|  | +  return found; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* When are writing out the .options or .MIPS.options section, | 
|  | +   remember the bytes we are writing out, so that we can install the | 
|  | +   GP value in the section_processing routine.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_set_section_contents (bfd *abfd, sec_ptr section, | 
|  | +				    const void *location, | 
|  | +				    file_ptr offset, bfd_size_type count) | 
|  | +{ | 
|  | +  if (MIPS_ELF_OPTIONS_SECTION_NAME_P (section->name)) | 
|  | +    { | 
|  | +      bfd_byte *c; | 
|  | + | 
|  | +      if (elf_section_data (section) == NULL) | 
|  | +	{ | 
|  | +	  bfd_size_type amt = sizeof (struct bfd_elf_section_data); | 
|  | +	  section->used_by_bfd = bfd_zalloc (abfd, amt); | 
|  | +	  if (elf_section_data (section) == NULL) | 
|  | +	    return FALSE; | 
|  | +	} | 
|  | +      c = mips_elf_section_data (section)->u.tdata; | 
|  | +      if (c == NULL) | 
|  | +	{ | 
|  | +	  c = bfd_zalloc (abfd, section->size); | 
|  | +	  if (c == NULL) | 
|  | +	    return FALSE; | 
|  | +	  mips_elf_section_data (section)->u.tdata = c; | 
|  | +	} | 
|  | + | 
|  | +      memcpy (c + offset, location, count); | 
|  | +    } | 
|  | + | 
|  | +  return _bfd_elf_set_section_contents (abfd, section, location, offset, | 
|  | +					count); | 
|  | +} | 
|  | + | 
|  | +/* This is almost identical to bfd_generic_get_... except that some | 
|  | +   MIPS relocations need to be handled specially.  Sigh.  */ | 
|  | + | 
|  | +bfd_byte * | 
|  | +_bfd_elf_riscv_get_relocated_section_contents | 
|  | +  (bfd *abfd, | 
|  | +   struct bfd_link_info *link_info, | 
|  | +   struct bfd_link_order *link_order, | 
|  | +   bfd_byte *data, | 
|  | +   bfd_boolean relocatable, | 
|  | +   asymbol **symbols) | 
|  | +{ | 
|  | +  /* Get enough memory to hold the stuff */ | 
|  | +  bfd *input_bfd = link_order->u.indirect.section->owner; | 
|  | +  asection *input_section = link_order->u.indirect.section; | 
|  | +  bfd_size_type sz; | 
|  | + | 
|  | +  long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); | 
|  | +  arelent **reloc_vector = NULL; | 
|  | +  long reloc_count; | 
|  | + | 
|  | +  if (reloc_size < 0) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  reloc_vector = bfd_malloc (reloc_size); | 
|  | +  if (reloc_vector == NULL && reloc_size != 0) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  /* read in the section */ | 
|  | +  sz = input_section->rawsize ? input_section->rawsize : input_section->size; | 
|  | +  if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz)) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  reloc_count = bfd_canonicalize_reloc (input_bfd, | 
|  | +					input_section, | 
|  | +					reloc_vector, | 
|  | +					symbols); | 
|  | +  if (reloc_count < 0) | 
|  | +    goto error_return; | 
|  | + | 
|  | +  if (reloc_count > 0) | 
|  | +    { | 
|  | +      arelent **parent; | 
|  | + | 
|  | +      { | 
|  | +	struct bfd_hash_entry *h; | 
|  | +	struct bfd_link_hash_entry *lh; | 
|  | +	/* Skip all this stuff if we aren't mixing formats.  */ | 
|  | +	if (abfd && input_bfd | 
|  | +	    && abfd->xvec == input_bfd->xvec) | 
|  | +	  lh = 0; | 
|  | +	else | 
|  | +	  { | 
|  | +	    h = bfd_hash_lookup (&link_info->hash->table, "_gp", FALSE, FALSE); | 
|  | +	    lh = (struct bfd_link_hash_entry *) h; | 
|  | +	  } | 
|  | +      lookup: | 
|  | +	if (lh) | 
|  | +	  { | 
|  | +	    switch (lh->type) | 
|  | +	      { | 
|  | +	      case bfd_link_hash_undefined: | 
|  | +	      case bfd_link_hash_undefweak: | 
|  | +	      case bfd_link_hash_common: | 
|  | +	      case bfd_link_hash_defined: | 
|  | +	      case bfd_link_hash_defweak: | 
|  | +		break; | 
|  | +	      case bfd_link_hash_indirect: | 
|  | +	      case bfd_link_hash_warning: | 
|  | +		lh = lh->u.i.link; | 
|  | +		/* @@FIXME  ignoring warning for now */ | 
|  | +		goto lookup; | 
|  | +	      case bfd_link_hash_new: | 
|  | +	      default: | 
|  | +		abort (); | 
|  | +	      } | 
|  | +	  } | 
|  | +      } | 
|  | +      /* end mips */ | 
|  | +      for (parent = reloc_vector; *parent != NULL; parent++) | 
|  | +	{ | 
|  | +	  char *error_message = NULL; | 
|  | +	  bfd_reloc_status_type r; | 
|  | + | 
|  | +	  r = bfd_perform_relocation (input_bfd, *parent, data, | 
|  | +				      input_section, | 
|  | +				      relocatable ? abfd : NULL, | 
|  | +				      &error_message); | 
|  | + | 
|  | +	  if (relocatable) | 
|  | +	    { | 
|  | +	      asection *os = input_section->output_section; | 
|  | + | 
|  | +	      /* A partial link, so keep the relocs */ | 
|  | +	      os->orelocation[os->reloc_count] = *parent; | 
|  | +	      os->reloc_count++; | 
|  | +	    } | 
|  | + | 
|  | +	  if (r != bfd_reloc_ok) | 
|  | +	    { | 
|  | +	      switch (r) | 
|  | +		{ | 
|  | +		case bfd_reloc_undefined: | 
|  | +		  if (!((*link_info->callbacks->undefined_symbol) | 
|  | +			(link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), | 
|  | +			 input_bfd, input_section, (*parent)->address, TRUE))) | 
|  | +		    goto error_return; | 
|  | +		  break; | 
|  | +		case bfd_reloc_dangerous: | 
|  | +		  BFD_ASSERT (error_message != NULL); | 
|  | +		  if (!((*link_info->callbacks->reloc_dangerous) | 
|  | +			(link_info, error_message, input_bfd, input_section, | 
|  | +			 (*parent)->address))) | 
|  | +		    goto error_return; | 
|  | +		  break; | 
|  | +		case bfd_reloc_overflow: | 
|  | +		  if (!((*link_info->callbacks->reloc_overflow) | 
|  | +			(link_info, NULL, | 
|  | +			 bfd_asymbol_name (*(*parent)->sym_ptr_ptr), | 
|  | +			 (*parent)->howto->name, (*parent)->addend, | 
|  | +			 input_bfd, input_section, (*parent)->address))) | 
|  | +		    goto error_return; | 
|  | +		  break; | 
|  | +		case bfd_reloc_outofrange: | 
|  | +		default: | 
|  | +		  abort (); | 
|  | +		  break; | 
|  | +		} | 
|  | + | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | +  if (reloc_vector != NULL) | 
|  | +    free (reloc_vector); | 
|  | +  return data; | 
|  | + | 
|  | +error_return: | 
|  | +  if (reloc_vector != NULL) | 
|  | +    free (reloc_vector); | 
|  | +  return NULL; | 
|  | +} | 
|  | + | 
|  | +/* Create a MIPS ELF linker hash table.  */ | 
|  | + | 
|  | +struct bfd_link_hash_table * | 
|  | +_bfd_riscv_elf_link_hash_table_create (bfd *abfd) | 
|  | +{ | 
|  | +  struct mips_elf_link_hash_table *ret; | 
|  | +  bfd_size_type amt = sizeof (struct mips_elf_link_hash_table); | 
|  | + | 
|  | +  ret = bfd_malloc (amt); | 
|  | +  if (ret == NULL) | 
|  | +    return NULL; | 
|  | + | 
|  | +  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, | 
|  | +				      mips_elf_link_hash_newfunc, | 
|  | +				      sizeof (struct mips_elf_link_hash_entry), | 
|  | +				      MIPS_ELF_DATA)) | 
|  | +    { | 
|  | +      free (ret); | 
|  | +      return NULL; | 
|  | +    } | 
|  | + | 
|  | +#if 0 | 
|  | +  /* We no longer use this.  */ | 
|  | +  for (i = 0; i < SIZEOF_MIPS_DYNSYM_SECNAMES; i++) | 
|  | +    ret->dynsym_sec_strindex[i] = (bfd_size_type) -1; | 
|  | +#endif | 
|  | +  ret->srelbss = NULL; | 
|  | +  ret->sdynbss = NULL; | 
|  | +  ret->srelplt = NULL; | 
|  | +  ret->srelplt2 = NULL; | 
|  | +  ret->sgotplt = NULL; | 
|  | +  ret->splt = NULL; | 
|  | +  ret->sgot = NULL; | 
|  | +  ret->got_info = NULL; | 
|  | +  ret->plt_header_size = 0; | 
|  | +  ret->plt_entry_size = 0; | 
|  | + | 
|  | +  return &ret->root.root; | 
|  | +} | 
|  | + | 
|  | +/* We need to use a special link routine to handle the .reginfo and | 
|  | +   the .mdebug sections.  We need to merge all instances of these | 
|  | +   sections together, not write them all out sequentially.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_final_link (bfd *abfd, struct bfd_link_info *info) | 
|  | +{ | 
|  | +  asection *o; | 
|  | +  struct bfd_link_order *p; | 
|  | +  asection *reginfo_sec, *mdebug_sec; | 
|  | +  Elf32_RegInfo reginfo; | 
|  | +  struct ecoff_debug_info debug; | 
|  | +  const struct elf_backend_data *bed = get_elf_backend_data (abfd); | 
|  | +  const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap; | 
|  | +  HDRR *symhdr = &debug.symbolic_header; | 
|  | +  void *mdebug_handle = NULL; | 
|  | +  asection *s; | 
|  | +  EXTR esym; | 
|  | +  unsigned int i; | 
|  | +  struct mips_elf_link_hash_table *htab; | 
|  | + | 
|  | +  static const char * const secname[] = | 
|  | +  { | 
|  | +    ".text", ".init", ".fini", ".data", | 
|  | +    ".rodata", ".bss" | 
|  | +  }; | 
|  | +  static const int sc[] = | 
|  | +  { | 
|  | +    scText, scInit, scFini, scData, | 
|  | +    scRData, scBss | 
|  | +  }; | 
|  | + | 
|  | +  /* Sort the dynamic symbols so that those with GOT entries come after | 
|  | +     those without.  */ | 
|  | +  htab = mips_elf_hash_table (info); | 
|  | +  BFD_ASSERT (htab != NULL); | 
|  | + | 
|  | +  if (!mips_elf_sort_hash_table (abfd, info)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Get a value for the GP register.  */ | 
|  | +  if (elf_gp (abfd) == 0) | 
|  | +    { | 
|  | +      struct bfd_link_hash_entry *h; | 
|  | + | 
|  | +      h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); | 
|  | +      if (h != NULL && h->type == bfd_link_hash_defined) | 
|  | +	elf_gp (abfd) = (h->u.def.value | 
|  | +			 + h->u.def.section->output_section->vma | 
|  | +			 + h->u.def.section->output_offset); | 
|  | +      else if (info->relocatable) | 
|  | +	{ | 
|  | +	  bfd_vma lo = MINUS_ONE; | 
|  | + | 
|  | +	  /* Find the GP-relative section with the lowest offset.  */ | 
|  | +	  for (o = abfd->sections; o != NULL; o = o->next) | 
|  | +	    if (o->vma < lo | 
|  | +		&& (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL)) | 
|  | +	      lo = o->vma; | 
|  | + | 
|  | +	  /* And calculate GP relative to that.  */ | 
|  | +	  elf_gp (abfd) = lo; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  /* If the relocate_section function needs to do a reloc | 
|  | +	     involving the GP value, it should make a reloc_dangerous | 
|  | +	     callback to warn that GP is not defined.  */ | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Go through the sections and collect the .reginfo and .mdebug | 
|  | +     information.  */ | 
|  | +  reginfo_sec = NULL; | 
|  | +  mdebug_sec = NULL; | 
|  | +  for (o = abfd->sections; o != NULL; o = o->next) | 
|  | +    { | 
|  | +      if (strcmp (o->name, ".reginfo") == 0) | 
|  | +	{ | 
|  | +	  memset (®info, 0, sizeof reginfo); | 
|  | + | 
|  | +	  /* We have found the .reginfo section in the output file. | 
|  | +	     Look through all the link_orders comprising it and merge | 
|  | +	     the information together.  */ | 
|  | +	  for (p = o->map_head.link_order; p != NULL; p = p->next) | 
|  | +	    { | 
|  | +	      asection *input_section; | 
|  | +	      bfd *input_bfd; | 
|  | +	      Elf32_External_RegInfo ext; | 
|  | +	      Elf32_RegInfo sub; | 
|  | + | 
|  | +	      if (p->type != bfd_indirect_link_order) | 
|  | +		{ | 
|  | +		  if (p->type == bfd_data_link_order) | 
|  | +		    continue; | 
|  | +		  abort (); | 
|  | +		} | 
|  | + | 
|  | +	      input_section = p->u.indirect.section; | 
|  | +	      input_bfd = input_section->owner; | 
|  | + | 
|  | +	      if (! bfd_get_section_contents (input_bfd, input_section, | 
|  | +					      &ext, 0, sizeof ext)) | 
|  | +		return FALSE; | 
|  | + | 
|  | +	      bfd_riscv_elf32_swap_reginfo_in (input_bfd, &ext, &sub); | 
|  | + | 
|  | +	      reginfo.ri_gprmask |= sub.ri_gprmask; | 
|  | +	      reginfo.ri_cprmask[0] |= sub.ri_cprmask[0]; | 
|  | +	      reginfo.ri_cprmask[1] |= sub.ri_cprmask[1]; | 
|  | +	      reginfo.ri_cprmask[2] |= sub.ri_cprmask[2]; | 
|  | +	      reginfo.ri_cprmask[3] |= sub.ri_cprmask[3]; | 
|  | + | 
|  | +	      /* ri_gp_value is set by the function | 
|  | +		 mips_elf32_section_processing when the section is | 
|  | +		 finally written out.  */ | 
|  | + | 
|  | +	      /* Hack: reset the SEC_HAS_CONTENTS flag so that | 
|  | +		 elf_link_input_bfd ignores this section.  */ | 
|  | +	      input_section->flags &= ~SEC_HAS_CONTENTS; | 
|  | +	    } | 
|  | + | 
|  | +	  /* Size has been set in _bfd_riscv_elf_always_size_sections.  */ | 
|  | +	  BFD_ASSERT(o->size == sizeof (Elf32_External_RegInfo)); | 
|  | + | 
|  | +	  /* Skip this section later on (I don't think this currently | 
|  | +	     matters, but someday it might).  */ | 
|  | +	  o->map_head.link_order = NULL; | 
|  | + | 
|  | +	  reginfo_sec = o; | 
|  | +	} | 
|  | + | 
|  | +      if (strcmp (o->name, ".mdebug") == 0) | 
|  | +	{ | 
|  | +	  struct extsym_info einfo; | 
|  | +	  bfd_vma last; | 
|  | + | 
|  | +	  /* We have found the .mdebug section in the output file. | 
|  | +	     Look through all the link_orders comprising it and merge | 
|  | +	     the information together.  */ | 
|  | +	  symhdr->magic = swap->sym_magic; | 
|  | +	  /* FIXME: What should the version stamp be?  */ | 
|  | +	  symhdr->vstamp = 0; | 
|  | +	  symhdr->ilineMax = 0; | 
|  | +	  symhdr->cbLine = 0; | 
|  | +	  symhdr->idnMax = 0; | 
|  | +	  symhdr->ipdMax = 0; | 
|  | +	  symhdr->isymMax = 0; | 
|  | +	  symhdr->ioptMax = 0; | 
|  | +	  symhdr->iauxMax = 0; | 
|  | +	  symhdr->issMax = 0; | 
|  | +	  symhdr->issExtMax = 0; | 
|  | +	  symhdr->ifdMax = 0; | 
|  | +	  symhdr->crfd = 0; | 
|  | +	  symhdr->iextMax = 0; | 
|  | + | 
|  | +	  /* We accumulate the debugging information itself in the | 
|  | +	     debug_info structure.  */ | 
|  | +	  debug.line = NULL; | 
|  | +	  debug.external_dnr = NULL; | 
|  | +	  debug.external_pdr = NULL; | 
|  | +	  debug.external_sym = NULL; | 
|  | +	  debug.external_opt = NULL; | 
|  | +	  debug.external_aux = NULL; | 
|  | +	  debug.ss = NULL; | 
|  | +	  debug.ssext = debug.ssext_end = NULL; | 
|  | +	  debug.external_fdr = NULL; | 
|  | +	  debug.external_rfd = NULL; | 
|  | +	  debug.external_ext = debug.external_ext_end = NULL; | 
|  | + | 
|  | +	  mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info); | 
|  | +	  if (mdebug_handle == NULL) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  esym.jmptbl = 0; | 
|  | +	  esym.cobol_main = 0; | 
|  | +	  esym.weakext = 0; | 
|  | +	  esym.reserved = 0; | 
|  | +	  esym.ifd = ifdNil; | 
|  | +	  esym.asym.iss = issNil; | 
|  | +	  esym.asym.st = stLocal; | 
|  | +	  esym.asym.reserved = 0; | 
|  | +	  esym.asym.index = indexNil; | 
|  | +	  last = 0; | 
|  | +	  for (i = 0; i < sizeof (secname) / sizeof (secname[0]); i++) | 
|  | +	    { | 
|  | +	      esym.asym.sc = sc[i]; | 
|  | +	      s = bfd_get_section_by_name (abfd, secname[i]); | 
|  | +	      if (s != NULL) | 
|  | +		{ | 
|  | +		  esym.asym.value = s->vma; | 
|  | +		  last = s->vma + s->size; | 
|  | +		} | 
|  | +	      else | 
|  | +		esym.asym.value = last; | 
|  | +	      if (!bfd_ecoff_debug_one_external (abfd, &debug, swap, | 
|  | +						 secname[i], &esym)) | 
|  | +		return FALSE; | 
|  | +	    } | 
|  | + | 
|  | +	  for (p = o->map_head.link_order; p != NULL; p = p->next) | 
|  | +	    { | 
|  | +	      asection *input_section; | 
|  | +	      bfd *input_bfd; | 
|  | +	      const struct ecoff_debug_swap *input_swap; | 
|  | +	      struct ecoff_debug_info input_debug; | 
|  | +	      char *eraw_src; | 
|  | +	      char *eraw_end; | 
|  | + | 
|  | +	      if (p->type != bfd_indirect_link_order) | 
|  | +		{ | 
|  | +		  if (p->type == bfd_data_link_order) | 
|  | +		    continue; | 
|  | +		  abort (); | 
|  | +		} | 
|  | + | 
|  | +	      input_section = p->u.indirect.section; | 
|  | +	      input_bfd = input_section->owner; | 
|  | + | 
|  | +	      if (!is_mips_elf (input_bfd)) | 
|  | +		{ | 
|  | +		  /* I don't know what a non MIPS ELF bfd would be | 
|  | +		     doing with a .mdebug section, but I don't really | 
|  | +		     want to deal with it.  */ | 
|  | +		  continue; | 
|  | +		} | 
|  | + | 
|  | +	      input_swap = (get_elf_backend_data (input_bfd) | 
|  | +			    ->elf_backend_ecoff_debug_swap); | 
|  | + | 
|  | +	      BFD_ASSERT (p->size == input_section->size); | 
|  | + | 
|  | +	      /* The ECOFF linking code expects that we have already | 
|  | +		 read in the debugging information and set up an | 
|  | +		 ecoff_debug_info structure, so we do that now.  */ | 
|  | +	      if (! _bfd_riscv_elf_read_ecoff_info (input_bfd, input_section, | 
|  | +						   &input_debug)) | 
|  | +		return FALSE; | 
|  | + | 
|  | +	      if (! (bfd_ecoff_debug_accumulate | 
|  | +		     (mdebug_handle, abfd, &debug, swap, input_bfd, | 
|  | +		      &input_debug, input_swap, info))) | 
|  | +		return FALSE; | 
|  | + | 
|  | +	      /* Loop through the external symbols.  For each one with | 
|  | +		 interesting information, try to find the symbol in | 
|  | +		 the linker global hash table and save the information | 
|  | +		 for the output external symbols.  */ | 
|  | +	      eraw_src = input_debug.external_ext; | 
|  | +	      eraw_end = (eraw_src | 
|  | +			  + (input_debug.symbolic_header.iextMax | 
|  | +			     * input_swap->external_ext_size)); | 
|  | +	      for (; | 
|  | +		   eraw_src < eraw_end; | 
|  | +		   eraw_src += input_swap->external_ext_size) | 
|  | +		{ | 
|  | +		  EXTR ext; | 
|  | +		  const char *name; | 
|  | +		  struct mips_elf_link_hash_entry *h; | 
|  | + | 
|  | +		  (*input_swap->swap_ext_in) (input_bfd, eraw_src, &ext); | 
|  | +		  if (ext.asym.sc == scNil | 
|  | +		      || ext.asym.sc == scUndefined | 
|  | +		      || ext.asym.sc == scSUndefined) | 
|  | +		    continue; | 
|  | + | 
|  | +		  name = input_debug.ssext + ext.asym.iss; | 
|  | +		  h = mips_elf_link_hash_lookup (mips_elf_hash_table (info), | 
|  | +						 name, FALSE, FALSE, TRUE); | 
|  | +		  if (h == NULL || h->esym.ifd != -2) | 
|  | +		    continue; | 
|  | + | 
|  | +		  if (ext.ifd != -1) | 
|  | +		    { | 
|  | +		      BFD_ASSERT (ext.ifd | 
|  | +				  < input_debug.symbolic_header.ifdMax); | 
|  | +		      ext.ifd = input_debug.ifdmap[ext.ifd]; | 
|  | +		    } | 
|  | + | 
|  | +		  h->esym = ext; | 
|  | +		} | 
|  | + | 
|  | +	      /* Free up the information we just read.  */ | 
|  | +	      free (input_debug.line); | 
|  | +	      free (input_debug.external_dnr); | 
|  | +	      free (input_debug.external_pdr); | 
|  | +	      free (input_debug.external_sym); | 
|  | +	      free (input_debug.external_opt); | 
|  | +	      free (input_debug.external_aux); | 
|  | +	      free (input_debug.ss); | 
|  | +	      free (input_debug.ssext); | 
|  | +	      free (input_debug.external_fdr); | 
|  | +	      free (input_debug.external_rfd); | 
|  | +	      free (input_debug.external_ext); | 
|  | + | 
|  | +	      /* Hack: reset the SEC_HAS_CONTENTS flag so that | 
|  | +		 elf_link_input_bfd ignores this section.  */ | 
|  | +	      input_section->flags &= ~SEC_HAS_CONTENTS; | 
|  | +	    } | 
|  | + | 
|  | +	  /* Build the external symbol information.  */ | 
|  | +	  einfo.abfd = abfd; | 
|  | +	  einfo.info = info; | 
|  | +	  einfo.debug = &debug; | 
|  | +	  einfo.swap = swap; | 
|  | +	  einfo.failed = FALSE; | 
|  | +	  mips_elf_link_hash_traverse (mips_elf_hash_table (info), | 
|  | +				       mips_elf_output_extsym, &einfo); | 
|  | +	  if (einfo.failed) | 
|  | +	    return FALSE; | 
|  | + | 
|  | +	  /* Set the size of the .mdebug section.  */ | 
|  | +	  o->size = bfd_ecoff_debug_size (abfd, &debug, swap); | 
|  | + | 
|  | +	  /* Skip this section later on (I don't think this currently | 
|  | +	     matters, but someday it might).  */ | 
|  | +	  o->map_head.link_order = NULL; | 
|  | + | 
|  | +	  mdebug_sec = o; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Invoke the regular ELF backend linker to do all the work.  */ | 
|  | +  if (!bfd_elf_final_link (abfd, info)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  /* Now write out the computed sections.  */ | 
|  | + | 
|  | +  if (reginfo_sec != NULL) | 
|  | +    { | 
|  | +      Elf32_External_RegInfo ext; | 
|  | + | 
|  | +      bfd_riscv_elf32_swap_reginfo_out (abfd, ®info, &ext); | 
|  | +      if (! bfd_set_section_contents (abfd, reginfo_sec, &ext, 0, sizeof ext)) | 
|  | +	return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  if (mdebug_sec != NULL) | 
|  | +    { | 
|  | +      BFD_ASSERT (abfd->output_has_begun); | 
|  | +      if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug, | 
|  | +					       swap, info, | 
|  | +					       mdebug_sec->filepos)) | 
|  | +	return FALSE; | 
|  | + | 
|  | +      bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Return true if bfd machine EXTENSION is an extension of machine BASE.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_mach_extends_p (unsigned long base, unsigned long extension) | 
|  | +{ | 
|  | +  return extension == base; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* Return true if the given ELF header flags describe a 32-bit binary.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +mips_32bit_flags_p (flagword flags) | 
|  | +{ | 
|  | +  return ((flags & EF_MIPS_32BITMODE) != 0 | 
|  | +	  || (flags & EF_MIPS_ABI) == E_RISCV_ABI_32 | 
|  | +	  || (flags & EF_MIPS_ARCH) == E_RISCV_ARCH_RV32); | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* Merge object attributes from IBFD into OBFD.  Raise an error if | 
|  | +   there are conflicting attributes.  */ | 
|  | +static bfd_boolean | 
|  | +mips_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) | 
|  | +{ | 
|  | +  if (!elf_known_obj_attributes_proc (obfd)[0].i) | 
|  | +    { | 
|  | +      /* This is the first object.  Copy the attributes.  */ | 
|  | +      _bfd_elf_copy_obj_attributes (ibfd, obfd); | 
|  | + | 
|  | +      /* Use the Tag_null value to indicate the attributes have been | 
|  | +	 initialized.  */ | 
|  | +      elf_known_obj_attributes_proc (obfd)[0].i = 1; | 
|  | + | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* Merge Tag_compatibility attributes and any common GNU ones.  */ | 
|  | +  _bfd_elf_merge_object_attributes (ibfd, obfd); | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Merge backend specific data from an object file to the output | 
|  | +   object file when linking.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) | 
|  | +{ | 
|  | +  flagword old_flags; | 
|  | +  flagword new_flags; | 
|  | +  bfd_boolean ok; | 
|  | +  bfd_boolean null_input_bfd = TRUE; | 
|  | +  asection *sec; | 
|  | + | 
|  | +  /* Check if we have the same endianess */ | 
|  | +  if (! _bfd_generic_verify_endian_match (ibfd, obfd)) | 
|  | +    { | 
|  | +      (*_bfd_error_handler) | 
|  | +	(_("%B: endianness incompatible with that of the selected emulation"), | 
|  | +	 ibfd); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  if (!is_mips_elf (ibfd) || !is_mips_elf (obfd)) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) | 
|  | +    { | 
|  | +      (*_bfd_error_handler) | 
|  | +	(_("%B: ABI is incompatible with that of the selected emulation"), | 
|  | +	 ibfd); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  if (!mips_elf_merge_obj_attributes (ibfd, obfd)) | 
|  | +    return FALSE; | 
|  | + | 
|  | +  new_flags = elf_elfheader (ibfd)->e_flags; | 
|  | +  elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; | 
|  | +  old_flags = elf_elfheader (obfd)->e_flags; | 
|  | + | 
|  | +  if (! elf_flags_init (obfd)) | 
|  | +    { | 
|  | +      elf_flags_init (obfd) = TRUE; | 
|  | +      elf_elfheader (obfd)->e_flags = new_flags; | 
|  | +      elf_elfheader (obfd)->e_ident[EI_CLASS] | 
|  | +	= elf_elfheader (ibfd)->e_ident[EI_CLASS]; | 
|  | + | 
|  | +      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) | 
|  | +	  && (bfd_get_arch_info (obfd)->the_default | 
|  | +	      || mips_mach_extends_p (bfd_get_mach (obfd), | 
|  | +				      bfd_get_mach (ibfd)))) | 
|  | +	{ | 
|  | +	  if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), | 
|  | +				   bfd_get_mach (ibfd))) | 
|  | +	    return FALSE; | 
|  | +	} | 
|  | + | 
|  | +      return TRUE; | 
|  | +    } | 
|  | + | 
|  | +  /* Check flag compatibility.  */ | 
|  | + | 
|  | +  new_flags &= ~EF_MIPS_NOREORDER; | 
|  | +  old_flags &= ~EF_MIPS_NOREORDER; | 
|  | + | 
|  | +  /* Some IRIX 6 BSD-compatibility objects have this bit set.  It | 
|  | +     doesn't seem to matter.  */ | 
|  | +  new_flags &= ~EF_MIPS_XGOT; | 
|  | +  old_flags &= ~EF_MIPS_XGOT; | 
|  | + | 
|  | +  /* MIPSpro generates ucode info in n64 objects.  Again, we should | 
|  | +     just be able to ignore this.  */ | 
|  | +  new_flags &= ~EF_MIPS_UCODE; | 
|  | +  old_flags &= ~EF_MIPS_UCODE; | 
|  | + | 
|  | +  /* DSOs should only be linked with CPIC code.  */ | 
|  | +  if ((ibfd->flags & DYNAMIC) != 0) | 
|  | +    new_flags |= EF_MIPS_PIC | EF_MIPS_CPIC; | 
|  | + | 
|  | +  if (new_flags == old_flags) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  /* Check to see if the input BFD actually contains any sections. | 
|  | +     If not, its flags may not have been initialised either, but it cannot | 
|  | +     actually cause any incompatibility.  */ | 
|  | +  for (sec = ibfd->sections; sec != NULL; sec = sec->next) | 
|  | +    { | 
|  | +      /* Ignore synthetic sections and empty .text, .data and .bss sections | 
|  | +	 which are automatically generated by gas.  Also ignore fake | 
|  | +	 (s)common sections, since merely defining a common symbol does | 
|  | +	 not affect compatibility.  */ | 
|  | +      if ((sec->flags & SEC_IS_COMMON) == 0 | 
|  | +	  && strcmp (sec->name, ".reginfo") | 
|  | +	  && strcmp (sec->name, ".mdebug") | 
|  | +	  && (sec->size != 0 | 
|  | +	      || (strcmp (sec->name, ".text") | 
|  | +		  && strcmp (sec->name, ".data") | 
|  | +		  && strcmp (sec->name, ".bss")))) | 
|  | +	{ | 
|  | +	  null_input_bfd = FALSE; | 
|  | +	  break; | 
|  | +	} | 
|  | +    } | 
|  | +  if (null_input_bfd) | 
|  | +    return TRUE; | 
|  | + | 
|  | +  ok = TRUE; | 
|  | + | 
|  | +  if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) | 
|  | +    elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC; | 
|  | +  if (! (new_flags & EF_MIPS_PIC)) | 
|  | +    elf_elfheader (obfd)->e_flags &= ~EF_MIPS_PIC; | 
|  | + | 
|  | +  new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC); | 
|  | +  old_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC); | 
|  | + | 
|  | +  /* Compare the ISAs.  */ | 
|  | +  if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags)) | 
|  | +    { | 
|  | +      (*_bfd_error_handler) | 
|  | +	(_("%B: linking 32-bit code with 64-bit code"), | 
|  | +	 ibfd); | 
|  | +      ok = FALSE; | 
|  | +    } | 
|  | +  else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd))) | 
|  | +    { | 
|  | +      /* OBFD's ISA isn't the same as, or an extension of, IBFD's.  */ | 
|  | +      if (mips_mach_extends_p (bfd_get_mach (obfd), bfd_get_mach (ibfd))) | 
|  | +	{ | 
|  | +	  /* Copy the architecture info from IBFD to OBFD.  Also copy | 
|  | +	     the 32-bit flag (if set) so that we continue to recognise | 
|  | +	     OBFD as a 32-bit binary.  */ | 
|  | +	  bfd_set_arch_info (obfd, bfd_get_arch_info (ibfd)); | 
|  | +	  elf_elfheader (obfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); | 
|  | +	  elf_elfheader (obfd)->e_flags | 
|  | +	    |= new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); | 
|  | + | 
|  | +	  /* Copy across the ABI flags if OBFD doesn't use them | 
|  | +	     and if that was what caused us to treat IBFD as 32-bit.  */ | 
|  | +	  if ((old_flags & EF_MIPS_ABI) == 0 | 
|  | +	      && mips_32bit_flags_p (new_flags) | 
|  | +	      && !mips_32bit_flags_p (new_flags & ~EF_MIPS_ABI)) | 
|  | +	    elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ABI; | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  /* The ISAs aren't compatible.  */ | 
|  | +	  (*_bfd_error_handler) | 
|  | +	    (_("%B: linking %s module with previous %s modules"), | 
|  | +	     ibfd, | 
|  | +	     bfd_printable_name (ibfd), | 
|  | +	     bfd_printable_name (obfd)); | 
|  | +	  ok = FALSE; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  new_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); | 
|  | +  old_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH | EF_MIPS_32BITMODE); | 
|  | + | 
|  | +  /* Compare ABIs.  The 64-bit ABI does not use EF_MIPS_ABI.  But, it | 
|  | +     does set EI_CLASS differently from any 32-bit ABI.  */ | 
|  | +  if ((new_flags & EF_MIPS_ABI) != (old_flags & EF_MIPS_ABI) | 
|  | +      || (elf_elfheader (ibfd)->e_ident[EI_CLASS] | 
|  | +	  != elf_elfheader (obfd)->e_ident[EI_CLASS])) | 
|  | +    { | 
|  | +      /* Only error if both are set (to different values).  */ | 
|  | +      if (((new_flags & EF_MIPS_ABI) && (old_flags & EF_MIPS_ABI)) | 
|  | +	  || (elf_elfheader (ibfd)->e_ident[EI_CLASS] | 
|  | +	      != elf_elfheader (obfd)->e_ident[EI_CLASS])) | 
|  | +	{ | 
|  | +	  (*_bfd_error_handler) | 
|  | +	    (_("%B: ABI mismatch: linking %s module with previous %s modules"), | 
|  | +	     ibfd, | 
|  | +	     elf_mips_abi_name (ibfd), | 
|  | +	     elf_mips_abi_name (obfd)); | 
|  | +	  ok = FALSE; | 
|  | +	} | 
|  | +      new_flags &= ~EF_MIPS_ABI; | 
|  | +      old_flags &= ~EF_MIPS_ABI; | 
|  | +    } | 
|  | + | 
|  | +  /* For now, allow arbitrary mixing of ASEs (retain the union).  */ | 
|  | +  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE)) | 
|  | +    { | 
|  | +      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE; | 
|  | + | 
|  | +      new_flags &= ~ EF_MIPS_ARCH_ASE; | 
|  | +      old_flags &= ~ EF_MIPS_ARCH_ASE; | 
|  | +    } | 
|  | + | 
|  | +  /* Warn about any other mismatches */ | 
|  | +  if (new_flags != old_flags) | 
|  | +    { | 
|  | +      (*_bfd_error_handler) | 
|  | +	(_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), | 
|  | +	 ibfd, (unsigned long) new_flags, | 
|  | +	 (unsigned long) old_flags); | 
|  | +      ok = FALSE; | 
|  | +    } | 
|  | + | 
|  | +  if (! ok) | 
|  | +    { | 
|  | +      bfd_set_error (bfd_error_bad_value); | 
|  | +      return FALSE; | 
|  | +    } | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +/* Function to keep MIPS specific file flags like as EF_MIPS_PIC.  */ | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_set_private_flags (bfd *abfd, flagword flags) | 
|  | +{ | 
|  | +  BFD_ASSERT (!elf_flags_init (abfd) | 
|  | +	      || elf_elfheader (abfd)->e_flags == flags); | 
|  | + | 
|  | +  elf_elfheader (abfd)->e_flags = flags; | 
|  | +  elf_flags_init (abfd) = TRUE; | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +char * | 
|  | +_bfd_riscv_elf_get_target_dtag (bfd_vma dtag) | 
|  | +{ | 
|  | +  switch (dtag) | 
|  | +    { | 
|  | +    default: return ""; | 
|  | +    case DT_MIPS_RLD_VERSION: | 
|  | +      return "MIPS_RLD_VERSION"; | 
|  | +    case DT_MIPS_TIME_STAMP: | 
|  | +      return "MIPS_TIME_STAMP"; | 
|  | +    case DT_MIPS_ICHECKSUM: | 
|  | +      return "MIPS_ICHECKSUM"; | 
|  | +    case DT_MIPS_IVERSION: | 
|  | +      return "MIPS_IVERSION"; | 
|  | +    case DT_MIPS_FLAGS: | 
|  | +      return "MIPS_FLAGS"; | 
|  | +    case DT_MIPS_BASE_ADDRESS: | 
|  | +      return "MIPS_BASE_ADDRESS"; | 
|  | +    case DT_MIPS_MSYM: | 
|  | +      return "MIPS_MSYM"; | 
|  | +    case DT_MIPS_CONFLICT: | 
|  | +      return "MIPS_CONFLICT"; | 
|  | +    case DT_MIPS_LIBLIST: | 
|  | +      return "MIPS_LIBLIST"; | 
|  | +    case DT_MIPS_LOCAL_GOTNO: | 
|  | +      return "MIPS_LOCAL_GOTNO"; | 
|  | +    case DT_MIPS_CONFLICTNO: | 
|  | +      return "MIPS_CONFLICTNO"; | 
|  | +    case DT_MIPS_LIBLISTNO: | 
|  | +      return "MIPS_LIBLISTNO"; | 
|  | +    case DT_MIPS_SYMTABNO: | 
|  | +      return "MIPS_SYMTABNO"; | 
|  | +    case DT_MIPS_UNREFEXTNO: | 
|  | +      return "MIPS_UNREFEXTNO"; | 
|  | +    case DT_MIPS_GOTSYM: | 
|  | +      return "MIPS_GOTSYM"; | 
|  | +    case DT_MIPS_HIPAGENO: | 
|  | +      return "MIPS_HIPAGENO"; | 
|  | +    case DT_MIPS_RLD_MAP: | 
|  | +      return "MIPS_RLD_MAP"; | 
|  | +    case DT_MIPS_DELTA_CLASS: | 
|  | +      return "MIPS_DELTA_CLASS"; | 
|  | +    case DT_MIPS_DELTA_CLASS_NO: | 
|  | +      return "MIPS_DELTA_CLASS_NO"; | 
|  | +    case DT_MIPS_DELTA_INSTANCE: | 
|  | +      return "MIPS_DELTA_INSTANCE"; | 
|  | +    case DT_MIPS_DELTA_INSTANCE_NO: | 
|  | +      return "MIPS_DELTA_INSTANCE_NO"; | 
|  | +    case DT_MIPS_DELTA_RELOC: | 
|  | +      return "MIPS_DELTA_RELOC"; | 
|  | +    case DT_MIPS_DELTA_RELOC_NO: | 
|  | +      return "MIPS_DELTA_RELOC_NO"; | 
|  | +    case DT_MIPS_DELTA_SYM: | 
|  | +      return "MIPS_DELTA_SYM"; | 
|  | +    case DT_MIPS_DELTA_SYM_NO: | 
|  | +      return "MIPS_DELTA_SYM_NO"; | 
|  | +    case DT_MIPS_DELTA_CLASSSYM: | 
|  | +      return "MIPS_DELTA_CLASSSYM"; | 
|  | +    case DT_MIPS_DELTA_CLASSSYM_NO: | 
|  | +      return "MIPS_DELTA_CLASSSYM_NO"; | 
|  | +    case DT_MIPS_CXX_FLAGS: | 
|  | +      return "MIPS_CXX_FLAGS"; | 
|  | +    case DT_MIPS_PIXIE_INIT: | 
|  | +      return "MIPS_PIXIE_INIT"; | 
|  | +    case DT_MIPS_SYMBOL_LIB: | 
|  | +      return "MIPS_SYMBOL_LIB"; | 
|  | +    case DT_MIPS_LOCALPAGE_GOTIDX: | 
|  | +      return "MIPS_LOCALPAGE_GOTIDX"; | 
|  | +    case DT_MIPS_LOCAL_GOTIDX: | 
|  | +      return "MIPS_LOCAL_GOTIDX"; | 
|  | +    case DT_MIPS_HIDDEN_GOTIDX: | 
|  | +      return "MIPS_HIDDEN_GOTIDX"; | 
|  | +    case DT_MIPS_PROTECTED_GOTIDX: | 
|  | +      return "MIPS_PROTECTED_GOT_IDX"; | 
|  | +    case DT_MIPS_OPTIONS: | 
|  | +      return "MIPS_OPTIONS"; | 
|  | +    case DT_MIPS_INTERFACE: | 
|  | +      return "MIPS_INTERFACE"; | 
|  | +    case DT_MIPS_DYNSTR_ALIGN: | 
|  | +      return "DT_MIPS_DYNSTR_ALIGN"; | 
|  | +    case DT_MIPS_INTERFACE_SIZE: | 
|  | +      return "DT_MIPS_INTERFACE_SIZE"; | 
|  | +    case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: | 
|  | +      return "DT_MIPS_RLD_TEXT_RESOLVE_ADDR"; | 
|  | +    case DT_MIPS_PERF_SUFFIX: | 
|  | +      return "DT_MIPS_PERF_SUFFIX"; | 
|  | +    case DT_MIPS_COMPACT_SIZE: | 
|  | +      return "DT_MIPS_COMPACT_SIZE"; | 
|  | +    case DT_MIPS_GP_VALUE: | 
|  | +      return "DT_MIPS_GP_VALUE"; | 
|  | +    case DT_MIPS_AUX_DYNAMIC: | 
|  | +      return "DT_MIPS_AUX_DYNAMIC"; | 
|  | +    case DT_MIPS_PLTGOT: | 
|  | +      return "DT_MIPS_PLTGOT"; | 
|  | +    case DT_MIPS_RWPLT: | 
|  | +      return "DT_MIPS_RWPLT"; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_print_private_bfd_data (bfd *abfd, void *ptr) | 
|  | +{ | 
|  | +  FILE *file = ptr; | 
|  | + | 
|  | +  BFD_ASSERT (abfd != NULL && ptr != NULL); | 
|  | + | 
|  | +  /* Print normal ELF private data.  */ | 
|  | +  _bfd_elf_print_private_bfd_data (abfd, ptr); | 
|  | + | 
|  | +  /* xgettext:c-format */ | 
|  | +  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags); | 
|  | + | 
|  | +  if (ABI_32_P (abfd)) | 
|  | +    fprintf (file, _(" [abi=32]")); | 
|  | +  else if (ABI_64_P (abfd)) | 
|  | +    fprintf (file, _(" [abi=64]")); | 
|  | +  else | 
|  | +    fprintf (file, _(" [no abi set]")); | 
|  | + | 
|  | +  if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32) | 
|  | +    fprintf (file, " [rv32]"); | 
|  | +  else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64) | 
|  | +    fprintf (file, " [rv64]"); | 
|  | +  else | 
|  | +    fprintf (file, _(" [unknown ISA]")); | 
|  | + | 
|  | +  if (elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) | 
|  | +    fprintf (file, " [PIC]"); | 
|  | + | 
|  | +  if (elf_elfheader (abfd)->e_flags & EF_MIPS_CPIC) | 
|  | +    fprintf (file, " [CPIC]"); | 
|  | + | 
|  | +  if (elf_elfheader (abfd)->e_flags & EF_MIPS_XGOT) | 
|  | +    fprintf (file, " [XGOT]"); | 
|  | + | 
|  | +  fputc ('\n', file); | 
|  | + | 
|  | +  return TRUE; | 
|  | +} | 
|  | + | 
|  | +const struct bfd_elf_special_section _bfd_riscv_elf_special_sections[] = | 
|  | +{ | 
|  | +  { STRING_COMMA_LEN (".lit4"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, | 
|  | +  { STRING_COMMA_LEN (".lit8"),   0, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, | 
|  | +  { STRING_COMMA_LEN (".mdebug"), 0, SHT_MIPS_DEBUG, 0 }, | 
|  | +  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,     SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, | 
|  | +  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS,   SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, | 
|  | +  { STRING_COMMA_LEN (".ucode"),  0, SHT_MIPS_UCODE, 0 }, | 
|  | +  { NULL,                     0,  0, 0,              0 } | 
|  | +}; | 
|  | + | 
|  | +/* Merge non visibility st_other attributes.  Ensure that the | 
|  | +   STO_OPTIONAL flag is copied into h->other, even if this is not a | 
|  | +   definiton of the symbol.  */ | 
|  | +void | 
|  | +_bfd_riscv_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, | 
|  | +				      const Elf_Internal_Sym *isym, | 
|  | +				      bfd_boolean definition, | 
|  | +				      bfd_boolean dynamic ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  if ((isym->st_other & ~ELF_ST_VISIBILITY (-1)) != 0) | 
|  | +    { | 
|  | +      unsigned char other; | 
|  | + | 
|  | +      other = (definition ? isym->st_other : h->other); | 
|  | +      other &= ~ELF_ST_VISIBILITY (-1); | 
|  | +      h->other = other | ELF_ST_VISIBILITY (h->other); | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +bfd_boolean | 
|  | +_bfd_riscv_elf_common_definition (Elf_Internal_Sym *sym) | 
|  | +{ | 
|  | +  return (sym->st_shndx == SHN_COMMON | 
|  | +	  || sym->st_shndx == SHN_MIPS_ACOMMON | 
|  | +	  || sym->st_shndx == SHN_MIPS_SCOMMON); | 
|  | +} | 
|  | + | 
|  | +/* Return address for Ith PLT stub in section PLT, for relocation REL | 
|  | +   or (bfd_vma) -1 if it should not be included.  */ | 
|  | + | 
|  | +bfd_vma | 
|  | +_bfd_riscv_elf_plt_sym_val (bfd_vma i, const asection *plt, | 
|  | +			   const arelent *rel ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  return (plt->vma | 
|  | +	  + RISCV_PLT0_ENTRY_INSNS * 4 | 
|  | +	  + i * RISCV_PLT_ENTRY_INSNS * 4); | 
|  | +} | 
|  | diff -ruN binutils-2.24/bfd/elfxx-riscv.h binutils-2.24-riscv/bfd/elfxx-riscv.h | 
|  | --- binutils-2.24/bfd/elfxx-riscv.h	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/elfxx-riscv.h	2014-12-02 16:05:44.909434942 -0800 | 
|  | @@ -0,0 +1,144 @@ | 
|  | +/* RISC-V ELF specific backend routines. | 
|  | +   Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 | 
|  | +   Free Software Foundation, Inc. | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | +#include "elf/common.h" | 
|  | +#include "elf/internal.h" | 
|  | +#include "elf/riscv.h" | 
|  | + | 
|  | +extern bfd_boolean _bfd_riscv_elf_new_section_hook | 
|  | +  (bfd *, asection *); | 
|  | +extern void _bfd_riscv_elf_symbol_processing | 
|  | +  (bfd *, asymbol *); | 
|  | +extern unsigned int _bfd_riscv_elf_eh_frame_address_size | 
|  | +  (bfd *, asection *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_name_local_section_symbols | 
|  | +  (bfd *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_section_processing | 
|  | +  (bfd *, Elf_Internal_Shdr *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_section_from_shdr | 
|  | +  (bfd *, Elf_Internal_Shdr *, const char *, int); | 
|  | +extern bfd_boolean _bfd_riscv_elf_fake_sections | 
|  | +  (bfd *, Elf_Internal_Shdr *, asection *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_section_from_bfd_section | 
|  | +  (bfd *, asection *, int *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_add_symbol_hook | 
|  | +  (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, | 
|  | +   const char **, flagword *, asection **, bfd_vma *); | 
|  | +extern int _bfd_riscv_elf_link_output_symbol_hook | 
|  | +  (struct bfd_link_info *, const char *, Elf_Internal_Sym *, | 
|  | +   asection *, struct elf_link_hash_entry *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_create_dynamic_sections | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_check_relocs | 
|  | +  (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_adjust_dynamic_symbol | 
|  | +  (struct bfd_link_info *, struct elf_link_hash_entry *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_always_size_sections | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_size_dynamic_sections | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_relocate_section | 
|  | +  (bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, | 
|  | +   Elf_Internal_Rela *, Elf_Internal_Sym *, asection **); | 
|  | +extern bfd_boolean _bfd_riscv_elf_finish_dynamic_symbol | 
|  | +  (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, | 
|  | +   Elf_Internal_Sym *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_finish_dynamic_sections | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern void _bfd_riscv_elf_final_write_processing | 
|  | +  (bfd *, bfd_boolean); | 
|  | +extern int _bfd_riscv_elf_additional_program_headers | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_modify_segment_map | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern asection * _bfd_riscv_elf_gc_mark_hook | 
|  | +  (asection *, struct bfd_link_info *, Elf_Internal_Rela *, | 
|  | +   struct elf_link_hash_entry *, Elf_Internal_Sym *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_gc_sweep_hook | 
|  | +  (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); | 
|  | +extern void _bfd_riscv_elf_copy_indirect_symbol | 
|  | +  (struct bfd_link_info *, struct elf_link_hash_entry *, | 
|  | +   struct elf_link_hash_entry *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_ignore_discarded_relocs | 
|  | +  (asection *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_find_nearest_line | 
|  | +  (bfd *, asection *, asymbol **, bfd_vma, const char **, | 
|  | +   const char **, unsigned int *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_find_inliner_info | 
|  | +  (bfd *, const char **, const char **, unsigned int *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_set_section_contents | 
|  | +  (bfd *, asection *, const void *, file_ptr, bfd_size_type); | 
|  | +extern bfd_byte *_bfd_elf_riscv_get_relocated_section_contents | 
|  | +  (bfd *, struct bfd_link_info *, struct bfd_link_order *, | 
|  | +   bfd_byte *, bfd_boolean, asymbol **); | 
|  | +extern struct bfd_link_hash_table *_bfd_riscv_elf_link_hash_table_create | 
|  | +  (bfd *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_final_link | 
|  | +  (bfd *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_merge_private_bfd_data | 
|  | +  (bfd *, bfd *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_set_private_flags | 
|  | +  (bfd *, flagword); | 
|  | +extern bfd_boolean _bfd_riscv_elf_print_private_bfd_data | 
|  | +  (bfd *, void *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_discard_info | 
|  | +  (bfd *, struct elf_reloc_cookie *, struct bfd_link_info *); | 
|  | +extern bfd_boolean _bfd_riscv_elf_write_section | 
|  | +  (bfd *, struct bfd_link_info *, asection *, bfd_byte *); | 
|  | + | 
|  | +extern bfd_boolean _bfd_riscv_elf_read_ecoff_info | 
|  | +  (bfd *, asection *, struct ecoff_debug_info *); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf_gprel16_with_gp | 
|  | +  (bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf32_gprel16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf_hi16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf_got16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf_lo16_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +extern bfd_reloc_status_type _bfd_riscv_elf_generic_reloc | 
|  | +  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); | 
|  | +extern unsigned long _bfd_elf_riscv_mach | 
|  | +  (flagword); | 
|  | +extern bfd_boolean _bfd_riscv_relax_section | 
|  | +  (bfd *, asection *, struct bfd_link_info *, bfd_boolean *); | 
|  | +extern bfd_vma _bfd_riscv_elf_sign_extend | 
|  | +  (bfd_vma, int); | 
|  | +extern void _bfd_riscv_elf_merge_symbol_attribute | 
|  | +  (struct elf_link_hash_entry *, const Elf_Internal_Sym *, bfd_boolean, bfd_boolean); | 
|  | +extern char *_bfd_riscv_elf_get_target_dtag (bfd_vma); | 
|  | +extern void _bfd_riscv_elf_use_plts_and_copy_relocs | 
|  | +  (struct bfd_link_info *); | 
|  | +extern bfd_vma _bfd_riscv_elf_plt_sym_val | 
|  | +  (bfd_vma, const asection *, const arelent *rel); | 
|  | + | 
|  | +extern const struct bfd_elf_special_section _bfd_riscv_elf_special_sections []; | 
|  | + | 
|  | +extern bfd_boolean _bfd_riscv_elf_common_definition (Elf_Internal_Sym *); | 
|  | + | 
|  | +#define elf_backend_common_definition   _bfd_riscv_elf_common_definition | 
|  | +#define elf_backend_name_local_section_symbols \ | 
|  | +  _bfd_riscv_elf_name_local_section_symbols | 
|  | +#define elf_backend_special_sections _bfd_riscv_elf_special_sections | 
|  | +#define elf_backend_eh_frame_address_size _bfd_riscv_elf_eh_frame_address_size | 
|  | +#define elf_backend_merge_symbol_attribute  _bfd_riscv_elf_merge_symbol_attribute | 
|  | diff -ruN binutils-2.24/bfd/targets.c binutils-2.24-riscv/bfd/targets.c | 
|  | --- binutils-2.24/bfd/targets.c	2013-11-04 07:33:37.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/bfd/targets.c	2014-12-02 16:20:33.686987626 -0800 | 
|  | @@ -646,6 +646,7 @@ | 
|  | extern const bfd_target bfd_elf32_littlemips_vxworks_vec; | 
|  | extern const bfd_target bfd_elf32_littlemoxie_vec; | 
|  | extern const bfd_target bfd_elf32_littlenios2_vec; | 
|  | +extern const bfd_target bfd_elf32_littleriscv_vec; | 
|  | extern const bfd_target bfd_elf32_m32c_vec; | 
|  | extern const bfd_target bfd_elf32_m32r_vec; | 
|  | extern const bfd_target bfd_elf32_m32rle_vec; | 
|  | @@ -747,6 +748,7 @@ | 
|  | extern const bfd_target bfd_elf64_littlemips_vec; | 
|  | extern const bfd_target bfd_elf64_littleaarch64_vec; | 
|  | extern const bfd_target bfd_elf32_littleaarch64_vec; | 
|  | +extern const bfd_target bfd_elf64_littleriscv_vec; | 
|  | extern const bfd_target bfd_elf64_mmix_vec; | 
|  | extern const bfd_target bfd_elf64_powerpc_vec; | 
|  | extern const bfd_target bfd_elf64_powerpcle_vec; | 
|  | diff -ruN binutils-2.24/binutils/readelf.c binutils-2.24-riscv/binutils/readelf.c | 
|  | --- binutils-2.24/binutils/readelf.c	2013-11-18 00:40:15.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/binutils/readelf.c	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -125,6 +125,7 @@ | 
|  | #include "elf/metag.h" | 
|  | #include "elf/microblaze.h" | 
|  | #include "elf/mips.h" | 
|  | +#include "elf/riscv.h" | 
|  | #include "elf/mmix.h" | 
|  | #include "elf/mn10200.h" | 
|  | #include "elf/mn10300.h" | 
|  | @@ -1157,6 +1158,10 @@ | 
|  | rtype = elf_mips_reloc_type (type); | 
|  | break; | 
|  |  | 
|  | +	case EM_RISCV: | 
|  | +	  rtype = elf_riscv_reloc_type (type); | 
|  | +	  break; | 
|  | + | 
|  | case EM_ALPHA: | 
|  | rtype = elf_alpha_reloc_type (type); | 
|  | break; | 
|  | @@ -2648,6 +2653,28 @@ | 
|  | default: strcat (buf, _(", unknown ISA")); break; | 
|  | } | 
|  | break; | 
|  | + | 
|  | +	case EM_RISCV: | 
|  | +	  if (e_flags & EF_RISCV_PIC) | 
|  | +	    strcat (buf, ", pic"); | 
|  | + | 
|  | +	  if (e_flags & EF_MIPS_OPTIONS_FIRST) | 
|  | +	    strcat (buf, ", odk first"); | 
|  | + | 
|  | +	  switch ((e_flags & EF_RISCV_ABI)) | 
|  | +	    { | 
|  | +	    case E_RISCV_ABI_32: strcat (buf, ", abi32"); break; | 
|  | +	    case E_RISCV_ABI_64: strcat (buf, ", abi64"); break; | 
|  | +	    default: strcat (buf, _(", unknown ABI")); break; | 
|  | +	    } | 
|  | + | 
|  | +	  switch ((e_flags & EF_RISCV_ARCH)) | 
|  | +	    { | 
|  | +	    case E_RISCV_ARCH_RV32: strcat (buf, ", rv32"); break; | 
|  | +	    case E_RISCV_ARCH_RV64: strcat (buf, ", rv64"); break; | 
|  | +	    default: strcat (buf, _(", unknown ISA")); break; | 
|  | +	    } | 
|  | +	  break; | 
|  |  | 
|  | case EM_SH: | 
|  | switch ((e_flags & EF_SH_MACH_MASK)) | 
|  | diff -ruN binutils-2.24/config.sub binutils-2.24-riscv/config.sub | 
|  | --- binutils-2.24/config.sub	2013-11-26 03:37:33.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/config.sub	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -334,6 +334,9 @@ | 
|  | ms1) | 
|  | basic_machine=mt-unknown | 
|  | ;; | 
|  | +	riscv) | 
|  | +		basic_machine=riscv-ucb | 
|  | +		;; | 
|  |  | 
|  | strongarm | thumb | xscale) | 
|  | basic_machine=arm-unknown | 
|  | diff -ruN binutils-2.24/gas/config/tc-riscv.c binutils-2.24-riscv/gas/config/tc-riscv.c | 
|  | --- binutils-2.24/gas/config/tc-riscv.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/gas/config/tc-riscv.c	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -0,0 +1,3857 @@ | 
|  | +/* tc-mips.c -- assemble code for a MIPS chip. | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | 
|  | +   2003, 2004, 2005, 2006, 2007, 2008, 2009  Free Software Foundation, Inc. | 
|  | +   Contributed by the OSF and Ralph Campbell. | 
|  | +   Written by Keith Knowles and Ralph Campbell, working independently. | 
|  | +   Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus | 
|  | +   Support. | 
|  | + | 
|  | +   This file is part of GAS. | 
|  | + | 
|  | +   GAS is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3, or (at your option) | 
|  | +   any later version. | 
|  | + | 
|  | +   GAS is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with GAS; see the file COPYING.  If not, write to the Free | 
|  | +   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | +   02110-1301, USA.  */ | 
|  | + | 
|  | +#include "as.h" | 
|  | +#include "config.h" | 
|  | +#include "subsegs.h" | 
|  | +#include "safe-ctype.h" | 
|  | + | 
|  | +#include "itbl-ops.h" | 
|  | +#include "dwarf2dbg.h" | 
|  | +#include "dw2gencfi.h" | 
|  | + | 
|  | +#include <execinfo.h> | 
|  | +#include <stdint.h> | 
|  | + | 
|  | +#ifdef DEBUG | 
|  | +#define DBG(x) printf x | 
|  | +#else | 
|  | +#define DBG(x) | 
|  | +#endif | 
|  | + | 
|  | +#ifdef OBJ_MAYBE_ELF | 
|  | +/* Clean up namespace so we can include obj-elf.h too.  */ | 
|  | +static int mips_output_flavor (void); | 
|  | +static int mips_output_flavor (void) { return OUTPUT_FLAVOR; } | 
|  | +#undef OBJ_PROCESS_STAB | 
|  | +#undef OUTPUT_FLAVOR | 
|  | +#undef S_GET_ALIGN | 
|  | +#undef S_GET_SIZE | 
|  | +#undef S_SET_ALIGN | 
|  | +#undef S_SET_SIZE | 
|  | +#undef obj_frob_file | 
|  | +#undef obj_frob_file_after_relocs | 
|  | +#undef obj_frob_symbol | 
|  | +#undef obj_pop_insert | 
|  | +#undef obj_sec_sym_ok_for_reloc | 
|  | +#undef OBJ_COPY_SYMBOL_ATTRIBUTES | 
|  | + | 
|  | +#include "obj-elf.h" | 
|  | +/* Fix any of them that we actually care about.  */ | 
|  | +#undef OUTPUT_FLAVOR | 
|  | +#define OUTPUT_FLAVOR mips_output_flavor() | 
|  | +#endif | 
|  | + | 
|  | +#if defined (OBJ_ELF) | 
|  | +#include "elf/riscv.h" | 
|  | +#endif | 
|  | + | 
|  | +#include "ecoff.h" | 
|  | + | 
|  | +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) | 
|  | +static char *mips_regmask_frag; | 
|  | +#endif | 
|  | + | 
|  | +#define ILLEGAL_REG (32) | 
|  | + | 
|  | +#define ZERO 0 | 
|  | +#define TREG 18 | 
|  | +#define PIC_CALL_REG 19 | 
|  | +#define KT0 ILLEGAL_REG | 
|  | +#define KT1 ILLEGAL_REG | 
|  | +#define GP  ILLEGAL_REG | 
|  | +#define FP  29 | 
|  | +#define SP  30 | 
|  | +#define ATREG ILLEGAL_REG | 
|  | +#define RA  LINK_REG | 
|  | + | 
|  | +/* Allow override of standard little-endian ECOFF format.  */ | 
|  | + | 
|  | +#ifndef ECOFF_LITTLE_FORMAT | 
|  | +#define ECOFF_LITTLE_FORMAT "ecoff-littlemips" | 
|  | +#endif | 
|  | + | 
|  | +extern int target_big_endian; | 
|  | + | 
|  | +/* Information about an instruction, including its format, operands | 
|  | +   and fixups.  */ | 
|  | +struct mips_cl_insn | 
|  | +{ | 
|  | +  /* The opcode's entry in riscv_opcodes or mips16_opcodes.  */ | 
|  | +  const struct riscv_opcode *insn_mo; | 
|  | + | 
|  | +  /* The 16-bit or 32-bit bitstring of the instruction itself.  This is | 
|  | +     a copy of INSN_MO->match with the operands filled in.  */ | 
|  | +  unsigned long insn_opcode; | 
|  | + | 
|  | +  /* The frag that contains the instruction.  */ | 
|  | +  struct frag *frag; | 
|  | + | 
|  | +  /* The offset into FRAG of the first instruction byte.  */ | 
|  | +  long where; | 
|  | + | 
|  | +  /* The relocs associated with the instruction, if any.  */ | 
|  | +  fixS *fixp[3]; | 
|  | +}; | 
|  | + | 
|  | +static bfd_boolean rv64 = TRUE; /* RV64 (true) or RV32 (false) */ | 
|  | +#define HAVE_32BIT_SYMBOLS 1 /* LUI/ADDI for symbols, even in RV64 */ | 
|  | +#define HAVE_32BIT_ADDRESSES (!rv64) | 
|  | +#define LOAD_ADDRESS_INSN (HAVE_32BIT_ADDRESSES ? "lw" : "ld") | 
|  | +#define ADD32_INSN (rv64 ? "addiw" : "addi") | 
|  | + | 
|  | +/* This is the set of options which may be modified by the .set | 
|  | +   pseudo-op.  We use a struct so that .set push and .set pop are more | 
|  | +   reliable.  */ | 
|  | + | 
|  | +struct mips_set_options | 
|  | +{ | 
|  | +  /* Enable RVC instruction compression */ | 
|  | +  int rvc; | 
|  | +}; | 
|  | + | 
|  | +static struct mips_set_options mips_opts = | 
|  | +{ | 
|  | +  /* rvc */ 0 | 
|  | +}; | 
|  | + | 
|  | +/* These variables are filled in with the masks of registers used. | 
|  | +   The object format code reads them and puts them in the appropriate | 
|  | +   place.  */ | 
|  | +unsigned long mips_gprmask; | 
|  | +unsigned long mips_fprmask; | 
|  | + | 
|  | +/* Whether or not we're generating position-independent code.  */ | 
|  | +static bfd_boolean is_pic = FALSE; | 
|  | + | 
|  | +/* handle of the OPCODE hash table */ | 
|  | +static struct hash_control *op_hash = NULL; | 
|  | + | 
|  | +/* This array holds the chars that always start a comment.  If the | 
|  | +    pre-processor is disabled, these aren't very useful */ | 
|  | +const char comment_chars[] = "#"; | 
|  | + | 
|  | +/* This array holds the chars that only start a comment at the beginning of | 
|  | +   a line.  If the line seems to have the form '# 123 filename' | 
|  | +   .line and .file directives will appear in the pre-processed output */ | 
|  | +/* Note that input_file.c hand checks for '#' at the beginning of the | 
|  | +   first line of the input file.  This is because the compiler outputs | 
|  | +   #NO_APP at the beginning of its output.  */ | 
|  | +/* Also note that C style comments are always supported.  */ | 
|  | +const char line_comment_chars[] = "#"; | 
|  | + | 
|  | +/* This array holds machine specific line separator characters.  */ | 
|  | +const char line_separator_chars[] = ";"; | 
|  | + | 
|  | +/* Chars that can be used to separate mant from exp in floating point nums */ | 
|  | +const char EXP_CHARS[] = "eE"; | 
|  | + | 
|  | +/* Chars that mean this number is a floating point constant */ | 
|  | +/* As in 0f12.456 */ | 
|  | +/* or    0d1.2345e12 */ | 
|  | +const char FLT_CHARS[] = "rRsSfFdDxXpP"; | 
|  | + | 
|  | +/* Also be aware that MAXIMUM_NUMBER_OF_CHARS_FOR_FLOAT may have to be | 
|  | +   changed in read.c .  Ideally it shouldn't have to know about it at all, | 
|  | +   but nothing is ideal around here. | 
|  | + */ | 
|  | + | 
|  | +static char *insn_error; | 
|  | + | 
|  | +static int auto_align = 1; | 
|  | + | 
|  | +/* To output NOP instructions correctly, we need to keep information | 
|  | +   about the previous two instructions.  */ | 
|  | + | 
|  | +/* Debugging level.  -g sets this to 2.  -gN sets this to N.  -g0 is | 
|  | +   equivalent to seeing no -g option at all.  */ | 
|  | +static int mips_debug = 0; | 
|  | + | 
|  | +/* For ECOFF and ELF, relocations against symbols are done in two | 
|  | +   parts, with a HI relocation and a LO relocation.  Each relocation | 
|  | +   has only 16 bits of space to store an addend.  This means that in | 
|  | +   order for the linker to handle carries correctly, it must be able | 
|  | +   to locate both the HI and the LO relocation.  This means that the | 
|  | +   relocations must appear in order in the relocation table. | 
|  | + | 
|  | +   In order to implement this, we keep track of each unmatched HI | 
|  | +   relocation.  We then sort them so that they immediately precede the | 
|  | +   corresponding LO relocation.  */ | 
|  | + | 
|  | +struct mips_hi_fixup | 
|  | +{ | 
|  | +  /* Next HI fixup.  */ | 
|  | +  struct mips_hi_fixup *next; | 
|  | +  /* This fixup.  */ | 
|  | +  fixS *fixp; | 
|  | +  /* The section this fixup is in.  */ | 
|  | +  segT seg; | 
|  | +}; | 
|  | + | 
|  | +/* The frag containing the last explicit relocation operator. | 
|  | +   Null if explicit relocations have not been used.  */ | 
|  | + | 
|  | +static fragS *prev_reloc_op_frag; | 
|  | + | 
|  | +#define RELAX_BRANCH_ENCODE(uncond, toofar) \ | 
|  | +  ((relax_substateT) \ | 
|  | +   (0xc0000000 \ | 
|  | +    | ((toofar) ? 1 : 0) \ | 
|  | +    | ((uncond) ? 8 : 0))) | 
|  | +#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000) | 
|  | +#define RELAX_BRANCH_UNCOND(i) (((i) & 8) != 0) | 
|  | +#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0) | 
|  | + | 
|  | +/* Is the given value a sign-extended 32-bit value?  */ | 
|  | +#define IS_SEXT_32BIT_NUM(x)						\ | 
|  | +  (((x) &~ (offsetT) 0x7fffffff) == 0					\ | 
|  | +   || (((x) &~ (offsetT) 0x7fffffff) == ~ (offsetT) 0x7fffffff)) | 
|  | + | 
|  | +#define IS_SEXT_NBIT_NUM(x,n) \ | 
|  | +  ({ int64_t __tmp = (x); \ | 
|  | +     __tmp = (__tmp << (64-(n))) >> (64-(n)); \ | 
|  | +     __tmp == (x); }) | 
|  | + | 
|  | +/* Is the given value a zero-extended 32-bit value?  Or a negated one?  */ | 
|  | +#define IS_ZEXT_32BIT_NUM(x)						\ | 
|  | +  (((x) &~ (offsetT) 0xffffffff) == 0					\ | 
|  | +   || (((x) &~ (offsetT) 0xffffffff) == ~ (offsetT) 0xffffffff)) | 
|  | + | 
|  | +/* Replace bits MASK << SHIFT of STRUCT with the equivalent bits in | 
|  | +   VALUE << SHIFT.  VALUE is evaluated exactly once.  */ | 
|  | +#define INSERT_BITS(STRUCT, VALUE, MASK, SHIFT) \ | 
|  | +  (STRUCT) = (((STRUCT) & ~((MASK) << (SHIFT))) \ | 
|  | +	      | (((VALUE) & (MASK)) << (SHIFT))) | 
|  | + | 
|  | +/* Extract bits MASK << SHIFT from STRUCT and shift them right | 
|  | +   SHIFT places.  */ | 
|  | +#define EXTRACT_BITS(STRUCT, MASK, SHIFT) \ | 
|  | +  (((STRUCT) >> (SHIFT)) & (MASK)) | 
|  | + | 
|  | +/* Change INSN's opcode so that the operand given by FIELD has value VALUE. | 
|  | +   INSN is a mips_cl_insn structure and VALUE is evaluated exactly once. | 
|  | + | 
|  | +   include/opcode/mips.h specifies operand fields using the macros | 
|  | +   OP_MASK_<FIELD> and OP_SH_<FIELD>.  The MIPS16 equivalents start | 
|  | +   with "MIPS16OP" instead of "OP".  */ | 
|  | +#define INSERT_OPERAND(FIELD, INSN, VALUE) \ | 
|  | +  INSERT_BITS ((INSN).insn_opcode, VALUE, OP_MASK_##FIELD, OP_SH_##FIELD) | 
|  | + | 
|  | +/* Extract the operand given by FIELD from mips_cl_insn INSN.  */ | 
|  | +#define EXTRACT_OPERAND(FIELD, INSN) \ | 
|  | +  EXTRACT_BITS ((INSN).insn_opcode, OP_MASK_##FIELD, OP_SH_##FIELD) | 
|  | + | 
|  | +/* Determine if an instruction matches an opcode. */ | 
|  | +#define OPCODE_MATCHES(OPCODE, OP) \ | 
|  | +  (((OPCODE) & MASK_##OP) == MATCH_##OP) | 
|  | + | 
|  | +#define INSN_MATCHES(INSN, OP) \ | 
|  | +  (((INSN).insn_opcode & MASK_##OP) == MATCH_##OP) | 
|  | + | 
|  | +#define OPCODE_IS_STORE(OPCODE) \ | 
|  | +  (OPCODE_MATCHES(OPCODE, SD)  || OPCODE_MATCHES(OPCODE, SW) || \ | 
|  | +   OPCODE_MATCHES(OPCODE, SH)  || OPCODE_MATCHES(OPCODE, SB) || \ | 
|  | +   OPCODE_MATCHES(OPCODE, FSW) || OPCODE_MATCHES(OPCODE, FSD)) | 
|  | + | 
|  | +/* Prototypes for static functions.  */ | 
|  | + | 
|  | +#define internalError()							\ | 
|  | +    as_fatal (_("internal Error, line %d, %s"), __LINE__, __FILE__) | 
|  | + | 
|  | +enum mips_regclass { MIPS_GR_REG, MIPS_FP_REG }; | 
|  | + | 
|  | +static void append_insn | 
|  | +  (struct mips_cl_insn *ip, expressionS *p, bfd_reloc_code_real_type *r); | 
|  | +static void macro (struct mips_cl_insn * ip); | 
|  | +static void mips_ip (char *str, struct mips_cl_insn * ip); | 
|  | +static size_t my_getSmallExpression | 
|  | +  (expressionS *, bfd_reloc_code_real_type *, char *); | 
|  | +static void my_getExpression (expressionS *, char *); | 
|  | +static void s_align (int); | 
|  | +static void s_change_sec (int); | 
|  | +static void s_change_section (int); | 
|  | +static void s_cons (int); | 
|  | +static void s_float_cons (int); | 
|  | +static void s_mips_globl (int); | 
|  | +static void s_mipsset (int); | 
|  | +static void s_dtprelword (int); | 
|  | +static void s_dtpreldword (int); | 
|  | +static void s_mips_weakext (int); | 
|  | +static void s_mips_file (int); | 
|  | +static void s_mips_loc (int); | 
|  | +static int validate_mips_insn (const struct riscv_opcode *); | 
|  | +static int relaxed_branch_length (fragS *fragp, asection *sec, int update); | 
|  | + | 
|  | +/* Pseudo-op table. | 
|  | + | 
|  | +   The following pseudo-ops from the Kane and Heinrich MIPS book | 
|  | +   should be defined here, but are currently unsupported: .alias, | 
|  | +   .galive, .gjaldef, .gjrlive, .livereg, .noalias. | 
|  | + | 
|  | +   The following pseudo-ops from the Kane and Heinrich MIPS book are | 
|  | +   specific to the type of debugging information being generated, and | 
|  | +   should be defined by the object format: .aent, .begin, .bend, | 
|  | +   .bgnb, .end, .endb, .ent, .fmask, .frame, .loc, .mask, .verstamp, | 
|  | +   .vreg. | 
|  | + | 
|  | +   The following pseudo-ops from the Kane and Heinrich MIPS book are | 
|  | +   not MIPS CPU specific, but are also not specific to the object file | 
|  | +   format.  This file is probably the best place to define them, but | 
|  | +   they are not currently supported: .asm0, .endr, .lab, .struct.  */ | 
|  | + | 
|  | +static const pseudo_typeS mips_pseudo_table[] = | 
|  | +{ | 
|  | +  /* MIPS specific pseudo-ops.  */ | 
|  | +  {"set", s_mipsset, 0}, | 
|  | +  {"rdata", s_change_sec, 'r'}, | 
|  | +  {"dtprelword", s_dtprelword, 0}, | 
|  | +  {"dtpreldword", s_dtpreldword, 0}, | 
|  | + | 
|  | +  /* Relatively generic pseudo-ops that happen to be used on MIPS | 
|  | +     chips.  */ | 
|  | +  {"asciiz", stringer, 8 + 1}, | 
|  | +  {"bss", s_change_sec, 'b'}, | 
|  | +  {"err", s_err, 0}, | 
|  | +  {"half", s_cons, 1}, | 
|  | +  {"dword", s_cons, 3}, | 
|  | +  {"weakext", s_mips_weakext, 0}, | 
|  | +  {"origin", s_org, 0}, | 
|  | +  {"repeat", s_rept, 0}, | 
|  | + | 
|  | +  /* These pseudo-ops are defined in read.c, but must be overridden | 
|  | +     here for one reason or another.  */ | 
|  | +  {"align", s_align, 0}, | 
|  | +  {"byte", s_cons, 0}, | 
|  | +  {"data", s_change_sec, 'd'}, | 
|  | +  {"double", s_float_cons, 'd'}, | 
|  | +  {"float", s_float_cons, 'f'}, | 
|  | +  {"globl", s_mips_globl, 0}, | 
|  | +  {"global", s_mips_globl, 0}, | 
|  | +  {"hword", s_cons, 1}, | 
|  | +  {"int", s_cons, 2}, | 
|  | +  {"long", s_cons, 2}, | 
|  | +  {"octa", s_cons, 4}, | 
|  | +  {"quad", s_cons, 3}, | 
|  | +  {"section", s_change_section, 0}, | 
|  | +  {"short", s_cons, 1}, | 
|  | +  {"single", s_float_cons, 'f'}, | 
|  | +  {"text", s_change_sec, 't'}, | 
|  | +  {"word", s_cons, 2}, | 
|  | + | 
|  | +  { NULL, NULL, 0 }, | 
|  | +}; | 
|  | + | 
|  | +static const pseudo_typeS mips_nonecoff_pseudo_table[] = | 
|  | +{ | 
|  | +  /* These pseudo-ops should be defined by the object file format. | 
|  | +     However, a.out doesn't support them, so we have versions here.  */ | 
|  | +  {"bgnb", s_ignore, 0}, | 
|  | +  {"endb", s_ignore, 0}, | 
|  | +  {"file", s_mips_file, 0}, | 
|  | +  {"loc", s_mips_loc, 0}, | 
|  | +  {"verstamp", s_ignore, 0}, | 
|  | +  { NULL, NULL, 0 }, | 
|  | +}; | 
|  | + | 
|  | +extern void pop_insert (const pseudo_typeS *); | 
|  | + | 
|  | +void | 
|  | +mips_pop_insert (void) | 
|  | +{ | 
|  | +  pop_insert (mips_pseudo_table); | 
|  | +  pop_insert (mips_nonecoff_pseudo_table); | 
|  | +} | 
|  | + | 
|  | +/* Symbols labelling the current insn.  */ | 
|  | + | 
|  | +struct insn_label_list | 
|  | +{ | 
|  | +  struct insn_label_list *next; | 
|  | +  symbolS *label; | 
|  | +}; | 
|  | + | 
|  | +static struct insn_label_list *free_insn_labels; | 
|  | +#define label_list tc_segment_info_data.labels | 
|  | + | 
|  | +void | 
|  | +mips_clear_insn_labels (void) | 
|  | +{ | 
|  | +  register struct insn_label_list **pl; | 
|  | +  segment_info_type *si; | 
|  | + | 
|  | +  if (now_seg) | 
|  | +    { | 
|  | +      for (pl = &free_insn_labels; *pl != NULL; pl = &(*pl)->next) | 
|  | +	; | 
|  | + | 
|  | +      si = seg_info (now_seg); | 
|  | +      *pl = si->label_list; | 
|  | +      si->label_list = NULL; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | + | 
|  | +static char *expr_end; | 
|  | + | 
|  | +/* Expressions which appear in instructions.  These are set by | 
|  | +   mips_ip.  */ | 
|  | + | 
|  | +static expressionS imm_expr; | 
|  | +static expressionS imm2_expr; | 
|  | +static expressionS offset_expr; | 
|  | + | 
|  | +/* Relocs associated with imm_expr and offset_expr.  */ | 
|  | + | 
|  | +static bfd_reloc_code_real_type imm_reloc[3] | 
|  | +  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; | 
|  | +static bfd_reloc_code_real_type offset_reloc[3] | 
|  | +  = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; | 
|  | + | 
|  | +/* The default target format to use.  */ | 
|  | + | 
|  | +const char * | 
|  | +mips_target_format (void) | 
|  | +{ | 
|  | +  return rv64 ? "elf64-littleriscv" : "elf32-littleriscv"; | 
|  | +} | 
|  | + | 
|  | +/* Return the length of instruction INSN.  */ | 
|  | + | 
|  | +static inline unsigned int | 
|  | +insn_length (const struct mips_cl_insn *insn) | 
|  | +{ | 
|  | +  /* RVC instructions have insn[1:0] != 3 */ | 
|  | +  return mips_opts.rvc && (insn->insn_opcode & 0x3) != 0x3 ? 2 : 4; | 
|  | +} | 
|  | + | 
|  | +static int | 
|  | +imm_bits_needed(int32_t imm) | 
|  | +{ | 
|  | +  int imm_bits = 32; | 
|  | +  while(imm_bits > 1 && (imm << (32-(imm_bits-1)) >> (32-(imm_bits-1))) == imm) | 
|  | +    imm_bits--; | 
|  | +  return imm_bits; | 
|  | +} | 
|  | + | 
|  | +/* return the rvc small register id, if it exists; else, return -1. */ | 
|  | +#define ARRAY_FIND(array, x) ({ \ | 
|  | +  size_t _pos = ARRAY_SIZE(array), _i; \ | 
|  | +  for(_i = 0; _i < ARRAY_SIZE(array); _i++) \ | 
|  | +    if((x) == (array)[_i]) \ | 
|  | +      { _pos = _i; break; } \ | 
|  | +  _pos; }) | 
|  | +#define IN_ARRAY(array, x) (ARRAY_FIND(array, x) != ARRAY_SIZE(array)) | 
|  | + | 
|  | +#define is_rvc_reg(type, x) IN_ARRAY(rvc_##type##_regmap, x) | 
|  | +#define rvc_reg(type, x) ARRAY_FIND(rvc_##type##_regmap, x) | 
|  | + | 
|  | +/* If insn can be compressed, compress it and return 1; else return 0. */ | 
|  | +static int | 
|  | +riscv_rvc_compress(struct mips_cl_insn* insn) | 
|  | +{ | 
|  | +  int rd = EXTRACT_OPERAND(RD, *insn); | 
|  | +  int rs1 = EXTRACT_OPERAND(RS, *insn); | 
|  | +  int rs2 ATTRIBUTE_UNUSED = EXTRACT_OPERAND(RT, *insn); | 
|  | +  int32_t imm = EXTRACT_OPERAND(IMMEDIATE, *insn); | 
|  | +  imm = imm << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS); | 
|  | +  int32_t shamt = imm & 0x3f; | 
|  | +  int32_t bimm = EXTRACT_OPERAND(IMMLO, *insn) | | 
|  | +                 (EXTRACT_OPERAND(IMMHI, *insn) << RISCV_IMMLO_BITS); | 
|  | +  bimm = bimm << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS); | 
|  | +  int32_t jt = EXTRACT_OPERAND(TARGET, *insn); | 
|  | +  jt = jt << (32-RISCV_JUMP_BITS) >> (32-RISCV_JUMP_BITS); | 
|  | + | 
|  | +  gas_assert(insn_length(insn) == 4); | 
|  | + | 
|  | +  int imm_bits = imm_bits_needed(imm); | 
|  | +  int bimm_bits = imm_bits_needed(bimm); | 
|  | +  int jt_bits = imm_bits_needed(jt); | 
|  | + | 
|  | +  if(INSN_MATCHES(*insn, ADDI) && rd != 0 && rd == rs1 && imm_bits <= 6) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_ADDI; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, ADDIW) && rd != 0 && rd == rs1 && imm_bits <= 6) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_ADDIW; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, JALR_J) && rd == 0 && rs1 != 1 && imm == 0) | 
|  | +  { | 
|  | +    // jalr.j rd=0, rs1 != 1, imm=0 is encoded as c.addi rd=0, imm={1'b0,rs1} | 
|  | +    insn->insn_opcode = MATCH_C_ADDI; | 
|  | +    INSERT_OPERAND(CIMM6, *insn, rs1); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, JALR_R) && rd == 0 && rs1 == 1 && imm == 0) | 
|  | +  { | 
|  | +    // jalr.r rd=0, rs1=1, imm=0 is encoded as c.addi rd=0, imm={1'b0,rs1} | 
|  | +    insn->insn_opcode = MATCH_C_ADDI; | 
|  | +    INSERT_OPERAND(CIMM6, *insn, rs1); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, JALR_C) && rd == 1 && imm == 0) | 
|  | +  { | 
|  | +    // jalr.c rd=1, rs1, imm=0 is encoded as c.addi rd=0, imm={1'b1,rs1} | 
|  | +    insn->insn_opcode = MATCH_C_ADDI; | 
|  | +    INSERT_OPERAND(CIMM6, *insn, 0x20 | rs1); | 
|  | +  } | 
|  | +  else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) || | 
|  | +          INSN_MATCHES(*insn, XORI)) && rs1 == 0 && imm_bits <= 6) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LI; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm); | 
|  | +  } | 
|  | +  else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) || | 
|  | +          INSN_MATCHES(*insn, XORI)) && rs1 == 0 && imm_bits <= 6) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LI; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm); | 
|  | +  } | 
|  | +  else if((INSN_MATCHES(*insn, ADDI) || INSN_MATCHES(*insn, ORI) || | 
|  | +           INSN_MATCHES(*insn, XORI)) && imm == 0) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_MOVE; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CRS1, *insn, rs1); | 
|  | +  } | 
|  | +  else if((INSN_MATCHES(*insn, ADD) || INSN_MATCHES(*insn, OR) || | 
|  | +           INSN_MATCHES(*insn, XOR)) && | 
|  | +          (rs1 == 0 || rs2 == 0)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_MOVE; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CRS1, *insn, rs1 == 0 ? rs2 : rs1); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, ADD) && (rd == rs1 || rd == rs2)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_ADD; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CRS1, *insn, rd == rs1 ? rs2 : rs1); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SUB) && rd == rs2) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SUB; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CRS1, *insn, rs1); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, ADD) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_ADD3; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2)); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SUB) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SUB3; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2)); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, OR) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_OR3; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2)); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, AND) && is_rvc_reg(rd, rd) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2b, rs2)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_AND3; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2BS, *insn, rvc_reg(rs2b, rs2)); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SLLI) && rd == rs1 && is_rvc_reg(rd, rd)) | 
|  | +  { | 
|  | +    insn->insn_opcode = shamt >= 32 ? MATCH_C_SLLI32 : MATCH_C_SLLI; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, shamt); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SRLI) && rd == rs1 && is_rvc_reg(rd, rd)) | 
|  | +  { | 
|  | +    insn->insn_opcode = shamt >= 32 ? MATCH_C_SRLI32 : MATCH_C_SRLI; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, shamt); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SRAI) && rd == rs1 && is_rvc_reg(rd, rd)) | 
|  | +  { | 
|  | +    insn->insn_opcode = shamt >= 32 ? MATCH_C_SRAI32 : MATCH_C_SRAI; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, shamt); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SLLIW) && rd == rs1 && is_rvc_reg(rd, rd)) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SLLIW; | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, shamt); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, J) && jt_bits <= 10) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_J; | 
|  | +    INSERT_OPERAND(CIMM10, *insn, jt); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, BEQ) && rs1 == rs2 && bimm_bits <= 10) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_J; | 
|  | +    INSERT_OPERAND(CIMM10, *insn, bimm); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, BEQ) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm_bits <= 5) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_BEQ; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, BNE) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm_bits <= 5) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_BNE; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LD) && rs1 == 30 && imm%8 == 0 && imm_bits <= 9) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LDSP; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LW) && rs1 == 30 && imm%4 == 0 && imm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LWSP; | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, imm/4); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SD) && rs1 == 30 && bimm%8 == 0 && bimm_bits <= 9) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SDSP; | 
|  | +    INSERT_OPERAND(CRS2, *insn, rs2); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, bimm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SW) && rs1 == 30 && bimm%4 == 0 && bimm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SWSP; | 
|  | +    INSERT_OPERAND(CRS2, *insn, rs2); | 
|  | +    INSERT_OPERAND(CIMM6, *insn, bimm/4); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%8 == 0 && imm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LD; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, imm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%4 == 0 && imm_bits <= 7) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LW; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, imm/4); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%8 == 0 && bimm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SD; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, SW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%4 == 0 && bimm_bits <= 7) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_SW; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm/4); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LD) && imm == 0) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LD0; | 
|  | +    INSERT_OPERAND(CRS1, *insn, rs1); | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, LW) && imm == 0) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_LW0; | 
|  | +    INSERT_OPERAND(CRS1, *insn, rs1); | 
|  | +    INSERT_OPERAND(CRD, *insn, rd); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, FLD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%8 == 0 && imm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_FLD; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, imm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, FLW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rd, rd) && imm%4 == 0 && imm_bits <= 7) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_FLW; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRDS, *insn, rvc_reg(rd, rd)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, imm/4); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, FSD) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%8 == 0 && bimm_bits <= 8) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_FSD; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm/8); | 
|  | +  } | 
|  | +  else if(INSN_MATCHES(*insn, FSW) && is_rvc_reg(rs1, rs1) && is_rvc_reg(rs2, rs2) && bimm%4 == 0 && bimm_bits <= 7) | 
|  | +  { | 
|  | +    insn->insn_opcode = MATCH_C_FSW; | 
|  | +    INSERT_OPERAND(CRS1S, *insn, rvc_reg(rs1, rs1)); | 
|  | +    INSERT_OPERAND(CRS2S, *insn, rvc_reg(rs2, rs2)); | 
|  | +    INSERT_OPERAND(CIMM5, *insn, bimm/4); | 
|  | +  } | 
|  | +  else | 
|  | +    return 0; | 
|  | + | 
|  | +  gas_assert(insn_length(insn) == 2); | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Initialise INSN from opcode entry MO.  Leave its position unspecified.  */ | 
|  | + | 
|  | +static void | 
|  | +create_insn (struct mips_cl_insn *insn, const struct riscv_opcode *mo) | 
|  | +{ | 
|  | +  size_t i; | 
|  | + | 
|  | +  insn->insn_mo = mo; | 
|  | +  insn->insn_opcode = mo->match; | 
|  | +  insn->frag = NULL; | 
|  | +  insn->where = 0; | 
|  | +  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++) | 
|  | +    insn->fixp[i] = NULL; | 
|  | +} | 
|  | + | 
|  | +/* Install INSN at the location specified by its "frag" and "where" fields.  */ | 
|  | + | 
|  | +static void | 
|  | +install_insn (const struct mips_cl_insn *insn) | 
|  | +{ | 
|  | +  char *f = insn->frag->fr_literal + insn->where; | 
|  | +  md_number_to_chars (f, insn->insn_opcode, insn_length(insn)); | 
|  | +} | 
|  | + | 
|  | +/* Move INSN to offset WHERE in FRAG.  Adjust the fixups accordingly | 
|  | +   and install the opcode in the new location.  */ | 
|  | + | 
|  | +static void | 
|  | +move_insn (struct mips_cl_insn *insn, fragS *frag, long where) | 
|  | +{ | 
|  | +  size_t i; | 
|  | + | 
|  | +  insn->frag = frag; | 
|  | +  insn->where = where; | 
|  | +  for (i = 0; i < ARRAY_SIZE (insn->fixp); i++) | 
|  | +    if (insn->fixp[i] != NULL) | 
|  | +      { | 
|  | +	insn->fixp[i]->fx_frag = frag; | 
|  | +	insn->fixp[i]->fx_where = where; | 
|  | +      } | 
|  | +  install_insn (insn); | 
|  | +} | 
|  | + | 
|  | +/* Add INSN to the end of the output.  */ | 
|  | + | 
|  | +static void | 
|  | +add_fixed_insn (struct mips_cl_insn *insn) | 
|  | +{ | 
|  | +  char *f = frag_more (insn_length (insn)); | 
|  | +  move_insn (insn, frag_now, f - frag_now->fr_literal); | 
|  | +} | 
|  | + | 
|  | +struct regname { | 
|  | +  const char *name; | 
|  | +  unsigned int num; | 
|  | +}; | 
|  | + | 
|  | +#define RTYPE_MASK	0x1ff00 | 
|  | +#define RTYPE_NUM	0x00100 | 
|  | +#define RTYPE_FPU	0x00200 | 
|  | +#define RTYPE_VEC	0x00800 | 
|  | +#define RTYPE_GP	0x01000 | 
|  | +#define RTYPE_CP0	0x02000 | 
|  | +#define RTYPE_VGR_REG	0x20000 | 
|  | +#define RTYPE_VFP_REG	0x40000 | 
|  | +#define RNUM_MASK	0x000ff | 
|  | +#define RWARN		0x80000 | 
|  | + | 
|  | +#define GENERIC_REGISTER_NUMBERS \ | 
|  | +    {"x0",	RTYPE_NUM | 0},  \ | 
|  | +    {"x1",	RTYPE_NUM | 1},  \ | 
|  | +    {"x2",	RTYPE_NUM | 2},  \ | 
|  | +    {"x3",	RTYPE_NUM | 3},  \ | 
|  | +    {"x4",	RTYPE_NUM | 4},  \ | 
|  | +    {"x5",	RTYPE_NUM | 5},  \ | 
|  | +    {"x6",	RTYPE_NUM | 6},  \ | 
|  | +    {"x7",	RTYPE_NUM | 7},  \ | 
|  | +    {"x8",	RTYPE_NUM | 8},  \ | 
|  | +    {"x9",	RTYPE_NUM | 9},  \ | 
|  | +    {"x10",	RTYPE_NUM | 10}, \ | 
|  | +    {"x11",	RTYPE_NUM | 11}, \ | 
|  | +    {"x12",	RTYPE_NUM | 12}, \ | 
|  | +    {"x13",	RTYPE_NUM | 13}, \ | 
|  | +    {"x14",	RTYPE_NUM | 14}, \ | 
|  | +    {"x15",	RTYPE_NUM | 15}, \ | 
|  | +    {"x16",	RTYPE_NUM | 16}, \ | 
|  | +    {"x17",	RTYPE_NUM | 17}, \ | 
|  | +    {"x18",	RTYPE_NUM | 18}, \ | 
|  | +    {"x19",	RTYPE_NUM | 19}, \ | 
|  | +    {"x20",	RTYPE_NUM | 20}, \ | 
|  | +    {"x21",	RTYPE_NUM | 21}, \ | 
|  | +    {"x22",	RTYPE_NUM | 22}, \ | 
|  | +    {"x23",	RTYPE_NUM | 23}, \ | 
|  | +    {"x24",	RTYPE_NUM | 24}, \ | 
|  | +    {"x25",	RTYPE_NUM | 25}, \ | 
|  | +    {"x26",	RTYPE_NUM | 26}, \ | 
|  | +    {"x27",	RTYPE_NUM | 27}, \ | 
|  | +    {"x28",	RTYPE_NUM | 28}, \ | 
|  | +    {"x29",	RTYPE_NUM | 29}, \ | 
|  | +    {"x30",	RTYPE_NUM | 30}, \ | 
|  | +    {"x31",	RTYPE_NUM | 31} | 
|  | + | 
|  | +#define FP_REGISTER_NAMES       \ | 
|  | +    {"f0",	RTYPE_FPU | 0},  \ | 
|  | +    {"f1",	RTYPE_FPU | 1},  \ | 
|  | +    {"f2",	RTYPE_FPU | 2},  \ | 
|  | +    {"f3",	RTYPE_FPU | 3},  \ | 
|  | +    {"f4",	RTYPE_FPU | 4},  \ | 
|  | +    {"f5",	RTYPE_FPU | 5},  \ | 
|  | +    {"f6",	RTYPE_FPU | 6},  \ | 
|  | +    {"f7",	RTYPE_FPU | 7},  \ | 
|  | +    {"f8",	RTYPE_FPU | 8},  \ | 
|  | +    {"f9",	RTYPE_FPU | 9},  \ | 
|  | +    {"f10",	RTYPE_FPU | 10}, \ | 
|  | +    {"f11",	RTYPE_FPU | 11}, \ | 
|  | +    {"f12",	RTYPE_FPU | 12}, \ | 
|  | +    {"f13",	RTYPE_FPU | 13}, \ | 
|  | +    {"f14",	RTYPE_FPU | 14}, \ | 
|  | +    {"f15",	RTYPE_FPU | 15}, \ | 
|  | +    {"f16",	RTYPE_FPU | 16}, \ | 
|  | +    {"f17",	RTYPE_FPU | 17}, \ | 
|  | +    {"f18",	RTYPE_FPU | 18}, \ | 
|  | +    {"f19",	RTYPE_FPU | 19}, \ | 
|  | +    {"f20",	RTYPE_FPU | 20}, \ | 
|  | +    {"f21",	RTYPE_FPU | 21}, \ | 
|  | +    {"f22",	RTYPE_FPU | 22}, \ | 
|  | +    {"f23",	RTYPE_FPU | 23}, \ | 
|  | +    {"f24",	RTYPE_FPU | 24}, \ | 
|  | +    {"f25",	RTYPE_FPU | 25}, \ | 
|  | +    {"f26",	RTYPE_FPU | 26}, \ | 
|  | +    {"f27",	RTYPE_FPU | 27}, \ | 
|  | +    {"f28",	RTYPE_FPU | 28}, \ | 
|  | +    {"f29",	RTYPE_FPU | 29}, \ | 
|  | +    {"f30",	RTYPE_FPU | 30}, \ | 
|  | +    {"f31",	RTYPE_FPU | 31} | 
|  | + | 
|  | +#define CR_REGISTER_NUMBERS \ | 
|  | +    {"cr0",	RTYPE_CP0 | 0},  \ | 
|  | +    {"cr1",	RTYPE_CP0 | 1},  \ | 
|  | +    {"cr2",	RTYPE_CP0 | 2},  \ | 
|  | +    {"cr3",	RTYPE_CP0 | 3},  \ | 
|  | +    {"cr4",	RTYPE_CP0 | 4},  \ | 
|  | +    {"cr5",	RTYPE_CP0 | 5},  \ | 
|  | +    {"cr6",	RTYPE_CP0 | 6},  \ | 
|  | +    {"cr7",	RTYPE_CP0 | 7},  \ | 
|  | +    {"cr8",	RTYPE_CP0 | 8},  \ | 
|  | +    {"cr9",	RTYPE_CP0 | 9},  \ | 
|  | +    {"cr10",	RTYPE_CP0 | 10}, \ | 
|  | +    {"cr11",	RTYPE_CP0 | 11}, \ | 
|  | +    {"cr12",	RTYPE_CP0 | 12}, \ | 
|  | +    {"cr13",	RTYPE_CP0 | 13}, \ | 
|  | +    {"cr14",	RTYPE_CP0 | 14}, \ | 
|  | +    {"cr15",	RTYPE_CP0 | 15}, \ | 
|  | +    {"cr16",	RTYPE_CP0 | 16}, \ | 
|  | +    {"cr17",	RTYPE_CP0 | 17}, \ | 
|  | +    {"cr18",	RTYPE_CP0 | 18}, \ | 
|  | +    {"cr19",	RTYPE_CP0 | 19}, \ | 
|  | +    {"cr20",	RTYPE_CP0 | 20}, \ | 
|  | +    {"cr21",	RTYPE_CP0 | 21}, \ | 
|  | +    {"cr22",	RTYPE_CP0 | 22}, \ | 
|  | +    {"cr23",	RTYPE_CP0 | 23}, \ | 
|  | +    {"cr24",	RTYPE_CP0 | 24}, \ | 
|  | +    {"cr25",	RTYPE_CP0 | 25}, \ | 
|  | +    {"cr26",	RTYPE_CP0 | 26}, \ | 
|  | +    {"cr27",	RTYPE_CP0 | 27}, \ | 
|  | +    {"cr28",	RTYPE_CP0 | 28}, \ | 
|  | +    {"cr29",	RTYPE_CP0 | 29}, \ | 
|  | +    {"cr30",	RTYPE_CP0 | 30}, \ | 
|  | +    {"cr31",	RTYPE_CP0 | 31} | 
|  | + | 
|  | +/* Remaining symbolic register names */ | 
|  | +#define SYMBOLIC_REGISTER_NAMES \ | 
|  | +  { "zero",	 0 | RTYPE_GP }, \ | 
|  | +  { "ra",	 1 | RTYPE_GP }, \ | 
|  | +  { "s0",	 2 | RTYPE_GP }, \ | 
|  | +  { "s1",	 3 | RTYPE_GP }, \ | 
|  | +  { "s2",	 4 | RTYPE_GP }, \ | 
|  | +  { "s3",	 5 | RTYPE_GP }, \ | 
|  | +  { "s4",	 6 | RTYPE_GP }, \ | 
|  | +  { "s5",	 7 | RTYPE_GP }, \ | 
|  | +  { "s6",	 8 | RTYPE_GP }, \ | 
|  | +  { "s7",	 9 | RTYPE_GP }, \ | 
|  | +  { "s8",	10 | RTYPE_GP }, \ | 
|  | +  { "s9",	11 | RTYPE_GP }, \ | 
|  | +  { "s10",	12 | RTYPE_GP }, \ | 
|  | +  { "s11",	13 | RTYPE_GP }, \ | 
|  | +  { "sp",	14 | RTYPE_GP }, \ | 
|  | +  { "tp",	15 | RTYPE_GP }, \ | 
|  | +  { "v0",	16 | RTYPE_GP }, \ | 
|  | +  { "v1",	17 | RTYPE_GP }, \ | 
|  | +  { "a0",	18 | RTYPE_GP }, \ | 
|  | +  { "a1",	19 | RTYPE_GP }, \ | 
|  | +  { "a2",	20 | RTYPE_GP }, \ | 
|  | +  { "a3",	21 | RTYPE_GP }, \ | 
|  | +  { "a4",	22 | RTYPE_GP }, \ | 
|  | +  { "a5",	23 | RTYPE_GP }, \ | 
|  | +  { "a6",	24 | RTYPE_GP }, \ | 
|  | +  { "a7",	25 | RTYPE_GP }, \ | 
|  | +  { "a8",	26 | RTYPE_GP }, \ | 
|  | +  { "a9",	27 | RTYPE_GP }, \ | 
|  | +  { "a10",	28 | RTYPE_GP }, \ | 
|  | +  { "a11",	29 | RTYPE_GP }, \ | 
|  | +  { "a12",	30 | RTYPE_GP }, \ | 
|  | +  { "a13",	31 | RTYPE_GP } | 
|  | + | 
|  | +#define FP_SYMBOLIC_REGISTER_NAMES  \ | 
|  | +  { "fs0",	 0 | RTYPE_FPU }, \ | 
|  | +  { "fs1",	 1 | RTYPE_FPU }, \ | 
|  | +  { "fs2",	 2 | RTYPE_FPU }, \ | 
|  | +  { "fs3",	 3 | RTYPE_FPU }, \ | 
|  | +  { "fs4",	 4 | RTYPE_FPU }, \ | 
|  | +  { "fs5",	 5 | RTYPE_FPU }, \ | 
|  | +  { "fs6",	 6 | RTYPE_FPU }, \ | 
|  | +  { "fs7",	 7 | RTYPE_FPU }, \ | 
|  | +  { "fs8",	 8 | RTYPE_FPU }, \ | 
|  | +  { "fs9",	 9 | RTYPE_FPU }, \ | 
|  | +  { "fs10",	10 | RTYPE_FPU }, \ | 
|  | +  { "fs11",	11 | RTYPE_FPU }, \ | 
|  | +  { "fs12",	12 | RTYPE_FPU }, \ | 
|  | +  { "fs13",	13 | RTYPE_FPU }, \ | 
|  | +  { "fs14",	14 | RTYPE_FPU }, \ | 
|  | +  { "fs15",	15 | RTYPE_FPU }, \ | 
|  | +  { "fv0",	16 | RTYPE_FPU }, \ | 
|  | +  { "fv1",	17 | RTYPE_FPU }, \ | 
|  | +  { "fa0",	18 | RTYPE_FPU }, \ | 
|  | +  { "fa1",	19 | RTYPE_FPU }, \ | 
|  | +  { "fa2",	20 | RTYPE_FPU }, \ | 
|  | +  { "fa3",	21 | RTYPE_FPU }, \ | 
|  | +  { "fa4",	22 | RTYPE_FPU }, \ | 
|  | +  { "fa5",	23 | RTYPE_FPU }, \ | 
|  | +  { "fa6",	24 | RTYPE_FPU }, \ | 
|  | +  { "fa7",	25 | RTYPE_FPU }, \ | 
|  | +  { "fa8",	26 | RTYPE_FPU }, \ | 
|  | +  { "fa9",	27 | RTYPE_FPU }, \ | 
|  | +  { "fa10",	28 | RTYPE_FPU }, \ | 
|  | +  { "fa11",	29 | RTYPE_FPU }, \ | 
|  | +  { "fa12",	30 | RTYPE_FPU }, \ | 
|  | +  { "fa13",	31 | RTYPE_FPU } | 
|  | + | 
|  | +#define RISCV_VEC_GR_REGISTER_NAMES \ | 
|  | +    {"vx0",	RTYPE_VGR_REG | 0}, \ | 
|  | +    {"vx1",	RTYPE_VGR_REG | 1}, \ | 
|  | +    {"vx2",	RTYPE_VGR_REG | 2}, \ | 
|  | +    {"vx3",	RTYPE_VGR_REG | 3}, \ | 
|  | +    {"vx4",	RTYPE_VGR_REG | 4}, \ | 
|  | +    {"vx5",	RTYPE_VGR_REG | 5}, \ | 
|  | +    {"vx6",	RTYPE_VGR_REG | 6}, \ | 
|  | +    {"vx7",	RTYPE_VGR_REG | 7}, \ | 
|  | +    {"vx8",	RTYPE_VGR_REG | 8}, \ | 
|  | +    {"vx9",	RTYPE_VGR_REG | 9}, \ | 
|  | +    {"vx10",	RTYPE_VGR_REG | 10}, \ | 
|  | +    {"vx11",	RTYPE_VGR_REG | 11}, \ | 
|  | +    {"vx12",	RTYPE_VGR_REG | 12}, \ | 
|  | +    {"vx13",	RTYPE_VGR_REG | 13}, \ | 
|  | +    {"vx14",	RTYPE_VGR_REG | 14}, \ | 
|  | +    {"vx15",	RTYPE_VGR_REG | 15}, \ | 
|  | +    {"vx16",	RTYPE_VGR_REG | 16}, \ | 
|  | +    {"vx17",	RTYPE_VGR_REG | 17}, \ | 
|  | +    {"vx18",	RTYPE_VGR_REG | 18}, \ | 
|  | +    {"vx19",	RTYPE_VGR_REG | 19}, \ | 
|  | +    {"vx20",	RTYPE_VGR_REG | 20}, \ | 
|  | +    {"vx21",	RTYPE_VGR_REG | 21}, \ | 
|  | +    {"vx22",	RTYPE_VGR_REG | 22}, \ | 
|  | +    {"vx23",	RTYPE_VGR_REG | 23}, \ | 
|  | +    {"vx24",	RTYPE_VGR_REG | 24}, \ | 
|  | +    {"vx25",	RTYPE_VGR_REG | 25}, \ | 
|  | +    {"vx26",	RTYPE_VGR_REG | 26}, \ | 
|  | +    {"vx27",	RTYPE_VGR_REG | 27}, \ | 
|  | +    {"vx28",	RTYPE_VGR_REG | 28}, \ | 
|  | +    {"vx29",	RTYPE_VGR_REG | 29}, \ | 
|  | +    {"vx30",	RTYPE_VGR_REG | 30}, \ | 
|  | +    {"vx31",	RTYPE_VGR_REG | 31} | 
|  | + | 
|  | +#define RISCV_VEC_FP_REGISTER_NAMES \ | 
|  | +    {"vf0",	RTYPE_VFP_REG | 0}, \ | 
|  | +    {"vf1",	RTYPE_VFP_REG | 1}, \ | 
|  | +    {"vf2",	RTYPE_VFP_REG | 2}, \ | 
|  | +    {"vf3",	RTYPE_VFP_REG | 3}, \ | 
|  | +    {"vf4",	RTYPE_VFP_REG | 4}, \ | 
|  | +    {"vf5",	RTYPE_VFP_REG | 5}, \ | 
|  | +    {"vf6",	RTYPE_VFP_REG | 6}, \ | 
|  | +    {"vf7",	RTYPE_VFP_REG | 7}, \ | 
|  | +    {"vf8",	RTYPE_VFP_REG | 8}, \ | 
|  | +    {"vf9",	RTYPE_VFP_REG | 9}, \ | 
|  | +    {"vf10",	RTYPE_VFP_REG | 10}, \ | 
|  | +    {"vf11",	RTYPE_VFP_REG | 11}, \ | 
|  | +    {"vf12",	RTYPE_VFP_REG | 12}, \ | 
|  | +    {"vf13",	RTYPE_VFP_REG | 13}, \ | 
|  | +    {"vf14",	RTYPE_VFP_REG | 14}, \ | 
|  | +    {"vf15",	RTYPE_VFP_REG | 15}, \ | 
|  | +    {"vf16",	RTYPE_VFP_REG | 16}, \ | 
|  | +    {"vf17",	RTYPE_VFP_REG | 17}, \ | 
|  | +    {"vf18",	RTYPE_VFP_REG | 18}, \ | 
|  | +    {"vf19",	RTYPE_VFP_REG | 19}, \ | 
|  | +    {"vf20",	RTYPE_VFP_REG | 20}, \ | 
|  | +    {"vf21",	RTYPE_VFP_REG | 21}, \ | 
|  | +    {"vf22",	RTYPE_VFP_REG | 22}, \ | 
|  | +    {"vf23",	RTYPE_VFP_REG | 23}, \ | 
|  | +    {"vf24",	RTYPE_VFP_REG | 24}, \ | 
|  | +    {"vf25",	RTYPE_VFP_REG | 25}, \ | 
|  | +    {"vf26",	RTYPE_VFP_REG | 26}, \ | 
|  | +    {"vf27",	RTYPE_VFP_REG | 27}, \ | 
|  | +    {"vf28",	RTYPE_VFP_REG | 28}, \ | 
|  | +    {"vf29",	RTYPE_VFP_REG | 29}, \ | 
|  | +    {"vf30",	RTYPE_VFP_REG | 30}, \ | 
|  | +    {"vf31",	RTYPE_VFP_REG | 31} | 
|  | + | 
|  | +static const struct regname reg_names[] = { | 
|  | +  GENERIC_REGISTER_NUMBERS, | 
|  | +  FP_REGISTER_NAMES, | 
|  | +  CR_REGISTER_NUMBERS, | 
|  | + | 
|  | +  SYMBOLIC_REGISTER_NAMES, | 
|  | +  FP_SYMBOLIC_REGISTER_NAMES, | 
|  | + | 
|  | +  RISCV_VEC_GR_REGISTER_NAMES, | 
|  | +  RISCV_VEC_FP_REGISTER_NAMES, | 
|  | + | 
|  | +  {0, 0} | 
|  | +}; | 
|  | + | 
|  | +static struct hash_control *reg_names_hash = NULL; | 
|  | + | 
|  | +static int | 
|  | +reg_lookup (char **s, unsigned int types, unsigned int *regnop) | 
|  | +{ | 
|  | +  struct regname *r; | 
|  | +  char *e; | 
|  | +  char save_c; | 
|  | +  int reg = -1; | 
|  | + | 
|  | +  /* Find end of name.  */ | 
|  | +  e = *s; | 
|  | +  if (is_name_beginner (*e)) | 
|  | +    ++e; | 
|  | +  while (is_part_of_name (*e)) | 
|  | +    ++e; | 
|  | + | 
|  | +  /* Terminate name.  */ | 
|  | +  save_c = *e; | 
|  | +  *e = '\0'; | 
|  | + | 
|  | +  /* Look for the register.  */ | 
|  | +  r = (struct regname *) hash_find (reg_names_hash, *s); | 
|  | +  if (r != NULL && (r->num & types)) | 
|  | +    reg = r->num & RNUM_MASK; | 
|  | + | 
|  | +  /* Advance to next token if a register was recognised.  */ | 
|  | +  if (reg >= 0) | 
|  | +    *s = e; | 
|  | +  else if (types & RWARN) | 
|  | +    as_warn ("Unrecognized register name `%s'", *s); | 
|  | + | 
|  | +  *e = save_c; | 
|  | +  if (regnop) | 
|  | +    *regnop = reg; | 
|  | +  return reg >= 0; | 
|  | +} | 
|  | + | 
|  | +/* This function is called once, at assembler startup time.  It should set up | 
|  | +   all the tables, etc. that the MD part of the assembler will need.  */ | 
|  | + | 
|  | +void | 
|  | +md_begin (void) | 
|  | +{ | 
|  | +  const char *retval = NULL; | 
|  | +  int i = 0; | 
|  | + | 
|  | +  if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, CPU_UNKNOWN)) | 
|  | +    as_warn (_("Could not set architecture and machine")); | 
|  | + | 
|  | +  op_hash = hash_new (); | 
|  | + | 
|  | +  for (i = 0; i < NUMOPCODES;) | 
|  | +    { | 
|  | +      const char *name = riscv_opcodes[i].name; | 
|  | + | 
|  | +      retval = hash_insert (op_hash, name, (void *) &riscv_opcodes[i]); | 
|  | +      if (retval != NULL) | 
|  | +	{ | 
|  | +	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"), | 
|  | +		   riscv_opcodes[i].name, retval); | 
|  | +	  /* Probably a memory allocation problem?  Give up now.  */ | 
|  | +	  as_fatal (_("Broken assembler.  No assembly attempted.")); | 
|  | +	} | 
|  | +      do | 
|  | +	{ | 
|  | +	  if (riscv_opcodes[i].pinfo != INSN_MACRO) | 
|  | +	    { | 
|  | +	      if (!validate_mips_insn (&riscv_opcodes[i])) | 
|  | +		as_fatal (_("Broken assembler.  No assembly attempted.")); | 
|  | +	    } | 
|  | +	  ++i; | 
|  | +	} | 
|  | +      while ((i < NUMOPCODES) && !strcmp (riscv_opcodes[i].name, name)); | 
|  | +    } | 
|  | + | 
|  | +  reg_names_hash = hash_new (); | 
|  | +  for (i = 0; reg_names[i].name; i++) | 
|  | +    { | 
|  | +      retval = hash_insert (reg_names_hash, reg_names[i].name, | 
|  | +			    (void*) ®_names[i]); | 
|  | +      if (retval != NULL) | 
|  | +	{ | 
|  | +	  fprintf (stderr, _("internal error: can't hash `%s': %s\n"), | 
|  | +		   reg_names[i].name, retval); | 
|  | +	  /* Probably a memory allocation problem?  Give up now.  */ | 
|  | +	  as_fatal (_("Broken assembler.  No assembly attempted.")); | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  mips_clear_insn_labels (); | 
|  | + | 
|  | +  mips_gprmask = 0; | 
|  | +  mips_fprmask = 0; | 
|  | + | 
|  | +  /* set the default alignment for the text section (2**2) */ | 
|  | +  record_alignment (text_section, 2); | 
|  | + | 
|  | +#ifdef OBJ_ELF | 
|  | +  if (IS_ELF) | 
|  | +    { | 
|  | +      /* Sections must be aligned to 16 byte boundaries.  When configured | 
|  | +         for an embedded ELF target, we don't bother.  */ | 
|  | +      if (strncmp (TARGET_OS, "elf", 3) != 0) | 
|  | +	{ | 
|  | +	  (void) bfd_set_section_alignment (stdoutput, text_section, 4); | 
|  | +	  (void) bfd_set_section_alignment (stdoutput, data_section, 4); | 
|  | +	  (void) bfd_set_section_alignment (stdoutput, bss_section, 4); | 
|  | +	} | 
|  | + | 
|  | +      /* Create a .reginfo section for register masks and a .mdebug | 
|  | +	 section for debugging information.  */ | 
|  | +      { | 
|  | +	segT seg; | 
|  | +	subsegT subseg; | 
|  | +	flagword flags; | 
|  | +	segT sec; | 
|  | + | 
|  | +	seg = now_seg; | 
|  | +	subseg = now_subseg; | 
|  | + | 
|  | +	/* The ABI says this section should be loaded so that the | 
|  | +	   running program can access it.  However, we don't load it | 
|  | +	   if we are configured for an embedded target */ | 
|  | +	flags = SEC_READONLY | SEC_DATA; | 
|  | +	if (strncmp (TARGET_OS, "elf", 3) != 0) | 
|  | +	  flags |= SEC_ALLOC | SEC_LOAD; | 
|  | + | 
|  | +	if (!rv64) | 
|  | +	  { | 
|  | +	    sec = subseg_new (".reginfo", (subsegT) 0); | 
|  | + | 
|  | +	    bfd_set_section_flags (stdoutput, sec, flags); | 
|  | +	    bfd_set_section_alignment (stdoutput, sec, 3); | 
|  | + | 
|  | +	    mips_regmask_frag = frag_more (sizeof (Elf32_External_RegInfo)); | 
|  | +	  } | 
|  | +	else | 
|  | +	  { | 
|  | +	    /* The 64-bit ABI uses a .MIPS.options section rather than | 
|  | +               .reginfo section.  */ | 
|  | +	    sec = subseg_new (".MIPS.options", (subsegT) 0); | 
|  | +	    bfd_set_section_flags (stdoutput, sec, flags); | 
|  | +	    bfd_set_section_alignment (stdoutput, sec, 3); | 
|  | + | 
|  | +	    /* Set up the option header.  */ | 
|  | +	    { | 
|  | +	      Elf_Internal_Options opthdr; | 
|  | +	      char *f; | 
|  | + | 
|  | +	      opthdr.kind = ODK_REGINFO; | 
|  | +	      opthdr.size = (sizeof (Elf_External_Options) | 
|  | +			     + sizeof (Elf64_External_RegInfo)); | 
|  | +	      opthdr.section = 0; | 
|  | +	      opthdr.info = 0; | 
|  | +	      f = frag_more (sizeof (Elf_External_Options)); | 
|  | +	      bfd_riscv_elf_swap_options_out (stdoutput, &opthdr, | 
|  | +					     (Elf_External_Options *) f); | 
|  | + | 
|  | +	      mips_regmask_frag = frag_more (sizeof (Elf64_External_RegInfo)); | 
|  | +	    } | 
|  | +	  } | 
|  | + | 
|  | +	subseg_set (seg, subseg); | 
|  | +      } | 
|  | +    } | 
|  | +#endif /* OBJ_ELF */ | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +md_assemble (char *str) | 
|  | +{ | 
|  | +  struct mips_cl_insn insn; | 
|  | +  bfd_reloc_code_real_type unused_reloc[3] | 
|  | +    = {BFD_RELOC_UNUSED, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; | 
|  | + | 
|  | +  imm_expr.X_op = O_absent; | 
|  | +  imm2_expr.X_op = O_absent; | 
|  | +  offset_expr.X_op = O_absent; | 
|  | +  imm_reloc[0] = BFD_RELOC_UNUSED; | 
|  | +  imm_reloc[1] = BFD_RELOC_UNUSED; | 
|  | +  imm_reloc[2] = BFD_RELOC_UNUSED; | 
|  | +  offset_reloc[0] = BFD_RELOC_UNUSED; | 
|  | +  offset_reloc[1] = BFD_RELOC_UNUSED; | 
|  | +  offset_reloc[2] = BFD_RELOC_UNUSED; | 
|  | + | 
|  | +  mips_ip (str, &insn); | 
|  | +  DBG ((_("returned from mips_ip(%s) insn_opcode = 0x%x\n"), | 
|  | +    str, insn.insn_opcode)); | 
|  | + | 
|  | + | 
|  | +  if (insn_error) | 
|  | +    { | 
|  | +      as_bad ("%s `%s'", insn_error, str); | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  if (insn.insn_mo->pinfo == INSN_MACRO) | 
|  | +    macro (&insn); | 
|  | +  else | 
|  | +    { | 
|  | +      if (imm_expr.X_op != O_absent) | 
|  | +	append_insn (&insn, &imm_expr, imm_reloc); | 
|  | +      else if (offset_expr.X_op != O_absent) | 
|  | +	append_insn (&insn, &offset_expr, offset_reloc); | 
|  | +      else | 
|  | +	append_insn (&insn, NULL, unused_reloc); | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +got16_reloc_p (bfd_reloc_code_real_type reloc) | 
|  | +{ | 
|  | +  return reloc == BFD_RELOC_MIPS_GOT16 || reloc == BFD_RELOC_MIPS16_GOT16; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +hi16_reloc_p (bfd_reloc_code_real_type reloc) | 
|  | +{ | 
|  | +  return reloc == BFD_RELOC_HI16_S || reloc == BFD_RELOC_MIPS16_HI16_S; | 
|  | +} | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +lo16_reloc_p (bfd_reloc_code_real_type reloc) | 
|  | +{ | 
|  | +  return reloc == BFD_RELOC_LO16 || reloc == BFD_RELOC_MIPS16_LO16; | 
|  | +} | 
|  | + | 
|  | +/* Return true if the given fixup is followed by a matching R_MIPS_LO16 | 
|  | +   relocation.  */ | 
|  | + | 
|  | +static inline bfd_boolean | 
|  | +fixup_has_matching_lo_p (fixS *fixp) | 
|  | +{ | 
|  | +  return (fixp->fx_next != NULL | 
|  | +	  && fixp->fx_next->fx_r_type == BFD_RELOC_LO16 | 
|  | +	  && fixp->fx_addsy == fixp->fx_next->fx_addsy | 
|  | +	  && fixp->fx_offset == fixp->fx_next->fx_offset); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +add_relaxed_insn (struct mips_cl_insn *insn, int max_chars, int var, | 
|  | +      relax_substateT subtype, symbolS *symbol, offsetT offset) | 
|  | +{ | 
|  | +  frag_grow (max_chars); | 
|  | +  move_insn (insn, frag_now, frag_more (0) - frag_now->fr_literal); | 
|  | +  frag_var (rs_machine_dependent, max_chars, var, | 
|  | +      subtype, symbol, offset, NULL); | 
|  | +} | 
|  | + | 
|  | +/* Output an instruction.  IP is the instruction information. | 
|  | +   ADDRESS_EXPR is an operand of the instruction to be used with | 
|  | +   RELOC_TYPE.  */ | 
|  | + | 
|  | +static void | 
|  | +append_insn (struct mips_cl_insn *ip, expressionS *address_expr, | 
|  | +	     bfd_reloc_code_real_type *reloc_type) | 
|  | +{ | 
|  | +  unsigned long pinfo; | 
|  | + | 
|  | +  pinfo = ip->insn_mo->pinfo; | 
|  | + | 
|  | +#ifdef OBJ_ELF | 
|  | +  /* The value passed to dwarf2_emit_insn is the distance between | 
|  | +     the beginning of the current instruction and the address that | 
|  | +     should be recorded in the debug tables.  For MIPS16 debug info | 
|  | +     we want to use ISA-encoded addresses, so we pass -1 for an | 
|  | +     address higher by one than the current.  */ | 
|  | +  dwarf2_emit_insn (0); | 
|  | +#endif | 
|  | + | 
|  | +  gas_assert(*reloc_type <= BFD_RELOC_UNUSED); | 
|  | + | 
|  | +  /* don't compress instructions with relocs */ | 
|  | +  int compressible = (*reloc_type == BFD_RELOC_UNUSED || | 
|  | +    address_expr == NULL || address_expr->X_op == O_constant) && mips_opts.rvc; | 
|  | + | 
|  | +  /* speculate that branches/jumps can be compressed.  if not, we'll relax. */ | 
|  | +  if (address_expr != NULL && mips_opts.rvc) | 
|  | +  { | 
|  | +    int compressible_branch = *reloc_type == BFD_RELOC_16_PCREL_S2 && | 
|  | +      (INSN_MATCHES(*ip, BEQ) || INSN_MATCHES(*ip, BNE)); | 
|  | +    int compressible_jump = *reloc_type == BFD_RELOC_MIPS_JMP && | 
|  | +      INSN_MATCHES(*ip, J); | 
|  | +    if(compressible_branch || compressible_jump) | 
|  | +    { | 
|  | +      if(riscv_rvc_compress(ip)) | 
|  | +      { | 
|  | +        add_relaxed_insn(ip, 4 /* worst case length */, 0, | 
|  | +                         RELAX_BRANCH_ENCODE(compressible_jump, 0), | 
|  | +                         address_expr->X_add_symbol, | 
|  | +                         address_expr->X_add_number); | 
|  | +        *reloc_type = BFD_RELOC_UNUSED; | 
|  | +        return; | 
|  | +      } | 
|  | +    } | 
|  | +  } | 
|  | + | 
|  | +  if(!compressible) | 
|  | +    add_fixed_insn(ip); | 
|  | + | 
|  | +  if (address_expr != NULL) | 
|  | +    { | 
|  | +      if (address_expr->X_op == O_constant) | 
|  | +	{ | 
|  | +	  unsigned int tmp; | 
|  | + | 
|  | +	  switch (*reloc_type) | 
|  | +	    { | 
|  | +	    case BFD_RELOC_32: | 
|  | +	      ip->insn_opcode |= address_expr->X_add_number; | 
|  | +	      break; | 
|  | + | 
|  | +	    case BFD_RELOC_HI16_S: | 
|  | +	      tmp = (address_expr->X_add_number + RISCV_IMM_REACH/2) >> RISCV_IMM_BITS; | 
|  | +	      ip->insn_opcode |= (tmp & ((1<<(32-RISCV_IMM_BITS))-1)) << OP_SH_BIGIMMEDIATE; // assumes lui bits == 32 - imm bits | 
|  | +	      break; | 
|  | + | 
|  | +	    case BFD_RELOC_HI16: | 
|  | +	      ip->insn_opcode |= ((address_expr->X_add_number >> RISCV_IMM_BITS) & (RISCV_BIGIMM_REACH-1)) << OP_SH_BIGIMMEDIATE; | 
|  | +	      break; | 
|  | + | 
|  | +	    case BFD_RELOC_UNUSED: | 
|  | +	    case BFD_RELOC_LO16: | 
|  | +	    case BFD_RELOC_MIPS_GOT_DISP: | 
|  | +		  /* Stores have a split immediate field. */ | 
|  | +	      if (OPCODE_IS_STORE(ip->insn_opcode)) | 
|  | +		{ | 
|  | +		  int value = address_expr->X_add_number & (RISCV_IMM_REACH-1); | 
|  | +		  value = ((value >> RISCV_IMMLO_BITS) << OP_SH_IMMHI) | | 
|  | +		          ((value & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO); | 
|  | +		  ip->insn_opcode |= value; | 
|  | +		} | 
|  | +	      else | 
|  | +	        ip->insn_opcode |= (address_expr->X_add_number & (RISCV_IMM_REACH-1)) << OP_SH_IMMEDIATE; | 
|  | +	      break; | 
|  | + | 
|  | +	    case BFD_RELOC_MIPS_JMP: | 
|  | +	      if ((address_expr->X_add_number & 1) != 0) | 
|  | +		as_bad (_("jump to misaligned address (0x%lx)"), | 
|  | +			(unsigned long) address_expr->X_add_number); | 
|  | +	      if ((address_expr->X_add_number + RISCV_JUMP_REACH/2) & (RISCV_JUMP_REACH-1)) | 
|  | +		as_bad (_("jump address range overflow (0x%lx)"), | 
|  | +			(unsigned long) address_expr->X_add_number); | 
|  | +	      ip->insn_opcode |= ((unsigned long long)(address_expr->X_add_number & (RISCV_JUMP_REACH-1))/RISCV_JUMP_ALIGN) << OP_SH_TARGET; | 
|  | +	      break; | 
|  | + | 
|  | +	    case BFD_RELOC_16_PCREL_S2: | 
|  | +	      if ((address_expr->X_add_number & 1) != 0) | 
|  | +		as_bad (_("branch to misaligned address (0x%lx)"), | 
|  | +			(unsigned long) address_expr->X_add_number); | 
|  | +	      if ((address_expr->X_add_number + RISCV_BRANCH_REACH/2) & (RISCV_BRANCH_REACH-1)) | 
|  | +		as_bad (_("branch address range overflow (0x%lx)"), | 
|  | +			(unsigned long) address_expr->X_add_number); | 
|  | +	      unsigned delta = (((unsigned)address_expr->X_add_number & (RISCV_BRANCH_REACH-1)) >> RISCV_BRANCH_ALIGN_BITS) & ((1<<RISCV_BRANCH_BITS)-1); | 
|  | +	      ip->insn_opcode |= ((delta & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO) | (((delta >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1)) << OP_SH_IMMHI); | 
|  | +	      break; | 
|  | + | 
|  | +	    default: | 
|  | +	      internalError (); | 
|  | +	    } | 
|  | +	    *reloc_type = BFD_RELOC_UNUSED; | 
|  | +	} | 
|  | +      else if (*reloc_type < BFD_RELOC_UNUSED) | 
|  | +	{ | 
|  | +	  reloc_howto_type *howto; | 
|  | +	  int i; | 
|  | + | 
|  | +	  /* In a compound relocation, it is the final (outermost) | 
|  | +	     operator that determines the relocated field.  */ | 
|  | +	  for (i = 1; i < 3; i++) | 
|  | +	    if (reloc_type[i] == BFD_RELOC_UNUSED) | 
|  | +	      break; | 
|  | + | 
|  | +	  howto = bfd_reloc_type_lookup (stdoutput, reloc_type[i - 1]); | 
|  | +	  if (howto == NULL) | 
|  | +	    as_bad (_("Unsupported MIPS relocation number %d"), reloc_type[i - 1]); | 
|  | + | 
|  | +	  ip->fixp[0] = fix_new_exp (ip->frag, ip->where, | 
|  | +				     bfd_get_reloc_size (howto), | 
|  | +				     address_expr, | 
|  | +				     reloc_type[0] == BFD_RELOC_16_PCREL_S2 || | 
|  | +				     reloc_type[0] == BFD_RELOC_MIPS_JMP, | 
|  | +				     reloc_type[0]); | 
|  | + | 
|  | +	  /* These relocations can have an addend that won't fit in | 
|  | +	     4 octets for 64bit assembly.  */ | 
|  | +	  if (rv64 | 
|  | +	      && ! howto->partial_inplace | 
|  | +	      && (reloc_type[0] == BFD_RELOC_32 | 
|  | +		  || reloc_type[0] == BFD_RELOC_GPREL16 | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS_LITERAL | 
|  | +		  || reloc_type[0] == BFD_RELOC_GPREL32 | 
|  | +		  || reloc_type[0] == BFD_RELOC_64 | 
|  | +		  || reloc_type[0] == BFD_RELOC_CTOR | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS_SUB | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS_SCN_DISP | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS_REL16 | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS_RELGOT | 
|  | +		  || reloc_type[0] == BFD_RELOC_MIPS16_GPREL | 
|  | +		  || hi16_reloc_p (reloc_type[0]) | 
|  | +		  || lo16_reloc_p (reloc_type[0]))) | 
|  | +	    ip->fixp[0]->fx_no_overflow = 1; | 
|  | + | 
|  | +	  /* Add fixups for the second and third relocations, if given. | 
|  | +	     Note that the ABI allows the second relocation to be | 
|  | +	     against RSS_UNDEF, RSS_GP, RSS_GP0 or RSS_LOC.  At the | 
|  | +	     moment we only use RSS_UNDEF, but we could add support | 
|  | +	     for the others if it ever becomes necessary.  */ | 
|  | +	  for (i = 1; i < 3; i++) | 
|  | +	    if (reloc_type[i] != BFD_RELOC_UNUSED) | 
|  | +	      { | 
|  | +		ip->fixp[i] = fix_new (ip->frag, ip->where, | 
|  | +				       ip->fixp[0]->fx_size, NULL, 0, | 
|  | +				       FALSE, reloc_type[i]); | 
|  | + | 
|  | +		/* Use fx_tcbit to mark compound relocs.  */ | 
|  | +		ip->fixp[0]->fx_tcbit = 1; | 
|  | +		ip->fixp[i]->fx_tcbit = 1; | 
|  | +	      } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  if(compressible) | 
|  | +  { | 
|  | +    riscv_rvc_compress(ip); | 
|  | +    add_fixed_insn (ip); | 
|  | +  } | 
|  | + | 
|  | +  install_insn (ip); | 
|  | + | 
|  | +  /* Update the register mask information.  */ | 
|  | +      if (pinfo & INSN_WRITE_GPR_D) | 
|  | +	mips_gprmask |= 1 << EXTRACT_OPERAND (RD, *ip); | 
|  | +      if (pinfo & INSN_WRITE_GPR_RA) | 
|  | +	mips_gprmask |= 1 << RA; | 
|  | +      if (pinfo & INSN_WRITE_FPR_D) | 
|  | +	mips_fprmask |= 1 << EXTRACT_OPERAND (FD, *ip); | 
|  | + | 
|  | +      if (pinfo & INSN_READ_GPR_S) | 
|  | +	mips_gprmask |= 1 << EXTRACT_OPERAND (RS, *ip); | 
|  | +      if (pinfo & INSN_READ_GPR_T) | 
|  | +	mips_gprmask |= 1 << EXTRACT_OPERAND (RT, *ip); | 
|  | +      if (pinfo & INSN_READ_FPR_S) | 
|  | +	mips_fprmask |= 1 << EXTRACT_OPERAND (FS, *ip); | 
|  | +      if (pinfo & INSN_READ_FPR_T) | 
|  | +	mips_fprmask |= 1 << EXTRACT_OPERAND (FT, *ip); | 
|  | +      if (pinfo & INSN_READ_FPR_R) | 
|  | +	mips_fprmask |= 1 << EXTRACT_OPERAND (FR, *ip); | 
|  | +      /* Never set the bit for $0, which is always zero.  */ | 
|  | +      mips_gprmask &= ~1 << 0; | 
|  | + | 
|  | +  /* We just output an insn, so the next one doesn't have a label.  */ | 
|  | +  mips_clear_insn_labels (); | 
|  | +} | 
|  | + | 
|  | +/* Read a macro's relocation codes from *ARGS and store them in *R. | 
|  | +   The first argument in *ARGS will be either the code for a single | 
|  | +   relocation or -1 followed by the three codes that make up a | 
|  | +   composite relocation.  */ | 
|  | + | 
|  | +static void | 
|  | +macro_read_relocs (va_list *args, bfd_reloc_code_real_type *r) | 
|  | +{ | 
|  | +  int i, next; | 
|  | + | 
|  | +  next = va_arg (*args, int); | 
|  | +  if (next >= 0) | 
|  | +    r[0] = (bfd_reloc_code_real_type) next; | 
|  | +  else | 
|  | +    for (i = 0; i < 3; i++) | 
|  | +      r[i] = (bfd_reloc_code_real_type) va_arg (*args, int); | 
|  | +} | 
|  | + | 
|  | +/* Build an instruction created by a macro expansion.  This is passed | 
|  | +   a pointer to the count of instructions created so far, an | 
|  | +   expression, the name of the instruction to build, an operand format | 
|  | +   string, and corresponding arguments.  */ | 
|  | + | 
|  | +static void | 
|  | +macro_build (expressionS *ep, const char *name, const char *fmt, ...) | 
|  | +{ | 
|  | +  const struct riscv_opcode *mo; | 
|  | +  struct mips_cl_insn insn; | 
|  | +  bfd_reloc_code_real_type r[3]; | 
|  | +  va_list args; | 
|  | + | 
|  | +  va_start (args, fmt); | 
|  | + | 
|  | +  r[0] = BFD_RELOC_UNUSED; | 
|  | +  r[1] = BFD_RELOC_UNUSED; | 
|  | +  r[2] = BFD_RELOC_UNUSED; | 
|  | +  mo = (struct riscv_opcode *) hash_find (op_hash, name); | 
|  | +  gas_assert (mo); | 
|  | +  gas_assert (strcmp (name, mo->name) == 0); | 
|  | + | 
|  | +  create_insn (&insn, mo); | 
|  | +  for (;;) | 
|  | +    { | 
|  | +      switch (*fmt++) | 
|  | +	{ | 
|  | +	case '\0': | 
|  | +	  break; | 
|  | + | 
|  | +        case '#': | 
|  | +          switch ( *fmt++ ) { | 
|  | +            case 'g': | 
|  | +              INSERT_OPERAND( IMMNGPR, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'f': | 
|  | +              INSERT_OPERAND( IMMNFPR, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'n': | 
|  | +              INSERT_OPERAND( IMMSEGNELM, insn, va_arg( args, int ) - 1 ); | 
|  | +              continue; | 
|  | +            case 'm': | 
|  | +              INSERT_OPERAND( IMMSEGSTNELM, insn, va_arg( args, int ) - 1 ); | 
|  | +              continue; | 
|  | +            case 'd': | 
|  | +              INSERT_OPERAND( VRD, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 's': | 
|  | +              INSERT_OPERAND( VRS, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 't': | 
|  | +              INSERT_OPERAND( VRT, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'r': | 
|  | +              INSERT_OPERAND( VRR, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'D': | 
|  | +              INSERT_OPERAND( VFD, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'S': | 
|  | +              INSERT_OPERAND( VFS, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'T': | 
|  | +              INSERT_OPERAND( VFT, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            case 'R': | 
|  | +              INSERT_OPERAND( VFR, insn, va_arg( args, int ) ); | 
|  | +              continue; | 
|  | +            default: | 
|  | +              internalError(); | 
|  | +          } | 
|  | +          continue; | 
|  | + | 
|  | +	case ',': | 
|  | +	case '(': | 
|  | +	case ')': | 
|  | +	  continue; | 
|  | + | 
|  | +	case 't': | 
|  | +	  INSERT_OPERAND (RT, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'T': | 
|  | +	case 'W': | 
|  | +	  INSERT_OPERAND (FT, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'd': | 
|  | +	  INSERT_OPERAND (RD, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'U': | 
|  | +	  { | 
|  | +	    int tmp = va_arg (args, int); | 
|  | + | 
|  | +	    INSERT_OPERAND (RT, insn, tmp); | 
|  | +	    INSERT_OPERAND (RD, insn, tmp); | 
|  | +	    continue; | 
|  | +	  } | 
|  | + | 
|  | +	case 'S': | 
|  | +	  INSERT_OPERAND (FS, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'z': | 
|  | +	  continue; | 
|  | + | 
|  | +	case '<': | 
|  | +	  INSERT_OPERAND (SHAMTW, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case '>': | 
|  | +	  INSERT_OPERAND (SHAMT, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'D': | 
|  | +	  INSERT_OPERAND (FD, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'b': | 
|  | +	case 's': | 
|  | +	case 'E': | 
|  | +	  INSERT_OPERAND (RS, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'm': | 
|  | +	  INSERT_OPERAND (RM, insn, va_arg (args, int)); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'O': /* An off-by-4 PC-relative address for PIC. */ | 
|  | +	  INSERT_OPERAND (IMMEDIATE, insn, 4); | 
|  | +	  macro_read_relocs (&args, r); | 
|  | +	  gas_assert (*r == BFD_RELOC_RISCV_TLS_GD_LO16 | 
|  | +		  || *r == BFD_RELOC_RISCV_TLS_GOT_LO16 | 
|  | +		  || *r == BFD_RELOC_MIPS_GOT_LO16); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'j': | 
|  | +	  macro_read_relocs (&args, r); | 
|  | +	  gas_assert (*r == BFD_RELOC_GPREL16 | 
|  | +		  || *r == BFD_RELOC_MIPS_LITERAL | 
|  | +		  || *r == BFD_RELOC_LO16 | 
|  | +		  || *r == BFD_RELOC_MIPS_GOT16 | 
|  | +		  || *r == BFD_RELOC_MIPS_CALL16 | 
|  | +		  || *r == BFD_RELOC_MIPS_GOT_DISP | 
|  | +		  || *r == BFD_RELOC_MIPS_GOT_LO16 | 
|  | +		  || *r == BFD_RELOC_MIPS_CALL_LO16); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'u': | 
|  | +	  macro_read_relocs (&args, r); | 
|  | +	  gas_assert (ep != NULL | 
|  | +		  && (ep->X_op == O_constant | 
|  | +		      || (ep->X_op == O_symbol | 
|  | +			  && (*r == BFD_RELOC_HI16_S | 
|  | +			      || *r == BFD_RELOC_HI16 | 
|  | +			      /*|| *r == BFD_RELOC_GPREL16*/ | 
|  | +			      || *r == BFD_RELOC_MIPS_GOT_HI16 | 
|  | +			      || *r == BFD_RELOC_MIPS_CALL_HI16)))); | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'p': | 
|  | +	  gas_assert (ep != NULL); | 
|  | + | 
|  | +	  /* | 
|  | +	   * This allows macro() to pass an immediate expression for | 
|  | +	   * creating short branches without creating a symbol. | 
|  | +	   * | 
|  | +	   * We don't allow branch relaxation for these branches, as | 
|  | +	   * they should only appear in ".set nomacro" anyway. | 
|  | +	   */ | 
|  | +	  if (ep->X_op == O_constant) | 
|  | +	    { | 
|  | +	      unsigned long long delta; | 
|  | +	      if ((ep->X_add_number & (RISCV_BRANCH_ALIGN-1)) != 0) | 
|  | +		as_bad (_("branch to misaligned address (0x%lx)"), | 
|  | +			(unsigned long) ep->X_add_number); | 
|  | +	      if ((ep->X_add_number + RISCV_BRANCH_REACH/2) & ~(RISCV_BRANCH_REACH-1)) | 
|  | +		as_bad (_("branch address range overflow (0x%lx)"), | 
|  | +			(unsigned long) ep->X_add_number); | 
|  | +	      delta = (unsigned long long)(ep->X_add_number & (RISCV_BRANCH_REACH-1))/RISCV_BRANCH_ALIGN; | 
|  | +	      insn.insn_opcode |= ((delta & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO) | (((delta >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1)) << OP_SH_IMMHI); | 
|  | +	      ep = NULL; | 
|  | +	    } | 
|  | +	  else | 
|  | +	    *r = BFD_RELOC_16_PCREL_S2; | 
|  | +	  continue; | 
|  | + | 
|  | +	case 'a': | 
|  | +	  gas_assert (ep != NULL); | 
|  | +	  if (ep->X_op == O_constant) | 
|  | +	    { | 
|  | +	      if ((ep->X_add_number & (RISCV_JUMP_ALIGN-1)) != 0) | 
|  | +		as_bad (_("jump to misaligned address (0x%lx)"), | 
|  | +			(unsigned long) ep->X_add_number); | 
|  | +	      if ((ep->X_add_number + RISCV_JUMP_REACH/2) & ~(RISCV_JUMP_REACH-1)) | 
|  | +		as_bad (_("jump address range overflow (0x%lx)"), | 
|  | +			(unsigned long) ep->X_add_number); | 
|  | +	      insn.insn_opcode |= ((unsigned long long)(ep->X_add_number & (RISCV_JUMP_REACH-1))/RISCV_JUMP_ALIGN) << OP_SH_TARGET; | 
|  | +	      ep = NULL; | 
|  | +	    } | 
|  | +	  else | 
|  | +	    *r = BFD_RELOC_MIPS_JMP; | 
|  | +	  continue; | 
|  | + | 
|  | +	default: | 
|  | +	  internalError (); | 
|  | +	} | 
|  | +      break; | 
|  | +    } | 
|  | +  va_end (args); | 
|  | +  gas_assert (*r == BFD_RELOC_UNUSED ? ep == NULL : ep != NULL); | 
|  | + | 
|  | +  append_insn (&insn, ep, r); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | + * Sign-extend 32-bit mode constants that have bit 31 set and all | 
|  | + * higher bits unset. | 
|  | + */ | 
|  | +static void | 
|  | +normalize_constant_expr (expressionS *ex) | 
|  | +{ | 
|  | +  if (rv64) | 
|  | +    return; | 
|  | +  if (ex->X_op == O_constant | 
|  | +      && IS_ZEXT_32BIT_NUM (ex->X_add_number)) | 
|  | +    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000) | 
|  | +			- 0x80000000); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | + * Sign-extend 32-bit mode address offsets that have bit 31 set and | 
|  | + * all higher bits unset. | 
|  | + */ | 
|  | +static void | 
|  | +normalize_address_expr (expressionS *ex) | 
|  | +{ | 
|  | +  if (((ex->X_op == O_constant && HAVE_32BIT_ADDRESSES) | 
|  | +	|| (ex->X_op == O_symbol && HAVE_32BIT_SYMBOLS)) | 
|  | +      && IS_ZEXT_32BIT_NUM (ex->X_add_number)) | 
|  | +    ex->X_add_number = (((ex->X_add_number & 0xffffffff) ^ 0x80000000) | 
|  | +			- 0x80000000); | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | + * Generate a "lui" instruction. | 
|  | + */ | 
|  | +static void | 
|  | +macro_build_lui (const char* name, expressionS *ep, int regnum, bfd_reloc_code_real_type reloc) | 
|  | +{ | 
|  | +  const struct riscv_opcode *mo; | 
|  | +  struct mips_cl_insn insn; | 
|  | +  bfd_reloc_code_real_type r[3] = {reloc, BFD_RELOC_UNUSED, BFD_RELOC_UNUSED}; | 
|  | + | 
|  | +  gas_assert (ep->X_op == O_symbol); | 
|  | + | 
|  | +  mo = hash_find (op_hash, name); | 
|  | +  gas_assert (mo); | 
|  | +  create_insn (&insn, mo); | 
|  | + | 
|  | +  insn.insn_opcode = insn.insn_mo->match; | 
|  | +  INSERT_OPERAND (RD, insn, regnum); | 
|  | +  append_insn (&insn, ep, r); | 
|  | +} | 
|  | + | 
|  | +/* Load an entry from the GOT. */ | 
|  | +static void | 
|  | +load_static_addr (int destreg, expressionS *ep) | 
|  | +{ | 
|  | +  macro_build_lui ("lui", ep, destreg, BFD_RELOC_HI16_S); | 
|  | +  macro_build (ep, "addi", "d,s,j", destreg, destreg, BFD_RELOC_LO16); | 
|  | +} | 
|  | + | 
|  | +/* Load an entry from the GOT. */ | 
|  | +static void | 
|  | +load_got_addr (int destreg, expressionS *ep, const char* lo_insn, | 
|  | +               bfd_reloc_code_real_type hi_reloc, | 
|  | +	       bfd_reloc_code_real_type lo_reloc) | 
|  | +{ | 
|  | +  macro_build_lui ("auipc", ep, destreg, hi_reloc); | 
|  | +  macro_build (ep, lo_insn, "d,O(b)", destreg, lo_reloc, destreg); | 
|  | +} | 
|  | + | 
|  | +/* Warn if an expression is not a constant.  */ | 
|  | + | 
|  | +static void | 
|  | +check_absolute_expr (struct mips_cl_insn *ip, expressionS *ex) | 
|  | +{ | 
|  | +  if (ex->X_op == O_big) | 
|  | +    as_bad (_("unsupported large constant")); | 
|  | +  else if (ex->X_op != O_constant) | 
|  | +    as_bad (_("Instruction %s requires absolute expression"), | 
|  | +	    ip->insn_mo->name); | 
|  | +  normalize_constant_expr (ex); | 
|  | +} | 
|  | + | 
|  | +/* load_const generates an unoptimized instruction sequence to load | 
|  | + * an absolute expression into a register. */ | 
|  | +static void | 
|  | +load_const (int reg, expressionS *ep) | 
|  | +{ | 
|  | +  gas_assert (ep->X_op == O_constant); | 
|  | +  gas_assert (reg != ZERO); | 
|  | + | 
|  | +  // this is an awful way to generate arbitrary 64-bit constants. | 
|  | +  // fortunately, this is just used for hand-coded assembly programs. | 
|  | +  if (rv64 && !IS_SEXT_32BIT_NUM(ep->X_add_number)) | 
|  | +  { | 
|  | +    expressionS upper = *ep, lower = *ep; | 
|  | +    upper.X_add_number = (int64_t)ep->X_add_number >> (RISCV_IMM_BITS-1); | 
|  | +    load_const(reg, &upper); | 
|  | + | 
|  | +    macro_build (NULL, "slli", "d,s,>", reg, reg, RISCV_IMM_BITS-1); | 
|  | + | 
|  | +    lower.X_add_number = ep->X_add_number & (RISCV_IMM_REACH/2-1); | 
|  | +    if (lower.X_add_number != 0) | 
|  | +      macro_build (&lower, "addi", "d,s,j", reg, reg, BFD_RELOC_LO16); | 
|  | +  } | 
|  | +  else // load a sign-extended 32-bit constant | 
|  | +  { | 
|  | +    int hi_reg = ZERO; | 
|  | + | 
|  | +    int32_t hi = ep->X_add_number & (RISCV_IMM_REACH-1); | 
|  | +    hi = hi << (32-RISCV_IMM_BITS) >> (32-RISCV_IMM_BITS); | 
|  | +    hi = (int32_t)ep->X_add_number - hi; | 
|  | +    if(hi) | 
|  | +    { | 
|  | +      macro_build (ep, "lui", "d,u", reg, BFD_RELOC_HI16_S); | 
|  | +      hi_reg = reg; | 
|  | +    } | 
|  | + | 
|  | +    if((ep->X_add_number & (RISCV_IMM_REACH-1)) || hi_reg == ZERO) | 
|  | +      macro_build (ep, ADD32_INSN, "d,s,j", reg, hi_reg, BFD_RELOC_LO16); | 
|  | +  } | 
|  | +} | 
|  | + | 
|  | +/* | 
|  | + *			Build macros | 
|  | + *   This routine implements the seemingly endless macro or synthesized | 
|  | + * instructions and addressing modes in the mips assembly language. Many | 
|  | + * of these macros are simple and are similar to each other. These could | 
|  | + * probably be handled by some kind of table or grammar approach instead of | 
|  | + * this verbose method. Others are not simple macros but are more like | 
|  | + * optimizing code generation. | 
|  | + *   One interesting optimization is when several store macros appear | 
|  | + * consecutively that would load AT with the upper half of the same address. | 
|  | + * The ensuing load upper instructions are ommited. This implies some kind | 
|  | + * of global optimization. We currently only optimize within a single macro. | 
|  | + *   For many of the load and store macros if the address is specified as a | 
|  | + * constant expression in the first 64k of memory (ie ld $2,0x4000c) we | 
|  | + * first load register 'at' with zero and use it as the base register. The | 
|  | + * mips assembler simply uses register $zero. Just one tiny optimization | 
|  | + * we're missing. | 
|  | + */ | 
|  | +static void | 
|  | +macro (struct mips_cl_insn *ip) | 
|  | +{ | 
|  | +  unsigned int sreg, dreg, breg; | 
|  | +  int mask; | 
|  | + | 
|  | +  dreg = (ip->insn_opcode >> OP_SH_RD) & OP_MASK_RD; | 
|  | +  breg = sreg = (ip->insn_opcode >> OP_SH_RS) & OP_MASK_RS; | 
|  | +  mask = ip->insn_mo->mask; | 
|  | + | 
|  | +  switch (mask) | 
|  | +    { | 
|  | +    case M_LA_AB: | 
|  | +      /* Load the address of a symbol into a register. */ | 
|  | +      if (!IS_SEXT_32BIT_NUM (offset_expr.X_add_number)) | 
|  | +        as_bad(_("offset too large")); | 
|  | +      if (breg == dreg && breg != ZERO) | 
|  | +        as_bad(_("expression too complex: dest and base regs must differ")); | 
|  | + | 
|  | +      if (offset_expr.X_op == O_constant) | 
|  | +        load_const (dreg, &offset_expr); | 
|  | +      else if (is_pic) /* O_symbol */ | 
|  | +	load_got_addr (dreg, &offset_expr, LOAD_ADDRESS_INSN, | 
|  | +	               BFD_RELOC_MIPS_GOT_HI16, BFD_RELOC_MIPS_GOT_LO16); | 
|  | +      else /* non-PIC O_symbol */ | 
|  | +	load_static_addr (dreg, &offset_expr); | 
|  | + | 
|  | +      if (breg != ZERO) | 
|  | +        macro_build (NULL, "add", "d,s,t", dreg, dreg, breg); | 
|  | +      break; | 
|  | + | 
|  | +    case M_LA_TLS_GD: | 
|  | +      load_got_addr(dreg, &offset_expr, "addi", | 
|  | +                    BFD_RELOC_RISCV_TLS_GD_HI16, BFD_RELOC_RISCV_TLS_GD_LO16); | 
|  | +      break; | 
|  | + | 
|  | +    case M_LA_TLS_IE: | 
|  | +      load_got_addr(dreg, &offset_expr, LOAD_ADDRESS_INSN, | 
|  | +                    BFD_RELOC_RISCV_TLS_GOT_HI16, BFD_RELOC_RISCV_TLS_GOT_LO16); | 
|  | +      break; | 
|  | + | 
|  | +    case M_J: /* replace "j $rs" with "ret" if rs=ra, else with "jr $rs" */ | 
|  | +      if (sreg == LINK_REG) | 
|  | +        macro_build (NULL, "ret", ""); | 
|  | +      else | 
|  | +        macro_build (NULL, "jr", "s", sreg); | 
|  | +      break; | 
|  | + | 
|  | +    case M_LI: | 
|  | +      load_const (dreg, &imm_expr); | 
|  | +      break; | 
|  | + | 
|  | +    default: | 
|  | +      as_bad (_("Macro %s not implemented"), ip->insn_mo->name); | 
|  | +      break; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* For consistency checking, verify that all bits are specified either | 
|  | +   by the match/mask part of the instruction definition, or by the | 
|  | +   operand list.  */ | 
|  | +static int | 
|  | +validate_mips_insn (const struct riscv_opcode *opc) | 
|  | +{ | 
|  | +  const char *p = opc->args; | 
|  | +  char c; | 
|  | +  unsigned long used_bits = opc->mask; | 
|  | + | 
|  | +  if ((used_bits & opc->match) != opc->match) | 
|  | +    { | 
|  | +      as_bad (_("internal: bad mips opcode (mask error): %s %s"), | 
|  | +	      opc->name, opc->args); | 
|  | +      return 0; | 
|  | +    } | 
|  | +#define USE_BITS(mask,shift)	(used_bits |= ((mask) << (shift))) | 
|  | +  while (*p) | 
|  | +    switch (c = *p++) | 
|  | +      { | 
|  | +      case '#': | 
|  | +    	switch (c = *p++) | 
|  | +	  { | 
|  | +	  case 'g': USE_BITS (OP_MASK_IMMNGPR, OP_SH_IMMNGPR); break; | 
|  | +	  case 'f': USE_BITS (OP_MASK_IMMNFPR, OP_SH_IMMNFPR); break; | 
|  | +	  case 'n': USE_BITS (OP_MASK_IMMSEGNELM, OP_SH_IMMSEGNELM); break; | 
|  | +	  case 'm': USE_BITS (OP_MASK_IMMSEGSTNELM, OP_SH_IMMSEGSTNELM); break; | 
|  | +	  case 'd': USE_BITS (OP_MASK_VRD, OP_SH_VRD); break; | 
|  | +	  case 's': USE_BITS (OP_MASK_VRS, OP_SH_VRS); break; | 
|  | +	  case 't': USE_BITS (OP_MASK_VRT, OP_SH_VRT); break; | 
|  | +	  case 'r': USE_BITS (OP_MASK_VRR, OP_SH_VRR); break; | 
|  | +	  case 'D': USE_BITS (OP_MASK_VFD, OP_SH_VFD); break; | 
|  | +	  case 'S': USE_BITS (OP_MASK_VFS, OP_SH_VFS); break; | 
|  | +	  case 'T': USE_BITS (OP_MASK_VFT, OP_SH_VFT); break; | 
|  | +	  case 'R': USE_BITS (OP_MASK_VFR, OP_SH_VFR); break; | 
|  | + | 
|  | +	  default: | 
|  | +	    as_bad (_("internal: bad mips opcode (unknown extension operand type `#%c'): %s %s"), | 
|  | +		    c, opc->name, opc->args); | 
|  | +	    return 0; | 
|  | +	  } | 
|  | +	break; | 
|  | +      case ',': break; | 
|  | +      case '(': break; | 
|  | +      case ')': break; | 
|  | +      case '<': USE_BITS (OP_MASK_SHAMTW,	OP_SH_SHAMTW);	break; | 
|  | +      case '>':	USE_BITS (OP_MASK_SHAMT,	OP_SH_SHAMT);	break; | 
|  | +      case 'A': break; | 
|  | +      case 'D':	USE_BITS (OP_MASK_FD,		OP_SH_FD);	break; | 
|  | +      case 'E':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break; | 
|  | +      case 'I': break; | 
|  | +      case 'R':	USE_BITS (OP_MASK_FR,		OP_SH_FR);	break; | 
|  | +      case 'S':	USE_BITS (OP_MASK_FS,		OP_SH_FS);	break; | 
|  | +      case 'T':	USE_BITS (OP_MASK_FT,		OP_SH_FT);	break; | 
|  | +      case 'a':	USE_BITS (OP_MASK_TARGET,	OP_SH_TARGET);	break; | 
|  | +      case 'b':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break; | 
|  | +      case 'd':	USE_BITS (OP_MASK_RD,		OP_SH_RD);	break; | 
|  | +      case 'j':	USE_BITS (OP_MASK_IMMEDIATE,	OP_SH_IMMEDIATE);	break; | 
|  | +      case 'm':	USE_BITS (OP_MASK_RM,		OP_SH_RM);	break; | 
|  | +      case 'o': USE_BITS (OP_MASK_IMMEDIATE,	OP_SH_IMMEDIATE);	break; | 
|  | +      case 'p':	USE_BITS (OP_MASK_IMMLO,	OP_SH_IMMLO); | 
|  | +              	USE_BITS (OP_MASK_IMMHI,	OP_SH_IMMHI);	break; | 
|  | +      case 'q':	USE_BITS (OP_MASK_IMMLO,	OP_SH_IMMLO); | 
|  | +              	USE_BITS (OP_MASK_IMMHI,	OP_SH_IMMHI);	break; | 
|  | +      case 's':	USE_BITS (OP_MASK_RS,		OP_SH_RS);	break; | 
|  | +      case 't':	USE_BITS (OP_MASK_RT,		OP_SH_RT);	break; | 
|  | +      case 'u':	USE_BITS (OP_MASK_BIGIMMEDIATE,	OP_SH_BIGIMMEDIATE); break; | 
|  | +      case '[': break; | 
|  | +      case ']': break; | 
|  | +      case '0': break; | 
|  | +      default: | 
|  | +	as_bad (_("internal: bad mips opcode (unknown operand type `%c'): %s %s"), | 
|  | +		c, opc->name, opc->args); | 
|  | +	return 0; | 
|  | +      } | 
|  | +#undef USE_BITS | 
|  | +  if ((used_bits&0xffffffff) != 0xffffffff) | 
|  | +    { | 
|  | +      as_bad (_("internal: bad mips opcode (bits 0x%lx undefined): %s %s"), | 
|  | +	      ~used_bits & 0xffffffff, opc->name, opc->args); | 
|  | +      return 0; | 
|  | +    } | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* This routine assembles an instruction into its binary format.  As a | 
|  | +   side effect, it sets one of the global variables imm_reloc or | 
|  | +   offset_reloc to the type of relocation to do if one of the operands | 
|  | +   is an address expression.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_ip (char *str, struct mips_cl_insn *ip) | 
|  | +{ | 
|  | +  char *s; | 
|  | +  const char *args; | 
|  | +  char c = 0; | 
|  | +  struct riscv_opcode *insn; | 
|  | +  char *argsStart; | 
|  | +  unsigned int regno; | 
|  | +  char save_c = 0; | 
|  | +  int argnum; | 
|  | +  unsigned int rtype; | 
|  | + | 
|  | +  insn_error = NULL; | 
|  | + | 
|  | +  /* If the instruction contains a '.', we first try to match an instruction | 
|  | +     including the '.'.  Then we try again without the '.'.  */ | 
|  | +  insn = NULL; | 
|  | +  for (s = str; *s != '\0' && !ISSPACE (*s); ++s) | 
|  | +    continue; | 
|  | + | 
|  | +  /* If we stopped on whitespace, then replace the whitespace with null for | 
|  | +     the call to hash_find.  Save the character we replaced just in case we | 
|  | +     have to re-parse the instruction.  */ | 
|  | +  if (ISSPACE (*s)) | 
|  | +    { | 
|  | +      save_c = *s; | 
|  | +      *s++ = '\0'; | 
|  | +    } | 
|  | + | 
|  | +  insn = (struct riscv_opcode *) hash_find (op_hash, str); | 
|  | + | 
|  | +  /* If we didn't find the instruction in the opcode table, try again, but | 
|  | +     this time with just the instruction up to, but not including the | 
|  | +     first '.'.  */ | 
|  | +  if (insn == NULL) | 
|  | +    { | 
|  | +      /* Restore the character we overwrite above (if any).  */ | 
|  | +      if (save_c) | 
|  | +	*(--s) = save_c; | 
|  | + | 
|  | +      /* Scan up to the first '.' or whitespace.  */ | 
|  | +      for (s = str; | 
|  | +	   *s != '\0' && *s != '.' && !ISSPACE (*s); | 
|  | +	   ++s) | 
|  | +	continue; | 
|  | + | 
|  | +      /* If we did not find a '.', then we can quit now.  */ | 
|  | +      if (*s != '.') | 
|  | +	{ | 
|  | +	  insn_error = "unrecognized opcode"; | 
|  | +	  return; | 
|  | +	} | 
|  | + | 
|  | +      /* Lookup the instruction in the hash table.  */ | 
|  | +      *s++ = '\0'; | 
|  | +      if ((insn = (struct riscv_opcode *) hash_find (op_hash, str)) == NULL) | 
|  | +	{ | 
|  | +	  insn_error = "unrecognized opcode"; | 
|  | +	  return; | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  argsStart = s; | 
|  | +  for (;;) | 
|  | +    { | 
|  | +      bfd_boolean ok = TRUE; | 
|  | +      gas_assert (strcmp (insn->name, str) == 0); | 
|  | + | 
|  | +      create_insn (ip, insn); | 
|  | +      insn_error = NULL; | 
|  | +      argnum = 1; | 
|  | +      for (args = insn->args;; ++args) | 
|  | +	{ | 
|  | +	  s += strspn (s, " \t"); | 
|  | +	  switch (*args) | 
|  | +	    { | 
|  | +	    case '\0':		/* end of args */ | 
|  | +	      if (*s == '\0') | 
|  | +		return; | 
|  | +	      break; | 
|  | + | 
|  | +            case '#': | 
|  | +              switch ( *++args ) | 
|  | +                { | 
|  | +                case 'g': | 
|  | +                  my_getExpression( &imm_expr, s ); | 
|  | +                  check_absolute_expr( ip, &imm_expr ); | 
|  | +                  if ((unsigned long) imm_expr.X_add_number > 32 ) | 
|  | +                    as_warn( _( "Improper ngpr amount (%lu)" ), | 
|  | +                             (unsigned long) imm_expr.X_add_number ); | 
|  | +                  INSERT_OPERAND( IMMNGPR, *ip, imm_expr.X_add_number ); | 
|  | +                  imm_expr.X_op = O_absent; | 
|  | +                  s = expr_end; | 
|  | +                  continue; | 
|  | +                case 'f': | 
|  | +                  my_getExpression( &imm_expr, s ); | 
|  | +                  check_absolute_expr( ip, &imm_expr ); | 
|  | +                  if ((unsigned long) imm_expr.X_add_number > 32 ) | 
|  | +                    as_warn( _( "Improper nfpr amount (%lu)" ), | 
|  | +                             (unsigned long) imm_expr.X_add_number ); | 
|  | +                  INSERT_OPERAND( IMMNFPR, *ip, imm_expr.X_add_number ); | 
|  | +                  imm_expr.X_op = O_absent; | 
|  | +                  s = expr_end; | 
|  | +                  continue; | 
|  | +                case 'n': | 
|  | +                  my_getExpression( &imm_expr, s ); | 
|  | +                  check_absolute_expr( ip, &imm_expr ); | 
|  | +                  if ((unsigned long) imm_expr.X_add_number > 32 ) | 
|  | +                    as_warn( _( "Improper nelm amount (%lu)" ), | 
|  | +                             (unsigned long) imm_expr.X_add_number ); | 
|  | +                  INSERT_OPERAND( IMMSEGNELM, *ip, imm_expr.X_add_number - 1 ); | 
|  | +                  imm_expr.X_op = O_absent; | 
|  | +                  s = expr_end; | 
|  | +                  continue; | 
|  | +                case 'm': | 
|  | +                  my_getExpression( &imm_expr, s ); | 
|  | +                  check_absolute_expr( ip, &imm_expr ); | 
|  | +                  if ((unsigned long) imm_expr.X_add_number > 32 ) | 
|  | +                    as_warn( _( "Improper nelm amount (%lu)" ), | 
|  | +                             (unsigned long) imm_expr.X_add_number ); | 
|  | +                  INSERT_OPERAND( IMMSEGSTNELM, *ip, imm_expr.X_add_number - 1 ); | 
|  | +                  imm_expr.X_op = O_absent; | 
|  | +                  s = expr_end; | 
|  | +                  continue; | 
|  | +                case 'd': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VRD, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 's': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VRS, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 't': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VRT, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 'r': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VGR_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VRR, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 'D': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VFD, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 'S': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VFS, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 'T': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VFT, *ip, regno ); | 
|  | +                  continue; | 
|  | +                case 'R': | 
|  | +                  ok = reg_lookup( &s, RTYPE_NUM|RTYPE_VFP_REG, ®no ); | 
|  | +                  if ( !ok ) | 
|  | +                    as_bad( _( "Invalid vector register" ) ); | 
|  | +                  INSERT_OPERAND( VFR, *ip, regno ); | 
|  | +                  continue; | 
|  | +                } | 
|  | +              break; | 
|  | + | 
|  | +	    case '0': /* memory instruction with 0-offset (namely, AMOs) */ | 
|  | +	      if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0 | 
|  | +		  && (offset_expr.X_op != O_constant | 
|  | +		      || offset_expr.X_add_number != 0)) | 
|  | +		break; | 
|  | + | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case ',': | 
|  | +	      ++argnum; | 
|  | +	      if (*s++ == *args) | 
|  | +		continue; | 
|  | +	      s--; | 
|  | +	      break; | 
|  | + | 
|  | +	    case '(': | 
|  | +	      /* Handle optional base register. | 
|  | +		 Either the base register is omitted or | 
|  | +		 we must have a left paren.  */ | 
|  | +	      /* This is dependent on the next operand specifier | 
|  | +		 is a base register specification.  */ | 
|  | +	      gas_assert (args[1] == 'b' || args[1] == '5' | 
|  | +		      || args[1] == '-' || args[1] == '4'); | 
|  | +	      if (*s == '\0') | 
|  | +		return; | 
|  | + | 
|  | +	    case ')':		/* these must match exactly */ | 
|  | +	    case '[': | 
|  | +	    case ']': | 
|  | +	      if (*s++ == *args) | 
|  | +		continue; | 
|  | +	      break; | 
|  | + | 
|  | +	    case '<':		/* must be at least one digit */ | 
|  | +	      /* | 
|  | +	       * According to the manual, if the shift amount is greater | 
|  | +	       * than 31 or less than 0, then the shift amount should be | 
|  | +	       * mod 32.  In reality the mips assembler issues an error. | 
|  | +	       * We issue a warning and mask out all but the low 5 bits. | 
|  | +	       */ | 
|  | +	      my_getExpression (&imm_expr, s); | 
|  | +	      check_absolute_expr (ip, &imm_expr); | 
|  | +	      if ((unsigned long) imm_expr.X_add_number > 31) | 
|  | +		as_warn (_("Improper shift amount (%lu)"), | 
|  | +			 (unsigned long) imm_expr.X_add_number); | 
|  | +	      INSERT_OPERAND (SHAMTW, *ip, imm_expr.X_add_number); | 
|  | +	      imm_expr.X_op = O_absent; | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case '>':		/* shift amount, 0-63 */ | 
|  | +	      my_getExpression (&imm_expr, s); | 
|  | +	      check_absolute_expr (ip, &imm_expr); | 
|  | +	      INSERT_OPERAND (SHAMT, *ip, imm_expr.X_add_number); | 
|  | +	      imm_expr.X_op = O_absent; | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'E':		/* Control register.  */ | 
|  | +	      ok = reg_lookup (&s, RTYPE_NUM | RTYPE_CP0, ®no); | 
|  | +	      INSERT_OPERAND (RS, *ip, regno); | 
|  | +	      if (ok) | 
|  | +		continue; | 
|  | +	      else | 
|  | +		break; | 
|  | + | 
|  | +            case 'm':		/* rounding mode */ | 
|  | +            { | 
|  | +              size_t i, found = ARRAY_SIZE(riscv_rm); | 
|  | +              for(i = 0; i < found; i++) | 
|  | +                if(riscv_rm[i] && !strncmp(s,riscv_rm[i],strlen(riscv_rm[i]))) | 
|  | +                    found = i; | 
|  | + | 
|  | +              if(found == ARRAY_SIZE(riscv_rm)) | 
|  | +                as_bad("bad rounding mode: `%s'",s); | 
|  | + | 
|  | +              INSERT_OPERAND(RM, *ip, found); | 
|  | +              s += strlen(riscv_rm[found]); | 
|  | +              continue; | 
|  | +            } | 
|  | + | 
|  | +	    case 'b':		/* base register */ | 
|  | +	    case 'd':		/* destination register */ | 
|  | +	    case 's':		/* source register */ | 
|  | +	    case 't':		/* target register */ | 
|  | +	    case 'z':		/* must be zero register */ | 
|  | +	    case 'U':           /* destination register (clo/clz).  */ | 
|  | +	    case 'g':		/* coprocessor destination register */ | 
|  | +	      ok = reg_lookup (&s, RTYPE_NUM | RTYPE_GP, ®no); | 
|  | +	      if (ok) | 
|  | +		{ | 
|  | +		  c = *args; | 
|  | +		  if (*s == ' ') | 
|  | +		    ++s; | 
|  | +		  /* 'z' only matches $0.  */ | 
|  | +		  if (c == 'z' && regno != 0) | 
|  | +		    break; | 
|  | + | 
|  | +	/* Now that we have assembled one operand, we use the args string | 
|  | +	 * to figure out where it goes in the instruction.  */ | 
|  | +		  switch (c) | 
|  | +		    { | 
|  | +		    case 's': | 
|  | +		    case 'b': | 
|  | +		    case 'E': | 
|  | +		      INSERT_OPERAND (RS, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'd': | 
|  | +		      INSERT_OPERAND (RD, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'g': | 
|  | +		      INSERT_OPERAND (FS, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'U': | 
|  | +		      INSERT_OPERAND (RD, *ip, regno); | 
|  | +		      INSERT_OPERAND (RT, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 't': | 
|  | +		      INSERT_OPERAND (RT, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'x': | 
|  | +		      /* This case exists because on the r3000 trunc | 
|  | +			 expands into a macro which requires a gp | 
|  | +			 register.  On the r6000 or r4000 it is | 
|  | +			 assembled into a single instruction which | 
|  | +			 ignores the register.  Thus the insn version | 
|  | +			 is MIPS_ISA2 and uses 'x', and the macro | 
|  | +			 version is MIPS_ISA1 and uses 't'.  */ | 
|  | +		      break; | 
|  | +		    case 'z': | 
|  | +		      /* This case is for the div instruction, which | 
|  | +			 acts differently if the destination argument | 
|  | +			 is $0.  This only matches $0, and is checked | 
|  | +			 outside the switch.  */ | 
|  | +		      break; | 
|  | +		    case 'D': | 
|  | +		      /* Itbl operand; not yet implemented. FIXME ?? */ | 
|  | +		      break; | 
|  | +		      /* What about all other operands like 'i', which | 
|  | +			 can be specified in the opcode table? */ | 
|  | +		    } | 
|  | +		  continue; | 
|  | +		} | 
|  | +	      break; | 
|  | + | 
|  | +	    case 'D':		/* floating point destination register */ | 
|  | +	    case 'S':		/* floating point source register */ | 
|  | +	    case 'T':		/* floating point target register */ | 
|  | +	    case 'R':		/* floating point source register */ | 
|  | +	      rtype = RTYPE_FPU; | 
|  | +	      if (reg_lookup (&s, rtype, ®no)) | 
|  | +		{ | 
|  | +		  c = *args; | 
|  | +		  if (*s == ' ') | 
|  | +		    ++s; | 
|  | +		  switch (c) | 
|  | +		    { | 
|  | +		    case 'D': | 
|  | +		      INSERT_OPERAND (FD, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'S': | 
|  | +		      INSERT_OPERAND (FS, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'T': | 
|  | +		      INSERT_OPERAND (FT, *ip, regno); | 
|  | +		      break; | 
|  | +		    case 'R': | 
|  | +		      INSERT_OPERAND (FR, *ip, regno); | 
|  | +		      break; | 
|  | +		    } | 
|  | +		  continue; | 
|  | +		} | 
|  | + | 
|  | +	      break; | 
|  | + | 
|  | +	    case 'I': | 
|  | +	      my_getExpression (&imm_expr, s); | 
|  | +	      if (imm_expr.X_op != O_big | 
|  | +		  && imm_expr.X_op != O_constant) | 
|  | +		insn_error = _("absolute expression required"); | 
|  | +	      normalize_constant_expr (&imm_expr); | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'A': | 
|  | +	      my_getExpression (&offset_expr, s); | 
|  | +	      normalize_address_expr (&offset_expr); | 
|  | +	      *imm_reloc = BFD_RELOC_32; | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'j':		/* sign-extended RISCV_IMM_BITS immediate */ | 
|  | +	      *imm_reloc = BFD_RELOC_LO16; | 
|  | +	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0) | 
|  | +		{ | 
|  | +		  int more; | 
|  | +		  offsetT minval, maxval; | 
|  | + | 
|  | +		  more = (insn + 1 < &riscv_opcodes[NUMOPCODES] | 
|  | +			  && strcmp (insn->name, insn[1].name) == 0); | 
|  | + | 
|  | +		  /* If the expression was written as an unsigned number, | 
|  | +		     only treat it as signed if there are no more | 
|  | +		     alternatives.  */ | 
|  | +		  if (more | 
|  | +		      && *args == 'j' | 
|  | +		      && sizeof (imm_expr.X_add_number) <= 4 | 
|  | +		      && imm_expr.X_op == O_constant | 
|  | +		      && imm_expr.X_add_number < 0 | 
|  | +		      && imm_expr.X_unsigned | 
|  | +		      && rv64) | 
|  | +		    break; | 
|  | + | 
|  | +		  /* For compatibility with older assemblers, we accept | 
|  | +		     0x8000-0xffff as signed 16-bit numbers when only | 
|  | +		     signed numbers are allowed.  */ | 
|  | +		  if (more) | 
|  | +		    minval = -(signed)RISCV_IMM_REACH/2, maxval = RISCV_IMM_REACH/2-1; | 
|  | +		  else | 
|  | +		    minval = -(signed)RISCV_IMM_REACH/2, maxval = RISCV_IMM_REACH-1; | 
|  | + | 
|  | +		  if (imm_expr.X_op != O_constant | 
|  | +		      || imm_expr.X_add_number < minval | 
|  | +		      || imm_expr.X_add_number > maxval) | 
|  | +		    { | 
|  | +		      if (more) | 
|  | +			break; | 
|  | +		      if (imm_expr.X_op == O_constant | 
|  | +			  || imm_expr.X_op == O_big) | 
|  | +			as_bad (_("expression out of range")); | 
|  | +		    } | 
|  | +		} | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'q':		/* 16 bit offset */ | 
|  | +	    case 'o':		/* 16 bit offset */ | 
|  | +	      /* Check whether there is only a single bracketed expression | 
|  | +		 left.  If so, it must be the base register and the | 
|  | +		 constant must be zero.  */ | 
|  | +	      if (*s == '(' && strchr (s + 1, '(') == 0) | 
|  | +		{ | 
|  | +		  offset_expr.X_op = O_constant; | 
|  | +		  offset_expr.X_add_number = 0; | 
|  | +		  continue; | 
|  | +		} | 
|  | + | 
|  | +	      /* If this value won't fit into a 16 bit offset, then go | 
|  | +		 find a macro that will generate the 32 bit offset | 
|  | +		 code pattern.  */ | 
|  | +	      if (my_getSmallExpression (&offset_expr, offset_reloc, s) == 0 | 
|  | +		  && (offset_expr.X_op != O_constant | 
|  | +		      || offset_expr.X_add_number >= (signed)RISCV_IMM_REACH/2 | 
|  | +		      || offset_expr.X_add_number < -(signed)RISCV_IMM_REACH/2)) | 
|  | +		break; | 
|  | + | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'p':		/* pc relative offset */ | 
|  | +	      *offset_reloc = BFD_RELOC_16_PCREL_S2; | 
|  | +	      my_getExpression (&offset_expr, s); | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'u':		/* upper 20 bits */ | 
|  | +	      if (my_getSmallExpression (&imm_expr, imm_reloc, s) == 0 | 
|  | +		  && imm_expr.X_op == O_constant) | 
|  | +		{ | 
|  | +		  if (imm_expr.X_add_number < 0 | 
|  | +		      || imm_expr.X_add_number >= (signed)RISCV_BIGIMM_REACH) | 
|  | +		    as_bad (_("lui expression not in range 0..1048575")); | 
|  | + | 
|  | +		  *imm_reloc = BFD_RELOC_HI16; | 
|  | +		  imm_expr.X_add_number <<= RISCV_IMM_BITS; | 
|  | +		} | 
|  | +	      s = expr_end; | 
|  | +	      continue; | 
|  | + | 
|  | +	    case 'a':		/* 26 bit address */ | 
|  | +	      my_getExpression (&offset_expr, s); | 
|  | +	      s = expr_end; | 
|  | +	      *offset_reloc = BFD_RELOC_MIPS_JMP; | 
|  | +	      continue; | 
|  | + | 
|  | +	    default: | 
|  | +	      as_bad (_("bad char = '%c'\n"), *args); | 
|  | +	      internalError (); | 
|  | +	    } | 
|  | +	  break; | 
|  | +	} | 
|  | +      /* Args don't match.  */ | 
|  | +      if (insn + 1 < &riscv_opcodes[NUMOPCODES] && | 
|  | +	  !strcmp (insn->name, insn[1].name)) | 
|  | +	{ | 
|  | +	  ++insn; | 
|  | +	  s = argsStart; | 
|  | +	  insn_error = _("illegal operands"); | 
|  | +	  continue; | 
|  | +	} | 
|  | +      if (save_c) | 
|  | +	*(--argsStart) = save_c; | 
|  | +      insn_error = _("illegal operands"); | 
|  | +      return; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +struct percent_op_match | 
|  | +{ | 
|  | +  const char *str; | 
|  | +  bfd_reloc_code_real_type reloc; | 
|  | +}; | 
|  | + | 
|  | +static const struct percent_op_match mips_percent_op[] = | 
|  | +{ | 
|  | +  {"%lo", BFD_RELOC_LO16}, | 
|  | +#ifdef OBJ_ELF | 
|  | +  {"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16}, | 
|  | +  {"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16}, | 
|  | +#endif | 
|  | +  {"%hi", BFD_RELOC_HI16_S} | 
|  | +}; | 
|  | + | 
|  | +/* Return true if *STR points to a relocation operator.  When returning true, | 
|  | +   move *STR over the operator and store its relocation code in *RELOC. | 
|  | +   Leave both *STR and *RELOC alone when returning false.  */ | 
|  | + | 
|  | +static bfd_boolean | 
|  | +parse_relocation (char **str, bfd_reloc_code_real_type *reloc) | 
|  | +{ | 
|  | +  const struct percent_op_match *percent_op; | 
|  | +  size_t limit, i; | 
|  | + | 
|  | +  percent_op = mips_percent_op; | 
|  | +  limit = ARRAY_SIZE (mips_percent_op); | 
|  | + | 
|  | +  for (i = 0; i < limit; i++) | 
|  | +    if (strncasecmp (*str, percent_op[i].str, strlen (percent_op[i].str)) == 0) | 
|  | +      { | 
|  | +	int len = strlen (percent_op[i].str); | 
|  | + | 
|  | +	if (!ISSPACE ((*str)[len]) && (*str)[len] != '(') | 
|  | +	  continue; | 
|  | + | 
|  | +	*str += strlen (percent_op[i].str); | 
|  | +	*reloc = percent_op[i].reloc; | 
|  | + | 
|  | +	/* Check whether the output BFD supports this relocation. | 
|  | +	   If not, issue an error and fall back on something safe.  */ | 
|  | +	if (!bfd_reloc_type_lookup (stdoutput, percent_op[i].reloc)) | 
|  | +	  { | 
|  | +	    as_bad ("relocation %s isn't supported by the current ABI", | 
|  | +		    percent_op[i].str); | 
|  | +	    *reloc = BFD_RELOC_UNUSED; | 
|  | +	  } | 
|  | +	return TRUE; | 
|  | +      } | 
|  | +  return FALSE; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* Parse string STR as a 16-bit relocatable operand.  Store the | 
|  | +   expression in *EP and the relocations in the array starting | 
|  | +   at RELOC.  Return the number of relocation operators used. | 
|  | + | 
|  | +   On exit, EXPR_END points to the first character after the expression.  */ | 
|  | + | 
|  | +static size_t | 
|  | +my_getSmallExpression (expressionS *ep, bfd_reloc_code_real_type *reloc, | 
|  | +		       char *str) | 
|  | +{ | 
|  | +  bfd_reloc_code_real_type reversed_reloc[3]; | 
|  | +  size_t reloc_index, i; | 
|  | +  int crux_depth, str_depth; | 
|  | +  char *crux; | 
|  | + | 
|  | +  /* Search for the start of the main expression, recoding relocations | 
|  | +     in REVERSED_RELOC.  End the loop with CRUX pointing to the start | 
|  | +     of the main expression and with CRUX_DEPTH containing the number | 
|  | +     of open brackets at that point.  */ | 
|  | +  reloc_index = -1; | 
|  | +  str_depth = 0; | 
|  | +  do | 
|  | +    { | 
|  | +      reloc_index++; | 
|  | +      crux = str; | 
|  | +      crux_depth = str_depth; | 
|  | + | 
|  | +      /* Skip over whitespace and brackets, keeping count of the number | 
|  | +	 of brackets.  */ | 
|  | +      while (*str == ' ' || *str == '\t' || *str == '(') | 
|  | +	if (*str++ == '(') | 
|  | +	  str_depth++; | 
|  | +    } | 
|  | +  while (*str == '%' | 
|  | +	 && reloc_index < 3 | 
|  | +	 && parse_relocation (&str, &reversed_reloc[reloc_index])); | 
|  | + | 
|  | +  my_getExpression (ep, crux); | 
|  | +  str = expr_end; | 
|  | + | 
|  | +  /* Match every open bracket.  */ | 
|  | +  while (crux_depth > 0 && (*str == ')' || *str == ' ' || *str == '\t')) | 
|  | +    if (*str++ == ')') | 
|  | +      crux_depth--; | 
|  | + | 
|  | +  if (crux_depth > 0) | 
|  | +    as_bad ("unclosed '('"); | 
|  | + | 
|  | +  expr_end = str; | 
|  | + | 
|  | +  if (reloc_index != 0) | 
|  | +    { | 
|  | +      prev_reloc_op_frag = frag_now; | 
|  | +      for (i = 0; i < reloc_index; i++) | 
|  | +	reloc[i] = reversed_reloc[reloc_index - 1 - i]; | 
|  | +    } | 
|  | + | 
|  | +  return reloc_index; | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +my_getExpression (expressionS *ep, char *str) | 
|  | +{ | 
|  | +  char *save_in; | 
|  | + | 
|  | +  save_in = input_line_pointer; | 
|  | +  input_line_pointer = str; | 
|  | +  expression (ep); | 
|  | +  expr_end = input_line_pointer; | 
|  | +  input_line_pointer = save_in; | 
|  | +} | 
|  | + | 
|  | +char * | 
|  | +md_atof (int type, char *litP, int *sizeP) | 
|  | +{ | 
|  | +  return ieee_md_atof (type, litP, sizeP, target_big_endian); | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +md_number_to_chars (char *buf, valueT val, int n) | 
|  | +{ | 
|  | +  if (target_big_endian) | 
|  | +    number_to_chars_bigendian (buf, val, n); | 
|  | +  else | 
|  | +    number_to_chars_littleendian (buf, val, n); | 
|  | +} | 
|  | + | 
|  | +const char *md_shortopts = "O::g::G:"; | 
|  | + | 
|  | +enum options | 
|  | +  { | 
|  | +    OPTION_M32 = OPTION_MD_BASE, | 
|  | +    OPTION_M64, | 
|  | +    OPTION_PIC, | 
|  | +    OPTION_NO_PIC, | 
|  | +    OPTION_EB, | 
|  | +    OPTION_EL, | 
|  | +    OPTION_MRVC, | 
|  | +    OPTION_MNO_RVC, | 
|  | +    OPTION_END_OF_ENUM | 
|  | +  }; | 
|  | + | 
|  | +struct option md_longopts[] = | 
|  | +{ | 
|  | +  {"m32", no_argument, NULL, OPTION_M32}, | 
|  | +  {"m64", no_argument, NULL, OPTION_M64}, | 
|  | +  {"fPIC", no_argument, NULL, OPTION_PIC}, | 
|  | +  {"fpic", no_argument, NULL, OPTION_PIC}, | 
|  | +  {"fno-pic", no_argument, NULL, OPTION_NO_PIC}, | 
|  | +  {"EB", no_argument, NULL, OPTION_EB}, | 
|  | +  {"EL", no_argument, NULL, OPTION_EL}, | 
|  | +  {"mrvc", no_argument, NULL, OPTION_MRVC}, | 
|  | +  {"mno-rvc", no_argument, NULL, OPTION_MNO_RVC}, | 
|  | + | 
|  | +  {NULL, no_argument, NULL, 0} | 
|  | +}; | 
|  | +size_t md_longopts_size = sizeof (md_longopts); | 
|  | + | 
|  | +int | 
|  | +md_parse_option (int c, char *arg) | 
|  | +{ | 
|  | +  switch (c) | 
|  | +    { | 
|  | +    case OPTION_EB: | 
|  | +      target_big_endian = 1; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_EL: | 
|  | +      target_big_endian = 0; | 
|  | +      break; | 
|  | + | 
|  | +    case 'g': | 
|  | +      if (arg == NULL) | 
|  | +	mips_debug = 2; | 
|  | +      else | 
|  | +	mips_debug = atoi (arg); | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_MRVC: | 
|  | +      mips_opts.rvc = 1; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_MNO_RVC: | 
|  | +      mips_opts.rvc = 0; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_M32: | 
|  | +      rv64 = FALSE; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_M64: | 
|  | +      rv64 = TRUE; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_NO_PIC: | 
|  | +      is_pic = FALSE; | 
|  | +      break; | 
|  | + | 
|  | +    case OPTION_PIC: | 
|  | +      is_pic = TRUE; | 
|  | +      break; | 
|  | + | 
|  | +    default: | 
|  | +      return 0; | 
|  | +    } | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +mips_after_parse_args (void) | 
|  | +{ | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +mips_init_after_args (void) | 
|  | +{ | 
|  | +  /* initialize opcodes */ | 
|  | +  bfd_riscv_num_opcodes = bfd_riscv_num_builtin_opcodes; | 
|  | +  riscv_opcodes = (struct riscv_opcode *) riscv_builtin_opcodes; | 
|  | +} | 
|  | + | 
|  | +long | 
|  | +md_pcrel_from (fixS *fixP) | 
|  | +{ | 
|  | +  return fixP->fx_where + fixP->fx_frag->fr_address; | 
|  | +} | 
|  | + | 
|  | +/* We may have combined relocations without symbols in the N32/N64 ABI. | 
|  | +   We have to prevent gas from dropping them.  */ | 
|  | + | 
|  | +int | 
|  | +mips_force_relocation (fixS *fixp) | 
|  | +{ | 
|  | +  if (generic_force_reloc (fixp)) | 
|  | +    return 1; | 
|  | + | 
|  | +  if (S_GET_SEGMENT (fixp->fx_addsy) == bfd_abs_section_ptr | 
|  | +      && (fixp->fx_r_type == BFD_RELOC_MIPS_SUB | 
|  | +	  || hi16_reloc_p (fixp->fx_r_type) | 
|  | +	  || lo16_reloc_p (fixp->fx_r_type))) | 
|  | +    return 1; | 
|  | + | 
|  | +  return 0; | 
|  | +} | 
|  | + | 
|  | +/* Apply a fixup to the object file.  */ | 
|  | + | 
|  | +void | 
|  | +md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  bfd_byte *buf; | 
|  | +  long insn; | 
|  | +  reloc_howto_type *howto; | 
|  | + | 
|  | + | 
|  | +  /* We ignore generic BFD relocations we don't know about.  */ | 
|  | +  howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type); | 
|  | +  if (! howto) | 
|  | +    return; | 
|  | + | 
|  | +  gas_assert (fixP->fx_size == 4 | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_64 | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_CTOR | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_MIPS_SUB | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY | 
|  | +	  || fixP->fx_r_type == BFD_RELOC_MIPS_TLS_DTPREL64); | 
|  | + | 
|  | +  buf = (bfd_byte *) (fixP->fx_frag->fr_literal + fixP->fx_where); | 
|  | + | 
|  | +  gas_assert (!fixP->fx_pcrel || (fixP->fx_r_type == BFD_RELOC_16_PCREL_S2 || | 
|  | +                                 fixP->fx_r_type == BFD_RELOC_MIPS_JMP)); | 
|  | + | 
|  | +  /* Don't treat parts of a composite relocation as done.  There are two | 
|  | +     reasons for this: | 
|  | + | 
|  | +     (1) The second and third parts will be against 0 (RSS_UNDEF) but | 
|  | +	 should nevertheless be emitted if the first part is. | 
|  | + | 
|  | +     (2) In normal usage, composite relocations are never assembly-time | 
|  | +	 constants.  The easiest way of dealing with the pathological | 
|  | +	 exceptions is to generate a relocation against STN_UNDEF and | 
|  | +	 leave everything up to the linker.  */ | 
|  | +  if (fixP->fx_addsy == NULL && !fixP->fx_pcrel && fixP->fx_tcbit == 0) | 
|  | +    fixP->fx_done = 1; | 
|  | + | 
|  | +  if (target_big_endian) | 
|  | +    insn = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; | 
|  | +  else | 
|  | +    insn = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; | 
|  | + | 
|  | +  switch (fixP->fx_r_type) | 
|  | +    { | 
|  | +    case BFD_RELOC_MIPS_TLS_GD: | 
|  | +    case BFD_RELOC_RISCV_TLS_GD_HI16: | 
|  | +    case BFD_RELOC_RISCV_TLS_GD_LO16: | 
|  | +    case BFD_RELOC_MIPS_TLS_LDM: | 
|  | +    case BFD_RELOC_RISCV_TLS_LDM_HI16: | 
|  | +    case BFD_RELOC_RISCV_TLS_LDM_LO16: | 
|  | +    case BFD_RELOC_MIPS_TLS_DTPREL32: | 
|  | +    case BFD_RELOC_MIPS_TLS_DTPREL64: | 
|  | +    case BFD_RELOC_MIPS_TLS_DTPREL_HI16: | 
|  | +    case BFD_RELOC_MIPS_TLS_DTPREL_LO16: | 
|  | +    case BFD_RELOC_MIPS_TLS_GOTTPREL: | 
|  | +    case BFD_RELOC_RISCV_TLS_GOT_HI16: | 
|  | +    case BFD_RELOC_RISCV_TLS_GOT_LO16: | 
|  | +    case BFD_RELOC_MIPS_TLS_TPREL_HI16: | 
|  | +    case BFD_RELOC_MIPS_TLS_TPREL_LO16: | 
|  | +      S_SET_THREAD_LOCAL (fixP->fx_addsy); | 
|  | +      /* fall through */ | 
|  | + | 
|  | +    case BFD_RELOC_MIPS_GOT_DISP: | 
|  | +    case BFD_RELOC_MIPS_SUB: | 
|  | +    case BFD_RELOC_MIPS_INSERT_A: | 
|  | +    case BFD_RELOC_MIPS_INSERT_B: | 
|  | +    case BFD_RELOC_MIPS_DELETE: | 
|  | +    case BFD_RELOC_MIPS_SCN_DISP: | 
|  | +    case BFD_RELOC_MIPS_REL16: | 
|  | +    case BFD_RELOC_MIPS_RELGOT: | 
|  | +    case BFD_RELOC_HI16: | 
|  | +    case BFD_RELOC_HI16_S: | 
|  | +    case BFD_RELOC_GPREL16: | 
|  | +    case BFD_RELOC_MIPS_LITERAL: | 
|  | +    case BFD_RELOC_MIPS_CALL16: | 
|  | +    case BFD_RELOC_MIPS_GOT16: | 
|  | +    case BFD_RELOC_GPREL32: | 
|  | +    case BFD_RELOC_MIPS_GOT_HI16: | 
|  | +    case BFD_RELOC_MIPS_GOT_LO16: | 
|  | +    case BFD_RELOC_MIPS_CALL_HI16: | 
|  | +    case BFD_RELOC_MIPS_CALL_LO16: | 
|  | +    case BFD_RELOC_MIPS16_GPREL: | 
|  | +    case BFD_RELOC_MIPS16_GOT16: | 
|  | +    case BFD_RELOC_MIPS16_CALL16: | 
|  | +    case BFD_RELOC_MIPS16_HI16: | 
|  | +    case BFD_RELOC_MIPS16_HI16_S: | 
|  | +    case BFD_RELOC_MIPS16_JMP: | 
|  | +      /* Nothing needed to do.  The value comes from the reloc entry.  */ | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_64: | 
|  | +      /* This is handled like BFD_RELOC_32, but we output a sign | 
|  | +         extended value if we are only 32 bits.  */ | 
|  | +      if (fixP->fx_done) | 
|  | +	{ | 
|  | +	  if (8 <= sizeof (valueT)) | 
|  | +	    md_number_to_chars ((char *) buf, *valP, 8); | 
|  | +	  else | 
|  | +	    { | 
|  | +	      valueT hiv; | 
|  | + | 
|  | +	      if ((*valP & 0x80000000) != 0) | 
|  | +		hiv = 0xffffffff; | 
|  | +	      else | 
|  | +		hiv = 0; | 
|  | +	      md_number_to_chars ((char *)(buf + (target_big_endian ? 4 : 0)), | 
|  | +				  *valP, 4); | 
|  | +	      md_number_to_chars ((char *)(buf + (target_big_endian ? 0 : 4)), | 
|  | +				  hiv, 4); | 
|  | +	    } | 
|  | +	} | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_RVA: | 
|  | +    case BFD_RELOC_32: | 
|  | +      /* If we are deleting this reloc entry, we must fill in the | 
|  | +	 value now.  This can happen if we have a .word which is not | 
|  | +	 resolved when it appears but is later defined.  */ | 
|  | +      if (fixP->fx_done) | 
|  | +	md_number_to_chars ((char *) buf, *valP, fixP->fx_size); | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_LO16: | 
|  | +    case BFD_RELOC_MIPS16_LO16: | 
|  | +      if (!fixP->fx_done) | 
|  | +	break; | 
|  | + | 
|  | +      if (*valP + RISCV_IMM_REACH/2 > RISCV_IMM_REACH-1) | 
|  | +        as_bad_where (fixP->fx_file, fixP->fx_line, | 
|  | +		      _("relocation overflow")); | 
|  | + | 
|  | +      if (OPCODE_IS_STORE(insn)) /* Stores have a split immediate field. */ | 
|  | +	{ | 
|  | +	  valueT value = *valP & (RISCV_IMM_REACH-1); | 
|  | +	  value = ((value >> RISCV_IMMLO_BITS) << OP_SH_IMMHI) | | 
|  | +	          ((value & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO); | 
|  | +	  insn |= value; | 
|  | +	} | 
|  | +      else | 
|  | +	insn |= (*valP & ((1<<RISCV_IMM_BITS)-1)) << OP_SH_IMMEDIATE; | 
|  | + | 
|  | +      md_number_to_chars ((char *) buf, insn, 4); | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_MIPS_JMP: | 
|  | +      if ((*valP & (RISCV_JUMP_ALIGN-1)) != 0) | 
|  | +	as_bad_where (fixP->fx_file, fixP->fx_line, | 
|  | +		      _("Branch to misaligned address (%lx)"), (long) *valP); | 
|  | + | 
|  | +      /* We need to save the bits in the instruction since fixup_segment() | 
|  | +	 might be deleting the relocation entry (i.e., a branch within | 
|  | +	 the current segment).  */ | 
|  | +      if (! fixP->fx_done) | 
|  | +	break; | 
|  | + | 
|  | +      /* Update old instruction data.  */ | 
|  | + | 
|  | +      if (*valP + RISCV_JUMP_REACH/2 <= RISCV_JUMP_REACH-1) | 
|  | +	{ | 
|  | +	  insn |= ((*valP >> RISCV_JUMP_ALIGN_BITS) & ((1<<RISCV_JUMP_BITS)-1)) << OP_SH_TARGET; | 
|  | +	  md_number_to_chars ((char *) buf, insn, 4); | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  /* If we got here, we have branch-relaxation disabled, | 
|  | +	     and there's nothing we can do to fix this instruction | 
|  | +	     without turning it into a longer sequence.  */ | 
|  | +	  as_bad_where (fixP->fx_file, fixP->fx_line, | 
|  | +			_("Jump out of range")); | 
|  | +	} | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_16_PCREL_S2: | 
|  | +      if ((*valP & (RISCV_BRANCH_ALIGN-1)) != 0) | 
|  | +	as_bad_where (fixP->fx_file, fixP->fx_line, | 
|  | +		      _("Branch to misaligned address (%lx)"), (long) *valP); | 
|  | + | 
|  | +      /* We need to save the bits in the instruction since fixup_segment() | 
|  | +	 might be deleting the relocation entry (i.e., a branch within | 
|  | +	 the current segment).  */ | 
|  | +      if (! fixP->fx_done) | 
|  | +	break; | 
|  | + | 
|  | +      /* Update old instruction data.  */ | 
|  | +      if (*valP + RISCV_BRANCH_REACH/2 <= RISCV_BRANCH_REACH-1) | 
|  | +	{ | 
|  | +	  unsigned delta = ((unsigned)*valP >> RISCV_BRANCH_ALIGN_BITS) & ((1<<RISCV_BRANCH_BITS)-1);; | 
|  | +	  insn |= ((delta & ((1<<RISCV_IMMLO_BITS)-1)) << OP_SH_IMMLO) | (((delta >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1)) << OP_SH_IMMHI); | 
|  | +	  md_number_to_chars ((char *) buf, insn, 4); | 
|  | +	} | 
|  | +      else | 
|  | +	{ | 
|  | +	  /* If we got here, we have branch-relaxation disabled, | 
|  | +	     and there's nothing we can do to fix this instruction | 
|  | +	     without turning it into a longer sequence.  */ | 
|  | +	  as_bad_where (fixP->fx_file, fixP->fx_line, | 
|  | +			_("Branch out of range")); | 
|  | +	} | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_VTABLE_INHERIT: | 
|  | +      fixP->fx_done = 0; | 
|  | +      if (fixP->fx_addsy | 
|  | +          && !S_IS_DEFINED (fixP->fx_addsy) | 
|  | +          && !S_IS_WEAK (fixP->fx_addsy)) | 
|  | +        S_SET_WEAK (fixP->fx_addsy); | 
|  | +      break; | 
|  | + | 
|  | +    case BFD_RELOC_VTABLE_ENTRY: | 
|  | +      fixP->fx_done = 0; | 
|  | +      break; | 
|  | + | 
|  | +    default: | 
|  | +      internalError (); | 
|  | +    } | 
|  | + | 
|  | +  /* Remember value for tc_gen_reloc.  */ | 
|  | +  fixP->fx_addnumber = *valP; | 
|  | +} | 
|  | + | 
|  | +/* Align the current frag to a given power of two.  If a particular | 
|  | +   fill byte should be used, FILL points to an integer that contains | 
|  | +   that byte, otherwise FILL is null. | 
|  | + | 
|  | +   The MIPS assembler also automatically adjusts any preceding | 
|  | +   label.  */ | 
|  | + | 
|  | +static void | 
|  | +mips_align (int to, int *fill, symbolS *label) | 
|  | +{ | 
|  | +  mips_clear_insn_labels (); | 
|  | +  if (fill == NULL && subseg_text_p (now_seg)) | 
|  | +    frag_align_code (to, 0); | 
|  | +  else | 
|  | +    frag_align (to, fill ? *fill : 0, 0); | 
|  | +  record_alignment (now_seg, to); | 
|  | +  if (label != NULL) | 
|  | +    { | 
|  | +      gas_assert (S_GET_SEGMENT (label) == now_seg); | 
|  | +      symbol_set_frag (label, frag_now); | 
|  | +      S_SET_VALUE (label, (valueT) frag_now_fix ()); | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Align to a given power of two.  .align 0 turns off the automatic | 
|  | +   alignment used by the data creating pseudo-ops.  */ | 
|  | + | 
|  | +static void | 
|  | +s_align (int x ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  int temp, fill_value, *fill_ptr; | 
|  | +  long max_alignment = 28; | 
|  | + | 
|  | +  /* o Note that the assembler pulls down any immediately preceding label | 
|  | +       to the aligned address. | 
|  | +     o It's not documented but auto alignment is reinstated by | 
|  | +       a .align pseudo instruction. | 
|  | +     o Note also that after auto alignment is turned off the mips assembler | 
|  | +       issues an error on attempt to assemble an improperly aligned data item. | 
|  | +       We don't.  */ | 
|  | + | 
|  | +  temp = get_absolute_expression (); | 
|  | +  if (temp > max_alignment) | 
|  | +    as_bad (_("Alignment too large: %d. assumed."), temp = max_alignment); | 
|  | +  else if (temp < 0) | 
|  | +    { | 
|  | +      as_warn (_("Alignment negative: 0 assumed.")); | 
|  | +      temp = 0; | 
|  | +    } | 
|  | +  if (*input_line_pointer == ',') | 
|  | +    { | 
|  | +      ++input_line_pointer; | 
|  | +      fill_value = get_absolute_expression (); | 
|  | +      fill_ptr = &fill_value; | 
|  | +    } | 
|  | +  else | 
|  | +    fill_ptr = 0; | 
|  | +  if (temp) | 
|  | +    { | 
|  | +      segment_info_type *si = seg_info (now_seg); | 
|  | +      struct insn_label_list *l = si->label_list; | 
|  | +      /* Auto alignment should be switched on by next section change.  */ | 
|  | +      auto_align = 1; | 
|  | +      mips_align (temp, fill_ptr, l != NULL ? l->label : NULL); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      auto_align = 0; | 
|  | +    } | 
|  | + | 
|  | +  demand_empty_rest_of_line (); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +s_change_sec (int sec) | 
|  | +{ | 
|  | +  segT seg; | 
|  | + | 
|  | +#ifdef OBJ_ELF | 
|  | +  /* The ELF backend needs to know that we are changing sections, so | 
|  | +     that .previous works correctly.  We could do something like check | 
|  | +     for an obj_section_change_hook macro, but that might be confusing | 
|  | +     as it would not be appropriate to use it in the section changing | 
|  | +     functions in read.c, since obj-elf.c intercepts those.  FIXME: | 
|  | +     This should be cleaner, somehow.  */ | 
|  | +  if (IS_ELF) | 
|  | +    obj_elf_section_change_hook (); | 
|  | +#endif | 
|  | + | 
|  | +  mips_clear_insn_labels (); | 
|  | + | 
|  | +  switch (sec) | 
|  | +    { | 
|  | +    case 't': | 
|  | +      s_text (0); | 
|  | +      break; | 
|  | +    case 'd': | 
|  | +      s_data (0); | 
|  | +      break; | 
|  | +    case 'b': | 
|  | +      subseg_set (bss_section, (subsegT) get_absolute_expression ()); | 
|  | +      demand_empty_rest_of_line (); | 
|  | +      break; | 
|  | + | 
|  | +    case 'r': | 
|  | +      seg = subseg_new (".rodata", (subsegT) get_absolute_expression ()); | 
|  | +      if (IS_ELF) | 
|  | +	{ | 
|  | +	  bfd_set_section_flags (stdoutput, seg, (SEC_ALLOC | SEC_LOAD | 
|  | +						  | SEC_READONLY | SEC_RELOC | 
|  | +						  | SEC_DATA)); | 
|  | +	  if (strncmp (TARGET_OS, "elf", 3) != 0) | 
|  | +	    record_alignment (seg, 4); | 
|  | +	} | 
|  | +      demand_empty_rest_of_line (); | 
|  | +      break; | 
|  | +    } | 
|  | + | 
|  | +  auto_align = 1; | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +s_change_section (int ignore ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +#ifdef OBJ_ELF | 
|  | +  char *section_name; | 
|  | +  char c; | 
|  | +  char next_c = 0; | 
|  | +  int section_type; | 
|  | +  int section_flag; | 
|  | +  int section_entry_size; | 
|  | + | 
|  | +  if (!IS_ELF) | 
|  | +    return; | 
|  | + | 
|  | +  section_name = input_line_pointer; | 
|  | +  c = get_symbol_end (); | 
|  | +  if (c) | 
|  | +    next_c = *(input_line_pointer + 1); | 
|  | + | 
|  | +  /* Do we have .section Name<,"flags">?  */ | 
|  | +  if (c != ',' || (c == ',' && next_c == '"')) | 
|  | +    { | 
|  | +      /* just after name is now '\0'.  */ | 
|  | +      *input_line_pointer = c; | 
|  | +      input_line_pointer = section_name; | 
|  | +      obj_elf_section (ignore); | 
|  | +      return; | 
|  | +    } | 
|  | +  input_line_pointer++; | 
|  | + | 
|  | +  /* Do we have .section Name<,type><,flag><,entry_size><,alignment>  */ | 
|  | +  if (c == ',') | 
|  | +    section_type = get_absolute_expression (); | 
|  | +  else | 
|  | +    section_type = 0; | 
|  | +  if (*input_line_pointer++ == ',') | 
|  | +    section_flag = get_absolute_expression (); | 
|  | +  else | 
|  | +    section_flag = 0; | 
|  | +  if (*input_line_pointer++ == ',') | 
|  | +    section_entry_size = get_absolute_expression (); | 
|  | +  else | 
|  | +    section_entry_size = 0; | 
|  | + | 
|  | +  section_name = xstrdup (section_name); | 
|  | + | 
|  | +  /* When using the generic form of .section (as implemented by obj-elf.c), | 
|  | +     there's no way to set the section type to SHT_MIPS_DWARF.  Users have | 
|  | +     traditionally had to fall back on the more common @progbits instead. | 
|  | + | 
|  | +     There's nothing really harmful in this, since bfd will correct | 
|  | +     SHT_PROGBITS to SHT_MIPS_DWARF before writing out the file.  But it | 
|  | +     means that, for backwards compatibility, the special_section entries | 
|  | +     for dwarf sections must use SHT_PROGBITS rather than SHT_MIPS_DWARF. | 
|  | + | 
|  | +     Even so, we shouldn't force users of the MIPS .section syntax to | 
|  | +     incorrectly label the sections as SHT_PROGBITS.  The best compromise | 
|  | +     seems to be to map SHT_MIPS_DWARF to SHT_PROGBITS before calling the | 
|  | +     generic type-checking code.  */ | 
|  | +  if (section_type == SHT_MIPS_DWARF) | 
|  | +    section_type = SHT_PROGBITS; | 
|  | + | 
|  | +  obj_elf_change_section (section_name, section_type, section_flag, | 
|  | +			  section_entry_size, 0, 0, 0); | 
|  | + | 
|  | +  if (now_seg->name != section_name) | 
|  | +    free (section_name); | 
|  | +#endif /* OBJ_ELF */ | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +mips_enable_auto_align (void) | 
|  | +{ | 
|  | +  auto_align = 1; | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +s_cons (int log_size) | 
|  | +{ | 
|  | +  segment_info_type *si = seg_info (now_seg); | 
|  | +  struct insn_label_list *l = si->label_list; | 
|  | +  symbolS *label; | 
|  | + | 
|  | +  label = l != NULL ? l->label : NULL; | 
|  | +  mips_clear_insn_labels (); | 
|  | +  if (log_size > 0 && auto_align) | 
|  | +    mips_align (log_size, 0, label); | 
|  | +  mips_clear_insn_labels (); | 
|  | +  cons (1 << log_size); | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +s_float_cons (int type) | 
|  | +{ | 
|  | +  segment_info_type *si = seg_info (now_seg); | 
|  | +  struct insn_label_list *l = si->label_list; | 
|  | +  symbolS *label; | 
|  | + | 
|  | +  label = l != NULL ? l->label : NULL; | 
|  | + | 
|  | +  mips_clear_insn_labels (); | 
|  | + | 
|  | +  if (auto_align) | 
|  | +    { | 
|  | +      if (type == 'd') | 
|  | +	mips_align (3, 0, label); | 
|  | +      else | 
|  | +	mips_align (2, 0, label); | 
|  | +    } | 
|  | + | 
|  | +  mips_clear_insn_labels (); | 
|  | + | 
|  | +  float_cons (type); | 
|  | +} | 
|  | + | 
|  | +/* Handle .globl.  We need to override it because on Irix 5 you are | 
|  | +   permitted to say | 
|  | +       .globl foo .text | 
|  | +   where foo is an undefined symbol, to mean that foo should be | 
|  | +   considered to be the address of a function.  */ | 
|  | + | 
|  | +static void | 
|  | +s_mips_globl (int x ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  char *name; | 
|  | +  int c; | 
|  | +  symbolS *symbolP; | 
|  | +  flagword flag; | 
|  | + | 
|  | +  do | 
|  | +    { | 
|  | +      name = input_line_pointer; | 
|  | +      c = get_symbol_end (); | 
|  | +      symbolP = symbol_find_or_make (name); | 
|  | +      S_SET_EXTERNAL (symbolP); | 
|  | + | 
|  | +      *input_line_pointer = c; | 
|  | +      SKIP_WHITESPACE (); | 
|  | + | 
|  | +      /* On Irix 5, every global symbol that is not explicitly labelled as | 
|  | +         being a function is apparently labelled as being an object.  */ | 
|  | +      flag = BSF_OBJECT; | 
|  | + | 
|  | +      if (!is_end_of_line[(unsigned char) *input_line_pointer] | 
|  | +	  && (*input_line_pointer != ',')) | 
|  | +	{ | 
|  | +	  char *secname; | 
|  | +	  asection *sec; | 
|  | + | 
|  | +	  secname = input_line_pointer; | 
|  | +	  c = get_symbol_end (); | 
|  | +	  sec = bfd_get_section_by_name (stdoutput, secname); | 
|  | +	  if (sec == NULL) | 
|  | +	    as_bad (_("%s: no such section"), secname); | 
|  | +	  *input_line_pointer = c; | 
|  | + | 
|  | +	  if (sec != NULL && (sec->flags & SEC_CODE) != 0) | 
|  | +	    flag = BSF_FUNCTION; | 
|  | +	} | 
|  | + | 
|  | +      symbol_get_bfdsym (symbolP)->flags |= flag; | 
|  | + | 
|  | +      c = *input_line_pointer; | 
|  | +      if (c == ',') | 
|  | +	{ | 
|  | +	  input_line_pointer++; | 
|  | +	  SKIP_WHITESPACE (); | 
|  | +	  if (is_end_of_line[(unsigned char) *input_line_pointer]) | 
|  | +	    c = '\n'; | 
|  | +	} | 
|  | +    } | 
|  | +  while (c == ','); | 
|  | + | 
|  | +  demand_empty_rest_of_line (); | 
|  | +} | 
|  | + | 
|  | +/* This structure is used to hold a stack of .set values.  */ | 
|  | + | 
|  | +struct mips_option_stack | 
|  | +{ | 
|  | +  struct mips_option_stack *next; | 
|  | +  struct mips_set_options options; | 
|  | +}; | 
|  | + | 
|  | +static struct mips_option_stack *mips_opts_stack; | 
|  | + | 
|  | +/* Handle the .set pseudo-op.  */ | 
|  | + | 
|  | +static void | 
|  | +s_mipsset (int x ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  char *name = input_line_pointer, ch; | 
|  | + | 
|  | +  while (!is_end_of_line[(unsigned char) *input_line_pointer]) | 
|  | +    ++input_line_pointer; | 
|  | +  ch = *input_line_pointer; | 
|  | +  *input_line_pointer = '\0'; | 
|  | + | 
|  | +  if (strcmp (name, "rvc") == 0) | 
|  | +    mips_opts.rvc = 1; | 
|  | +  else if (strcmp (name, "norvc") == 0) | 
|  | +    mips_opts.rvc = 0; | 
|  | +  else if (strcmp (name, "push") == 0) | 
|  | +    { | 
|  | +      struct mips_option_stack *s; | 
|  | + | 
|  | +      s = (struct mips_option_stack *) xmalloc (sizeof *s); | 
|  | +      s->next = mips_opts_stack; | 
|  | +      s->options = mips_opts; | 
|  | +      mips_opts_stack = s; | 
|  | +    } | 
|  | +  else if (strcmp (name, "pop") == 0) | 
|  | +    { | 
|  | +      struct mips_option_stack *s; | 
|  | + | 
|  | +      s = mips_opts_stack; | 
|  | +      if (s == NULL) | 
|  | +	as_bad (_(".set pop with no .set push")); | 
|  | +      else | 
|  | +	{ | 
|  | +	  mips_opts = s->options; | 
|  | +	  mips_opts_stack = s->next; | 
|  | +	  free (s); | 
|  | +	} | 
|  | +    } | 
|  | +  else if (strchr (name, ',')) | 
|  | +    { | 
|  | +      /* Generic ".set" directive; use the generic handler.  */ | 
|  | +      *input_line_pointer = ch; | 
|  | +      input_line_pointer = name; | 
|  | +      s_set (0); | 
|  | +      return; | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      as_warn (_("Tried to set unrecognized symbol: %s\n"), name); | 
|  | +    } | 
|  | +  *input_line_pointer = ch; | 
|  | +  demand_empty_rest_of_line (); | 
|  | +} | 
|  | + | 
|  | +/* Handle the .dtprelword and .dtpreldword pseudo-ops.  They generate | 
|  | +   a 32-bit or 64-bit DTP-relative relocation (BYTES says which) for | 
|  | +   use in DWARF debug information.  */ | 
|  | + | 
|  | +static void | 
|  | +s_dtprel_internal (size_t bytes) | 
|  | +{ | 
|  | +  expressionS ex; | 
|  | +  char *p; | 
|  | + | 
|  | +  expression (&ex); | 
|  | + | 
|  | +  if (ex.X_op != O_symbol) | 
|  | +    { | 
|  | +      as_bad (_("Unsupported use of %s"), (bytes == 8 | 
|  | +					   ? ".dtpreldword" | 
|  | +					   : ".dtprelword")); | 
|  | +      ignore_rest_of_line (); | 
|  | +    } | 
|  | + | 
|  | +  p = frag_more (bytes); | 
|  | +  md_number_to_chars (p, 0, bytes); | 
|  | +  fix_new_exp (frag_now, p - frag_now->fr_literal, bytes, &ex, FALSE, | 
|  | +	       (bytes == 8 | 
|  | +		? BFD_RELOC_MIPS_TLS_DTPREL64 | 
|  | +		: BFD_RELOC_MIPS_TLS_DTPREL32)); | 
|  | + | 
|  | +  demand_empty_rest_of_line (); | 
|  | +} | 
|  | + | 
|  | +/* Handle .dtprelword.  */ | 
|  | + | 
|  | +static void | 
|  | +s_dtprelword (int ignore ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  s_dtprel_internal (4); | 
|  | +} | 
|  | + | 
|  | +/* Handle .dtpreldword.  */ | 
|  | + | 
|  | +static void | 
|  | +s_dtpreldword (int ignore ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  s_dtprel_internal (8); | 
|  | +} | 
|  | + | 
|  | +/* Handle the .weakext pseudo-op as defined in Kane and Heinrich.  */ | 
|  | + | 
|  | +static void | 
|  | +s_mips_weakext (int ignore ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  char *name; | 
|  | +  int c; | 
|  | +  symbolS *symbolP; | 
|  | +  expressionS exp; | 
|  | + | 
|  | +  name = input_line_pointer; | 
|  | +  c = get_symbol_end (); | 
|  | +  symbolP = symbol_find_or_make (name); | 
|  | +  S_SET_WEAK (symbolP); | 
|  | +  *input_line_pointer = c; | 
|  | + | 
|  | +  SKIP_WHITESPACE (); | 
|  | + | 
|  | +  if (! is_end_of_line[(unsigned char) *input_line_pointer]) | 
|  | +    { | 
|  | +      if (S_IS_DEFINED (symbolP)) | 
|  | +	{ | 
|  | +	  as_bad ("ignoring attempt to redefine symbol %s", | 
|  | +		  S_GET_NAME (symbolP)); | 
|  | +	  ignore_rest_of_line (); | 
|  | +	  return; | 
|  | +	} | 
|  | + | 
|  | +      if (*input_line_pointer == ',') | 
|  | +	{ | 
|  | +	  ++input_line_pointer; | 
|  | +	  SKIP_WHITESPACE (); | 
|  | +	} | 
|  | + | 
|  | +      expression (&exp); | 
|  | +      if (exp.X_op != O_symbol) | 
|  | +	{ | 
|  | +	  as_bad ("bad .weakext directive"); | 
|  | +	  ignore_rest_of_line (); | 
|  | +	  return; | 
|  | +	} | 
|  | +      symbol_set_value_expression (symbolP, &exp); | 
|  | +    } | 
|  | + | 
|  | +  demand_empty_rest_of_line (); | 
|  | +} | 
|  | + | 
|  | +valueT | 
|  | +md_section_align (asection *seg, valueT addr) | 
|  | +{ | 
|  | +  int align = bfd_get_section_alignment (stdoutput, seg); | 
|  | + | 
|  | +  if (IS_ELF) | 
|  | +    { | 
|  | +      /* We don't need to align ELF sections to the full alignment. | 
|  | +	 However, Irix 5 may prefer that we align them at least to a 16 | 
|  | +	 byte boundary.  We don't bother to align the sections if we | 
|  | +	 are targeted for an embedded system.  */ | 
|  | +      if (strncmp (TARGET_OS, "elf", 3) == 0) | 
|  | +        return addr; | 
|  | +      if (align > 4) | 
|  | +        align = 4; | 
|  | +    } | 
|  | + | 
|  | +  return ((addr + (1 << align) - 1) & (-1 << align)); | 
|  | +} | 
|  | + | 
|  | +/* Compute the length of a branch sequence, and adjust the | 
|  | +   RELAX_BRANCH_TOOFAR bit accordingly.  If FRAGP is NULL, the | 
|  | +   worst-case length is computed, with UPDATE being used to indicate | 
|  | +   whether an unconditional (-1), branch-likely (+1) or regular (0) | 
|  | +   branch is to be computed.  */ | 
|  | +static int | 
|  | +relaxed_branch_length (fragS *fragp, asection *sec, int update) | 
|  | +{ | 
|  | +  bfd_boolean toofar; | 
|  | + | 
|  | +  if (fragp | 
|  | +      && S_IS_DEFINED (fragp->fr_symbol) | 
|  | +      && sec == S_GET_SEGMENT (fragp->fr_symbol)) | 
|  | +    { | 
|  | +      offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; | 
|  | +      val -= fragp->fr_address + fragp->fr_fix; | 
|  | + | 
|  | +      if(RELAX_BRANCH_UNCOND (fragp->fr_subtype)) | 
|  | +        toofar = (bfd_vma)(val + RVC_JUMP_REACH/2) >= RVC_JUMP_REACH; | 
|  | +      else | 
|  | +        toofar = (bfd_vma)(val + RVC_BRANCH_REACH/2) >= RVC_BRANCH_REACH; | 
|  | +    } | 
|  | +  else | 
|  | +    /* If the symbol is not defined or it's in a different segment, | 
|  | +       assume it's too far. */ | 
|  | +    toofar = TRUE; | 
|  | + | 
|  | +  if (fragp && update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype)) | 
|  | +    fragp->fr_subtype | 
|  | +      = RELAX_BRANCH_ENCODE (RELAX_BRANCH_UNCOND (fragp->fr_subtype), toofar); | 
|  | + | 
|  | +  return toofar ? 4 : 2; | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +md_estimate_size_before_relax (fragS *fragp, asection *segtype) | 
|  | +{ | 
|  | +  return (fragp->fr_var = relaxed_branch_length (fragp, segtype, FALSE)); | 
|  | +} | 
|  | + | 
|  | +/* This is called to see whether a reloc against a defined symbol | 
|  | +   should be converted into a reloc against a section.  */ | 
|  | + | 
|  | +int | 
|  | +mips_fix_adjustable (fixS *fixp) | 
|  | +{ | 
|  | +  if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT | 
|  | +      || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) | 
|  | +    return 0; | 
|  | + | 
|  | +  return 1; | 
|  | +} | 
|  | + | 
|  | +/* Translate internal representation of relocation info to BFD target | 
|  | +   format.  */ | 
|  | + | 
|  | +arelent ** | 
|  | +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) | 
|  | +{ | 
|  | +  static arelent *retval[4]; | 
|  | +  arelent *reloc; | 
|  | +  bfd_reloc_code_real_type code; | 
|  | + | 
|  | +  memset (retval, 0, sizeof(retval)); | 
|  | +  reloc = retval[0] = (arelent *) xcalloc (1, sizeof (arelent)); | 
|  | +  reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); | 
|  | +  *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); | 
|  | +  reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; | 
|  | + | 
|  | +  if (fixp->fx_pcrel) | 
|  | +    { | 
|  | +      gas_assert (fixp->fx_r_type == BFD_RELOC_16_PCREL_S2 || | 
|  | +                  fixp->fx_r_type == BFD_RELOC_MIPS_JMP); | 
|  | + | 
|  | +      /* At this point, fx_addnumber is "symbol offset - pcrel address". | 
|  | +	 Relocations want only the symbol offset.  */ | 
|  | +      reloc->addend = fixp->fx_addnumber + reloc->address; | 
|  | +      if (!IS_ELF) | 
|  | +	{ | 
|  | +	  /* A gruesome hack which is a result of the gruesome gas | 
|  | +	     reloc handling.  What's worse, for COFF (as opposed to | 
|  | +	     ECOFF), we might need yet another copy of reloc->address. | 
|  | +	     See bfd_install_relocation.  */ | 
|  | +	  reloc->addend += reloc->address; | 
|  | +	} | 
|  | +    } | 
|  | +  else | 
|  | +    reloc->addend = fixp->fx_addnumber; | 
|  | + | 
|  | +  code = fixp->fx_r_type; | 
|  | + | 
|  | +  reloc->howto = bfd_reloc_type_lookup (stdoutput, code); | 
|  | +  if (reloc->howto == NULL) | 
|  | +    { | 
|  | +      as_bad_where (fixp->fx_file, fixp->fx_line, | 
|  | +		    _("Can not represent %s relocation in this object file format"), | 
|  | +		    bfd_get_reloc_code_name (code)); | 
|  | +      retval[0] = NULL; | 
|  | +    } | 
|  | + | 
|  | +  return retval; | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +mips_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  if (RELAX_BRANCH_P (fragp->fr_subtype)) | 
|  | +    { | 
|  | +      offsetT old_var = fragp->fr_var; | 
|  | +      fragp->fr_var = relaxed_branch_length (fragp, sec, TRUE); | 
|  | +      return fragp->fr_var - old_var; | 
|  | +    } | 
|  | + | 
|  | +  return 0; | 
|  | +} | 
|  | + | 
|  | +/* Convert a machine dependent frag.  */ | 
|  | + | 
|  | +static void | 
|  | +md_convert_frag_branch (bfd *abfd ATTRIBUTE_UNUSED, segT asec ATTRIBUTE_UNUSED, | 
|  | +                 fragS *fragp) | 
|  | +{ | 
|  | +  bfd_byte *buf; | 
|  | +  unsigned long insn; | 
|  | +  expressionS exp; | 
|  | +  fixS *fixp; | 
|  | +  bfd_reloc_code_real_type reloc_type = BFD_RELOC_16_PCREL_S2; | 
|  | + | 
|  | +  buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix; | 
|  | + | 
|  | +  if (target_big_endian) | 
|  | +    insn = bfd_getb16 (buf); | 
|  | +  else | 
|  | +    insn = bfd_getl16 (buf); | 
|  | + | 
|  | +  if (!RELAX_BRANCH_TOOFAR (fragp->fr_subtype)) | 
|  | +    { | 
|  | +      gas_assert(S_IS_DEFINED(fragp->fr_symbol)); | 
|  | +      gas_assert(fragp->fr_var == 2); | 
|  | + | 
|  | +      offsetT target = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; | 
|  | +      target -= fragp->fr_address + fragp->fr_fix; | 
|  | +      target >>= RVC_JUMP_ALIGN_BITS; | 
|  | +      gas_assert(RVC_JUMP_ALIGN_BITS == RVC_BRANCH_ALIGN_BITS); | 
|  | + | 
|  | +      if((insn & MASK_C_J) == MATCH_C_J) | 
|  | +        insn |= ((target & OP_MASK_CIMM10) << OP_SH_CIMM10); | 
|  | +      else if((insn & MASK_C_BEQ) == MATCH_C_BEQ || | 
|  | +              (insn & MASK_C_BNE) == MATCH_C_BNE) | 
|  | +        insn |= ((target & OP_MASK_CIMM5) << OP_SH_CIMM5); | 
|  | +      else | 
|  | +        gas_assert(0); | 
|  | + | 
|  | +      md_number_to_chars ((char *) buf, insn, 2); | 
|  | +      buf += 2; | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      gas_assert(fragp->fr_var == 4); | 
|  | + | 
|  | +      int rs1 = rvc_rs1_regmap[(insn >> OP_SH_CRS1S) & OP_MASK_CRS1S]; | 
|  | +      int rs2 = rvc_rs2_regmap[(insn >> OP_SH_CRS2S) & OP_MASK_CRS2S]; | 
|  | + | 
|  | +      if((insn & MASK_C_J) == MATCH_C_J) | 
|  | +      { | 
|  | +        insn = MATCH_J; | 
|  | +        reloc_type = BFD_RELOC_MIPS_JMP; | 
|  | +      } | 
|  | +      else if((insn & MASK_C_BEQ) == MATCH_C_BEQ) | 
|  | +        insn = MATCH_BEQ | (rs1 << OP_SH_RS) | (rs2 << OP_SH_RT); | 
|  | +      else if((insn & MASK_C_BNE) == MATCH_C_BNE) | 
|  | +        insn = MATCH_BNE | (rs1 << OP_SH_RS) | (rs2 << OP_SH_RT); | 
|  | +      else | 
|  | +        gas_assert(0); | 
|  | + | 
|  | +      exp.X_op = O_symbol; | 
|  | +      exp.X_add_symbol = fragp->fr_symbol; | 
|  | +      exp.X_add_number = fragp->fr_offset; | 
|  | + | 
|  | +      fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal, | 
|  | +			  4, &exp, FALSE, reloc_type); | 
|  | +      fixp->fx_file = fragp->fr_file; | 
|  | +      fixp->fx_line = fragp->fr_line; | 
|  | +      fixp->fx_pcrel = 1; | 
|  | + | 
|  | +      md_number_to_chars ((char *) buf, insn, 4); | 
|  | +      buf += 4; | 
|  | +    } | 
|  | + | 
|  | +  gas_assert (buf == (bfd_byte *)fragp->fr_literal | 
|  | +          + fragp->fr_fix + fragp->fr_var); | 
|  | + | 
|  | +  fragp->fr_fix += fragp->fr_var; | 
|  | +} | 
|  | + | 
|  | +/* Relax a machine dependent frag.  This returns the amount by which | 
|  | +   the current size of the frag should change.  */ | 
|  | + | 
|  | +void | 
|  | +md_convert_frag(bfd *abfd, segT asec, fragS *fragp) | 
|  | +{ | 
|  | +  if(RELAX_BRANCH_P(fragp->fr_subtype)) | 
|  | +    md_convert_frag_branch(abfd, asec, fragp); | 
|  | +  else | 
|  | +    gas_assert(0); | 
|  | +} | 
|  | + | 
|  | +/* This function is called whenever a label is defined.  It is used | 
|  | +   when handling branch delays; if a branch has a label, we assume we | 
|  | +   can not move it.  */ | 
|  | + | 
|  | +void | 
|  | +mips_define_label (symbolS *sym) | 
|  | +{ | 
|  | +  segment_info_type *si = seg_info (now_seg); | 
|  | +  struct insn_label_list *l; | 
|  | + | 
|  | +  if (free_insn_labels == NULL) | 
|  | +    l = (struct insn_label_list *) xmalloc (sizeof *l); | 
|  | +  else | 
|  | +    { | 
|  | +      l = free_insn_labels; | 
|  | +      free_insn_labels = l->next; | 
|  | +    } | 
|  | + | 
|  | +  l->label = sym; | 
|  | +  l->next = si->label_list; | 
|  | +  si->label_list = l; | 
|  | + | 
|  | +#ifdef OBJ_ELF | 
|  | +  dwarf2_emit_label (sym); | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) | 
|  | + | 
|  | +/* Some special processing for a MIPS ELF file.  */ | 
|  | + | 
|  | +void | 
|  | +mips_elf_final_processing (void) | 
|  | +{ | 
|  | +  /* Write out the register information.  */ | 
|  | +  if (!rv64) | 
|  | +    { | 
|  | +      Elf32_RegInfo s; | 
|  | + | 
|  | +      s.ri_gprmask = mips_gprmask; | 
|  | +      s.ri_cprmask[0] = 0; | 
|  | +      s.ri_cprmask[1] = mips_fprmask; | 
|  | +      s.ri_cprmask[2] = 0; | 
|  | +      s.ri_cprmask[3] = 0; | 
|  | +      /* The gp_value field is set by the MIPS ELF backend.  */ | 
|  | + | 
|  | +      bfd_riscv_elf32_swap_reginfo_out (stdoutput, &s, | 
|  | +				       ((Elf32_External_RegInfo *) | 
|  | +					mips_regmask_frag)); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      Elf64_Internal_RegInfo s; | 
|  | + | 
|  | +      s.ri_gprmask = mips_gprmask; | 
|  | +      s.ri_pad = 0; | 
|  | +      s.ri_cprmask[0] = 0; | 
|  | +      s.ri_cprmask[1] = mips_fprmask; | 
|  | +      s.ri_cprmask[2] = 0; | 
|  | +      s.ri_cprmask[3] = 0; | 
|  | +      /* The gp_value field is set by the MIPS ELF backend.  */ | 
|  | + | 
|  | +      bfd_riscv_elf64_swap_reginfo_out (stdoutput, &s, | 
|  | +				       ((Elf64_External_RegInfo *) | 
|  | +					mips_regmask_frag)); | 
|  | +    } | 
|  | + | 
|  | +  /* Set the MIPS ELF flag bits.  FIXME: There should probably be some | 
|  | +     sort of BFD interface for this.  */ | 
|  | +  if (is_pic) | 
|  | +    { | 
|  | +      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_PIC; | 
|  | +      elf_elfheader (stdoutput)->e_flags |= EF_MIPS_CPIC; | 
|  | +    } | 
|  | + | 
|  | +  elf_elfheader (stdoutput)->e_flags |= rv64 ? E_RISCV_ABI_64 : E_RISCV_ABI_32; | 
|  | +} | 
|  | + | 
|  | +#endif /* OBJ_ELF || OBJ_MAYBE_ELF */ | 
|  | + | 
|  | +void | 
|  | +mips_handle_align (fragS *fragp) | 
|  | +{ | 
|  | +  char *p; | 
|  | + | 
|  | +  if (fragp->fr_type != rs_align_code) | 
|  | +    return; | 
|  | + | 
|  | +  p = fragp->fr_literal + fragp->fr_fix; | 
|  | +  md_number_to_chars (p, RISCV_NOP, 4); | 
|  | +  fragp->fr_var = 4; | 
|  | +} | 
|  | + | 
|  | +/* The .file directive; just like the usual .file directive, but there | 
|  | +   is an initial number which is the ECOFF file index.  In the non-ECOFF | 
|  | +   case .file implies DWARF-2.  */ | 
|  | + | 
|  | +static void | 
|  | +s_mips_file (int x ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  static int first_file_directive = 0; | 
|  | + | 
|  | +  char *filename; | 
|  | + | 
|  | +  filename = dwarf2_directive_file (0); | 
|  | + | 
|  | +  /* Versions of GCC up to 3.1 start files with a ".file" | 
|  | +     directive even for stabs output.  Make sure that this | 
|  | +     ".file" is handled.  Note that you need a version of GCC | 
|  | +     after 3.1 in order to support DWARF-2 on MIPS.  */ | 
|  | +  if (filename != NULL && ! first_file_directive) | 
|  | +    { | 
|  | +      (void) new_logical_line (filename, -1); | 
|  | +      s_app_file_string (filename, 0); | 
|  | +    } | 
|  | +  first_file_directive = 1; | 
|  | +} | 
|  | + | 
|  | +/* The .loc directive, implying DWARF-2.  */ | 
|  | + | 
|  | +static void | 
|  | +s_mips_loc (int x ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  dwarf2_directive_loc (0); | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +md_show_usage (FILE *stream) | 
|  | +{ | 
|  | +  fprintf (stream, _("\ | 
|  | +RISC-V options:\n\ | 
|  | +  -m32           assemble RV32 code\n\ | 
|  | +  -m64           assemble RV64 code (default)\n\ | 
|  | +  -fpic          generate position-independent code\n\ | 
|  | +  -fno-pic       don't generate position-independent code (default)\n\ | 
|  | +")); | 
|  | +} | 
|  | + | 
|  | +enum dwarf2_format | 
|  | +mips_dwarf2_format (asection *sec ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  if (HAVE_32BIT_SYMBOLS) | 
|  | +    return dwarf2_format_32bit; | 
|  | +  else | 
|  | +    return dwarf2_format_64bit; | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +mips_dwarf2_addr_size (void) | 
|  | +{ | 
|  | +  return rv64 ? 8 : 4; | 
|  | +} | 
|  | + | 
|  | +/* Standard calling conventions leave the CFA at SP on entry.  */ | 
|  | +void | 
|  | +mips_cfi_frame_initial_instructions (void) | 
|  | +{ | 
|  | +  cfi_add_CFA_def_cfa_register (SP); | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +tc_mips_regname_to_dw2regnum (char *regname) | 
|  | +{ | 
|  | +  unsigned int regnum = -1; | 
|  | +  unsigned int reg; | 
|  | + | 
|  | +  if (reg_lookup (®name, RTYPE_GP | RTYPE_NUM, ®)) | 
|  | +    regnum = reg; | 
|  | + | 
|  | +  return regnum; | 
|  | +} | 
|  | diff -ruN binutils-2.24/gas/config/tc-riscv.h binutils-2.24-riscv/gas/config/tc-riscv.h | 
|  | --- binutils-2.24/gas/config/tc-riscv.h	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/gas/config/tc-riscv.h	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -0,0 +1,146 @@ | 
|  | +/* tc-mips.h -- header file for tc-mips.c. | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004, | 
|  | +   2005, 2006, 2007  Free Software Foundation, Inc. | 
|  | +   Contributed by the OSF and Ralph Campbell. | 
|  | +   Written by Keith Knowles and Ralph Campbell, working independently. | 
|  | +   Modified for ECOFF support by Ian Lance Taylor of Cygnus Support. | 
|  | + | 
|  | +   This file is part of GAS. | 
|  | + | 
|  | +   GAS is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3, or (at your option) | 
|  | +   any later version. | 
|  | + | 
|  | +   GAS is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with GAS; see the file COPYING.  If not, write to the Free | 
|  | +   Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA | 
|  | +   02110-1301, USA.  */ | 
|  | + | 
|  | +#ifndef TC_RISCV | 
|  | +#define TC_RISCV | 
|  | + | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +struct frag; | 
|  | +struct expressionS; | 
|  | + | 
|  | +/* Default to big endian.  */ | 
|  | +#ifndef TARGET_BYTES_BIG_ENDIAN | 
|  | +#define TARGET_BYTES_BIG_ENDIAN		1 | 
|  | +#endif | 
|  | + | 
|  | +#define TARGET_ARCH bfd_arch_riscv | 
|  | + | 
|  | +#define WORKING_DOT_WORD	1 | 
|  | +#define OLD_FLOAT_READS | 
|  | +#define REPEAT_CONS_EXPRESSIONS | 
|  | +#define RELOC_EXPANSION_POSSIBLE | 
|  | +#define MAX_RELOC_EXPANSION 3 | 
|  | +#define LOCAL_LABELS_FB 1 | 
|  | + | 
|  | +#define md_relax_frag(segment, fragp, stretch) \ | 
|  | +  mips_relax_frag(segment, fragp, stretch) | 
|  | +extern int mips_relax_frag (asection *, struct frag *, long); | 
|  | + | 
|  | +#define md_undefined_symbol(name)	(0) | 
|  | +#define md_operand(x) | 
|  | + | 
|  | +#define NOP_OPCODE RISCV_NOP | 
|  | + | 
|  | +extern void mips_handle_align (struct frag *); | 
|  | +#define HANDLE_ALIGN(fragp)  mips_handle_align (fragp) | 
|  | + | 
|  | +#define MAX_MEM_FOR_RS_ALIGN_CODE  (1 + 2) | 
|  | + | 
|  | +struct insn_label_list; | 
|  | +struct mips_segment_info { | 
|  | +  struct insn_label_list *labels; | 
|  | +  unsigned int mips16 : 1; | 
|  | +}; | 
|  | +#define TC_SEGMENT_INFO_TYPE struct mips_segment_info | 
|  | + | 
|  | +/* This field is nonzero if the symbol is the target of a MIPS16 jump.  */ | 
|  | +#define TC_SYMFIELD_TYPE int | 
|  | + | 
|  | +/* The endianness of the target format may change based on command | 
|  | +   line arguments.  */ | 
|  | +#define TARGET_FORMAT mips_target_format() | 
|  | +extern const char *mips_target_format (void); | 
|  | + | 
|  | +#define md_after_parse_args() mips_after_parse_args() | 
|  | +extern void mips_after_parse_args (void); | 
|  | + | 
|  | +#define tc_init_after_args() mips_init_after_args() | 
|  | +extern void mips_init_after_args (void); | 
|  | + | 
|  | +#define md_parse_long_option(arg) mips_parse_long_option (arg) | 
|  | +extern int mips_parse_long_option (const char *); | 
|  | + | 
|  | +#define tc_frob_label(sym) mips_define_label (sym) | 
|  | +extern void mips_define_label (symbolS *); | 
|  | + | 
|  | +#define tc_fix_adjustable(fixp) mips_fix_adjustable (fixp) | 
|  | +extern int mips_fix_adjustable (struct fix *); | 
|  | + | 
|  | +/* Values passed to md_apply_fix don't include symbol values.  */ | 
|  | +#define MD_APPLY_SYM_VALUE(FIX) 0 | 
|  | + | 
|  | +/* Global syms must not be resolved, to support ELF shared libraries.  */ | 
|  | +#define EXTERN_FORCE_RELOC			\ | 
|  | +  (OUTPUT_FLAVOR == bfd_target_elf_flavour) | 
|  | + | 
|  | +/* When generating NEWABI code, we may need to have to keep combined | 
|  | +   relocations which don't have symbols.  */ | 
|  | +#define TC_FORCE_RELOCATION(FIX) mips_force_relocation (FIX) | 
|  | +extern int mips_force_relocation (struct fix *); | 
|  | + | 
|  | +#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEG) \ | 
|  | +  (! SEG_NORMAL (SEG) || mips_force_relocation (FIX)) | 
|  | + | 
|  | +/* Register mask variables.  These are set by the MIPS assembly code | 
|  | +   and used by ECOFF and possibly other object file formats.  */ | 
|  | +extern unsigned long mips_gprmask; | 
|  | +extern unsigned long mips_cprmask[4]; | 
|  | + | 
|  | +#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF) | 
|  | + | 
|  | +#define elf_tc_final_processing mips_elf_final_processing | 
|  | +extern void mips_elf_final_processing (void); | 
|  | + | 
|  | +#endif | 
|  | + | 
|  | +extern void mips_pop_insert (void); | 
|  | +#define md_pop_insert()		mips_pop_insert() | 
|  | + | 
|  | +extern void mips_clear_insn_labels (void); | 
|  | +#define md_flush_pending_output mips_clear_insn_labels | 
|  | + | 
|  | +extern void mips_enable_auto_align (void); | 
|  | +#define md_elf_section_change_hook()	mips_enable_auto_align() | 
|  | + | 
|  | +enum dwarf2_format; | 
|  | +extern enum dwarf2_format mips_dwarf2_format (asection *); | 
|  | +#define DWARF2_FORMAT(SEC) mips_dwarf2_format (SEC) | 
|  | + | 
|  | +extern int mips_dwarf2_addr_size (void); | 
|  | +#define DWARF2_ADDR_SIZE(bfd) mips_dwarf2_addr_size () | 
|  | +#define DWARF2_FDE_RELOC_SIZE mips_dwarf2_addr_size () | 
|  | + | 
|  | +#define TARGET_USE_CFIPOP 1 | 
|  | + | 
|  | +#define tc_cfi_frame_initial_instructions mips_cfi_frame_initial_instructions | 
|  | +extern void mips_cfi_frame_initial_instructions (void); | 
|  | + | 
|  | +#define tc_regname_to_dw2regnum tc_mips_regname_to_dw2regnum | 
|  | +extern int tc_mips_regname_to_dw2regnum (char *regname); | 
|  | + | 
|  | +#define DWARF2_DEFAULT_RETURN_COLUMN LINK_REG | 
|  | +#define DWARF2_CIE_DATA_ALIGNMENT (-4) | 
|  | + | 
|  | +#endif /* TC_RISCV */ | 
|  | diff -ruN binutils-2.24/gas/configure.tgt binutils-2.24-riscv/gas/configure.tgt | 
|  | --- binutils-2.24/gas/configure.tgt	2013-11-04 07:33:37.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/gas/configure.tgt	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -84,6 +84,7 @@ | 
|  | pj*)			cpu_type=pj endian=big ;; | 
|  | powerpc*le*)		cpu_type=ppc endian=little ;; | 
|  | powerpc*)		cpu_type=ppc endian=big ;; | 
|  | +  riscv*)		cpu_type=riscv endian=little ;; | 
|  | rs6000*)		cpu_type=ppc ;; | 
|  | rl78*)		cpu_type=rl78 ;; | 
|  | rx)			cpu_type=rx ;; | 
|  | @@ -375,6 +376,8 @@ | 
|  | ppc-*-kaos*)				fmt=elf ;; | 
|  | ppc-*-lynxos*)			fmt=elf em=lynx ;; | 
|  |  | 
|  | +  riscv*-*-*)			fmt=elf endian=little em=linux bfd_gas=yes ;; | 
|  | + | 
|  | s390-*-linux-*)			fmt=elf em=linux ;; | 
|  | s390-*-tpf*)				fmt=elf ;; | 
|  |  | 
|  | diff -ruN binutils-2.24/gas/Makefile.am binutils-2.24-riscv/gas/Makefile.am | 
|  | --- binutils-2.24/gas/Makefile.am	2013-11-04 07:33:37.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/gas/Makefile.am	2014-12-02 16:14:51.804849445 -0800 | 
|  | @@ -171,6 +171,7 @@ | 
|  | config/tc-pdp11.c \ | 
|  | config/tc-pj.c \ | 
|  | config/tc-ppc.c \ | 
|  | +	config/tc-riscv.c \ | 
|  | config/tc-rl78.c \ | 
|  | config/tc-rx.c \ | 
|  | config/tc-s390.c \ | 
|  | @@ -242,6 +243,7 @@ | 
|  | config/tc-pdp11.h \ | 
|  | config/tc-pj.h \ | 
|  | config/tc-ppc.h \ | 
|  | +	config/tc-riscv.h \ | 
|  | config/tc-rl78.h \ | 
|  | config/tc-rx.h \ | 
|  | config/tc-s390.h \ | 
|  | diff -ruN binutils-2.24/gas/Makefile.in binutils-2.24-riscv/gas/Makefile.in | 
|  | --- binutils-2.24/gas/Makefile.in	2013-11-04 07:33:37.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/gas/Makefile.in	2014-12-02 16:16:06.621317359 -0800 | 
|  | @@ -440,6 +440,7 @@ | 
|  | config/tc-pdp11.c \ | 
|  | config/tc-pj.c \ | 
|  | config/tc-ppc.c \ | 
|  | +	config/tc-riscv.c \ | 
|  | config/tc-rl78.c \ | 
|  | config/tc-rx.c \ | 
|  | config/tc-s390.c \ | 
|  | @@ -511,6 +512,7 @@ | 
|  | config/tc-pdp11.h \ | 
|  | config/tc-pj.h \ | 
|  | config/tc-ppc.h \ | 
|  | +	config/tc-riscv.h \ | 
|  | config/tc-rl78.h \ | 
|  | config/tc-rx.h \ | 
|  | config/tc-s390.h \ | 
|  | @@ -861,6 +863,7 @@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pdp11.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-pj.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-ppc.Po@am__quote@ | 
|  | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-riscv.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-rl78.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-rx.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tc-s390.Po@am__quote@ | 
|  | @@ -1580,6 +1583,20 @@ | 
|  | @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | 
|  | @am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-rl78.obj `if test -f 'config/tc-rl78.c'; then $(CYGPATH_W) 'config/tc-rl78.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-rl78.c'; fi` | 
|  |  | 
|  | +tc-riscv.o: config/tc-riscv.c | 
|  | +@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-riscv.o -MD -MP -MF $(DEPDIR)/tc-riscv.Tpo -c -o tc-riscv.o `test -f 'config/tc-riscv.c' || echo '$(srcdir)/'`config/tc-riscv.c | 
|  | +@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-riscv.Tpo $(DEPDIR)/tc-riscv.Po | 
|  | +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-riscv.c' object='tc-riscv.o' libtool=no @AMDEPBACKSLASH@ | 
|  | +@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | 
|  | +@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-riscv.o `test -f 'config/tc-riscv.c' || echo '$(srcdir)/'`config/tc-riscv.c | 
|  | + | 
|  | +tc-riscv.obj: config/tc-riscv.c | 
|  | +@am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-riscv.obj -MD -MP -MF $(DEPDIR)/tc-riscv.Tpo -c -o tc-riscv.obj `if test -f 'config/tc-riscv.c'; then $(CYGPATH_W) 'config/tc-riscv.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-riscv.c'; fi` | 
|  | +@am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-riscv.Tpo $(DEPDIR)/tc-riscv.Po | 
|  | +@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='config/tc-riscv.c' object='tc-riscv.obj' libtool=no @AMDEPBACKSLASH@ | 
|  | +@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ | 
|  | +@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o tc-riscv.obj `if test -f 'config/tc-riscv.c'; then $(CYGPATH_W) 'config/tc-riscv.c'; else $(CYGPATH_W) '$(srcdir)/config/tc-riscv.c'; fi` | 
|  | + | 
|  | tc-rx.o: config/tc-rx.c | 
|  | @am__fastdepCC_TRUE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT tc-rx.o -MD -MP -MF $(DEPDIR)/tc-rx.Tpo -c -o tc-rx.o `test -f 'config/tc-rx.c' || echo '$(srcdir)/'`config/tc-rx.c | 
|  | @am__fastdepCC_TRUE@	$(am__mv) $(DEPDIR)/tc-rx.Tpo $(DEPDIR)/tc-rx.Po | 
|  | diff -ruN binutils-2.24/include/dis-asm.h binutils-2.24-riscv/include/dis-asm.h | 
|  | --- binutils-2.24/include/dis-asm.h	2013-11-04 07:33:39.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/include/dis-asm.h	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -229,6 +229,7 @@ | 
|  | extern int print_insn_big_nios2		(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_big_or32		(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_big_powerpc	(bfd_vma, disassemble_info *); | 
|  | +extern int print_insn_big_riscv		(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_big_score         (bfd_vma, disassemble_info *); | 
|  | extern int print_insn_cr16              (bfd_vma, disassemble_info *); | 
|  | extern int print_insn_crx               (bfd_vma, disassemble_info *); | 
|  | @@ -257,6 +258,7 @@ | 
|  | extern int print_insn_little_nios2	(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_little_or32	(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_little_powerpc	(bfd_vma, disassemble_info *); | 
|  | +extern int print_insn_little_riscv		(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_little_score      (bfd_vma, disassemble_info *); | 
|  | extern int print_insn_lm32		(bfd_vma, disassemble_info *); | 
|  | extern int print_insn_m32c	        (bfd_vma, disassemble_info *); | 
|  | diff -ruN binutils-2.24/include/elf/common.h binutils-2.24-riscv/include/elf/common.h | 
|  | --- binutils-2.24/include/elf/common.h	2013-11-04 07:33:39.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/include/elf/common.h	2014-12-02 16:21:36.427380014 -0800 | 
|  | @@ -301,6 +301,7 @@ | 
|  | #define EM_INTEL207	207	/* Reserved by Intel */ | 
|  | #define EM_INTEL208	208	/* Reserved by Intel */ | 
|  | #define EM_INTEL209	209	/* Reserved by Intel */ | 
|  | +#define EM_RISCV	243	/* RISC-V */ | 
|  |  | 
|  | /* If it is necessary to assign new unofficial EM_* values, please pick large | 
|  | random numbers (0x8523, 0xa7f2, etc.) to minimize the chances of collision | 
|  | diff -ruN binutils-2.24/include/elf/riscv.h binutils-2.24-riscv/include/elf/riscv.h | 
|  | --- binutils-2.24/include/elf/riscv.h	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/include/elf/riscv.h	2014-12-02 16:05:44.913434966 -0800 | 
|  | @@ -0,0 +1,484 @@ | 
|  | +/* RISC-V ELF support for BFD. | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, | 
|  | +   2003, 2004, 2005, 2008, 2009, 2010 | 
|  | +   Free Software Foundation, Inc. | 
|  | + | 
|  | +   By Andrew Waterman, University of California, | 
|  | +   <waterman@eecs.berkeley.edu>. | 
|  | +   Based on MIPS ELF support for BFD, by Ian Lance Taylor. | 
|  | + | 
|  | +   This file is part of BFD, the Binary File Descriptor library. | 
|  | + | 
|  | +   This program is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3 of the License, or | 
|  | +   (at your option) any later version. | 
|  | + | 
|  | +   This program is distributed in the hope that it will be useful, | 
|  | +   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +   GNU General Public License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | +/* This file holds definitions specific to the RISCV ELF ABI.  Note | 
|  | +   that most of this is not actually implemented by BFD.  */ | 
|  | + | 
|  | +#ifndef _ELF_RISCV_H | 
|  | +#define _ELF_RISCV_H | 
|  | + | 
|  | +#include "elf/reloc-macros.h" | 
|  | + | 
|  | +/* Relocation types.  */ | 
|  | +START_RELOC_NUMBERS (elf_riscv_reloc_type) | 
|  | +  RELOC_NUMBER (R_RISCV_NONE, 0) | 
|  | +  RELOC_NUMBER (R_RISCV_32, 2)		/* In Elf 64: alias R_RISCV_ADD */ | 
|  | +  RELOC_NUMBER (R_RISCV_REL32, 3)	/* In Elf 64: alias R_RISCV_REL */ | 
|  | +  RELOC_NUMBER (R_RISCV_26, 4) | 
|  | +  RELOC_NUMBER (R_RISCV_HI16, 5) | 
|  | +  RELOC_NUMBER (R_RISCV_LO16, 6) | 
|  | +  RELOC_NUMBER (R_RISCV_GPREL16, 7)	/* In Elf 64: alias R_RISCV_GPREL */ | 
|  | +  RELOC_NUMBER (R_RISCV_LITERAL, 8) | 
|  | +  RELOC_NUMBER (R_RISCV_GOT16, 9)	/* In Elf 64: alias R_RISCV_GOT */ | 
|  | +  RELOC_NUMBER (R_RISCV_PC16, 10) | 
|  | +  RELOC_NUMBER (R_RISCV_CALL16, 11)	/* In Elf 64: alias R_RISCV_CALL */ | 
|  | +  RELOC_NUMBER (R_RISCV_GPREL32, 12) | 
|  | +  /* The remaining relocs are defined on Irix, although they are not | 
|  | +     in the RISC-V ELF ABI.  */ | 
|  | +  RELOC_NUMBER (R_RISCV_UNUSED1, 13) | 
|  | +  RELOC_NUMBER (R_RISCV_UNUSED2, 14) | 
|  | +  RELOC_NUMBER (R_RISCV_UNUSED3, 15) | 
|  | + | 
|  | +  RELOC_NUMBER (R_RISCV_64, 18) | 
|  | +  RELOC_NUMBER (R_RISCV_GOT_DISP, 19) | 
|  | +  RELOC_NUMBER (R_RISCV_GOT_HI16, 22) | 
|  | +  RELOC_NUMBER (R_RISCV_GOT_LO16, 23) | 
|  | +  RELOC_NUMBER (R_RISCV_SUB, 24) | 
|  | +  RELOC_NUMBER (R_RISCV_INSERT_A, 25) | 
|  | +  RELOC_NUMBER (R_RISCV_INSERT_B, 26) | 
|  | +  RELOC_NUMBER (R_RISCV_DELETE, 27) | 
|  | +  RELOC_NUMBER (R_RISCV_CALL_HI16, 30) | 
|  | +  RELOC_NUMBER (R_RISCV_CALL_LO16, 31) | 
|  | +  RELOC_NUMBER (R_RISCV_SCN_DISP, 32) | 
|  | +  RELOC_NUMBER (R_RISCV_REL16, 33) | 
|  | +  RELOC_NUMBER (R_RISCV_ADD_IMMEDIATE, 34) | 
|  | +  RELOC_NUMBER (R_RISCV_PJUMP, 35) | 
|  | +  RELOC_NUMBER (R_RISCV_RELGOT, 36) | 
|  | +  /* TLS relocations.  */ | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPMOD32, 38) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPREL32, 39) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPMOD64, 40) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPREL64, 41) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GD, 42) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_LDM, 43) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPREL_HI16, 44) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_DTPREL_LO16, 45) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GOTTPREL, 46) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_TPREL32, 47) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_TPREL64, 48) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_TPREL_HI16, 49) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_TPREL_LO16, 50) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GOT_HI16, 51) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GOT_LO16, 52) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GD_HI16, 53) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_GD_LO16, 54) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_LDM_HI16, 55) | 
|  | +  RELOC_NUMBER (R_RISCV_TLS_LDM_LO16, 56) | 
|  | +  RELOC_NUMBER (R_RISCV_GLOB_DAT, 57) | 
|  | +  FAKE_RELOC (R_RISCV_max, 58) | 
|  | +  /* These relocations are specific to VxWorks.  */ | 
|  | +  RELOC_NUMBER (R_RISCV_COPY, 126) | 
|  | +  RELOC_NUMBER (R_RISCV_JUMP_SLOT, 127) | 
|  | +  /* This was a GNU extension used by embedded-PIC.  It was co-opted by | 
|  | +     riscv-linux for exception-handling data.  It is no longer used, but | 
|  | +     should continue to be supported by the linker for backward | 
|  | +     compatibility.  (GCC stopped using it in May, 2004.)  */ | 
|  | +  RELOC_NUMBER (R_RISCV_PC32, 248) | 
|  | +  /* FIXME: this relocation is used internally by gas.  */ | 
|  | +  RELOC_NUMBER (R_RISCV_GNU_REL16_S2, 250) | 
|  | +  /* These are GNU extensions to enable C++ vtable garbage collection.  */ | 
|  | +  RELOC_NUMBER (R_RISCV_GNU_VTINHERIT, 253) | 
|  | +  RELOC_NUMBER (R_RISCV_GNU_VTENTRY, 254) | 
|  | +END_RELOC_NUMBERS (R_RISCV_maxext) | 
|  | + | 
|  | +/* Processor specific flags for the ELF header e_flags field.  */ | 
|  | + | 
|  | +/* File contains position independent code.  */ | 
|  | +#define EF_RISCV_PIC		0x00000002 | 
|  | + | 
|  | +/* Process the .RISCV.options section first by ld */ | 
|  | +#define EF_RISCV_OPTIONS_FIRST	0x00000080 | 
|  | + | 
|  | +/* Architectural Extensions used by this file */ | 
|  | +#define EF_RISCV_ARCH_ASE	0x0f000000 | 
|  | + | 
|  | +/* Four bit RISCV architecture field.  */ | 
|  | +#define EF_RISCV_ARCH		0xf0000000 | 
|  | + | 
|  | +/* RV32 code.  */ | 
|  | +#define E_RISCV_ARCH_RV32 0x10000000 | 
|  | + | 
|  | +/* RV64 code.  */ | 
|  | +#define E_RISCV_ARCH_RV64 0x20000000 | 
|  | + | 
|  | +/* The ABI of the file.  Also see EF_RISCV_ABI2 above. */ | 
|  | +#define EF_RISCV_ABI		0x0000f000 | 
|  | + | 
|  | +/* The 32-bit abi. */ | 
|  | +#define E_RISCV_ABI_32          0x00001000 | 
|  | + | 
|  | +/* The 64-bit abi. */ | 
|  | +#define E_RISCV_ABI_64          0x00002000 | 
|  | + | 
|  | +/* Machine variant if we know it.  This field was invented at Cygnus, | 
|  | +   but it is hoped that other vendors will adopt it.  If some standard | 
|  | +   is developed, this code should be changed to follow it. */ | 
|  | + | 
|  | +#define EF_RISCV_MACH		0x00ff0000 | 
|  | + | 
|  | +/* Cygnus is choosing values between 80 and 9F; | 
|  | +   00 - 7F should be left for a future standard; | 
|  | +   the rest are open. */ | 
|  | + | 
|  | +#define E_RISCV_MACH_ROCKET32 0x00810000 | 
|  | +#define E_RISCV_MACH_ROCKET64 0x00820000 | 
|  | + | 
|  | +/* Processor specific section indices.  These sections do not actually | 
|  | +   exist.  Symbols with a st_shndx field corresponding to one of these | 
|  | +   values have a special meaning.  */ | 
|  | + | 
|  | +/* Defined and allocated common symbol.  Value is virtual address.  If | 
|  | +   relocated, alignment must be preserved.  */ | 
|  | +#define SHN_RISCV_ACOMMON	SHN_LORESERVE | 
|  | + | 
|  | +/* Defined and allocated text symbol.  Value is virtual address. | 
|  | +   Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables.  */ | 
|  | +#define SHN_RISCV_TEXT		(SHN_LORESERVE + 1) | 
|  | + | 
|  | +/* Defined and allocated data symbol.  Value is virtual address. | 
|  | +   Occur in the dynamic symbol table of Alpha OSF/1 and Irix 5 executables.  */ | 
|  | +#define SHN_RISCV_DATA		(SHN_LORESERVE + 2) | 
|  | + | 
|  | +/* Small common symbol.  */ | 
|  | +#define SHN_RISCV_SCOMMON	(SHN_LORESERVE + 3) | 
|  | + | 
|  | +/* Small undefined symbol.  */ | 
|  | +#define SHN_RISCV_SUNDEFINED	(SHN_LORESERVE + 4) | 
|  | + | 
|  | +/* Processor specific section types.  */ | 
|  | + | 
|  | +/* Section contains the set of dynamic shared objects used when | 
|  | +   statically linking.  */ | 
|  | +#define SHT_RISCV_LIBLIST	0x70000000 | 
|  | + | 
|  | +/* Section contains list of symbols whose definitions conflict with | 
|  | +   symbols defined in shared objects.  */ | 
|  | +#define SHT_RISCV_CONFLICT	0x70000002 | 
|  | + | 
|  | +/* Section contains the global pointer table.  */ | 
|  | +#define SHT_RISCV_GPTAB		0x70000003 | 
|  | + | 
|  | +/* Section contains some sort of debugging information.  The exact | 
|  | +   format is unspecified.  It's probably ECOFF symbols.  */ | 
|  | +#define SHT_RISCV_DEBUG		0x70000005 | 
|  | + | 
|  | +/* Section contains register usage information.  */ | 
|  | +#define SHT_RISCV_REGINFO	0x70000006 | 
|  | + | 
|  | +/* Section contains interface information.  */ | 
|  | +#define SHT_RISCV_IFACE		0x7000000b | 
|  | + | 
|  | +/* Section contains description of contents of another section.  */ | 
|  | +#define SHT_RISCV_CONTENT	0x7000000c | 
|  | + | 
|  | +/* Section contains miscellaneous options.  */ | 
|  | +#define SHT_RISCV_OPTIONS	0x7000000d | 
|  | + | 
|  | +/* List of libraries the binary depends on.  Includes a time stamp, version | 
|  | +   number.  */ | 
|  | +#define SHT_RISCV_SYMBOL_LIB	0x70000020 | 
|  | + | 
|  | +/* Events section.  */ | 
|  | +#define SHT_RISCV_EVENTS		0x70000021 | 
|  | + | 
|  | +/* Get ELf32_xxx struct definitions */ | 
|  | +#include "mips.h" | 
|  | + | 
|  | +/* RISC-V ELF .reginfo swapping routines.  */ | 
|  | +extern void bfd_riscv_elf32_swap_reginfo_in | 
|  | +  (bfd *, const Elf32_External_RegInfo *, Elf32_RegInfo *); | 
|  | +extern void bfd_riscv_elf32_swap_reginfo_out | 
|  | +  (bfd *, const Elf32_RegInfo *, Elf32_External_RegInfo *); | 
|  | + | 
|  | +/* Processor specific section flags.  */ | 
|  | + | 
|  | +/* This section must be in the global data area.  */ | 
|  | +#define SHF_RISCV_GPREL		0x10000000 | 
|  | + | 
|  | +/* This section may not be stripped.  */ | 
|  | +#define SHF_RISCV_NOSTRIP	0x08000000 | 
|  | + | 
|  | +/* Processor specific program header types.  */ | 
|  | + | 
|  | +/* Register usage information.  Identifies one .reginfo section.  */ | 
|  | +#define PT_RISCV_REGINFO		0x70000000 | 
|  | + | 
|  | +/* Runtime procedure table.  */ | 
|  | +#define PT_RISCV_RTPROC		0x70000001 | 
|  | + | 
|  | +/* .RISCV.options section.  */ | 
|  | +#define PT_RISCV_OPTIONS		0x70000002 | 
|  | + | 
|  | +/* Processor specific dynamic array tags.  */ | 
|  | + | 
|  | +/* 32 bit version number for runtime linker interface.  */ | 
|  | +#define DT_RISCV_RLD_VERSION	0x70000001 | 
|  | + | 
|  | +/* Time stamp.  */ | 
|  | +#define DT_RISCV_TIME_STAMP	0x70000002 | 
|  | + | 
|  | +/* Checksum of external strings and common sizes.  */ | 
|  | +#define DT_RISCV_ICHECKSUM	0x70000003 | 
|  | + | 
|  | +/* Index of version string in string table.  */ | 
|  | +#define DT_RISCV_IVERSION	0x70000004 | 
|  | + | 
|  | +/* 32 bits of flags.  */ | 
|  | +#define DT_RISCV_FLAGS		0x70000005 | 
|  | + | 
|  | +/* Base address of the segment.  */ | 
|  | +#define DT_RISCV_BASE_ADDRESS	0x70000006 | 
|  | + | 
|  | +/* ??? */ | 
|  | +#define DT_RISCV_MSYM		0x70000007 | 
|  | + | 
|  | +/* Address of .conflict section.  */ | 
|  | +#define DT_RISCV_CONFLICT	0x70000008 | 
|  | + | 
|  | +/* Address of .liblist section.  */ | 
|  | +#define DT_RISCV_LIBLIST		0x70000009 | 
|  | + | 
|  | +/* Number of local global offset table entries.  */ | 
|  | +#define DT_RISCV_LOCAL_GOTNO	0x7000000a | 
|  | + | 
|  | +/* Number of entries in the .conflict section.  */ | 
|  | +#define DT_RISCV_CONFLICTNO	0x7000000b | 
|  | + | 
|  | +/* Number of entries in the .liblist section.  */ | 
|  | +#define DT_RISCV_LIBLISTNO	0x70000010 | 
|  | + | 
|  | +/* Number of entries in the .dynsym section.  */ | 
|  | +#define DT_RISCV_SYMTABNO	0x70000011 | 
|  | + | 
|  | +/* Index of first external dynamic symbol not referenced locally.  */ | 
|  | +#define DT_RISCV_UNREFEXTNO	0x70000012 | 
|  | + | 
|  | +/* Index of first dynamic symbol in global offset table.  */ | 
|  | +#define DT_RISCV_GOTSYM		0x70000013 | 
|  | + | 
|  | +/* Number of page table entries in global offset table.  */ | 
|  | +#define DT_RISCV_HIPAGENO	0x70000014 | 
|  | + | 
|  | +/* Address of run time loader map, used for debugging.  */ | 
|  | +#define DT_RISCV_RLD_MAP		0x70000016 | 
|  | + | 
|  | +/* Delta C++ class definition.  */ | 
|  | +#define DT_RISCV_DELTA_CLASS	0x70000017 | 
|  | + | 
|  | +/* Number of entries in DT_RISCV_DELTA_CLASS.  */ | 
|  | +#define DT_RISCV_DELTA_CLASS_NO	0x70000018 | 
|  | + | 
|  | +/* Delta C++ class instances.  */ | 
|  | +#define DT_RISCV_DELTA_INSTANCE	0x70000019 | 
|  | + | 
|  | +/* Number of entries in DT_RISCV_DELTA_INSTANCE.  */ | 
|  | +#define DT_RISCV_DELTA_INSTANCE_NO	0x7000001a | 
|  | + | 
|  | +/* Delta relocations.  */ | 
|  | +#define DT_RISCV_DELTA_RELOC	0x7000001b | 
|  | + | 
|  | +/* Number of entries in DT_RISCV_DELTA_RELOC.  */ | 
|  | +#define DT_RISCV_DELTA_RELOC_NO	0x7000001c | 
|  | + | 
|  | +/* Delta symbols that Delta relocations refer to.  */ | 
|  | +#define DT_RISCV_DELTA_SYM	0x7000001d | 
|  | + | 
|  | +/* Number of entries in DT_RISCV_DELTA_SYM.  */ | 
|  | +#define DT_RISCV_DELTA_SYM_NO	0x7000001e | 
|  | + | 
|  | +/* Delta symbols that hold class declarations.  */ | 
|  | +#define DT_RISCV_DELTA_CLASSSYM	0x70000020 | 
|  | + | 
|  | +/* Number of entries in DT_RISCV_DELTA_CLASSSYM.  */ | 
|  | +#define DT_RISCV_DELTA_CLASSSYM_NO	0x70000021 | 
|  | + | 
|  | +/* Flags indicating information about C++ flavor.  */ | 
|  | +#define DT_RISCV_CXX_FLAGS	0x70000022 | 
|  | + | 
|  | +/* Pixie information (???).  */ | 
|  | +#define DT_RISCV_PIXIE_INIT	0x70000023 | 
|  | + | 
|  | +/* Address of .RISCV.symlib */ | 
|  | +#define DT_RISCV_SYMBOL_LIB	0x70000024 | 
|  | + | 
|  | +/* The GOT index of the first PTE for a segment */ | 
|  | +#define DT_RISCV_LOCALPAGE_GOTIDX	0x70000025 | 
|  | + | 
|  | +/* The GOT index of the first PTE for a local symbol */ | 
|  | +#define DT_RISCV_LOCAL_GOTIDX	0x70000026 | 
|  | + | 
|  | +/* The GOT index of the first PTE for a hidden symbol */ | 
|  | +#define DT_RISCV_HIDDEN_GOTIDX	0x70000027 | 
|  | + | 
|  | +/* The GOT index of the first PTE for a protected symbol */ | 
|  | +#define DT_RISCV_PROTECTED_GOTIDX	0x70000028 | 
|  | + | 
|  | +/* Address of `.RISCV.options'.  */ | 
|  | +#define DT_RISCV_OPTIONS		0x70000029 | 
|  | + | 
|  | +/* Address of `.interface'.  */ | 
|  | +#define DT_RISCV_INTERFACE	0x7000002a | 
|  | + | 
|  | +/* ??? */ | 
|  | +#define DT_RISCV_DYNSTR_ALIGN	0x7000002b | 
|  | + | 
|  | +/* Size of the .interface section.  */ | 
|  | +#define DT_RISCV_INTERFACE_SIZE	0x7000002c | 
|  | + | 
|  | +/* Size of rld_text_resolve function stored in the GOT.  */ | 
|  | +#define DT_RISCV_RLD_TEXT_RESOLVE_ADDR	0x7000002d | 
|  | + | 
|  | +/* Default suffix of DSO to be added by rld on dlopen() calls.  */ | 
|  | +#define DT_RISCV_PERF_SUFFIX	0x7000002e | 
|  | + | 
|  | +/* Size of compact relocation section (O32).  */ | 
|  | +#define DT_RISCV_COMPACT_SIZE	0x7000002f | 
|  | + | 
|  | +/* GP value for auxiliary GOTs.  */ | 
|  | +#define DT_RISCV_GP_VALUE	0x70000030 | 
|  | + | 
|  | +/* Address of auxiliary .dynamic.  */ | 
|  | +#define DT_RISCV_AUX_DYNAMIC	0x70000031 | 
|  | + | 
|  | +/* Address of the base of the PLTGOT.  */ | 
|  | +#define DT_RISCV_PLTGOT         0x70000032 | 
|  | + | 
|  | +/* Points to the base of a writable PLT.  */ | 
|  | +#define DT_RISCV_RWPLT          0x70000034 | 
|  | + | 
|  | +/* The RISC-V psABI was updated in 2008 with support for PLTs and copy | 
|  | +   relocs.  There are therefore two types of nonzero SHN_UNDEF functions: | 
|  | +   PLT entries and traditional RISC-V lazy binding stubs.  We mark the former | 
|  | +   with STO_RISCV_PLT to distinguish them from the latter.  */ | 
|  | +#define STO_RISCV_PLT		0x8 | 
|  | + | 
|  | +/* This value is used to mark PIC functions in an object that mixes | 
|  | +   PIC and non-PIC.  */ | 
|  | +#define STO_RISCV_PIC		0x20 | 
|  | +#define ELF_ST_IS_RISCV_PIC(OTHER) \ | 
|  | +  (((OTHER) & ~ELF_ST_VISIBILITY (-1)) == STO_RISCV_PIC) | 
|  | +#define ELF_ST_SET_RISCV_PIC(OTHER) \ | 
|  | +  (STO_RISCV_PIC | ELF_ST_VISIBILITY (OTHER)) | 
|  | + | 
|  | +/* The 64-bit RISC-V ELF ABI uses an unusual reloc format.  Each | 
|  | +   relocation entry specifies up to three actual relocations, all at | 
|  | +   the same address.  The first relocation which required a symbol | 
|  | +   uses the symbol in the r_sym field.  The second relocation which | 
|  | +   requires a symbol uses the symbol in the r_ssym field.  If all | 
|  | +   three relocations require a symbol, the third one uses a zero | 
|  | +   value.  */ | 
|  | + | 
|  | +/* An entry in a 64 bit SHT_REL section.  */ | 
|  | + | 
|  | +typedef struct | 
|  | +{ | 
|  | +  /* Address of relocation.  */ | 
|  | +  unsigned char r_offset[8]; | 
|  | +  /* Symbol index.  */ | 
|  | +  unsigned char r_sym[4]; | 
|  | +  /* Special symbol.  */ | 
|  | +  unsigned char r_ssym[1]; | 
|  | +  /* Third relocation.  */ | 
|  | +  unsigned char r_type3[1]; | 
|  | +  /* Second relocation.  */ | 
|  | +  unsigned char r_type2[1]; | 
|  | +  /* First relocation.  */ | 
|  | +  unsigned char r_type[1]; | 
|  | +} Elf64_RISCV_External_Rel; | 
|  | + | 
|  | +typedef struct | 
|  | +{ | 
|  | +  /* Address of relocation.  */ | 
|  | +  bfd_vma r_offset; | 
|  | +  /* Symbol index.  */ | 
|  | +  unsigned long r_sym; | 
|  | +  /* Special symbol.  */ | 
|  | +  unsigned char r_ssym; | 
|  | +  /* Third relocation.  */ | 
|  | +  unsigned char r_type3; | 
|  | +  /* Second relocation.  */ | 
|  | +  unsigned char r_type2; | 
|  | +  /* First relocation.  */ | 
|  | +  unsigned char r_type; | 
|  | +} Elf64_RISCV_Internal_Rel; | 
|  | + | 
|  | +/* An entry in a 64 bit SHT_RELA section.  */ | 
|  | + | 
|  | +typedef struct | 
|  | +{ | 
|  | +  /* Address of relocation.  */ | 
|  | +  unsigned char r_offset[8]; | 
|  | +  /* Symbol index.  */ | 
|  | +  unsigned char r_sym[4]; | 
|  | +  /* Special symbol.  */ | 
|  | +  unsigned char r_ssym[1]; | 
|  | +  /* Third relocation.  */ | 
|  | +  unsigned char r_type3[1]; | 
|  | +  /* Second relocation.  */ | 
|  | +  unsigned char r_type2[1]; | 
|  | +  /* First relocation.  */ | 
|  | +  unsigned char r_type[1]; | 
|  | +  /* Addend.  */ | 
|  | +  unsigned char r_addend[8]; | 
|  | +} Elf64_RISCV_External_Rela; | 
|  | + | 
|  | +typedef struct | 
|  | +{ | 
|  | +  /* Address of relocation.  */ | 
|  | +  bfd_vma r_offset; | 
|  | +  /* Symbol index.  */ | 
|  | +  unsigned long r_sym; | 
|  | +  /* Special symbol.  */ | 
|  | +  unsigned char r_ssym; | 
|  | +  /* Third relocation.  */ | 
|  | +  unsigned char r_type3; | 
|  | +  /* Second relocation.  */ | 
|  | +  unsigned char r_type2; | 
|  | +  /* First relocation.  */ | 
|  | +  unsigned char r_type; | 
|  | +  /* Addend.  */ | 
|  | +  bfd_signed_vma r_addend; | 
|  | +} Elf64_RISCV_Internal_Rela; | 
|  | + | 
|  | +/* RISC-V ELF 64 relocation info access macros.  */ | 
|  | +#define ELF64_RISCV_R_SSYM(i) (((i) >> 24) & 0xff) | 
|  | +#define ELF64_RISCV_R_TYPE3(i) (((i) >> 16) & 0xff) | 
|  | +#define ELF64_RISCV_R_TYPE2(i) (((i) >> 8) & 0xff) | 
|  | +#define ELF64_RISCV_R_TYPE(i) ((i) & 0xff) | 
|  | + | 
|  | +/* RISC-V ELF option header swapping routines.  */ | 
|  | +extern void bfd_riscv_elf_swap_options_in | 
|  | +  (bfd *, const Elf_External_Options *, Elf_Internal_Options *); | 
|  | +extern void bfd_riscv_elf_swap_options_out | 
|  | +  (bfd *, const Elf_Internal_Options *, Elf_External_Options *); | 
|  | + | 
|  | +/* RISC-V ELF reginfo swapping routines.  */ | 
|  | +extern void bfd_riscv_elf64_swap_reginfo_in | 
|  | +  (bfd *, const Elf64_External_RegInfo *, Elf64_Internal_RegInfo *); | 
|  | +extern void bfd_riscv_elf64_swap_reginfo_out | 
|  | +  (bfd *, const Elf64_Internal_RegInfo *, Elf64_External_RegInfo *); | 
|  | + | 
|  | +#endif /* _ELF_RISCV_H */ | 
|  | diff -ruN binutils-2.24/include/opcode/riscv.h binutils-2.24-riscv/include/opcode/riscv.h | 
|  | --- binutils-2.24/include/opcode/riscv.h	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/include/opcode/riscv.h	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,257 @@ | 
|  | +/* riscv.h.  RISC-V opcode list for GDB, the GNU debugger. | 
|  | +   Copyright 2011 | 
|  | +   Free Software Foundation, Inc. | 
|  | +   Contributed by Andrew Waterman | 
|  | + | 
|  | +This file is part of GDB, GAS, and the GNU binutils. | 
|  | + | 
|  | +GDB, GAS, and the GNU binutils are free software; you can redistribute | 
|  | +them and/or modify them under the terms of the GNU General Public | 
|  | +License as published by the Free Software Foundation; either version | 
|  | +1, or (at your option) any later version. | 
|  | + | 
|  | +GDB, GAS, and the GNU binutils are distributed in the hope that they | 
|  | +will be useful, but WITHOUT ANY WARRANTY; without even the implied | 
|  | +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See | 
|  | +the GNU General Public License for more details. | 
|  | + | 
|  | +You should have received a copy of the GNU General Public License | 
|  | +along with this file; see the file COPYING.  If not, write to the Free | 
|  | +Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */ | 
|  | + | 
|  | +#ifndef _RISCV_H_ | 
|  | +#define _RISCV_H_ | 
|  | + | 
|  | +/* RVC fields */ | 
|  | + | 
|  | +#define OP_MASK_COP		0x1f | 
|  | +#define OP_SH_COP		0 | 
|  | +#define OP_MASK_CRD		0x1f | 
|  | +#define OP_SH_CRD		5 | 
|  | +#define OP_MASK_CRS2	0x1f | 
|  | +#define OP_SH_CRS2	5 | 
|  | +#define OP_MASK_CRS1	0x1f | 
|  | +#define OP_SH_CRS1	10 | 
|  | +#define OP_MASK_CRDS		0x7 | 
|  | +#define OP_SH_CRDS		13 | 
|  | +#define OP_MASK_CRS2S	0x7 | 
|  | +#define OP_SH_CRS2S	13 | 
|  | +#define OP_MASK_CRS2BS	0x7 | 
|  | +#define OP_SH_CRS2BS	5 | 
|  | +#define OP_MASK_CRS1S	0x7 | 
|  | +#define OP_SH_CRS1S	10 | 
|  | +#define OP_MASK_CIMM6	0x3f | 
|  | +#define OP_SH_CIMM6	10 | 
|  | +#define OP_MASK_CIMM5	0x1f | 
|  | +#define OP_SH_CIMM5	5 | 
|  | +#define OP_MASK_CIMM10	0x3ff | 
|  | +#define OP_SH_CIMM10	5 | 
|  | + | 
|  | +static const char rvc_rs1_regmap[8] = { 20, 21, 2, 3, 4, 5, 6, 7 }; | 
|  | +#define rvc_rd_regmap rvc_rs1_regmap | 
|  | +#define rvc_rs2b_regmap rvc_rs1_regmap | 
|  | +static const char rvc_rs2_regmap[8] = { 20, 21, 2, 3, 4, 5, 6, 0 }; | 
|  | + | 
|  | +#define RVC_JUMP_BITS 10 | 
|  | +#define RVC_JUMP_ALIGN_BITS 1 | 
|  | +#define RVC_JUMP_ALIGN (1 << RVC_JUMP_ALIGN_BITS) | 
|  | +#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RVC_JUMP_ALIGN) | 
|  | + | 
|  | +#define RVC_BRANCH_BITS 5 | 
|  | +#define RVC_BRANCH_ALIGN_BITS RVC_JUMP_ALIGN_BITS | 
|  | +#define RVC_BRANCH_ALIGN (1 << RVC_BRANCH_ALIGN_BITS) | 
|  | +#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RVC_BRANCH_ALIGN) | 
|  | + | 
|  | +#define RISCV_JTYPE(insn, target) \ | 
|  | +  ((MATCH_ ## insn) | (((target) & ((1<<RISCV_JUMP_BITS)-1)) << OP_SH_TARGET)) | 
|  | +#define RISCV_LTYPE(insn, rd, bigimm) \ | 
|  | +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | (((bigimm) & ((1<<RISCV_BIGIMM_BITS)-1)) << OP_SH_BIGIMMEDIATE)) | 
|  | +#define RISCV_ITYPE(insn, rd, rs1, imm) \ | 
|  | +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS) | (((imm) & (RISCV_IMM_REACH-1)) << OP_SH_IMMEDIATE)) | 
|  | +#define RISCV_BTYPE(insn, rs1, rs2, imm) \ | 
|  | +  ((MATCH_ ## insn) | ((rs1) << OP_SH_RS) | ((rs2) << OP_SH_RT) | (((imm) & OP_MASK_IMMLO) << OP_SH_IMMLO) | ((((imm) >> RISCV_IMMLO_BITS) & OP_MASK_IMMHI) << OP_SH_IMMHI)) | 
|  | +#define RISCV_RTYPE(insn, rd, rs1, rs2) \ | 
|  | +  ((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS) | ((rs2) << OP_SH_RT)) | 
|  | + | 
|  | +#define RISCV_NOP RISCV_ITYPE(ADDI, 0, 0, 0) | 
|  | + | 
|  | +#define RISCV_JUMP_TARGET(address) ((address) >> RISCV_JUMP_ALIGN_BITS) | 
|  | +#define RISCV_CONST_HIGH_PART(VALUE) \ | 
|  | +  (((VALUE) + (RISCV_IMM_REACH/2)) & ~(RISCV_IMM_REACH-1)) | 
|  | +#define RISCV_CONST_LOW_PART(VALUE) ((VALUE) - RISCV_CONST_HIGH_PART (VALUE)) | 
|  | +#define RISCV_LUI_HIGH_PART(VALUE) (RISCV_CONST_HIGH_PART(VALUE) >> RISCV_IMM_BITS) | 
|  | + | 
|  | +/* RV fields */ | 
|  | + | 
|  | +#define OP_MASK_OP		0x7f | 
|  | +#define OP_SH_OP		0 | 
|  | +#define OP_MASK_RT		0x1f | 
|  | +#define OP_SH_RT		17 | 
|  | +#define OP_MASK_FT		0x1f | 
|  | +#define OP_SH_FT		17 | 
|  | +#define OP_MASK_RS		0x1f | 
|  | +#define OP_SH_RS		22 | 
|  | +#define OP_MASK_FS		0x1f | 
|  | +#define OP_SH_FS		22 | 
|  | +#define OP_MASK_FR		0x1f | 
|  | +#define OP_SH_FR		12 | 
|  | +#define OP_MASK_RD		0x1f | 
|  | +#define OP_SH_RD		27 | 
|  | +#define OP_MASK_FD		0x1f | 
|  | +#define OP_SH_FD		27 | 
|  | +#define OP_MASK_SHAMT		0x3f | 
|  | +#define OP_SH_SHAMT		10 | 
|  | +#define OP_MASK_SHAMTW		0x1f | 
|  | +#define OP_SH_SHAMTW	10 | 
|  | +#define OP_MASK_RM		0x7 | 
|  | +#define OP_SH_RM	9 | 
|  | + | 
|  | +static const char * const riscv_rm[8] = | 
|  | +  { "rne", "rtz", "rdn", "rup", "rmm", 0, 0, "dyn" }; | 
|  | + | 
|  | +#define OP_MASK_VRD		0x1f | 
|  | +#define OP_SH_VRD		27 | 
|  | +#define OP_MASK_VRS		0x1f | 
|  | +#define OP_SH_VRS		22 | 
|  | +#define OP_MASK_VRT		0x1f | 
|  | +#define OP_SH_VRT		17 | 
|  | +#define OP_MASK_VRR		0x1f | 
|  | +#define OP_SH_VRR		12 | 
|  | + | 
|  | +#define OP_MASK_VFD		0x1f | 
|  | +#define OP_SH_VFD		27 | 
|  | +#define OP_MASK_VFS		0x1f | 
|  | +#define OP_SH_VFS		22 | 
|  | +#define OP_MASK_VFT		0x1f | 
|  | +#define OP_SH_VFT		17 | 
|  | +#define OP_MASK_VFR		0x1f | 
|  | +#define OP_SH_VFR		12 | 
|  | + | 
|  | +#define OP_MASK_IMMNGPR         0x3f | 
|  | +#define OP_SH_IMMNGPR           10 | 
|  | +#define OP_MASK_IMMNFPR         0x3f | 
|  | +#define OP_SH_IMMNFPR           16 | 
|  | +#define OP_MASK_IMMSEGNELM      0x1f | 
|  | +#define OP_SH_IMMSEGNELM        17 | 
|  | +#define OP_MASK_IMMSEGSTNELM    0x1f | 
|  | +#define OP_SH_IMMSEGSTNELM      12 | 
|  | + | 
|  | +#define LINK_REG 1 | 
|  | + | 
|  | +#define RISCV_JUMP_BITS 25 | 
|  | +#define RISCV_JUMP_ALIGN_BITS 1 | 
|  | +#define RISCV_JUMP_ALIGN (1 << RISCV_JUMP_ALIGN_BITS) | 
|  | +#define RISCV_JUMP_REACH ((1ULL<<RISCV_JUMP_BITS)*RISCV_JUMP_ALIGN) | 
|  | + | 
|  | +#define OP_MASK_TARGET		((1<<RISCV_JUMP_BITS)-1) | 
|  | +#define OP_SH_TARGET		7 | 
|  | + | 
|  | +#define RISCV_IMM_BITS 12 | 
|  | +#define RISCV_IMMLO_BITS 7 | 
|  | +#define RISCV_IMMHI_BITS (RISCV_IMM_BITS - RISCV_IMMLO_BITS) | 
|  | +#define RISCV_BIGIMM_BITS (32-RISCV_IMM_BITS) | 
|  | +#define RISCV_IMM_REACH (1LL<<RISCV_IMM_BITS) | 
|  | +#define RISCV_BIGIMM_REACH (1LL<<RISCV_BIGIMM_BITS) | 
|  | +#define RISCV_BRANCH_BITS RISCV_IMM_BITS | 
|  | +#define RISCV_BRANCH_ALIGN_BITS RISCV_JUMP_ALIGN_BITS | 
|  | +#define RISCV_BRANCH_ALIGN (1 << RISCV_BRANCH_ALIGN_BITS) | 
|  | +#define RISCV_BRANCH_REACH (RISCV_IMM_REACH*RISCV_BRANCH_ALIGN) | 
|  | + | 
|  | +#define OP_MASK_BIGIMMEDIATE	((1<<RISCV_BIGIMM_BITS)-1) | 
|  | +#define OP_SH_BIGIMMEDIATE		7 | 
|  | +#define OP_MASK_IMMEDIATE	((1<<RISCV_IMM_BITS)-1) | 
|  | +#define OP_SH_IMMEDIATE		10 | 
|  | +#define OP_MASK_IMMLO ((1<<RISCV_IMMLO_BITS)-1) | 
|  | +#define OP_SH_IMMLO   10 | 
|  | +#define OP_MASK_IMMHI ((1<<(RISCV_IMM_BITS-RISCV_IMMLO_BITS))-1) | 
|  | +#define OP_SH_IMMHI   27 | 
|  | + | 
|  | +#include "riscv-opc.h" | 
|  | + | 
|  | +/* This structure holds information for a particular instruction.  */ | 
|  | + | 
|  | +struct riscv_opcode | 
|  | +{ | 
|  | +  /* The name of the instruction.  */ | 
|  | +  const char *name; | 
|  | +  /* A string describing the arguments for this instruction.  */ | 
|  | +  const char *args; | 
|  | +  /* The basic opcode for the instruction.  When assembling, this | 
|  | +     opcode is modified by the arguments to produce the actual opcode | 
|  | +     that is used.  If pinfo is INSN_MACRO, then this is 0.  */ | 
|  | +  unsigned long match; | 
|  | +  /* If pinfo is not INSN_MACRO, then this is a bit mask for the | 
|  | +     relevant portions of the opcode when disassembling.  If the | 
|  | +     actual opcode anded with the match field equals the opcode field, | 
|  | +     then we have found the correct instruction.  If pinfo is | 
|  | +     INSN_MACRO, then this field is the macro identifier.  */ | 
|  | +  unsigned long mask; | 
|  | +  /* For a macro, this is INSN_MACRO.  Otherwise, it is a collection | 
|  | +     of bits describing the instruction, notably any relevant hazard | 
|  | +     information.  */ | 
|  | +  unsigned long pinfo; | 
|  | +}; | 
|  | + | 
|  | +#define INSN_WRITE_GPR_D            0x00000001 | 
|  | +#define INSN_WRITE_GPR_RA           0x00000004 | 
|  | +#define INSN_WRITE_FPR_D            0x00000008 | 
|  | +#define INSN_READ_GPR_S             0x00000040 | 
|  | +#define INSN_READ_GPR_T             0x00000080 | 
|  | +#define INSN_READ_FPR_S             0x00000100 | 
|  | +#define INSN_READ_FPR_T             0x00000200 | 
|  | +#define INSN_READ_FPR_R        	    0x00000400 | 
|  | +/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */ | 
|  | +#define	INSN_ALIAS		    0x00001000 | 
|  | +/* Instruction is actually a macro.  It should be ignored by the | 
|  | +   disassembler, and requires special treatment by the assembler.  */ | 
|  | +#define INSN_MACRO                  0xffffffff | 
|  | + | 
|  | +/* These are the bits which may be set in the pinfo2 field of an | 
|  | +   instruction. */ | 
|  | + | 
|  | +/* MIPS ISA defines, use instead of hardcoding ISA level.  */ | 
|  | + | 
|  | +#define       ISA_UNKNOWN     0               /* Gas internal use.  */ | 
|  | +#define       ISA_RV32        1 | 
|  | +#define       ISA_RV64        2 | 
|  | + | 
|  | +#define CPU_UNKNOWN    0 | 
|  | +#define CPU_ROCKET32 132 | 
|  | +#define CPU_ROCKET64 164 | 
|  | + | 
|  | +/* This is a list of macro expanded instructions. | 
|  | + | 
|  | +   _I appended means immediate | 
|  | +   _A appended means address | 
|  | +   _AB appended means address with base register | 
|  | +   _D appended means 64 bit floating point constant | 
|  | +   _S appended means 32 bit floating point constant.  */ | 
|  | + | 
|  | +enum | 
|  | +{ | 
|  | +  M_LA_AB, | 
|  | +  M_LA_TLS_GD, | 
|  | +  M_LA_TLS_IE, | 
|  | +  M_J, | 
|  | +  M_LI, | 
|  | +  M_NUM_MACROS | 
|  | +}; | 
|  | + | 
|  | + | 
|  | +/* The order of overloaded instructions matters.  Label arguments and | 
|  | +   register arguments look the same. Instructions that can have either | 
|  | +   for arguments must apear in the correct order in this table for the | 
|  | +   assembler to pick the right one. In other words, entries with | 
|  | +   immediate operands must apear after the same instruction with | 
|  | +   registers. | 
|  | + | 
|  | +   Many instructions are short hand for other instructions (i.e., The | 
|  | +   jal <register> instruction is short for jalr <register>).  */ | 
|  | + | 
|  | +extern const struct riscv_opcode riscv_builtin_opcodes[]; | 
|  | +extern const int bfd_riscv_num_builtin_opcodes; | 
|  | +extern struct riscv_opcode *riscv_opcodes; | 
|  | +extern int bfd_riscv_num_opcodes; | 
|  | +#define NUMOPCODES bfd_riscv_num_opcodes | 
|  | + | 
|  | +#endif /* _MIPS_H_ */ | 
|  | diff -ruN binutils-2.24/include/opcode/riscv-opc.h binutils-2.24-riscv/include/opcode/riscv-opc.h | 
|  | --- binutils-2.24/include/opcode/riscv-opc.h	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/include/opcode/riscv-opc.h	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,571 @@ | 
|  | +/* Automatically generated by parse-opcodes */ | 
|  | +#define MATCH_MOVN 0x6f7 | 
|  | +#define  MASK_MOVN 0x1ffff | 
|  | +#define MATCH_VFSSTW 0x150f | 
|  | +#define  MASK_VFSSTW 0x1ffff | 
|  | +#define MATCH_REMUW 0x7bb | 
|  | +#define  MASK_REMUW 0x1ffff | 
|  | +#define MATCH_FMIN_D 0x180d3 | 
|  | +#define  MASK_FMIN_D 0x1ffff | 
|  | +#define MATCH_LR_W 0x1012b | 
|  | +#define  MASK_LR_W 0x3fffff | 
|  | +#define MATCH_VLSTHU 0x128b | 
|  | +#define  MASK_VLSTHU 0x1ffff | 
|  | +#define MATCH_C_SWSP 0x8 | 
|  | +#define  MASK_C_SWSP 0x1f | 
|  | +#define MATCH_BLTU 0x363 | 
|  | +#define  MASK_BLTU 0x3ff | 
|  | +#define MATCH_VLSEGSTWU 0xb0b | 
|  | +#define  MASK_VLSEGSTWU 0xfff | 
|  | +#define MATCH_VVCFG 0x473 | 
|  | +#define  MASK_VVCFG 0xf801ffff | 
|  | +#define MATCH_MOVZ 0x2f7 | 
|  | +#define  MASK_MOVZ 0x1ffff | 
|  | +#define MATCH_C_LD 0x9 | 
|  | +#define  MASK_C_LD 0x1f | 
|  | +#define MATCH_C_SRLI32 0xc19 | 
|  | +#define  MASK_C_SRLI32 0x1c1f | 
|  | +#define MATCH_FMIN_S 0x18053 | 
|  | +#define  MASK_FMIN_S 0x1ffff | 
|  | +#define MATCH_C_LW0 0x12 | 
|  | +#define  MASK_C_LW0 0x801f | 
|  | +#define MATCH_SLLIW 0x9b | 
|  | +#define  MASK_SLLIW 0x3f83ff | 
|  | +#define MATCH_LB 0x3 | 
|  | +#define  MASK_LB 0x3ff | 
|  | +#define MATCH_VLWU 0x30b | 
|  | +#define  MASK_VLWU 0x3fffff | 
|  | +#define MATCH_FCVT_S_WU 0xf053 | 
|  | +#define  MASK_FCVT_S_WU 0x3ff1ff | 
|  | +#define MATCH_FCVT_D_L 0xc0d3 | 
|  | +#define  MASK_FCVT_D_L 0x3ff1ff | 
|  | +#define MATCH_LH 0x83 | 
|  | +#define  MASK_LH 0x3ff | 
|  | +#define MATCH_FCVT_D_W 0xe0d3 | 
|  | +#define  MASK_FCVT_D_W 0x3ff1ff | 
|  | +#define MATCH_LW 0x103 | 
|  | +#define  MASK_LW 0x3ff | 
|  | +#define MATCH_ADD 0x33 | 
|  | +#define  MASK_ADD 0x1ffff | 
|  | +#define MATCH_FCVT_D_S 0x100d3 | 
|  | +#define  MASK_FCVT_D_S 0x3ff1ff | 
|  | +#define MATCH_MFPCR 0x17b | 
|  | +#define  MASK_MFPCR 0x3fffff | 
|  | +#define MATCH_C_FSD 0x18 | 
|  | +#define  MASK_C_FSD 0x1f | 
|  | +#define MATCH_FMAX_D 0x190d3 | 
|  | +#define  MASK_FMAX_D 0x1ffff | 
|  | +#define MATCH_BNE 0xe3 | 
|  | +#define  MASK_BNE 0x3ff | 
|  | +#define MATCH_RDCYCLE 0x277 | 
|  | +#define  MASK_RDCYCLE 0x7ffffff | 
|  | +#define MATCH_FCVT_S_D 0x11053 | 
|  | +#define  MASK_FCVT_S_D 0x3ff1ff | 
|  | +#define MATCH_VLH 0x8b | 
|  | +#define  MASK_VLH 0x3fffff | 
|  | +#define MATCH_BGEU 0x3e3 | 
|  | +#define  MASK_BGEU 0x3ff | 
|  | +#define MATCH_VFLSTD 0x158b | 
|  | +#define  MASK_VFLSTD 0x1ffff | 
|  | +#define MATCH_C_LI 0x0 | 
|  | +#define  MASK_C_LI 0x1f | 
|  | +#define MATCH_FADD_D 0xd3 | 
|  | +#define  MASK_FADD_D 0x1f1ff | 
|  | +#define MATCH_SLTIU 0x193 | 
|  | +#define  MASK_SLTIU 0x3ff | 
|  | +#define MATCH_MTPCR 0x1fb | 
|  | +#define  MASK_MTPCR 0x1ffff | 
|  | +#define MATCH_VLB 0xb | 
|  | +#define  MASK_VLB 0x3fffff | 
|  | +#define MATCH_STOP 0x177 | 
|  | +#define  MASK_STOP 0xffffffff | 
|  | +#define MATCH_VLD 0x18b | 
|  | +#define  MASK_VLD 0x3fffff | 
|  | +#define MATCH_C_SLLI 0x19 | 
|  | +#define  MASK_C_SLLI 0x1c1f | 
|  | +#define MATCH_BREAK 0xf7 | 
|  | +#define  MASK_BREAK 0xffffffff | 
|  | +#define MATCH_CFLUSH 0x2fb | 
|  | +#define  MASK_CFLUSH 0xffffffff | 
|  | +#define MATCH_FCVT_S_W 0xe053 | 
|  | +#define  MASK_FCVT_S_W 0x3ff1ff | 
|  | +#define MATCH_VFLSTW 0x150b | 
|  | +#define  MASK_VFLSTW 0x1ffff | 
|  | +#define MATCH_MUL 0x433 | 
|  | +#define  MASK_MUL 0x1ffff | 
|  | +#define MATCH_C_LW 0xa | 
|  | +#define  MASK_C_LW 0x1f | 
|  | +#define MATCH_VXCPTEVAC 0x237b | 
|  | +#define  MASK_VXCPTEVAC 0xf83fffff | 
|  | +#define MATCH_VLW 0x10b | 
|  | +#define  MASK_VLW 0x3fffff | 
|  | +#define MATCH_VSSEGSTW 0x90f | 
|  | +#define  MASK_VSSEGSTW 0xfff | 
|  | +#define MATCH_AMOMINU_D 0x19ab | 
|  | +#define  MASK_AMOMINU_D 0x1ffff | 
|  | +#define MATCH_C_SDSP 0x6 | 
|  | +#define  MASK_C_SDSP 0x1f | 
|  | +#define MATCH_UTIDX 0x1f7 | 
|  | +#define  MASK_UTIDX 0x7ffffff | 
|  | +#define MATCH_SRLI 0x293 | 
|  | +#define  MASK_SRLI 0x3f03ff | 
|  | +#define MATCH_C_SRLI 0x819 | 
|  | +#define  MASK_C_SRLI 0x1c1f | 
|  | +#define MATCH_C_LDSP 0x4 | 
|  | +#define  MASK_C_LDSP 0x1f | 
|  | +#define MATCH_C_FLW 0x14 | 
|  | +#define  MASK_C_FLW 0x1f | 
|  | +#define MATCH_C_SRAI32 0x1419 | 
|  | +#define  MASK_C_SRAI32 0x1c1f | 
|  | +#define MATCH_AMOMINU_W 0x192b | 
|  | +#define  MASK_AMOMINU_W 0x1ffff | 
|  | +#define MATCH_DIVUW 0x6bb | 
|  | +#define  MASK_DIVUW 0x1ffff | 
|  | +#define MATCH_MULW 0x43b | 
|  | +#define  MASK_MULW 0x1ffff | 
|  | +#define MATCH_VSSEGSTD 0x98f | 
|  | +#define  MASK_VSSEGSTD 0xfff | 
|  | +#define MATCH_SRLW 0x2bb | 
|  | +#define  MASK_SRLW 0x1ffff | 
|  | +#define MATCH_VSSEGSTB 0x80f | 
|  | +#define  MASK_VSSEGSTB 0xfff | 
|  | +#define MATCH_MFTX_D 0x1c0d3 | 
|  | +#define  MASK_MFTX_D 0x3fffff | 
|  | +#define MATCH_DIV 0x633 | 
|  | +#define  MASK_DIV 0x1ffff | 
|  | +#define MATCH_VTCFG 0xc73 | 
|  | +#define  MASK_VTCFG 0xf801ffff | 
|  | +#define MATCH_MFTX_S 0x1c053 | 
|  | +#define  MASK_MFTX_S 0x3fffff | 
|  | +#define MATCH_VSSEGSTH 0x88f | 
|  | +#define  MASK_VSSEGSTH 0xfff | 
|  | +#define MATCH_VVCFGIVL 0xf3 | 
|  | +#define  MASK_VVCFGIVL 0x3ff | 
|  | +#define MATCH_J 0x67 | 
|  | +#define  MASK_J 0x7f | 
|  | +#define MATCH_FENCE 0x12f | 
|  | +#define  MASK_FENCE 0x3ff | 
|  | +#define MATCH_VSW 0x10f | 
|  | +#define  MASK_VSW 0x3fffff | 
|  | +#define MATCH_FNMSUB_S 0x4b | 
|  | +#define  MASK_FNMSUB_S 0x1ff | 
|  | +#define MATCH_VFSSEGSTD 0xd8f | 
|  | +#define  MASK_VFSSEGSTD 0xfff | 
|  | +#define MATCH_FCVT_L_S 0x8053 | 
|  | +#define  MASK_FCVT_L_S 0x3ff1ff | 
|  | +#define MATCH_FLE_S 0x17053 | 
|  | +#define  MASK_FLE_S 0x1ffff | 
|  | +#define MATCH_FENCE_V_L 0x22f | 
|  | +#define  MASK_FENCE_V_L 0x3ff | 
|  | +#define MATCH_VSB 0xf | 
|  | +#define  MASK_VSB 0x3fffff | 
|  | +#define MATCH_MFFSR 0x1d053 | 
|  | +#define  MASK_MFFSR 0x7ffffff | 
|  | +#define MATCH_FDIV_S 0x3053 | 
|  | +#define  MASK_FDIV_S 0x1f1ff | 
|  | +#define MATCH_VLSTBU 0x120b | 
|  | +#define  MASK_VLSTBU 0x1ffff | 
|  | +#define MATCH_VSETVL 0x2f3 | 
|  | +#define  MASK_VSETVL 0x3fffff | 
|  | +#define MATCH_FLE_D 0x170d3 | 
|  | +#define  MASK_FLE_D 0x1ffff | 
|  | +#define MATCH_FENCE_I 0xaf | 
|  | +#define  MASK_FENCE_I 0x3ff | 
|  | +#define MATCH_VLSEGBU 0x220b | 
|  | +#define  MASK_VLSEGBU 0x1ffff | 
|  | +#define MATCH_FNMSUB_D 0xcb | 
|  | +#define  MASK_FNMSUB_D 0x1ff | 
|  | +#define MATCH_ADDW 0x3b | 
|  | +#define  MASK_ADDW 0x1ffff | 
|  | +#define MATCH_SLL 0xb3 | 
|  | +#define  MASK_SLL 0x1ffff | 
|  | +#define MATCH_XOR 0x233 | 
|  | +#define  MASK_XOR 0x1ffff | 
|  | +#define MATCH_SUB 0x10033 | 
|  | +#define  MASK_SUB 0x1ffff | 
|  | +#define MATCH_ERET 0x27b | 
|  | +#define  MASK_ERET 0xffffffff | 
|  | +#define MATCH_BLT 0x263 | 
|  | +#define  MASK_BLT 0x3ff | 
|  | +#define MATCH_VSSTW 0x110f | 
|  | +#define  MASK_VSSTW 0x1ffff | 
|  | +#define MATCH_MTFSR 0x1f053 | 
|  | +#define  MASK_MTFSR 0x3fffff | 
|  | +#define MATCH_VSSTH 0x108f | 
|  | +#define  MASK_VSSTH 0x1ffff | 
|  | +#define MATCH_SC_W 0x1052b | 
|  | +#define  MASK_SC_W 0x1ffff | 
|  | +#define MATCH_REM 0x733 | 
|  | +#define  MASK_REM 0x1ffff | 
|  | +#define MATCH_SRLIW 0x29b | 
|  | +#define  MASK_SRLIW 0x3f83ff | 
|  | +#define MATCH_LUI 0x37 | 
|  | +#define  MASK_LUI 0x7f | 
|  | +#define MATCH_VSSTB 0x100f | 
|  | +#define  MASK_VSSTB 0x1ffff | 
|  | +#define MATCH_FCVT_S_LU 0xd053 | 
|  | +#define  MASK_FCVT_S_LU 0x3ff1ff | 
|  | +#define MATCH_VSSTD 0x118f | 
|  | +#define  MASK_VSSTD 0x1ffff | 
|  | +#define MATCH_ADDI 0x13 | 
|  | +#define  MASK_ADDI 0x3ff | 
|  | +#define MATCH_VFMST 0x1173 | 
|  | +#define  MASK_VFMST 0x1ffff | 
|  | +#define MATCH_MULH 0x4b3 | 
|  | +#define  MASK_MULH 0x1ffff | 
|  | +#define MATCH_FMUL_S 0x2053 | 
|  | +#define  MASK_FMUL_S 0x1f1ff | 
|  | +#define MATCH_VLSEGSTHU 0xa8b | 
|  | +#define  MASK_VLSEGSTHU 0xfff | 
|  | +#define MATCH_SRAI 0x10293 | 
|  | +#define  MASK_SRAI 0x3f03ff | 
|  | +#define MATCH_AMOAND_D 0x9ab | 
|  | +#define  MASK_AMOAND_D 0x1ffff | 
|  | +#define MATCH_FLT_D 0x160d3 | 
|  | +#define  MASK_FLT_D 0x1ffff | 
|  | +#define MATCH_SRAW 0x102bb | 
|  | +#define  MASK_SRAW 0x1ffff | 
|  | +#define MATCH_FMUL_D 0x20d3 | 
|  | +#define  MASK_FMUL_D 0x1f1ff | 
|  | +#define MATCH_LD 0x183 | 
|  | +#define  MASK_LD 0x3ff | 
|  | +#define MATCH_ORI 0x313 | 
|  | +#define  MASK_ORI 0x3ff | 
|  | +#define MATCH_FLT_S 0x16053 | 
|  | +#define  MASK_FLT_S 0x1ffff | 
|  | +#define MATCH_ADDIW 0x1b | 
|  | +#define  MASK_ADDIW 0x3ff | 
|  | +#define MATCH_AMOAND_W 0x92b | 
|  | +#define  MASK_AMOAND_W 0x1ffff | 
|  | +#define MATCH_FEQ_S 0x15053 | 
|  | +#define  MASK_FEQ_S 0x1ffff | 
|  | +#define MATCH_FSGNJX_D 0x70d3 | 
|  | +#define  MASK_FSGNJX_D 0x1ffff | 
|  | +#define MATCH_SRA 0x102b3 | 
|  | +#define  MASK_SRA 0x1ffff | 
|  | +#define MATCH_C_LWSP 0x5 | 
|  | +#define  MASK_C_LWSP 0x1f | 
|  | +#define MATCH_BGE 0x2e3 | 
|  | +#define  MASK_BGE 0x3ff | 
|  | +#define MATCH_C_ADD3 0x1c | 
|  | +#define  MASK_C_ADD3 0x31f | 
|  | +#define MATCH_SRAIW 0x1029b | 
|  | +#define  MASK_SRAIW 0x3f83ff | 
|  | +#define MATCH_VSSEGD 0x218f | 
|  | +#define  MASK_VSSEGD 0x1ffff | 
|  | +#define MATCH_SRL 0x2b3 | 
|  | +#define  MASK_SRL 0x1ffff | 
|  | +#define MATCH_VENQCMD 0x2b7b | 
|  | +#define  MASK_VENQCMD 0xf801ffff | 
|  | +#define MATCH_FSUB_D 0x10d3 | 
|  | +#define  MASK_FSUB_D 0x1f1ff | 
|  | +#define MATCH_VFMTS 0x1973 | 
|  | +#define  MASK_VFMTS 0x1ffff | 
|  | +#define MATCH_VENQIMM1 0x2f7b | 
|  | +#define  MASK_VENQIMM1 0xf801ffff | 
|  | +#define MATCH_FSGNJX_S 0x7053 | 
|  | +#define  MASK_FSGNJX_S 0x1ffff | 
|  | +#define MATCH_VFMSV 0x973 | 
|  | +#define  MASK_VFMSV 0x3fffff | 
|  | +#define MATCH_VENQIMM2 0x337b | 
|  | +#define  MASK_VENQIMM2 0xf801ffff | 
|  | +#define MATCH_FCVT_D_WU 0xf0d3 | 
|  | +#define  MASK_FCVT_D_WU 0x3ff1ff | 
|  | +#define MATCH_VXCPTRESTORE 0x77b | 
|  | +#define  MASK_VXCPTRESTORE 0xf83fffff | 
|  | +#define MATCH_VMTS 0x1873 | 
|  | +#define  MASK_VMTS 0x1ffff | 
|  | +#define MATCH_OR 0x333 | 
|  | +#define  MASK_OR 0x1ffff | 
|  | +#define MATCH_RDINSTRET 0xa77 | 
|  | +#define  MASK_RDINSTRET 0x7ffffff | 
|  | +#define MATCH_FCVT_WU_D 0xb0d3 | 
|  | +#define  MASK_FCVT_WU_D 0x3ff1ff | 
|  | +#define MATCH_SUBW 0x1003b | 
|  | +#define  MASK_SUBW 0x1ffff | 
|  | +#define MATCH_JALR_C 0x6b | 
|  | +#define  MASK_JALR_C 0x3ff | 
|  | +#define MATCH_FMAX_S 0x19053 | 
|  | +#define  MASK_FMAX_S 0x1ffff | 
|  | +#define MATCH_AMOMAXU_D 0x1dab | 
|  | +#define  MASK_AMOMAXU_D 0x1ffff | 
|  | +#define MATCH_C_SLLIW 0x1819 | 
|  | +#define  MASK_C_SLLIW 0x1c1f | 
|  | +#define MATCH_JALR_J 0x16b | 
|  | +#define  MASK_JALR_J 0x3ff | 
|  | +#define MATCH_C_FLD 0x15 | 
|  | +#define  MASK_C_FLD 0x1f | 
|  | +#define MATCH_VLSTW 0x110b | 
|  | +#define  MASK_VLSTW 0x1ffff | 
|  | +#define MATCH_VLSTH 0x108b | 
|  | +#define  MASK_VLSTH 0x1ffff | 
|  | +#define MATCH_XORI 0x213 | 
|  | +#define  MASK_XORI 0x3ff | 
|  | +#define MATCH_JALR_R 0xeb | 
|  | +#define  MASK_JALR_R 0x3ff | 
|  | +#define MATCH_AMOMAXU_W 0x1d2b | 
|  | +#define  MASK_AMOMAXU_W 0x1ffff | 
|  | +#define MATCH_FCVT_WU_S 0xb053 | 
|  | +#define  MASK_FCVT_WU_S 0x3ff1ff | 
|  | +#define MATCH_VLSTB 0x100b | 
|  | +#define  MASK_VLSTB 0x1ffff | 
|  | +#define MATCH_VLSTD 0x118b | 
|  | +#define  MASK_VLSTD 0x1ffff | 
|  | +#define MATCH_C_LD0 0x8012 | 
|  | +#define  MASK_C_LD0 0x801f | 
|  | +#define MATCH_RDTIME 0x677 | 
|  | +#define  MASK_RDTIME 0x7ffffff | 
|  | +#define MATCH_ANDI 0x393 | 
|  | +#define  MASK_ANDI 0x3ff | 
|  | +#define MATCH_CLEARPCR 0x7b | 
|  | +#define  MASK_CLEARPCR 0x3ff | 
|  | +#define MATCH_VENQCNT 0x377b | 
|  | +#define  MASK_VENQCNT 0xf801ffff | 
|  | +#define MATCH_FSGNJN_D 0x60d3 | 
|  | +#define  MASK_FSGNJN_D 0x1ffff | 
|  | +#define MATCH_FNMADD_S 0x4f | 
|  | +#define  MASK_FNMADD_S 0x1ff | 
|  | +#define MATCH_JAL 0x6f | 
|  | +#define  MASK_JAL 0x7f | 
|  | +#define MATCH_LWU 0x303 | 
|  | +#define  MASK_LWU 0x3ff | 
|  | +#define MATCH_VLSEGSTBU 0xa0b | 
|  | +#define  MASK_VLSEGSTBU 0xfff | 
|  | +#define MATCH_C_BEQ 0x10 | 
|  | +#define  MASK_C_BEQ 0x1f | 
|  | +#define MATCH_VLHU 0x28b | 
|  | +#define  MASK_VLHU 0x3fffff | 
|  | +#define MATCH_VFSSTD 0x158f | 
|  | +#define  MASK_VFSSTD 0x1ffff | 
|  | +#define MATCH_C_BNE 0x11 | 
|  | +#define  MASK_C_BNE 0x1f | 
|  | +#define MATCH_FNMADD_D 0xcf | 
|  | +#define  MASK_FNMADD_D 0x1ff | 
|  | +#define MATCH_AMOADD_D 0x1ab | 
|  | +#define  MASK_AMOADD_D 0x1ffff | 
|  | +#define MATCH_C_SW 0xd | 
|  | +#define  MASK_C_SW 0x1f | 
|  | +#define MATCH_LR_D 0x101ab | 
|  | +#define  MASK_LR_D 0x3fffff | 
|  | +#define MATCH_C_MOVE 0x2 | 
|  | +#define  MASK_C_MOVE 0x801f | 
|  | +#define MATCH_FMOVN 0xef7 | 
|  | +#define  MASK_FMOVN 0x1ffff | 
|  | +#define MATCH_C_FSW 0x16 | 
|  | +#define  MASK_C_FSW 0x1f | 
|  | +#define MATCH_C_J 0x8002 | 
|  | +#define  MASK_C_J 0x801f | 
|  | +#define MATCH_MULHSU 0x533 | 
|  | +#define  MASK_MULHSU 0x1ffff | 
|  | +#define MATCH_C_SD 0xc | 
|  | +#define  MASK_C_SD 0x1f | 
|  | +#define MATCH_AMOADD_W 0x12b | 
|  | +#define  MASK_AMOADD_W 0x1ffff | 
|  | +#define MATCH_FCVT_D_LU 0xd0d3 | 
|  | +#define  MASK_FCVT_D_LU 0x3ff1ff | 
|  | +#define MATCH_AMOMAX_D 0x15ab | 
|  | +#define  MASK_AMOMAX_D 0x1ffff | 
|  | +#define MATCH_FSD 0x1a7 | 
|  | +#define  MASK_FSD 0x3ff | 
|  | +#define MATCH_FCVT_W_D 0xa0d3 | 
|  | +#define  MASK_FCVT_W_D 0x3ff1ff | 
|  | +#define MATCH_FMOVZ 0xaf7 | 
|  | +#define  MASK_FMOVZ 0x1ffff | 
|  | +#define MATCH_FEQ_D 0x150d3 | 
|  | +#define  MASK_FEQ_D 0x1ffff | 
|  | +#define MATCH_C_OR3 0x21c | 
|  | +#define  MASK_C_OR3 0x31f | 
|  | +#define MATCH_VMVV 0x73 | 
|  | +#define  MASK_VMVV 0x3fffff | 
|  | +#define MATCH_VFSSEGSTW 0xd0f | 
|  | +#define  MASK_VFSSEGSTW 0xfff | 
|  | +#define MATCH_SLT 0x133 | 
|  | +#define  MASK_SLT 0x1ffff | 
|  | +#define MATCH_MXTF_D 0x1e0d3 | 
|  | +#define  MASK_MXTF_D 0x3fffff | 
|  | +#define MATCH_SLLW 0xbb | 
|  | +#define  MASK_SLLW 0x1ffff | 
|  | +#define MATCH_AMOOR_D 0xdab | 
|  | +#define  MASK_AMOOR_D 0x1ffff | 
|  | +#define MATCH_SLTI 0x113 | 
|  | +#define  MASK_SLTI 0x3ff | 
|  | +#define MATCH_REMU 0x7b3 | 
|  | +#define  MASK_REMU 0x1ffff | 
|  | +#define MATCH_FLW 0x107 | 
|  | +#define  MASK_FLW 0x3ff | 
|  | +#define MATCH_REMW 0x73b | 
|  | +#define  MASK_REMW 0x1ffff | 
|  | +#define MATCH_SLTU 0x1b3 | 
|  | +#define  MASK_SLTU 0x1ffff | 
|  | +#define MATCH_SLLI 0x93 | 
|  | +#define  MASK_SLLI 0x3f03ff | 
|  | +#define MATCH_C_AND3 0x31c | 
|  | +#define  MASK_C_AND3 0x31f | 
|  | +#define MATCH_VSSEGW 0x210f | 
|  | +#define  MASK_VSSEGW 0x1ffff | 
|  | +#define MATCH_AMOOR_W 0xd2b | 
|  | +#define  MASK_AMOOR_W 0x1ffff | 
|  | +#define MATCH_VSD 0x18f | 
|  | +#define  MASK_VSD 0x3fffff | 
|  | +#define MATCH_BEQ 0x63 | 
|  | +#define  MASK_BEQ 0x3ff | 
|  | +#define MATCH_FLD 0x187 | 
|  | +#define  MASK_FLD 0x3ff | 
|  | +#define MATCH_MXTF_S 0x1e053 | 
|  | +#define  MASK_MXTF_S 0x3fffff | 
|  | +#define MATCH_FSUB_S 0x1053 | 
|  | +#define  MASK_FSUB_S 0x1f1ff | 
|  | +#define MATCH_AND 0x3b3 | 
|  | +#define  MASK_AND 0x1ffff | 
|  | +#define MATCH_VTCFGIVL 0x1f3 | 
|  | +#define  MASK_VTCFGIVL 0x3ff | 
|  | +#define MATCH_LBU 0x203 | 
|  | +#define  MASK_LBU 0x3ff | 
|  | +#define MATCH_VF 0x3f3 | 
|  | +#define  MASK_VF 0xf80003ff | 
|  | +#define MATCH_VLSEGSTW 0x90b | 
|  | +#define  MASK_VLSEGSTW 0xfff | 
|  | +#define MATCH_SYSCALL 0x77 | 
|  | +#define  MASK_SYSCALL 0xffffffff | 
|  | +#define MATCH_FSGNJ_S 0x5053 | 
|  | +#define  MASK_FSGNJ_S 0x1ffff | 
|  | +#define MATCH_C_ADDI 0x1 | 
|  | +#define  MASK_C_ADDI 0x1f | 
|  | +#define MATCH_VFMVV 0x173 | 
|  | +#define  MASK_VFMVV 0x3fffff | 
|  | +#define MATCH_VLSTWU 0x130b | 
|  | +#define  MASK_VLSTWU 0x1ffff | 
|  | +#define MATCH_C_SUB3 0x11c | 
|  | +#define  MASK_C_SUB3 0x31f | 
|  | +#define MATCH_VSH 0x8f | 
|  | +#define  MASK_VSH 0x3fffff | 
|  | +#define MATCH_VLSEGSTB 0x80b | 
|  | +#define  MASK_VLSEGSTB 0xfff | 
|  | +#define MATCH_VXCPTSAVE 0x37b | 
|  | +#define  MASK_VXCPTSAVE 0xf83fffff | 
|  | +#define MATCH_VLSEGSTD 0x98b | 
|  | +#define  MASK_VLSEGSTD 0xfff | 
|  | +#define MATCH_VFLSEGD 0x258b | 
|  | +#define  MASK_VFLSEGD 0x1ffff | 
|  | +#define MATCH_VFLSEGW 0x250b | 
|  | +#define  MASK_VFLSEGW 0x1ffff | 
|  | +#define MATCH_VLSEGSTH 0x88b | 
|  | +#define  MASK_VLSEGSTH 0xfff | 
|  | +#define MATCH_AMOMAX_W 0x152b | 
|  | +#define  MASK_AMOMAX_W 0x1ffff | 
|  | +#define MATCH_FSGNJ_D 0x50d3 | 
|  | +#define  MASK_FSGNJ_D 0x1ffff | 
|  | +#define MATCH_VFLSEGSTW 0xd0b | 
|  | +#define  MASK_VFLSEGSTW 0xfff | 
|  | +#define MATCH_C_SUB 0x801a | 
|  | +#define  MASK_C_SUB 0x801f | 
|  | +#define MATCH_MULHU 0x5b3 | 
|  | +#define  MASK_MULHU 0x1ffff | 
|  | +#define MATCH_FENCE_V_G 0x2af | 
|  | +#define  MASK_FENCE_V_G 0x3ff | 
|  | +#define MATCH_VMSV 0x873 | 
|  | +#define  MASK_VMSV 0x3fffff | 
|  | +#define MATCH_VMST 0x1073 | 
|  | +#define  MASK_VMST 0x1ffff | 
|  | +#define MATCH_SETPCR 0xfb | 
|  | +#define  MASK_SETPCR 0x3ff | 
|  | +#define MATCH_FCVT_LU_S 0x9053 | 
|  | +#define  MASK_FCVT_LU_S 0x3ff1ff | 
|  | +#define MATCH_VXCPTHOLD 0x277b | 
|  | +#define  MASK_VXCPTHOLD 0xffffffff | 
|  | +#define MATCH_FCVT_S_L 0xc053 | 
|  | +#define  MASK_FCVT_S_L 0x3ff1ff | 
|  | +#define MATCH_VFLSEGSTD 0xd8b | 
|  | +#define  MASK_VFLSEGSTD 0xfff | 
|  | +#define MATCH_AUIPC 0x17 | 
|  | +#define  MASK_AUIPC 0x7f | 
|  | +#define MATCH_C_ADD 0x1a | 
|  | +#define  MASK_C_ADD 0x801f | 
|  | +#define MATCH_FCVT_LU_D 0x90d3 | 
|  | +#define  MASK_FCVT_LU_D 0x3ff1ff | 
|  | +#define MATCH_VFLD 0x58b | 
|  | +#define  MASK_VFLD 0x3fffff | 
|  | +#define MATCH_SC_D 0x105ab | 
|  | +#define  MASK_SC_D 0x1ffff | 
|  | +#define MATCH_FMADD_S 0x43 | 
|  | +#define  MASK_FMADD_S 0x1ff | 
|  | +#define MATCH_FCVT_W_S 0xa053 | 
|  | +#define  MASK_FCVT_W_S 0x3ff1ff | 
|  | +#define MATCH_VSSEGH 0x208f | 
|  | +#define  MASK_VSSEGH 0x1ffff | 
|  | +#define MATCH_FSQRT_S 0x4053 | 
|  | +#define  MASK_FSQRT_S 0x3ff1ff | 
|  | +#define MATCH_VXCPTKILL 0xb7b | 
|  | +#define  MASK_VXCPTKILL 0xffffffff | 
|  | +#define MATCH_C_SRAI 0x1019 | 
|  | +#define  MASK_C_SRAI 0x1c1f | 
|  | +#define MATCH_AMOMIN_W 0x112b | 
|  | +#define  MASK_AMOMIN_W 0x1ffff | 
|  | +#define MATCH_FSGNJN_S 0x6053 | 
|  | +#define  MASK_FSGNJN_S 0x1ffff | 
|  | +#define MATCH_C_SLLI32 0x419 | 
|  | +#define  MASK_C_SLLI32 0x1c1f | 
|  | +#define MATCH_VLSEGWU 0x230b | 
|  | +#define  MASK_VLSEGWU 0x1ffff | 
|  | +#define MATCH_VFSW 0x50f | 
|  | +#define  MASK_VFSW 0x3fffff | 
|  | +#define MATCH_AMOSWAP_D 0x5ab | 
|  | +#define  MASK_AMOSWAP_D 0x1ffff | 
|  | +#define MATCH_FSQRT_D 0x40d3 | 
|  | +#define  MASK_FSQRT_D 0x3ff1ff | 
|  | +#define MATCH_VFLW 0x50b | 
|  | +#define  MASK_VFLW 0x3fffff | 
|  | +#define MATCH_FDIV_D 0x30d3 | 
|  | +#define  MASK_FDIV_D 0x1f1ff | 
|  | +#define MATCH_FMADD_D 0xc3 | 
|  | +#define  MASK_FMADD_D 0x1ff | 
|  | +#define MATCH_DIVW 0x63b | 
|  | +#define  MASK_DIVW 0x1ffff | 
|  | +#define MATCH_AMOMIN_D 0x11ab | 
|  | +#define  MASK_AMOMIN_D 0x1ffff | 
|  | +#define MATCH_DIVU 0x6b3 | 
|  | +#define  MASK_DIVU 0x1ffff | 
|  | +#define MATCH_AMOSWAP_W 0x52b | 
|  | +#define  MASK_AMOSWAP_W 0x1ffff | 
|  | +#define MATCH_VFSD 0x58f | 
|  | +#define  MASK_VFSD 0x3fffff | 
|  | +#define MATCH_FADD_S 0x53 | 
|  | +#define  MASK_FADD_S 0x1f1ff | 
|  | +#define MATCH_VLSEGB 0x200b | 
|  | +#define  MASK_VLSEGB 0x1ffff | 
|  | +#define MATCH_FCVT_L_D 0x80d3 | 
|  | +#define  MASK_FCVT_L_D 0x3ff1ff | 
|  | +#define MATCH_VLSEGD 0x218b | 
|  | +#define  MASK_VLSEGD 0x1ffff | 
|  | +#define MATCH_VLSEGH 0x208b | 
|  | +#define  MASK_VLSEGH 0x1ffff | 
|  | +#define MATCH_SW 0x123 | 
|  | +#define  MASK_SW 0x3ff | 
|  | +#define MATCH_FMSUB_S 0x47 | 
|  | +#define  MASK_FMSUB_S 0x1ff | 
|  | +#define MATCH_VFSSEGW 0x250f | 
|  | +#define  MASK_VFSSEGW 0x1ffff | 
|  | +#define MATCH_C_ADDIW 0x1d | 
|  | +#define  MASK_C_ADDIW 0x1f | 
|  | +#define MATCH_LHU 0x283 | 
|  | +#define  MASK_LHU 0x3ff | 
|  | +#define MATCH_SH 0xa3 | 
|  | +#define  MASK_SH 0x3ff | 
|  | +#define MATCH_VLSEGW 0x210b | 
|  | +#define  MASK_VLSEGW 0x1ffff | 
|  | +#define MATCH_FSW 0x127 | 
|  | +#define  MASK_FSW 0x3ff | 
|  | +#define MATCH_VLBU 0x20b | 
|  | +#define  MASK_VLBU 0x3fffff | 
|  | +#define MATCH_SB 0x23 | 
|  | +#define  MASK_SB 0x3ff | 
|  | +#define MATCH_FMSUB_D 0xc7 | 
|  | +#define  MASK_FMSUB_D 0x1ff | 
|  | +#define MATCH_VLSEGHU 0x228b | 
|  | +#define  MASK_VLSEGHU 0x1ffff | 
|  | +#define MATCH_VSSEGB 0x200f | 
|  | +#define  MASK_VSSEGB 0x1ffff | 
|  | +#define MATCH_VFSSEGD 0x258f | 
|  | +#define  MASK_VFSSEGD 0x1ffff | 
|  | +#define MATCH_SD 0x1a3 | 
|  | +#define  MASK_SD 0x3ff | 
|  | diff -ruN binutils-2.24/ld/configure.tgt binutils-2.24-riscv/ld/configure.tgt | 
|  | --- binutils-2.24/ld/configure.tgt	2013-11-26 03:37:33.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/configure.tgt	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -592,6 +592,9 @@ | 
|  | powerpc-*-beos*)	targ_emul=aixppc ;; | 
|  | powerpc-*-windiss*)	targ_emul=elf32ppcwindiss ;; | 
|  | powerpc-*-lynxos*)	targ_emul=ppclynx ;; | 
|  | +riscv*-*-*)		targ_emul=elf64lriscv | 
|  | +			targ_extra_emuls="elf32lriscv" | 
|  | +			targ_extra_libpath=$targ_extra_emuls ;; | 
|  | rs6000-*-aix[5-9]*)	targ_emul=aix5rs6 ;; | 
|  | rs6000-*-aix*)		targ_emul=aixrs6 | 
|  | ;; | 
|  | diff -ruN binutils-2.24/ld/emulparams/elf32lriscv-defs.sh binutils-2.24-riscv/ld/emulparams/elf32lriscv-defs.sh | 
|  | --- binutils-2.24/ld/emulparams/elf32lriscv-defs.sh	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/emulparams/elf32lriscv-defs.sh	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,90 @@ | 
|  | +# This is an ELF platform. | 
|  | +SCRIPT_NAME=elf | 
|  | + | 
|  | +# Handle both big- and little-ended 32-bit MIPS objects. | 
|  | +ARCH=riscv | 
|  | +OUTPUT_FORMAT="elf32-bigriscv" | 
|  | +BIG_OUTPUT_FORMAT="elf32-bigriscv" | 
|  | +LITTLE_OUTPUT_FORMAT="elf32-littleriscv" | 
|  | + | 
|  | +TEMPLATE_NAME=elf32 | 
|  | +EXTRA_EM_FILE=riscvelf | 
|  | + | 
|  | +case "$EMULATION_NAME" in | 
|  | +elf32*) ELFSIZE=32; LIBPATH_SUFFIX=32 ;; | 
|  | +elf64*) ELFSIZE=64; LIBPATH_SUFFIX=   ;; | 
|  | +*) echo $0: unhandled emulation $EMULATION_NAME >&2; exit 1 ;; | 
|  | +esac | 
|  | + | 
|  | +if test `echo "$host" | sed -e s/64//` = `echo "$target" | sed -e s/64//`; then | 
|  | +  case " $EMULATION_LIBPATH " in | 
|  | +    *" ${EMULATION_NAME} "*) | 
|  | +      NATIVE=yes | 
|  | +      ;; | 
|  | +  esac | 
|  | +fi | 
|  | + | 
|  | +GENERATE_SHLIB_SCRIPT=yes | 
|  | +GENERATE_PIE_SCRIPT=yes | 
|  | + | 
|  | +TEXT_START_ADDR=0x10000000 | 
|  | +MAXPAGESIZE="CONSTANT (MAXPAGESIZE)" | 
|  | +ENTRY=_start | 
|  | + | 
|  | +# Unlike most targets, the MIPS backend puts all dynamic relocations | 
|  | +# in a single dynobj section, which it also calls ".rel.dyn".  It does | 
|  | +# this so that it can easily sort all dynamic relocations before the | 
|  | +# output section has been populated. | 
|  | +OTHER_GOT_RELOC_SECTIONS=" | 
|  | +  .rel.dyn      ${RELOCATING-0} : { *(.rel.dyn) } | 
|  | +" | 
|  | +# GOT-related settings. | 
|  | +# If the output has a GOT section, there must be exactly 0x7ff0 bytes | 
|  | +# between .got and _gp.  The ". = ." below stops the orphan code from | 
|  | +# inserting other sections between the assignment to _gp and the start | 
|  | +# of .got. | 
|  | +OTHER_GOT_SYMBOLS=' | 
|  | +  . = .; | 
|  | +  _gp = ALIGN(16); | 
|  | +' | 
|  | +# .got.plt is only used for the PLT psABI extension.  It should not be | 
|  | +# included in the .sdata block with .got, as there is no need to access | 
|  | +# the section from _gp.  Note that the traditional: | 
|  | +# | 
|  | +#      . = . | 
|  | +#      _gp = ALIGN (16) + 0x7ff0; | 
|  | +#      .got : { *(.got.plt) *(.got) } | 
|  | +# | 
|  | +# would set _gp to the wrong value; _gp - 0x7ff0 must point to the start | 
|  | +# of *(.got). | 
|  | +GOT=".got          ${RELOCATING-0} : { *(.got) }" | 
|  | +unset OTHER_READWRITE_SECTIONS | 
|  | +unset OTHER_RELRO_SECTIONS | 
|  | +if test -n "$RELRO_NOW"; then | 
|  | +  OTHER_RELRO_SECTIONS=".got.plt      ${RELOCATING-0} : { *(.got.plt) }" | 
|  | +else | 
|  | +  OTHER_READWRITE_SECTIONS=".got.plt      ${RELOCATING-0} : { *(.got.plt) }" | 
|  | +fi | 
|  | + | 
|  | +OTHER_SDATA_SECTIONS=" | 
|  | +  .lit8         ${RELOCATING-0} : { *(.lit8) } | 
|  | +  .lit4         ${RELOCATING-0} : { *(.lit4) } | 
|  | +  .srdata       ${RELOCATING-0} : { *(.srdata) } | 
|  | +" | 
|  | + | 
|  | +# Magic symbols. | 
|  | +TEXT_START_SYMBOLS='_ftext = . ;' | 
|  | +DATA_START_SYMBOLS='_fdata = . ;' | 
|  | +OTHER_BSS_SYMBOLS='_fbss = .;' | 
|  | + | 
|  | +INITIAL_READONLY_SECTIONS= | 
|  | +if test -z "${CREATE_SHLIB}"; then | 
|  | +  INITIAL_READONLY_SECTIONS=".interp       ${RELOCATING-0} : { *(.interp) }" | 
|  | +fi | 
|  | +INITIAL_READONLY_SECTIONS="${INITIAL_READONLY_SECTIONS} | 
|  | +  .reginfo      ${RELOCATING-0} : { *(.reginfo) }" | 
|  | +# Discard any .MIPS.content* or .MIPS.events* sections.  The linker | 
|  | +# doesn't know how to adjust them. | 
|  | +OTHER_SECTIONS="/DISCARD/ : { *(.MIPS.content*) *(.MIPS.events*) }" | 
|  | + | 
|  | +TEXT_DYNAMIC= | 
|  | diff -ruN binutils-2.24/ld/emulparams/elf32lriscv.sh binutils-2.24-riscv/ld/emulparams/elf32lriscv.sh | 
|  | --- binutils-2.24/ld/emulparams/elf32lriscv.sh	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/emulparams/elf32lriscv.sh	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,15 @@ | 
|  | +# If you change this file, please also look at files which source this one: | 
|  | +# elf32ltsmipn32.sh | 
|  | + | 
|  | +. ${srcdir}/emulparams/elf32lriscv-defs.sh | 
|  | +OUTPUT_FORMAT="elf32-littleriscv" | 
|  | +BIG_OUTPUT_FORMAT="elf32-bigriscv" | 
|  | +LITTLE_OUTPUT_FORMAT="elf32-littleriscv" | 
|  | +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" | 
|  | + | 
|  | +# Magic sections. | 
|  | +OTHER_TEXT_SECTIONS='*(.mips16.fn.*) *(.mips16.call.*)' | 
|  | +OTHER_SECTIONS=' | 
|  | +  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } | 
|  | +  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } | 
|  | +' | 
|  | diff -ruN binutils-2.24/ld/emulparams/elf64lriscv-defs.sh binutils-2.24-riscv/ld/emulparams/elf64lriscv-defs.sh | 
|  | --- binutils-2.24/ld/emulparams/elf64lriscv-defs.sh	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/emulparams/elf64lriscv-defs.sh	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,3 @@ | 
|  | +. ${srcdir}/emulparams/elf32lriscv-defs.sh | 
|  | +COMMONPAGESIZE="CONSTANT (COMMONPAGESIZE)" | 
|  | +INITIAL_READONLY_SECTIONS=".MIPS.options : { *(.MIPS.options) }" | 
|  | diff -ruN binutils-2.24/ld/emulparams/elf64lriscv.sh binutils-2.24-riscv/ld/emulparams/elf64lriscv.sh | 
|  | --- binutils-2.24/ld/emulparams/elf64lriscv.sh	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/emulparams/elf64lriscv.sh	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,13 @@ | 
|  | +# If you change this file, please also look at files which source this one: | 
|  | +# elf64ltsmip.sh | 
|  | + | 
|  | +. ${srcdir}/emulparams/elf64lriscv-defs.sh | 
|  | +OUTPUT_FORMAT="elf64-littleriscv" | 
|  | +BIG_OUTPUT_FORMAT="elf64-bigriscv" | 
|  | +LITTLE_OUTPUT_FORMAT="elf64-littleriscv" | 
|  | + | 
|  | +# Magic sections. | 
|  | +OTHER_SECTIONS=' | 
|  | +  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) } | 
|  | +  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) } | 
|  | +' | 
|  | diff -ruN binutils-2.24/ld/emultempl/riscvelf.em binutils-2.24-riscv/ld/emultempl/riscvelf.em | 
|  | --- binutils-2.24/ld/emultempl/riscvelf.em	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/emultempl/riscvelf.em	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -0,0 +1,49 @@ | 
|  | +# This shell script emits a C file. -*- C -*- | 
|  | +#   Copyright 2004, 2006, 2007, 2008 Free Software Foundation, Inc. | 
|  | +# | 
|  | +# This file is part of the GNU Binutils. | 
|  | +# | 
|  | +# This program is free software; you can redistribute it and/or modify | 
|  | +# it under the terms of the GNU General Public License as published by | 
|  | +# the Free Software Foundation; either version 3 of the License, or | 
|  | +# (at your option) any later version. | 
|  | +# | 
|  | +# This program is distributed in the hope that it will be useful, | 
|  | +# but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | +# GNU General Public License for more details. | 
|  | +# | 
|  | +# You should have received a copy of the GNU General Public License | 
|  | +# along with this program; if not, write to the Free Software | 
|  | +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +# MA 02110-1301, USA. | 
|  | + | 
|  | +fragment <<EOF | 
|  | + | 
|  | +#include "ldctor.h" | 
|  | +#include "elf/riscv.h" | 
|  | +#include "elfxx-riscv.h" | 
|  | + | 
|  | +#define is_riscv_elf(bfd)				\ | 
|  | +  (bfd_get_flavour (bfd) == bfd_target_elf_flavour	\ | 
|  | +   && elf_tdata (bfd) != NULL				\ | 
|  | +   && elf_object_id (bfd) == MIPS_ELF_DATA) | 
|  | + | 
|  | +static void | 
|  | +riscv_after_parse (void) | 
|  | +{ | 
|  | +  /* .gnu.hash and the MIPS ABI require .dynsym to be sorted in different | 
|  | +     ways.  .gnu.hash needs symbols to be grouped by hash code whereas the | 
|  | +     MIPS ABI requires a mapping between the GOT and the symbol table.  */ | 
|  | +  if (link_info.emit_gnu_hash) | 
|  | +    { | 
|  | +      einfo ("%X%P: .gnu.hash is incompatible with the MIPS ABI\n"); | 
|  | +      link_info.emit_hash = TRUE; | 
|  | +      link_info.emit_gnu_hash = FALSE; | 
|  | +    } | 
|  | +  after_parse_default (); | 
|  | +} | 
|  | + | 
|  | +EOF | 
|  | + | 
|  | +LDEMUL_AFTER_PARSE=riscv_after_parse | 
|  | diff -ruN binutils-2.24/ld/Makefile.am binutils-2.24-riscv/ld/Makefile.am | 
|  | --- binutils-2.24/ld/Makefile.am	2013-11-26 03:37:33.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/Makefile.am	2014-12-02 16:11:22.363539568 -0800 | 
|  | @@ -234,6 +234,7 @@ | 
|  | eelf32lppclinux.c \ | 
|  | eelf32lppcnto.c \ | 
|  | eelf32lppcsim.c \ | 
|  | +	eelf32lriscv.c \ | 
|  | eelf32m32c.c \ | 
|  | eelf32mb_linux.c \ | 
|  | eelf32mcore.c \ | 
|  | @@ -510,6 +511,7 @@ | 
|  | eelf64btsmip_fbsd.c \ | 
|  | eelf64hppa.c \ | 
|  | eelf64lppc.c \ | 
|  | +	eelf64lriscv.c \ | 
|  | eelf64ltsmip.c \ | 
|  | eelf64ltsmip_fbsd.c \ | 
|  | eelf64mmix.c \ | 
|  | @@ -1123,6 +1125,10 @@ | 
|  | ldemul-list.h \ | 
|  | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | ${GENSCRIPTS} elf32lppcsim "$(tdir_elf32lppcsim)" | 
|  | +eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \ | 
|  | +  $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ | 
|  | +  $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | +	${GENSCRIPTS} elf32lriscv "$(tdir_elf32lriscv)" | 
|  | eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \ | 
|  | $(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \ | 
|  | $(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \ | 
|  | @@ -2088,6 +2094,11 @@ | 
|  | ldemul-list.h \ | 
|  | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | ${GENSCRIPTS} elf64lppc "$(tdir_elf64lppc)" | 
|  | +eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \ | 
|  | +  $(srcdir)/emulparams/elf64lriscv-defs.sh \ | 
|  | +  $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ | 
|  | +  $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | +	${GENSCRIPTS} elf64lriscv "$(tdir_elf64lriscv)" | 
|  | eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \ | 
|  | $(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \ | 
|  | $(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \ | 
|  | diff -ruN binutils-2.24/ld/Makefile.in binutils-2.24-riscv/ld/Makefile.in | 
|  | --- binutils-2.24/ld/Makefile.in	2013-11-26 03:37:33.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/ld/Makefile.in	2014-12-02 16:13:49.804461687 -0800 | 
|  | @@ -542,6 +542,7 @@ | 
|  | eelf32lppclinux.c \ | 
|  | eelf32lppcnto.c \ | 
|  | eelf32lppcsim.c \ | 
|  | +	eelf32lriscv.c \ | 
|  | eelf32m32c.c \ | 
|  | eelf32mb_linux.c \ | 
|  | eelf32mcore.c \ | 
|  | @@ -817,6 +818,7 @@ | 
|  | eelf64btsmip_fbsd.c \ | 
|  | eelf64hppa.c \ | 
|  | eelf64lppc.c \ | 
|  | +	eelf64lriscv.c \ | 
|  | eelf64ltsmip.c \ | 
|  | eelf64ltsmip_fbsd.c \ | 
|  | eelf64mmix.c \ | 
|  | @@ -1194,6 +1196,7 @@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppclinux.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppcnto.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lppcsim.Po@am__quote@ | 
|  | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lriscv.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lr5900.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lr5900n32.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf32lsmip.Po@am__quote@ | 
|  | @@ -1246,6 +1249,7 @@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64btsmip_fbsd.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64hppa.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lppc.Po@am__quote@ | 
|  | +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64lriscv.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64ltsmip.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64ltsmip_fbsd.Po@am__quote@ | 
|  | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eelf64mmix.Po@am__quote@ | 
|  | @@ -2607,6 +2611,10 @@ | 
|  | ldemul-list.h \ | 
|  | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | ${GENSCRIPTS} elf32lppcsim "$(tdir_elf32lppcsim)" | 
|  | +eelf32lriscv.c: $(srcdir)/emulparams/elf32lriscv.sh \ | 
|  | +  $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ | 
|  | +  $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | +	${GENSCRIPTS} elf32lriscv "$(tdir_elf32lriscv)" | 
|  | eelf32lsmip.c: $(srcdir)/emulparams/elf32lsmip.sh \ | 
|  | $(srcdir)/emulparams/elf32lmip.sh $(srcdir)/emulparams/elf32bmip.sh \ | 
|  | $(ELF_DEPS) $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc \ | 
|  | @@ -3572,6 +3580,11 @@ | 
|  | ldemul-list.h \ | 
|  | $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | ${GENSCRIPTS} elf64lppc "$(tdir_elf64lppc)" | 
|  | +eelf64lriscv.c: $(srcdir)/emulparams/elf64lriscv.sh \ | 
|  | +  $(srcdir)/emulparams/elf64lriscv-defs.sh \ | 
|  | +  $(srcdir)/emulparams/elf32lriscv-defs.sh $(ELF_DEPS) \ | 
|  | +  $(srcdir)/emultempl/mipself.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} | 
|  | +	${GENSCRIPTS} elf64lriscv "$(tdir_elf64lriscv)" | 
|  | eelf64ltsmip.c: $(srcdir)/emulparams/elf64ltsmip.sh \ | 
|  | $(srcdir)/emulparams/elf64btsmip.sh $(srcdir)/emulparams/elf64bmip-defs.sh \ | 
|  | $(srcdir)/emulparams/elf32bmipn32-defs.sh $(ELF_DEPS) \ | 
|  | diff -ruN binutils-2.24/opcodes/configure binutils-2.24-riscv/opcodes/configure | 
|  | --- binutils-2.24/opcodes/configure	2013-11-04 07:33:40.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/opcodes/configure	2014-12-02 16:05:44.917434991 -0800 | 
|  | @@ -12555,6 +12555,7 @@ | 
|  | bfd_powerpc_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_powerpc_64_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_pyramid_arch)	;; | 
|  | +	bfd_riscv_arch)		ta="$ta riscv-dis.lo riscv-opc.lo" ;; | 
|  | bfd_romp_arch)		;; | 
|  | bfd_rs6000_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_rl78_arch)		ta="$ta rl78-dis.lo rl78-decode.lo";; | 
|  | diff -ruN binutils-2.24/opcodes/configure.in binutils-2.24-riscv/opcodes/configure.in | 
|  | --- binutils-2.24/opcodes/configure.in	2013-11-04 07:33:40.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/opcodes/configure.in	2014-12-02 16:05:44.921435015 -0800 | 
|  | @@ -302,6 +302,7 @@ | 
|  | bfd_powerpc_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_powerpc_64_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_pyramid_arch)	;; | 
|  | +	bfd_riscv_arch)		ta="$ta riscv-dis.lo riscv-opc.lo" ;; | 
|  | bfd_romp_arch)		;; | 
|  | bfd_rs6000_arch)	ta="$ta ppc-dis.lo ppc-opc.lo" ;; | 
|  | bfd_rl78_arch)		ta="$ta rl78-dis.lo rl78-decode.lo";; | 
|  | diff -ruN binutils-2.24/opcodes/disassemble.c binutils-2.24-riscv/opcodes/disassemble.c | 
|  | --- binutils-2.24/opcodes/disassemble.c	2013-11-04 07:33:40.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/opcodes/disassemble.c	2014-12-02 16:05:44.921435015 -0800 | 
|  | @@ -378,6 +378,14 @@ | 
|  | disassemble = print_insn_little_powerpc; | 
|  | break; | 
|  | #endif | 
|  | +#ifdef ARCH_riscv | 
|  | +    case bfd_arch_riscv: | 
|  | +      if (bfd_big_endian (abfd)) | 
|  | +	disassemble = print_insn_big_riscv; | 
|  | +      else | 
|  | +	disassemble = print_insn_little_riscv; | 
|  | +      break; | 
|  | +#endif | 
|  | #ifdef ARCH_rs6000 | 
|  | case bfd_arch_rs6000: | 
|  | if (bfd_get_mach (abfd) == bfd_mach_ppc_620) | 
|  | diff -ruN binutils-2.24/opcodes/riscv-dis.c binutils-2.24-riscv/opcodes/riscv-dis.c | 
|  | --- binutils-2.24/opcodes/riscv-dis.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/opcodes/riscv-dis.c	2014-12-02 16:05:44.921435015 -0800 | 
|  | @@ -0,0 +1,902 @@ | 
|  | +/* Print mips instructions for GDB, the GNU debugger, or for objdump. | 
|  | +   Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, | 
|  | +   2000, 2001, 2002, 2003, 2005, 2007, 2008 | 
|  | +   Free Software Foundation, Inc. | 
|  | +   Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp). | 
|  | + | 
|  | +   This file is part of the GNU opcodes library. | 
|  | + | 
|  | +   This library is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3, or (at your option) | 
|  | +   any later version. | 
|  | + | 
|  | +   It is distributed in the hope that it will be useful, but WITHOUT | 
|  | +   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
|  | +   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
|  | +   License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this program; if not, write to the Free Software | 
|  | +   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | +#include "sysdep.h" | 
|  | +#include "dis-asm.h" | 
|  | +#include "libiberty.h" | 
|  | +#include "opcode/riscv.h" | 
|  | +#include "opintl.h" | 
|  | + | 
|  | +/* FIXME: These are needed to figure out if the code is mips16 or | 
|  | +   not. The low bit of the address is often a good indicator.  No | 
|  | +   symbol table is available when this code runs out in an embedded | 
|  | +   system as when it is used for disassembler support in a monitor.  */ | 
|  | + | 
|  | +#if !defined(EMBEDDED_ENV) | 
|  | +#define SYMTAB_AVAILABLE 1 | 
|  | +#include "elf-bfd.h" | 
|  | +#include "elf/riscv.h" | 
|  | +#endif | 
|  | + | 
|  | +#include <assert.h> | 
|  | + | 
|  | +/* Mips instructions are at maximum this many bytes long.  */ | 
|  | +#define INSNLEN 4 | 
|  | + | 
|  | + | 
|  | +/* FIXME: These should be shared with gdb somehow.  */ | 
|  | + | 
|  | +static const char * const mips_gpr_names_numeric[32] = | 
|  | +{ | 
|  | +  "x0",   "x1",   "x2",   "x3",   "x4",   "x5",   "x6",   "x7", | 
|  | +  "x8",   "x9",   "x10",  "x11",  "x12",  "x13",  "x14",  "x15", | 
|  | +  "x16",  "x17",  "x18",  "x19",  "x20",  "x21",  "x22",  "x23", | 
|  | +  "x24",  "x25",  "x26",  "x27",  "x28",  "x29",  "x30",  "x31" | 
|  | +}; | 
|  | + | 
|  | +static const char* mips_gpr_names_abi[32] = { | 
|  | +  "zero", "ra", "s0", "s1",  "s2",  "s3",  "s4",  "s5", | 
|  | +  "s6",   "s7", "s8", "s9", "s10", "s11",  "sp",  "tp", | 
|  | +  "v0",   "v1", "a0", "a1",  "a2",  "a3",  "a4",  "a5", | 
|  | +  "a6",   "a7", "a8", "a9", "a10", "a11", "a12", "a13" | 
|  | +}; | 
|  | + | 
|  | + | 
|  | +static const char * const mips_fpr_names_numeric[32] = | 
|  | +{ | 
|  | +  "f0",   "f1",   "f2",   "f3",   "f4",   "f5",   "f6",   "f7", | 
|  | +  "f8",   "f9",   "f10",  "f11",  "f12",  "f13",  "f14",  "f15", | 
|  | +  "f16",  "f17",  "f18",  "f19",  "f20",  "f21",  "f22",  "f23", | 
|  | +  "f24",  "f25",  "f26",  "f27",  "f28",  "f29",  "f30",  "f31" | 
|  | +}; | 
|  | + | 
|  | +static const char* mips_fpr_names_abi[32] = { | 
|  | +  "fs0", "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7", | 
|  | +  "fs8", "fs9", "fs10", "fs11", "fs12", "fs13", "fs14", "fs15", | 
|  | +  "fv0", "fv1", "fa0",   "fa1",  "fa2",  "fa3",  "fa4",  "fa5", | 
|  | +  "fa6", "fa7", "fa8",   "fa9", "fa10", "fa11", "fa12", "fa13" | 
|  | +}; | 
|  | + | 
|  | +static const char * const mips_cp0_names_numeric[32] = | 
|  | +{ | 
|  | +  "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7", | 
|  | +  "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15", | 
|  | +  "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23", | 
|  | +  "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31" | 
|  | +}; | 
|  | + | 
|  | +static const char * const mips_vgr_reg_names_riscv[32] = | 
|  | +{ | 
|  | +  "vzero","vra",  "vv0",  "vv1",  "va0",  "va1",  "va2",  "va3", | 
|  | +  "va4",  "va5",  "va6",  "va7",  "vt0",  "vt1",  "vt2",  "vt3", | 
|  | +  "vt4",  "vt5",  "vt6",  "vt7",  "vs0",  "vs1",  "vs2",  "vs3", | 
|  | +  "vs4",  "vs5",  "vs6",  "vs7",  "vs8",  "vs9",  "vsp",  "vtp" | 
|  | +}; | 
|  | + | 
|  | +static const char * const mips_vfp_reg_names_riscv[32] = | 
|  | +{ | 
|  | +  "vf0",  "vf1",  "vf2",  "vf3",  "vf4",  "vf5",  "vf6",  "vf7", | 
|  | +  "vf8",  "vf9",  "vf10", "vf11", "vf12", "vf13", "vf14", "vf15", | 
|  | +  "vf16", "vf17", "vf18", "vf19", "vf20", "vf21", "vf22", "vf23", | 
|  | +  "vf24", "vf25", "vf26", "vf27", "vf28", "vf29", "vf30", "vf31" | 
|  | +}; | 
|  | + | 
|  | +struct mips_abi_choice | 
|  | +{ | 
|  | +  const char * name; | 
|  | +  const char * const *gpr_names; | 
|  | +  const char * const *fpr_names; | 
|  | +}; | 
|  | + | 
|  | +struct mips_abi_choice mips_abi_choices[] = | 
|  | +{ | 
|  | +  { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric }, | 
|  | +  { "32", mips_gpr_names_abi, mips_fpr_names_abi }, | 
|  | +  { "64", mips_gpr_names_abi, mips_fpr_names_abi }, | 
|  | +}; | 
|  | + | 
|  | +struct mips_arch_choice | 
|  | +{ | 
|  | +  const char *name; | 
|  | +  int bfd_mach_valid; | 
|  | +  unsigned long bfd_mach; | 
|  | +  int processor; | 
|  | +  int isa; | 
|  | +  const char * const *cp0_names; | 
|  | +}; | 
|  | + | 
|  | +const struct mips_arch_choice mips_arch_choices[] = | 
|  | +{ | 
|  | +  { "numeric",	0, 0, 0, 0, | 
|  | +    mips_cp0_names_numeric }, | 
|  | + | 
|  | +  { "rv32",	1, bfd_mach_riscv_rocket32, CPU_ROCKET32, ISA_RV32, | 
|  | +    mips_cp0_names_numeric }, | 
|  | + | 
|  | +  { "rv64",	1, bfd_mach_riscv_rocket64, CPU_ROCKET64, ISA_RV64, | 
|  | +    mips_cp0_names_numeric }, | 
|  | +}; | 
|  | + | 
|  | +/* ISA and processor type to disassemble for, and register names to use. | 
|  | +   set_default_mips_dis_options and parse_mips_dis_options fill in these | 
|  | +   values.  */ | 
|  | +static int mips_processor; | 
|  | +static int mips_isa; | 
|  | +static const char * const *mips_gpr_names; | 
|  | +static const char * const *mips_fpr_names; | 
|  | +static const char * const *mips_cp0_names; | 
|  | + | 
|  | +/* Other options */ | 
|  | +static int no_aliases;	/* If set disassemble as most general inst.  */ | 
|  | + | 
|  | +static const struct mips_abi_choice * | 
|  | +choose_abi_by_name (const char *name, unsigned int namelen) | 
|  | +{ | 
|  | +  const struct mips_abi_choice *c; | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++) | 
|  | +    if (strncmp (mips_abi_choices[i].name, name, namelen) == 0 | 
|  | +	&& strlen (mips_abi_choices[i].name) == namelen) | 
|  | +      c = &mips_abi_choices[i]; | 
|  | + | 
|  | +  return c; | 
|  | +} | 
|  | + | 
|  | +static const struct mips_arch_choice * | 
|  | +choose_arch_by_name (const char *name, unsigned int namelen) | 
|  | +{ | 
|  | +  const struct mips_arch_choice *c = NULL; | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) | 
|  | +    if (strncmp (mips_arch_choices[i].name, name, namelen) == 0 | 
|  | +	&& strlen (mips_arch_choices[i].name) == namelen) | 
|  | +      c = &mips_arch_choices[i]; | 
|  | + | 
|  | +  return c; | 
|  | +} | 
|  | + | 
|  | +static const struct mips_arch_choice * | 
|  | +choose_arch_by_number (unsigned long mach) | 
|  | +{ | 
|  | +  static unsigned long hint_bfd_mach; | 
|  | +  static const struct mips_arch_choice *hint_arch_choice; | 
|  | +  const struct mips_arch_choice *c; | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  /* We optimize this because even if the user specifies no | 
|  | +     flags, this will be done for every instruction!  */ | 
|  | +  if (hint_bfd_mach == mach | 
|  | +      && hint_arch_choice != NULL | 
|  | +      && hint_arch_choice->bfd_mach == hint_bfd_mach) | 
|  | +    return hint_arch_choice; | 
|  | + | 
|  | +  for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++) | 
|  | +    { | 
|  | +      if (mips_arch_choices[i].bfd_mach_valid | 
|  | +	  && mips_arch_choices[i].bfd_mach == mach) | 
|  | +	{ | 
|  | +	  c = &mips_arch_choices[i]; | 
|  | +	  hint_bfd_mach = mach; | 
|  | +	  hint_arch_choice = c; | 
|  | +	} | 
|  | +    } | 
|  | +  return c; | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +set_default_mips_dis_options (struct disassemble_info *info) | 
|  | +{ | 
|  | +  const struct mips_arch_choice *chosen_arch; | 
|  | + | 
|  | +  /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names, | 
|  | +     and numeric FPR, CP0 register, and HWR names.  */ | 
|  | +  mips_isa = ISA_RV64; | 
|  | +  mips_processor =  CPU_ROCKET64; | 
|  | +  mips_gpr_names = mips_gpr_names_abi; | 
|  | +  mips_fpr_names = mips_fpr_names_abi; | 
|  | +  mips_cp0_names = mips_cp0_names_numeric; | 
|  | +  no_aliases = 0; | 
|  | + | 
|  | +  /* Set ISA, architecture, and cp0 register names as best we can.  */ | 
|  | +#if ! SYMTAB_AVAILABLE | 
|  | +  /* This is running out on a target machine, not in a host tool. | 
|  | +     FIXME: Where does mips_target_info come from?  */ | 
|  | +  target_processor = mips_target_info.processor; | 
|  | +  mips_isa = mips_target_info.isa; | 
|  | +#else | 
|  | +  chosen_arch = choose_arch_by_number (info->mach); | 
|  | +  if (chosen_arch != NULL) | 
|  | +    { | 
|  | +      mips_processor = chosen_arch->processor; | 
|  | +      mips_isa = chosen_arch->isa; | 
|  | +      mips_cp0_names = chosen_arch->cp0_names; | 
|  | +    } | 
|  | +#endif | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +parse_mips_dis_option (const char *option, unsigned int len) | 
|  | +{ | 
|  | +  unsigned int i, optionlen, vallen; | 
|  | +  const char *val; | 
|  | +  const struct mips_abi_choice *chosen_abi; | 
|  | +  const struct mips_arch_choice *chosen_arch; | 
|  | + | 
|  | +  /* Try to match options that are simple flags */ | 
|  | +  if (CONST_STRNEQ (option, "no-aliases")) | 
|  | +    { | 
|  | +      no_aliases = 1; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  /* Look for the = that delimits the end of the option name.  */ | 
|  | +  for (i = 0; i < len; i++) | 
|  | +    if (option[i] == '=') | 
|  | +      break; | 
|  | + | 
|  | +  if (i == 0)		/* Invalid option: no name before '='.  */ | 
|  | +    return; | 
|  | +  if (i == len)		/* Invalid option: no '='.  */ | 
|  | +    return; | 
|  | +  if (i == (len - 1))	/* Invalid option: no value after '='.  */ | 
|  | +    return; | 
|  | + | 
|  | +  optionlen = i; | 
|  | +  val = option + (optionlen + 1); | 
|  | +  vallen = len - (optionlen + 1); | 
|  | + | 
|  | +  if (strncmp ("gpr-names", option, optionlen) == 0 | 
|  | +      && strlen ("gpr-names") == optionlen) | 
|  | +    { | 
|  | +      chosen_abi = choose_abi_by_name (val, vallen); | 
|  | +      if (chosen_abi != NULL) | 
|  | +	mips_gpr_names = chosen_abi->gpr_names; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  if (strncmp ("fpr-names", option, optionlen) == 0 | 
|  | +      && strlen ("fpr-names") == optionlen) | 
|  | +    { | 
|  | +      chosen_abi = choose_abi_by_name (val, vallen); | 
|  | +      if (chosen_abi != NULL) | 
|  | +	mips_fpr_names = chosen_abi->fpr_names; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  if (strncmp ("cp0-names", option, optionlen) == 0 | 
|  | +      && strlen ("cp0-names") == optionlen) | 
|  | +    { | 
|  | +      chosen_arch = choose_arch_by_name (val, vallen); | 
|  | +      if (chosen_arch != NULL) | 
|  | +	{ | 
|  | +	  mips_cp0_names = chosen_arch->cp0_names; | 
|  | +	} | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  if (strncmp ("hwr-names", option, optionlen) == 0 | 
|  | +      && strlen ("hwr-names") == optionlen) | 
|  | +    { | 
|  | +      chosen_arch = choose_arch_by_name (val, vallen); | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  if (strncmp ("reg-names", option, optionlen) == 0 | 
|  | +      && strlen ("reg-names") == optionlen) | 
|  | +    { | 
|  | +      /* We check both ABI and ARCH here unconditionally, so | 
|  | +	 that "numeric" will do the desirable thing: select | 
|  | +	 numeric register names for all registers.  Other than | 
|  | +	 that, a given name probably won't match both.  */ | 
|  | +      chosen_abi = choose_abi_by_name (val, vallen); | 
|  | +      if (chosen_abi != NULL) | 
|  | +	{ | 
|  | +	  mips_gpr_names = chosen_abi->gpr_names; | 
|  | +	  mips_fpr_names = chosen_abi->fpr_names; | 
|  | +	} | 
|  | +      chosen_arch = choose_arch_by_name (val, vallen); | 
|  | +      if (chosen_arch != NULL) | 
|  | +	mips_cp0_names = chosen_arch->cp0_names; | 
|  | +      return; | 
|  | +    } | 
|  | + | 
|  | +  /* Invalid option.  */ | 
|  | +} | 
|  | + | 
|  | +static void | 
|  | +parse_mips_dis_options (const char *options) | 
|  | +{ | 
|  | +  const char *option_end; | 
|  | + | 
|  | +  if (options == NULL) | 
|  | +    return; | 
|  | + | 
|  | +  while (*options != '\0') | 
|  | +    { | 
|  | +      /* Skip empty options.  */ | 
|  | +      if (*options == ',') | 
|  | +	{ | 
|  | +	  options++; | 
|  | +	  continue; | 
|  | +	} | 
|  | + | 
|  | +      /* We know that *options is neither NUL or a comma.  */ | 
|  | +      option_end = options + 1; | 
|  | +      while (*option_end != ',' && *option_end != '\0') | 
|  | +	option_end++; | 
|  | + | 
|  | +      parse_mips_dis_option (options, option_end - options); | 
|  | + | 
|  | +      /* Go on to the next one.  If option_end points to a comma, it | 
|  | +	 will be skipped above.  */ | 
|  | +      options = option_end; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Print insn arguments for 32/64-bit code.  */ | 
|  | + | 
|  | +static void | 
|  | +print_insn_args (const char *d, | 
|  | +		 register unsigned long int l, | 
|  | +		 bfd_vma pc, | 
|  | +		 struct disassemble_info *info) | 
|  | +{ | 
|  | +  int delta; | 
|  | + | 
|  | +  for (; *d != '\0'; d++) | 
|  | +    { | 
|  | +      switch (*d) | 
|  | +	{ | 
|  | +        case '#': | 
|  | +          switch ( *++d ) { | 
|  | +            case 'g': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%d", | 
|  | +                  ((l >> OP_SH_IMMNGPR) & OP_MASK_IMMNGPR)); | 
|  | +              break; | 
|  | +            case 'f': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%d", | 
|  | +                  ((l >> OP_SH_IMMNFPR) & OP_MASK_IMMNFPR)); | 
|  | +              break; | 
|  | +            case 'n': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%d", | 
|  | +                  (((l >> OP_SH_IMMSEGNELM) & OP_MASK_IMMSEGNELM) + 1)); | 
|  | +              break; | 
|  | +            case 'm': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%d", | 
|  | +                  (((l >> OP_SH_IMMSEGSTNELM) & OP_MASK_IMMSEGSTNELM) + 1)); | 
|  | +              break; | 
|  | +            case 'd': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vgr_reg_names_riscv[(l >> OP_SH_VRD) & OP_MASK_VRD]); | 
|  | +              break; | 
|  | +            case 's': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vgr_reg_names_riscv[(l >> OP_SH_VRS) & OP_MASK_VRS]); | 
|  | +              break; | 
|  | +            case 't': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vgr_reg_names_riscv[(l >> OP_SH_VRT) & OP_MASK_VRT]); | 
|  | +              break; | 
|  | +            case 'r': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vgr_reg_names_riscv[(l >> OP_SH_VRR) & OP_MASK_VRR]); | 
|  | +              break; | 
|  | +            case 'D': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vfp_reg_names_riscv[(l >> OP_SH_VFD) & OP_MASK_VFD]); | 
|  | +              break; | 
|  | +            case 'S': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vfp_reg_names_riscv[(l >> OP_SH_VFS) & OP_MASK_VFS]); | 
|  | +              break; | 
|  | +            case 'T': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vfp_reg_names_riscv[(l >> OP_SH_VFT) & OP_MASK_VFT]); | 
|  | +              break; | 
|  | +            case 'R': | 
|  | +              (*info->fprintf_func) | 
|  | +                ( info->stream, "%s", | 
|  | +                  mips_vfp_reg_names_riscv[(l >> OP_SH_VFR) & OP_MASK_VFR]); | 
|  | +              break; | 
|  | +          } | 
|  | +          break; | 
|  | + | 
|  | +	case ',': | 
|  | +	case '(': | 
|  | +	case ')': | 
|  | +	case '[': | 
|  | +	case ']': | 
|  | +	  (*info->fprintf_func) (info->stream, "%c", *d); | 
|  | +	  break; | 
|  | + | 
|  | +	case '0': | 
|  | +	  (*info->fprintf_func) (info->stream, "0"); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'b': | 
|  | +	case 's': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 't': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'u': | 
|  | +	  (*info->fprintf_func) (info->stream, "0x%lx", | 
|  | +				 (l >> OP_SH_BIGIMMEDIATE) & OP_MASK_BIGIMMEDIATE); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'm': | 
|  | +        { | 
|  | +	  assert(OP_MASK_RM < ARRAY_SIZE(riscv_rm)); | 
|  | +          const char* rm = riscv_rm[(l >> OP_SH_RM) & OP_MASK_RM]; | 
|  | +          if(rm == NULL) | 
|  | +            rm = "unknown"; | 
|  | + | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", rm); | 
|  | +	  break; | 
|  | +	} | 
|  | +	case 'j': /* Same as i, but sign-extended.  */ | 
|  | +	case 'o': | 
|  | +	  delta = (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE; | 
|  | +	  if (delta & (RISCV_IMM_REACH/2)) | 
|  | +	    delta |= ~(RISCV_IMM_REACH-1); | 
|  | +	  (*info->fprintf_func) (info->stream, "%d", | 
|  | +				 delta); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'q': | 
|  | +	  delta = ((l >> OP_SH_IMMLO) & OP_MASK_IMMLO) | (((l >> OP_SH_IMMHI) & OP_MASK_IMMHI) << RISCV_IMMLO_BITS); | 
|  | +	  if (delta & (RISCV_IMM_REACH/2)) | 
|  | +	    delta |= ~(RISCV_IMM_REACH-1); | 
|  | +	  (*info->fprintf_func) (info->stream, "%d", | 
|  | +				 delta); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'a': | 
|  | +	  delta = (l >> OP_SH_TARGET) & OP_MASK_TARGET; | 
|  | +	  if (delta & ((1<<RISCV_JUMP_BITS)/2)) | 
|  | +	    delta |= ~((1<<RISCV_JUMP_BITS)-1); | 
|  | +	  info->target = (delta << RISCV_JUMP_ALIGN_BITS) + pc; | 
|  | +	  (*info->print_address_func) (info->target, info); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'p': | 
|  | +	  /* Sign extend the displacement.  */ | 
|  | +	  delta = ((l >> OP_SH_IMMLO) & OP_MASK_IMMLO) | (((l >> OP_SH_IMMHI) & OP_MASK_IMMHI) << RISCV_IMMLO_BITS); | 
|  | +	  if (delta & (RISCV_IMM_REACH/2)) | 
|  | +	    delta |= ~(RISCV_IMM_REACH-1); | 
|  | +	  info->target = (delta << RISCV_BRANCH_ALIGN_BITS) + pc; | 
|  | +	  (*info->print_address_func) (info->target, info); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'd': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'z': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]); | 
|  | +	  break; | 
|  | + | 
|  | +	case '>': | 
|  | +	  (*info->fprintf_func) (info->stream, "0x%lx", | 
|  | +				 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT); | 
|  | +	  break; | 
|  | + | 
|  | +	case '<': | 
|  | +	  (*info->fprintf_func) (info->stream, "0x%lx", | 
|  | +				 (l >> OP_SH_SHAMTW) & OP_MASK_SHAMTW); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'S': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'T': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'D': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'R': | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'E': | 
|  | +	  /* Coprocessor register for lwcN instructions, et al. | 
|  | + | 
|  | +	     Note that there is no load/store cp0 instructions, and | 
|  | +	     that FPU (cp1) instructions disassemble this field using | 
|  | +	     'T' format.  Therefore, until we gain understanding of | 
|  | +	     cp2 register names, we can simply print the register | 
|  | +	     numbers.  */ | 
|  | +	  (*info->fprintf_func) (info->stream, "cr%ld", | 
|  | +				 (l >> OP_SH_RS) & OP_MASK_RS); | 
|  | +	  break; | 
|  | + | 
|  | +	case 'G': | 
|  | +	  /* Control registers */ | 
|  | +	  (*info->fprintf_func) (info->stream, "%s", | 
|  | +				 mips_cp0_names[(l >> OP_SH_RS) & OP_MASK_RS]); | 
|  | +	  break; | 
|  | + | 
|  | +	default: | 
|  | +	  /* xgettext:c-format */ | 
|  | +	  (*info->fprintf_func) (info->stream, | 
|  | +				 _("# internal error, undefined modifier (%c)"), | 
|  | +				 *d); | 
|  | +	  return; | 
|  | +	} | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +/* Print the mips instruction at address MEMADDR in debugged memory, | 
|  | +   on using INFO.  Returns length of the instruction, in bytes. | 
|  | +   BIGENDIAN must be 1 if this is big-endian code, 0 if | 
|  | +   this is little-endian code.  */ | 
|  | + | 
|  | +static unsigned long | 
|  | +riscv_rvc_uncompress(unsigned long rvc_insn) | 
|  | +{ | 
|  | +  #define IS_INSN(x, op) (((x) & MASK_##op) == MATCH_##op) | 
|  | +  #define EXTRACT_OPERAND(x, op) (((x) >> OP_SH_##op) & OP_MASK_##op) | 
|  | + | 
|  | +  int crd = EXTRACT_OPERAND(rvc_insn, CRD); | 
|  | +  int crs1 = EXTRACT_OPERAND(rvc_insn, CRS1); | 
|  | +  int crs2 = EXTRACT_OPERAND(rvc_insn, CRS2); | 
|  | +  int crds = EXTRACT_OPERAND(rvc_insn, CRDS); | 
|  | +  int crs1s = EXTRACT_OPERAND(rvc_insn, CRS1S); | 
|  | +  int crs2s = EXTRACT_OPERAND(rvc_insn, CRS2S); | 
|  | +  int crs2bs = EXTRACT_OPERAND(rvc_insn, CRS2BS); | 
|  | + | 
|  | +  int cimm6 = EXTRACT_OPERAND(rvc_insn, CIMM6); | 
|  | +  int imm6 = ((int32_t)cimm6 << 26 >> 26) & (RISCV_IMM_REACH-1); | 
|  | +  //int imm6lo = imm6 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  //int imm6hi = (imm6 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | +  int imm6x4 = (((int32_t)cimm6 << 26 >> 26)*4) & (RISCV_IMM_REACH-1); | 
|  | +  int imm6x4lo = imm6x4 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  int imm6x4hi = (imm6x4 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | +  int imm6x8 = (((int32_t)cimm6 << 26 >> 26)*8) & (RISCV_IMM_REACH-1); | 
|  | +  int imm6x8lo = imm6x8 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  int imm6x8hi = (imm6x8 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | + | 
|  | +  int cimm5 = EXTRACT_OPERAND(rvc_insn, CIMM5); | 
|  | +  int imm5 = ((int32_t)cimm5 << 27 >> 27) & (RISCV_IMM_REACH-1); | 
|  | +  int imm5lo = imm5 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  int imm5hi = (imm5 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | +  int imm5x4 = (((int32_t)cimm5 << 27 >> 27)*4) & (RISCV_IMM_REACH-1); | 
|  | +  int imm5x4lo = imm5x4 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  int imm5x4hi = (imm5x4 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | +  int imm5x8 = (((int32_t)cimm5 << 27 >> 27)*8) & (RISCV_IMM_REACH-1); | 
|  | +  int imm5x8lo = imm5x8 & ((1<<RISCV_IMMLO_BITS)-1); | 
|  | +  int imm5x8hi = (imm5x8 >> RISCV_IMMLO_BITS) & ((1<<RISCV_IMMHI_BITS)-1); | 
|  | + | 
|  | +  int cimm10 = EXTRACT_OPERAND(rvc_insn, CIMM10); | 
|  | +  int jt10 = ((int32_t)cimm10 << 22 >> 22) & ((1<<RISCV_JUMP_BITS)-1); | 
|  | + | 
|  | +  if(IS_INSN(rvc_insn, C_ADDI)) | 
|  | +  { | 
|  | +    if(crd == 0) | 
|  | +    { | 
|  | +      if(imm6 & 0x20) | 
|  | +        return MATCH_JALR_C | (LINK_REG << OP_SH_RD) | (crs1 << OP_SH_RS); | 
|  | +      else if(crs1 == 1) | 
|  | +        return MATCH_JALR_R | (crs1 << OP_SH_RS); | 
|  | +      else | 
|  | +        return MATCH_JALR_J | (crs1 << OP_SH_RS); | 
|  | +    } | 
|  | +    return MATCH_ADDI | (crd << OP_SH_RD) | (crd << OP_SH_RS) | | 
|  | +           (imm6 << OP_SH_IMMEDIATE); | 
|  | +  } | 
|  | +  if(IS_INSN(rvc_insn, C_ADDIW)) | 
|  | +    return MATCH_ADDIW | (crd << OP_SH_RD) | (crd << OP_SH_RS) | (imm6 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_LI)) | 
|  | +    return MATCH_ADDI | (crd << OP_SH_RD) | (imm6 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_MOVE)) | 
|  | +    return MATCH_ADDI | (crd << OP_SH_RD) | (crs1 << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SLLI)) | 
|  | +    return MATCH_SLLI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SLLI32)) | 
|  | +    return MATCH_SLLI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SRLI)) | 
|  | +    return MATCH_SRLI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SRLI32)) | 
|  | +    return MATCH_SRLI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SRAI)) | 
|  | +    return MATCH_SRAI | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SRAI32)) | 
|  | +    return MATCH_SRAI | ((cimm5+32) << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_SLLIW)) | 
|  | +    return MATCH_SLLIW | (cimm5 << OP_SH_SHAMT) | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rd_regmap[crds] << OP_SH_RS); | 
|  | +  if(IS_INSN(rvc_insn, C_ADD)) | 
|  | +    return MATCH_ADD | (crd << OP_SH_RD) | (crs1 << OP_SH_RS) | (crd << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_SUB)) | 
|  | +    return MATCH_SUB | (crd << OP_SH_RD) | (crs1 << OP_SH_RS) | (crd << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_ADD3)) | 
|  | +    return MATCH_ADD | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_SUB3)) | 
|  | +    return MATCH_SUB | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_AND3)) | 
|  | +    return MATCH_AND | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_OR3)) | 
|  | +    return MATCH_OR | (rvc_rd_regmap[crds] << OP_SH_RD) | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2b_regmap[crs2bs] << OP_SH_RT); | 
|  | +  if(IS_INSN(rvc_insn, C_J)) | 
|  | +    return MATCH_J | (jt10 << OP_SH_TARGET); | 
|  | +  if(IS_INSN(rvc_insn, C_BEQ)) | 
|  | +    return MATCH_BEQ | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5lo << OP_SH_IMMLO) | (imm5hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_BNE)) | 
|  | +    return MATCH_BNE | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5lo << OP_SH_IMMLO) | (imm5hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_LDSP)) | 
|  | +    return MATCH_LD | (30 << OP_SH_RS) | (crd << OP_SH_RD) | (imm6x8 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_LWSP)) | 
|  | +    return MATCH_LW | (30 << OP_SH_RS) | (crd << OP_SH_RD) | (imm6x4 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_SDSP)) | 
|  | +    return MATCH_SD | (30 << OP_SH_RS) | (crs2 << OP_SH_RT) | (imm6x8lo << OP_SH_IMMLO) | (imm6x8hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_SWSP)) | 
|  | +    return MATCH_SW | (30 << OP_SH_RS) | (crs2 << OP_SH_RT) | (imm6x4lo << OP_SH_IMMLO) | (imm6x4hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_LD)) | 
|  | +    return MATCH_LD | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x8 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_LW)) | 
|  | +    return MATCH_LW | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x4 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_SD)) | 
|  | +    return MATCH_SD | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5x8lo << OP_SH_IMMLO) | (imm5x8hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_SW)) | 
|  | +    return MATCH_SW | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5x4lo << OP_SH_IMMLO) | (imm5x4hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_LD0)) | 
|  | +    return MATCH_LD | (crs1 << OP_SH_RS) | (crd << OP_SH_RD); | 
|  | +  if(IS_INSN(rvc_insn, C_LW0)) | 
|  | +    return MATCH_LW | (crs1 << OP_SH_RS) | (crd << OP_SH_RD); | 
|  | +  if(IS_INSN(rvc_insn, C_FLD)) | 
|  | +    return MATCH_FLD | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x8 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_FLW)) | 
|  | +    return MATCH_FLW | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rd_regmap[crds] << OP_SH_RD) | (imm5x4 << OP_SH_IMMEDIATE); | 
|  | +  if(IS_INSN(rvc_insn, C_FSD)) | 
|  | +    return MATCH_FSD | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5x8lo << OP_SH_IMMLO) | (imm5x8hi << OP_SH_IMMHI); | 
|  | +  if(IS_INSN(rvc_insn, C_FSW)) | 
|  | +    return MATCH_FSW | (rvc_rs1_regmap[crs1s] << OP_SH_RS) | (rvc_rs2_regmap[crs2s] << OP_SH_RT) | (imm5x4lo << OP_SH_IMMLO) | (imm5x4hi << OP_SH_IMMHI); | 
|  | + | 
|  | +  return rvc_insn; | 
|  | +} | 
|  | + | 
|  | +static int | 
|  | +print_insn_mips (bfd_vma memaddr, | 
|  | +		 unsigned long int word, | 
|  | +		 struct disassemble_info *info) | 
|  | +{ | 
|  | +  const struct riscv_opcode *op; | 
|  | +  static bfd_boolean init = 0; | 
|  | +  static const struct riscv_opcode *mips_hash[OP_MASK_OP + 1]; | 
|  | +  int insnlen; | 
|  | + | 
|  | +  /* Build a hash table to shorten the search time.  */ | 
|  | +  if (! init) | 
|  | +    { | 
|  | +      unsigned int i; | 
|  | + | 
|  | +      for (i = 0; i <= OP_MASK_OP; i++) | 
|  | +	{ | 
|  | +	  for (op = riscv_opcodes; op < &riscv_opcodes[NUMOPCODES]; op++) | 
|  | +	    { | 
|  | +	      if (op->pinfo == INSN_MACRO | 
|  | +		  || (no_aliases && (op->pinfo & INSN_ALIAS))) | 
|  | +		continue; | 
|  | +	      if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP)) | 
|  | +		{ | 
|  | +		  mips_hash[i] = op; | 
|  | +		  break; | 
|  | +		} | 
|  | +	    } | 
|  | +	} | 
|  | + | 
|  | +      init = 1; | 
|  | +    } | 
|  | + | 
|  | +  insnlen = 4; | 
|  | +#if 0 | 
|  | +  /* this enables rvc disassembly */ | 
|  | +  if ((word & 0x3) < 3) | 
|  | +    insnlen = 2; | 
|  | +#endif | 
|  | + | 
|  | +  if (insnlen == 2) | 
|  | +    word = riscv_rvc_uncompress(word); | 
|  | + | 
|  | +  info->bytes_per_chunk = insnlen; | 
|  | +  info->display_endian = info->endian; | 
|  | +  info->insn_info_valid = 1; | 
|  | +  info->branch_delay_insns = 0; | 
|  | +  info->data_size = 0; | 
|  | +  info->insn_type = dis_nonbranch; | 
|  | +  info->target = 0; | 
|  | +  info->target2 = 0; | 
|  | + | 
|  | +  op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP]; | 
|  | +  if (op != NULL) | 
|  | +    { | 
|  | +      for (; op < &riscv_opcodes[NUMOPCODES]; op++) | 
|  | +	{ | 
|  | +	  if (op->pinfo != INSN_MACRO | 
|  | +	      && !(no_aliases && (op->pinfo & INSN_ALIAS)) | 
|  | +	      && (word & op->mask) == op->match) | 
|  | +	    { | 
|  | +	      const char *d; | 
|  | + | 
|  | +	      (*info->fprintf_func) (info->stream, "%s", op->name); | 
|  | + | 
|  | +	      d = op->args; | 
|  | +	      if (d != NULL && *d != '\0') | 
|  | +		{ | 
|  | +		  (*info->fprintf_func) (info->stream, "\t"); | 
|  | +		  print_insn_args (d, word, memaddr, info); | 
|  | +		} | 
|  | + | 
|  | +	      return insnlen; | 
|  | +	    } | 
|  | +	} | 
|  | +    } | 
|  | + | 
|  | +  /* Handle undefined instructions.  */ | 
|  | +  info->insn_type = dis_noninsn; | 
|  | +  (*info->fprintf_func) (info->stream, "0x%lx", word); | 
|  | +  return insnlen; | 
|  | +} | 
|  | + | 
|  | + | 
|  | +/* In an environment where we do not know the symbol type of the | 
|  | +   instruction we are forced to assume that the low order bit of the | 
|  | +   instructions' address may mark it as a mips16 instruction.  If we | 
|  | +   are single stepping, or the pc is within the disassembled function, | 
|  | +   this works.  Otherwise, we need a clue.  Sometimes.  */ | 
|  | + | 
|  | +static int | 
|  | +_print_insn_mips (bfd_vma memaddr, | 
|  | +		  struct disassemble_info *info, | 
|  | +		  enum bfd_endian endianness) | 
|  | +{ | 
|  | +  bfd_byte buffer[INSNLEN]; | 
|  | +  int status; | 
|  | + | 
|  | +  set_default_mips_dis_options (info); | 
|  | +  parse_mips_dis_options (info->disassembler_options); | 
|  | + | 
|  | +  status = (*info->read_memory_func) (memaddr, buffer, 2, info); | 
|  | +  if(status == 0) | 
|  | +    { | 
|  | +      unsigned long insn; | 
|  | + | 
|  | +      if (endianness == BFD_ENDIAN_BIG) | 
|  | +	insn = (unsigned long) bfd_getb16 (buffer); | 
|  | +      else | 
|  | +	insn = (unsigned long) bfd_getl16 (buffer); | 
|  | + | 
|  | +      if ((insn & 0x3) < 3) | 
|  | +	return print_insn_mips (memaddr, insn, info); | 
|  | +    } | 
|  | + | 
|  | +  status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info); | 
|  | +  if (status == 0) | 
|  | +    { | 
|  | +      unsigned long insn; | 
|  | + | 
|  | +      if (endianness == BFD_ENDIAN_BIG) | 
|  | +	insn = (unsigned long) bfd_getb32 (buffer); | 
|  | +      else | 
|  | +	insn = (unsigned long) bfd_getl32 (buffer); | 
|  | + | 
|  | +      return print_insn_mips (memaddr, insn, info); | 
|  | +    } | 
|  | +  else | 
|  | +    { | 
|  | +      (*info->memory_error_func) (status, memaddr, info); | 
|  | +      return -1; | 
|  | +    } | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +print_insn_big_riscv (bfd_vma memaddr ATTRIBUTE_UNUSED, | 
|  | +                      struct disassemble_info *info ATTRIBUTE_UNUSED) | 
|  | +{ | 
|  | +  assert(0); | 
|  | +} | 
|  | + | 
|  | +int | 
|  | +print_insn_little_riscv (bfd_vma memaddr, struct disassemble_info *info) | 
|  | +{ | 
|  | +  return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE); | 
|  | +} | 
|  | + | 
|  | +void | 
|  | +print_mips_disassembler_options (FILE *stream) | 
|  | +{ | 
|  | +  unsigned int i; | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +The following MIPS specific disassembler options are supported for use\n\ | 
|  | +with the -M switch (multiple options should be separated by commas):\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  gpr-names=ABI            Print GPR names according to  specified ABI.\n\ | 
|  | +                           Default: based on binary being disassembled.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  fpr-names=ABI            Print FPR names according to specified ABI.\n\ | 
|  | +                           Default: numeric.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  cp0-names=ARCH           Print CP0 register names according to\n\ | 
|  | +                           specified architecture.\n\ | 
|  | +                           Default: based on binary being disassembled.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  hwr-names=ARCH           Print HWR names according to specified \n\ | 
|  | +			   architecture.\n\ | 
|  | +                           Default: based on binary being disassembled.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  reg-names=ABI            Print GPR and FPR names according to\n\ | 
|  | +                           specified ABI.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  reg-names=ARCH           Print CP0 register and HWR names according to\n\ | 
|  | +                           specified architecture.\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  For the options above, the following values are supported for \"ABI\":\n\ | 
|  | +   ")); | 
|  | +  for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++) | 
|  | +    fprintf (stream, " %s", mips_abi_choices[i].name); | 
|  | +  fprintf (stream, _("\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n\ | 
|  | +  For the options above, The following values are supported for \"ARCH\":\n\ | 
|  | +   ")); | 
|  | +  for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++) | 
|  | +    if (*mips_arch_choices[i].name != '\0') | 
|  | +      fprintf (stream, " %s", mips_arch_choices[i].name); | 
|  | +  fprintf (stream, _("\n")); | 
|  | + | 
|  | +  fprintf (stream, _("\n")); | 
|  | +} | 
|  | diff -ruN binutils-2.24/opcodes/riscv-opc.c binutils-2.24-riscv/opcodes/riscv-opc.c | 
|  | --- binutils-2.24/opcodes/riscv-opc.c	1969-12-31 16:00:00.000000000 -0800 | 
|  | +++ binutils-2.24-riscv/opcodes/riscv-opc.c	2014-12-02 16:05:44.921435015 -0800 | 
|  | @@ -0,0 +1,470 @@ | 
|  | +/* mips-opc.c -- MIPS opcode list. | 
|  | +   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 | 
|  | +   2003, 2004, 2005, 2007, 2008, 2009  Free Software Foundation, Inc. | 
|  | +   Contributed by Ralph Campbell and OSF | 
|  | +   Commented and modified by Ian Lance Taylor, Cygnus Support | 
|  | +   Extended for MIPS32 support by Anders Norlander, and by SiByte, Inc. | 
|  | +   MIPS-3D, MDMX, and MIPS32 Release 2 support added by Broadcom | 
|  | +   Corporation (SiByte). | 
|  | + | 
|  | +   This file is part of the GNU opcodes library. | 
|  | + | 
|  | +   This library is free software; you can redistribute it and/or modify | 
|  | +   it under the terms of the GNU General Public License as published by | 
|  | +   the Free Software Foundation; either version 3, or (at your option) | 
|  | +   any later version. | 
|  | + | 
|  | +   It is distributed in the hope that it will be useful, but WITHOUT | 
|  | +   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
|  | +   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
|  | +   License for more details. | 
|  | + | 
|  | +   You should have received a copy of the GNU General Public License | 
|  | +   along with this file; see the file COPYING.  If not, write to the | 
|  | +   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, | 
|  | +   MA 02110-1301, USA.  */ | 
|  | + | 
|  | +#include <stdio.h> | 
|  | +#include "sysdep.h" | 
|  | +#include "opcode/riscv.h" | 
|  | + | 
|  | +/* Short hand so the lines aren't too long.  */ | 
|  | + | 
|  | +/* The order of overloaded instructions matters.  Label arguments and | 
|  | +   register arguments look the same. Instructions that can have either | 
|  | +   for arguments must apear in the correct order in this table for the | 
|  | +   assembler to pick the right one. In other words, entries with | 
|  | +   immediate operands must apear after the same instruction with | 
|  | +   registers. | 
|  | + | 
|  | +   Because of the lookup algorithm used, entries with the same opcode | 
|  | +   name must be contiguous. | 
|  | + | 
|  | +   Many instructions are short hand for other instructions (i.e., The | 
|  | +   jal <register> instruction is short for jalr <register>).  */ | 
|  | + | 
|  | +#define WR_xd INSN_WRITE_GPR_D | 
|  | +#define WR_ra INSN_WRITE_GPR_RA | 
|  | +#define WR_fd INSN_WRITE_FPR_D | 
|  | +#define RD_xs1 INSN_READ_GPR_S | 
|  | +#define RD_xs2 INSN_READ_GPR_T | 
|  | +#define RD_fs1 INSN_READ_FPR_S | 
|  | +#define RD_fs2 INSN_READ_FPR_T | 
|  | +#define RD_fs3 INSN_READ_FPR_R | 
|  | + | 
|  | +#define MASK_RS (OP_MASK_RS << OP_SH_RS) | 
|  | +#define MASK_RT (OP_MASK_RT << OP_SH_RT) | 
|  | +#define MASK_RD (OP_MASK_RD << OP_SH_RD) | 
|  | +#define MASK_IMM (OP_MASK_IMMEDIATE << OP_SH_IMMEDIATE) | 
|  | +#define MASK_BIGIMM (OP_MASK_BIGIMMEDIATE << OP_SH_BIGIMMEDIATE) | 
|  | +#define MASK_RM (OP_MASK_RM << OP_SH_RM) | 
|  | + | 
|  | +const struct riscv_opcode riscv_builtin_opcodes[] = | 
|  | +{ | 
|  | +/* These instructions appear first so that the disassembler will find | 
|  | +   them first.  The assemblers uses a hash table based on the | 
|  | +   instruction name anyhow.  */ | 
|  | +/* name,    args,	match,	    mask,	pinfo,          	pinfo2,		membership */ | 
|  | +{"unimp",   "",         0, 0xffffffff,  0 }, | 
|  | +{"nop",     "",         MATCH_ADDI, MASK_ADDI | MASK_RD | MASK_RS | MASK_IMM,  0 }, | 
|  | +{"li",     "d,j",      MATCH_ADDI, MASK_ADDI | MASK_RS,  WR_xd }, /* addi */ | 
|  | +{"li",     "d,I",	0,    (int) M_LI,	INSN_MACRO }, | 
|  | +{"move",    "d,s",	MATCH_ADDI, MASK_ADDI | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"b",       "p",	MATCH_BEQ, MASK_BEQ | MASK_RS | MASK_RT,	 0 },/* beq 0,0 */ | 
|  | + | 
|  | +{"addw",     "d,s,t",	MATCH_ADDW, MASK_ADDW,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"addw",    "d,s,j",	MATCH_ADDIW, MASK_ADDIW,	 WR_xd|RD_xs1 }, | 
|  | +{"addiw",    "d,s,j",	MATCH_ADDIW, MASK_ADDIW,	 WR_xd|RD_xs1 }, | 
|  | +{"fadd.s",   "D,S,T",	MATCH_FADD_S | MASK_RM, MASK_FADD_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fadd.s",   "D,S,T,m",	MATCH_FADD_S, MASK_FADD_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fadd.d",   "D,S,T",	MATCH_FADD_D | MASK_RM, MASK_FADD_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fadd.d",   "D,S,T,m",	MATCH_FADD_D, MASK_FADD_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsub.d",   "D,S,T",	MATCH_FSUB_D | MASK_RM, MASK_FSUB_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsub.d",   "D,S,T,m",	MATCH_FSUB_D, MASK_FSUB_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsub.s",   "D,S,T",	MATCH_FSUB_S | MASK_RM, MASK_FSUB_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsub.s",   "D,S,T,m",	MATCH_FSUB_S, MASK_FSUB_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmul.d",   "D,S,T",	MATCH_FMUL_D | MASK_RM, MASK_FMUL_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmul.d",   "D,S,T,m",	MATCH_FMUL_D, MASK_FMUL_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmul.s",   "D,S,T",	MATCH_FMUL_S | MASK_RM, MASK_FMUL_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmul.s",   "D,S,T,m",	MATCH_FMUL_S, MASK_FMUL_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fdiv.d",   "D,S,T",	MATCH_FDIV_D | MASK_RM, MASK_FDIV_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fdiv.d",   "D,S,T,m",	MATCH_FDIV_D, MASK_FDIV_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fdiv.s",   "D,S,T",	MATCH_FDIV_S | MASK_RM, MASK_FDIV_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fdiv.s",   "D,S,T,m",	MATCH_FDIV_S, MASK_FDIV_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsqrt.d",  "D,S",	MATCH_FSQRT_D | MASK_RM, MASK_FSQRT_D | MASK_RM,  WR_fd|RD_fs1 }, | 
|  | +{"fsqrt.d",  "D,S,m",	MATCH_FSQRT_D, MASK_FSQRT_D,  WR_fd|RD_fs1 }, | 
|  | +{"fsqrt.s",  "D,S",	MATCH_FSQRT_S | MASK_RM, MASK_FSQRT_S | MASK_RM,  WR_fd|RD_fs1 }, | 
|  | +{"fsqrt.s",  "D,S,m",	MATCH_FSQRT_S, MASK_FSQRT_S,  WR_fd|RD_fs1 }, | 
|  | +{"fmadd.s",   "D,S,T,R",	MATCH_FMADD_S | MASK_RM, MASK_FMADD_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmadd.s",  "D,S,T,R,m",	MATCH_FMADD_S, MASK_FMADD_S,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmadd.d",   "D,S,T,R",	MATCH_FMADD_D | MASK_RM, MASK_FMADD_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmadd.d",  "D,S,T,R,m",	MATCH_FMADD_D, MASK_FMADD_D,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmadd.s",   "D,S,T,R",	MATCH_FNMADD_S | MASK_RM, MASK_FNMADD_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmadd.s", "D,S,T,R,m",	MATCH_FNMADD_S, MASK_FNMADD_S,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmadd.d",   "D,S,T,R",	MATCH_FNMADD_D | MASK_RM, MASK_FNMADD_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmadd.d", "D,S,T,R,m",	MATCH_FNMADD_D, MASK_FNMADD_D,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmsub.s",   "D,S,T,R",	MATCH_FMSUB_S | MASK_RM, MASK_FMSUB_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmsub.s",  "D,S,T,R,m",	MATCH_FMSUB_S, MASK_FMSUB_S,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmsub.d",   "D,S,T,R",	MATCH_FMSUB_D | MASK_RM, MASK_FMSUB_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fmsub.d",  "D,S,T,R,m",	MATCH_FMSUB_D, MASK_FMSUB_D,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmsub.s",   "D,S,T,R",	MATCH_FNMSUB_S | MASK_RM, MASK_FNMSUB_S | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmsub.s", "D,S,T,R,m",	MATCH_FNMSUB_S, MASK_FNMSUB_S,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmsub.d",   "D,S,T,R",	MATCH_FNMSUB_D | MASK_RM, MASK_FNMSUB_D | MASK_RM,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"fnmsub.d", "D,S,T,R,m",	MATCH_FNMSUB_D, MASK_FNMSUB_D,	 WR_fd|RD_fs1|RD_fs2|RD_fs3 }, | 
|  | +{"amoadd.d",		"d,t,0(b)",	MATCH_AMOADD_D, MASK_AMOADD_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoswap.d",		"d,t,0(b)",	MATCH_AMOSWAP_D, MASK_AMOSWAP_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoand.d",		"d,t,0(b)",	MATCH_AMOAND_D, MASK_AMOAND_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoor.d",		"d,t,0(b)",	MATCH_AMOOR_D, MASK_AMOOR_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomax.d",		"d,t,0(b)",	MATCH_AMOMAX_D, MASK_AMOMAX_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomaxu.d",		"d,t,0(b)",	MATCH_AMOMAXU_D, MASK_AMOMAXU_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomin.d",		"d,t,0(b)",	MATCH_AMOMIN_D, MASK_AMOMIN_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amominu.d",		"d,t,0(b)",	MATCH_AMOMINU_D, MASK_AMOMINU_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoadd.w",		"d,t,0(b)",	MATCH_AMOADD_W, MASK_AMOADD_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoswap.w",		"d,t,0(b)",	MATCH_AMOSWAP_W, MASK_AMOSWAP_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoand.w",		"d,t,0(b)",	MATCH_AMOAND_W, MASK_AMOAND_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amoor.w",		"d,t,0(b)",	MATCH_AMOOR_W, MASK_AMOOR_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomax.w",		"d,t,0(b)",	MATCH_AMOMAX_W, MASK_AMOMAX_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomaxu.w",		"d,t,0(b)",	MATCH_AMOMAXU_W, MASK_AMOMAXU_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amomin.w",		"d,t,0(b)",	MATCH_AMOMIN_W, MASK_AMOMIN_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"amominu.w",		"d,t,0(b)",	MATCH_AMOMINU_W, MASK_AMOMINU_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"lr.w",		"d,0(b)",	MATCH_LR_W, MASK_LR_W,	 WR_xd|RD_xs1 }, | 
|  | +{"lr.d",		"d,0(b)",	MATCH_LR_D, MASK_LR_D,	 WR_xd|RD_xs1 }, | 
|  | +{"sc.w",		"d,t,0(b)",	MATCH_SC_W, MASK_SC_W,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sc.d",		"d,t,0(b)",	MATCH_SC_D, MASK_SC_D,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"and",     "d,s,t",	MATCH_AND, MASK_AND,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"and",    "d,s,j",	MATCH_ANDI, MASK_ANDI,	 WR_xd|RD_xs1 }, | 
|  | +{"andi",    "d,s,j",	MATCH_ANDI, MASK_ANDI,	 WR_xd|RD_xs1 }, | 
|  | +/* b is at the top of the table.  */ | 
|  | +/* bal is at the top of the table.  */ | 
|  | +{"beqz",    "s,p",	MATCH_BEQ, MASK_BEQ | MASK_RT,	 RD_xs1 }, | 
|  | +{"beq",     "s,t,p",	MATCH_BEQ, MASK_BEQ,	 RD_xs1|RD_xs2 }, | 
|  | +{"blez",    "t,p",	MATCH_BGE, MASK_BGE | MASK_RS,	 RD_xs2 }, | 
|  | +{"bgez",    "s,p",	MATCH_BGE, MASK_BGE | MASK_RT,	 RD_xs1 }, | 
|  | +{"ble",     "t,s,p",	MATCH_BGE, MASK_BGE,	 RD_xs1|RD_xs2 }, | 
|  | +{"bleu",     "t,s,p",	MATCH_BGEU, MASK_BGEU,	 RD_xs1|RD_xs2 }, | 
|  | +{"bge",     "s,t,p",	MATCH_BGE, MASK_BGE,	 RD_xs1|RD_xs2 }, | 
|  | +{"bgeu",     "s,t,p",	MATCH_BGEU, MASK_BGEU,	 RD_xs1|RD_xs2 }, | 
|  | +{"bltz",    "s,p",	MATCH_BLT, MASK_BLT | MASK_RT,	 RD_xs1 }, | 
|  | +{"bgtz",    "t,p",	MATCH_BLT, MASK_BLT | MASK_RS,	 RD_xs2 }, | 
|  | +{"blt",     "s,t,p",	MATCH_BLT, MASK_BLT,	 RD_xs1|RD_xs2 }, | 
|  | +{"bltu",     "s,t,p",	MATCH_BLTU, MASK_BLTU,	 RD_xs1|RD_xs2 }, | 
|  | +{"bgt",     "t,s,p",	MATCH_BLT, MASK_BLT,	 RD_xs1|RD_xs2 }, | 
|  | +{"bgtu",     "t,s,p",	MATCH_BLTU, MASK_BLTU,	 RD_xs1|RD_xs2 }, | 
|  | +{"bnez",    "s,p",	MATCH_BNE, MASK_BNE | MASK_RT,	 RD_xs1 }, | 
|  | +{"bne",     "s,t,p",	MATCH_BNE, MASK_BNE,	 RD_xs1|RD_xs2 }, | 
|  | +{"feq.d",   "d,S,T",    MATCH_FEQ_D, MASK_FEQ_D,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +{"feq.s",   "d,S,T",    MATCH_FEQ_S, MASK_FEQ_S,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +{"flt.d",   "d,S,T",    MATCH_FLT_D, MASK_FLT_D,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +{"flt.s",   "d,S,T",    MATCH_FLT_S, MASK_FLT_S,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +{"fle.d",   "d,S,T",    MATCH_FLE_D, MASK_FLE_D,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +{"fle.s",   "d,S,T",    MATCH_FLE_S, MASK_FLE_S,  WR_xd|RD_fs1|RD_fs2 }, | 
|  | +/* CW4010 instructions which are aliases for the cache instruction.  */ | 
|  | +{"fcvt.d.l", "D,s",	MATCH_FCVT_D_L | MASK_RM, MASK_FCVT_D_L | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.d.l", "D,s,m",	MATCH_FCVT_D_L, MASK_FCVT_D_L,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.d.s", "D,S",	MATCH_FCVT_D_S, MASK_FCVT_D_S | MASK_RM,	 WR_fd|RD_fs1 }, | 
|  | +{"fcvt.d.w", "D,s",	MATCH_FCVT_D_W, MASK_FCVT_D_W | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.l", "D,s",	MATCH_FCVT_S_L | MASK_RM, MASK_FCVT_S_L | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.l", "D,s,m",	MATCH_FCVT_S_L, MASK_FCVT_S_L,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.d", "D,S",	MATCH_FCVT_S_D | MASK_RM, MASK_FCVT_S_D | MASK_RM,	 WR_fd|RD_fs1 }, | 
|  | +{"fcvt.s.d", "D,S,m",	MATCH_FCVT_S_D, MASK_FCVT_S_D,	 WR_fd|RD_fs1 }, | 
|  | +{"fcvt.s.w", "D,s",	MATCH_FCVT_S_W | MASK_RM, MASK_FCVT_S_W | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.w", "D,s,m",	MATCH_FCVT_S_W, MASK_FCVT_S_W,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.d.lu", "D,s",	MATCH_FCVT_D_LU | MASK_RM, MASK_FCVT_D_L | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.d.lu", "D,s,m",	MATCH_FCVT_D_LU, MASK_FCVT_D_LU,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.d.wu", "D,s",	MATCH_FCVT_D_WU, MASK_FCVT_D_WU | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.lu", "D,s",	MATCH_FCVT_S_LU | MASK_RM, MASK_FCVT_S_L | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.lu", "D,s,m",	MATCH_FCVT_S_LU, MASK_FCVT_S_LU,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.wu", "D,s",	MATCH_FCVT_S_WU | MASK_RM, MASK_FCVT_S_W | MASK_RM,	 WR_fd|RD_xs1 }, | 
|  | +{"fcvt.s.wu", "D,s,m",	MATCH_FCVT_S_WU, MASK_FCVT_S_WU,	 WR_fd|RD_xs1 }, | 
|  | +{"add",    "d,s,t",	MATCH_ADD, MASK_ADD,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"add",   "d,s,j",	MATCH_ADDI, MASK_ADDI,  WR_xd|RD_xs1 }, | 
|  | +{"addi",   "d,s,j",	MATCH_ADDI, MASK_ADDI,  WR_xd|RD_xs1 }, | 
|  | +{"clearpcr", "E,j",	MATCH_CLEARPCR, MASK_CLEARPCR | MASK_RD, 0 }, | 
|  | +{"clearpcr", "d,E,j",	MATCH_CLEARPCR, MASK_CLEARPCR | MASK_RD, WR_xd }, | 
|  | +{"div",    "d,s,t",	MATCH_DIV, MASK_DIV,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"divw",    "d,s,t",	MATCH_DIVW, MASK_DIVW,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"divu",    "d,s,t",	MATCH_DIVU, MASK_DIVU,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"divuw",    "d,s,t",	MATCH_DIVUW, MASK_DIVUW,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"la",     "d,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO }, | 
|  | +{"la.tls.gd", "d,A",	0,    (int) M_LA_TLS_GD,	INSN_MACRO }, | 
|  | +{"la.tls.ie", "d,A",	0,    (int) M_LA_TLS_IE,	INSN_MACRO }, | 
|  | +{"mffsr",   "d",	MATCH_MFFSR, MASK_MFFSR,  WR_xd }, | 
|  | +{"mtfsr",   "s",	MATCH_MTFSR, MASK_MTFSR | MASK_RD,  RD_xs1 }, | 
|  | +{"mtfsr",   "d,s",	MATCH_MTFSR, MASK_MTFSR,  WR_xd|RD_xs1 }, | 
|  | +{"mfpcr",   "d,E",	MATCH_MFPCR, MASK_MFPCR,  WR_xd }, | 
|  | +{"mtpcr",   "d,t,E",	MATCH_MTPCR, MASK_MTPCR,  WR_xd|RD_xs1 }, | 
|  | +{"mtpcr",   "t,E",	MATCH_MTPCR, MASK_MTPCR | MASK_RD,  RD_xs1 }, | 
|  | +{"mftx.s",   "d,S",	MATCH_MFTX_S, MASK_MFTX_S,  WR_xd|RD_fs1 }, | 
|  | +{"mftx.s",   "d,s",	MATCH_MFTX_S, MASK_MFTX_S,  WR_xd|RD_fs1 }, | 
|  | +{"mxtf.s",   "D,s",	MATCH_MXTF_S, MASK_MXTF_S,  WR_fd|RD_xs1 }, | 
|  | +{"mxtf.s",   "d,s",	MATCH_MXTF_S, MASK_MXTF_S,  WR_fd|RD_xs1 }, | 
|  | +{"mftx.d",   "d,S",	MATCH_MFTX_D, MASK_MFTX_D,  WR_xd|RD_fs1 }, | 
|  | +{"mftx.d",   "d,s",	MATCH_MFTX_D, MASK_MFTX_D,  WR_xd|RD_fs1 }, | 
|  | +{"mxtf.d",   "D,s",	MATCH_MXTF_D, MASK_MXTF_D,  WR_fd|RD_xs1 }, | 
|  | +{"mxtf.d",   "d,s",	MATCH_MXTF_D, MASK_MXTF_D,  WR_fd|RD_xs1 }, | 
|  | +{"mul",    "d,s,t",	MATCH_MUL, MASK_MUL,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"mulh",   "d,s,t",	MATCH_MULH, MASK_MULH,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"mulhu",  "d,s,t",	MATCH_MULHU, MASK_MULHU,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"mulhsu", "d,s,t",	MATCH_MULHSU, MASK_MULHSU,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"neg",    "d,t",	MATCH_SUB, MASK_SUB | MASK_RS,	 WR_xd|RD_xs2 }, /* sub 0 */ | 
|  | +{"neg",    "d,t",	MATCH_SUBW, MASK_SUBW | MASK_RS,	 WR_xd|RD_xs2 }, /* subw 0 */ | 
|  | +{"sll",    "d,s,t",	 MATCH_SLL, MASK_SLL,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sll",    "d,s,>",	 MATCH_SLLI, MASK_SLLI,	 WR_xd|RD_xs1 }, | 
|  | +{"slli",    "d,s,>",	 MATCH_SLLI, MASK_SLLI,	 WR_xd|RD_xs1 }, | 
|  | +{"srl",    "d,s,t",	 MATCH_SRL, MASK_SRL,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"srl",    "d,s,>",	 MATCH_SRLI, MASK_SRLI,	 WR_xd|RD_xs1 }, | 
|  | +{"srli",    "d,s,>",	 MATCH_SRLI, MASK_SRLI,	 WR_xd|RD_xs1 }, | 
|  | +{"sra",    "d,s,t",	 MATCH_SRA, MASK_SRA,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sra",    "d,s,>",	 MATCH_SRAI, MASK_SRAI,	 WR_xd|RD_xs1 }, | 
|  | +{"srai",    "d,s,>",	 MATCH_SRAI, MASK_SRAI,	 WR_xd|RD_xs1 }, | 
|  | +{"sub",    "d,s,t",	MATCH_SUB, MASK_SUB,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"setpcr", "E,j",	MATCH_SETPCR, MASK_SETPCR | MASK_RD, 0 }, | 
|  | +{"setpcr", "d,E,j",	MATCH_SETPCR, MASK_SETPCR, WR_xd }, | 
|  | +{"eret",    "",     MATCH_ERET, MASK_ERET,  0 }, | 
|  | +{"cflush",  "",	MATCH_CFLUSH, MASK_CFLUSH,	 0 }, | 
|  | +{"ret",      "",	MATCH_JALR_R | (LINK_REG << OP_SH_RS), MASK_JALR_R | MASK_RD | MASK_RS | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jr.r",      "s",	MATCH_JALR_R, MASK_JALR_R | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jr.r",      "s,j",	MATCH_JALR_R, MASK_JALR_R | MASK_RD,	 WR_xd|RD_xs1 }, | 
|  | +{"j.r",      "s",	MATCH_JALR_R, MASK_JALR_R | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, /* jr */ | 
|  | +{"j.r",      "s,j",	MATCH_JALR_R, MASK_JALR_R | MASK_RD,	 WR_xd|RD_xs1 }, /* jr */ | 
|  | +{"jr",      "s",	MATCH_JALR_J, MASK_JALR_J | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jr",      "s,j",	MATCH_JALR_J, MASK_JALR_J | MASK_RD,	 WR_xd|RD_xs1 }, | 
|  | +{"j",       "s",	0,    (int) M_J,	INSN_MACRO }, | 
|  | +{"j",       "a",	MATCH_J, MASK_J,	 0 }, | 
|  | +{"jalr",    "s",	MATCH_JALR_C | (LINK_REG << OP_SH_RD), MASK_JALR_C | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr",    "s,j",	MATCH_JALR_C | (LINK_REG << OP_SH_RD), MASK_JALR_C | MASK_RD,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr",    "d,s",	MATCH_JALR_C, MASK_JALR_C | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr",    "d,s,j",	MATCH_JALR_C, MASK_JALR_C,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.j",    "s",	MATCH_JALR_J | (LINK_REG << OP_SH_RD), MASK_JALR_J | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.j",    "s,j",	MATCH_JALR_J | (LINK_REG << OP_SH_RD), MASK_JALR_J | MASK_RD,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.j",    "d,s",	MATCH_JALR_J, MASK_JALR_J | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.j",    "d,s,j",	MATCH_JALR_J, MASK_JALR_J,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.r",    "s",	MATCH_JALR_R | (LINK_REG << OP_SH_RD), MASK_JALR_R | MASK_RD | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.r",    "s,j",	MATCH_JALR_R | (LINK_REG << OP_SH_RD), MASK_JALR_R | MASK_RD,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.r",    "d,s",	MATCH_JALR_R, MASK_JALR_R | MASK_IMM,	 WR_xd|RD_xs1 }, | 
|  | +{"jalr.r",    "d,s,j",	MATCH_JALR_R, MASK_JALR_R,	 WR_xd|RD_xs1 }, | 
|  | +/* SVR4 PIC code requires special handling for jal, so it must be a | 
|  | +   macro.  */ | 
|  | +{"jal",     "a",	MATCH_JAL, MASK_JAL,	 WR_ra }, | 
|  | +{"lb",      "d,o(b)",	MATCH_LB, MASK_LB,	 WR_xd|RD_xs1 }, | 
|  | +{"lbu",     "d,o(b)",	MATCH_LBU, MASK_LBU,	 WR_xd|RD_xs1 }, | 
|  | +{"lh",      "d,o(b)",	MATCH_LH, MASK_LH,	 WR_xd|RD_xs1 }, | 
|  | +{"lhu",     "d,o(b)",	MATCH_LHU, MASK_LHU,	 WR_xd|RD_xs1 }, | 
|  | +{"lw",      "d,o(b)",	MATCH_LW, MASK_LW,	 WR_xd|RD_xs1 }, | 
|  | +{"lwu",     "d,o(b)",	MATCH_LWU, MASK_LWU,	 WR_xd|RD_xs1 }, | 
|  | +{"ld",	    "d,o(b)", MATCH_LD, MASK_LD,  WR_xd|RD_xs1 }, | 
|  | +{"flw",    "D,o(b)",	MATCH_FLW, MASK_FLW,	 WR_fd|RD_xs1 }, | 
|  | +{"fld",    "D,o(b)",	MATCH_FLD, MASK_FLD,  WR_fd|RD_xs1 }, | 
|  | +{"lui",     "d,u",	MATCH_LUI, MASK_LUI,	 WR_xd }, | 
|  | +{"mulw",    "d,s,t",	MATCH_MULW, MASK_MULW,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"negw",     "d,t",	MATCH_SUBW, MASK_SUBW | MASK_RS,	 WR_xd|RD_xs2 }, /* sub 0 */ | 
|  | +/* nop is at the start of the table.  */ | 
|  | +{"not",     "d,s",	MATCH_XORI | MASK_IMM, MASK_XORI | MASK_IMM,	 WR_xd|RD_xs1 },/*nor d,s,0*/ | 
|  | +{"or",      "d,s,t",	MATCH_OR, MASK_OR,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"or",     "d,s,j",	MATCH_ORI, MASK_ORI,	 WR_xd|RD_xs1 }, | 
|  | +{"ori",     "d,s,j",	MATCH_ORI, MASK_ORI,	 WR_xd|RD_xs1 }, | 
|  | +  /* pref and prefx are at the start of the table.  */ | 
|  | +{"auipc",   "d,u",	MATCH_AUIPC, MASK_AUIPC,  WR_xd }, | 
|  | +{"rdpc",   "d",		MATCH_AUIPC, MASK_AUIPC | MASK_BIGIMM,  WR_xd }, | 
|  | +{"rem",    "d,s,t",	MATCH_REM, MASK_REM,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"remw",    "d,s,t",	MATCH_REMW, MASK_REMW,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"remu",    "d,s,t",	MATCH_REMU, MASK_REMU,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"remuw",    "d,s,t",	MATCH_REMUW, MASK_REMUW,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"fsgnj.s",   "D,S,T",	MATCH_FSGNJ_S, MASK_FSGNJ_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsgnj.d",   "D,S,T",	MATCH_FSGNJ_D, MASK_FSGNJ_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsgnjn.s",   "D,S,T",	MATCH_FSGNJN_S, MASK_FSGNJN_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsgnjn.d",   "D,S,T",	MATCH_FSGNJN_D, MASK_FSGNJN_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsgnjx.s",   "D,S,T",	MATCH_FSGNJX_S, MASK_FSGNJX_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fsgnjx.d",   "D,S,T",	MATCH_FSGNJX_D, MASK_FSGNJX_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmin.s",   "D,S,T",	MATCH_FMIN_S, MASK_FMIN_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmin.d",   "D,S,T",	MATCH_FMIN_D, MASK_FMIN_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmax.s",   "D,S,T",	MATCH_FMAX_S, MASK_FMAX_S,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"fmax.d",   "D,S,T",	MATCH_FMAX_D, MASK_FMAX_D,	 WR_fd|RD_fs1|RD_fs2 }, | 
|  | +{"sllw",    "d,s,t",	 MATCH_SLLW, MASK_SLLW,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sllw",    "d,s,<",	 MATCH_SLLIW, MASK_SLLIW,	 WR_xd|RD_xs1 }, | 
|  | +{"slliw",    "d,s,<",	 MATCH_SLLIW, MASK_SLLIW,	 WR_xd|RD_xs1 }, | 
|  | +{"srlw",    "d,s,t",	 MATCH_SRLW, MASK_SRLW,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"srlw",    "d,s,<",	 MATCH_SRLIW, MASK_SRLIW,	 WR_xd|RD_xs1 }, | 
|  | +{"srliw",    "d,s,<",	 MATCH_SRLIW, MASK_SRLIW,	 WR_xd|RD_xs1 }, | 
|  | +{"sraw",    "d,s,t",	 MATCH_SRAW, MASK_SRAW,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sraw",    "d,s,<",	 MATCH_SRAIW, MASK_SRAIW,	 WR_xd|RD_xs1 }, | 
|  | +{"sraiw",    "d,s,<",	 MATCH_SRAIW, MASK_SRAIW,	 WR_xd|RD_xs1 }, | 
|  | +{"slt",     "d,s,t",	MATCH_SLT, MASK_SLT,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"slt",    "d,s,j",	MATCH_SLTI, MASK_SLTI,	 WR_xd|RD_xs1 }, | 
|  | +{"slti",    "d,s,j",	MATCH_SLTI, MASK_SLTI,	 WR_xd|RD_xs1 }, | 
|  | +{"sltu",    "d,s,t",	MATCH_SLTU, MASK_SLTU,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sltu",   "d,s,j",	MATCH_SLTIU, MASK_SLTIU,	 WR_xd|RD_xs1 }, | 
|  | +{"sltiu",   "d,s,j",	MATCH_SLTIU, MASK_SLTIU,	 WR_xd|RD_xs1 }, | 
|  | +{"subw",     "d,s,t",	MATCH_SUBW, MASK_SUBW,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"sb",      "t,q(b)",	MATCH_SB, MASK_SB,	 RD_xs1|RD_xs2 }, | 
|  | +{"sh",      "t,q(b)",	MATCH_SH, MASK_SH,	 RD_xs1|RD_xs2 }, | 
|  | +{"sw",      "t,q(b)",	MATCH_SW, MASK_SW,	 RD_xs1|RD_xs2 }, | 
|  | +{"sd",	    "t,q(b)",	MATCH_SD, MASK_SD,	 RD_xs1|RD_xs2 }, | 
|  | +{"fsw",    "T,q(b)",	MATCH_FSW, MASK_FSW,	 RD_xs1|RD_fs2 }, | 
|  | +{"fsd",    "T,q(b)",	MATCH_FSD, MASK_FSD,  RD_xs1|RD_fs2 }, | 
|  | +{"fence",    "",	MATCH_FENCE, MASK_FENCE | MASK_RD | MASK_RS | MASK_IMM,	 0 }, | 
|  | +{"fence.i",   "",	MATCH_FENCE_I, MASK_FENCE_I | MASK_RD | MASK_RS | MASK_IMM,	 0 }, | 
|  | +{"fence.v.l",   "",	MATCH_FENCE_V_L, MASK_FENCE_V_L | MASK_RD | MASK_RS | MASK_IMM,	 0 }, | 
|  | +{"fence.v.g",   "",	MATCH_FENCE_V_G, MASK_FENCE_V_G | MASK_RD | MASK_RS | MASK_IMM,	 0 }, | 
|  | +{"rdcycle",   "d",	MATCH_RDCYCLE, MASK_RDCYCLE,  WR_xd }, | 
|  | +{"rdinstret",   "d",	MATCH_RDINSTRET, MASK_RDINSTRET,  WR_xd }, | 
|  | +{"rdtime",   "d",	MATCH_RDTIME, MASK_RDTIME,  WR_xd }, | 
|  | +{"break", "",		MATCH_BREAK, MASK_BREAK,	 0 }, | 
|  | +{"syscall", "",		MATCH_SYSCALL, MASK_SYSCALL,	 0 }, | 
|  | +{"stop", "",		MATCH_STOP, MASK_STOP,	 0 }, | 
|  | +{"utidx", "d",		MATCH_UTIDX, MASK_UTIDX,	 WR_xd }, | 
|  | +{"movz",    "d,s,t",	MATCH_MOVZ, MASK_MOVZ,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"movn",    "d,s,t",	MATCH_MOVN, MASK_MOVN,  WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"fmovz",   "D,s,T",	MATCH_FMOVZ, MASK_FMOVZ,  WR_fd|RD_xs1|RD_fs2 }, | 
|  | +{"fmovn",   "D,s,T",	MATCH_FMOVN, MASK_FMOVN,  WR_fd|RD_xs1|RD_fs2 }, | 
|  | +{"fcvt.l.d", "d,S",	MATCH_FCVT_L_D | MASK_RM, MASK_FCVT_L_D | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.l.d", "d,S,m",	MATCH_FCVT_L_D, MASK_FCVT_L_D,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.l.s", "d,S",	MATCH_FCVT_L_S | MASK_RM, MASK_FCVT_L_S | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.l.s", "d,S,m",	MATCH_FCVT_L_S, MASK_FCVT_L_S,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.w.d", "d,S",	MATCH_FCVT_W_D | MASK_RM, MASK_FCVT_W_D | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.w.d", "d,S,m",	MATCH_FCVT_W_D, MASK_FCVT_W_D,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.w.s", "d,S",	MATCH_FCVT_W_S | MASK_RM, MASK_FCVT_W_S | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.w.s", "d,S,m",	MATCH_FCVT_W_S, MASK_FCVT_W_S,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.lu.d", "d,S",	MATCH_FCVT_LU_D | MASK_RM, MASK_FCVT_LU_D | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.lu.d", "d,S,m",	MATCH_FCVT_LU_D, MASK_FCVT_LU_D,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.lu.s", "d,S",	MATCH_FCVT_LU_S | MASK_RM, MASK_FCVT_LU_S | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.lu.s", "d,S,m",	MATCH_FCVT_LU_S, MASK_FCVT_LU_S,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.wu.d", "d,S",	MATCH_FCVT_WU_D | MASK_RM, MASK_FCVT_WU_D | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.wu.d", "d,S,m",	MATCH_FCVT_WU_D, MASK_FCVT_WU_D,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.wu.s", "d,S",	MATCH_FCVT_WU_S | MASK_RM, MASK_FCVT_WU_S | MASK_RM,  WR_xd|RD_fs1 }, | 
|  | +{"fcvt.wu.s", "d,S,m",	MATCH_FCVT_WU_S, MASK_FCVT_WU_S,  WR_xd|RD_fs1 }, | 
|  | +{"xor",     "d,s,t",	MATCH_XOR, MASK_XOR,	 WR_xd|RD_xs1|RD_xs2 }, | 
|  | +{"xor",    "d,s,j",	MATCH_XORI, MASK_XORI,	 WR_xd|RD_xs1 }, | 
|  | +{"xori",    "d,s,j",	MATCH_XORI, MASK_XORI,	 WR_xd|RD_xs1 }, | 
|  | + | 
|  | +/* unit stride */ | 
|  | +/* xloads */ | 
|  | +{"vld",       "#d,s",        MATCH_VLD, MASK_VLD,  0 }, | 
|  | +{"vlw",       "#d,s",        MATCH_VLW, MASK_VLW,  0 }, | 
|  | +{"vlwu",      "#d,s",        MATCH_VLWU, MASK_VLWU,  0 }, | 
|  | +{"vlh",       "#d,s",        MATCH_VLH, MASK_VLH,  0 }, | 
|  | +{"vlhu",      "#d,s",        MATCH_VLHU, MASK_VLHU,  0 }, | 
|  | +{"vlb",       "#d,s",        MATCH_VLB, MASK_VLB,  0 }, | 
|  | +{"vlbu",      "#d,s",        MATCH_VLBU, MASK_VLBU,  0 }, | 
|  | +/* floads */ | 
|  | +{"vfld",      "#D,s",        MATCH_VFLD, MASK_VFLD,  0 }, | 
|  | +{"vflw",      "#D,s",        MATCH_VFLW, MASK_VFLW,  0 }, | 
|  | + | 
|  | +/* stride */ | 
|  | +/* xloads */ | 
|  | +{"vlstd",     "#d,s,t",      MATCH_VLSTD, MASK_VLSTD,  0 }, | 
|  | +{"vlstw",     "#d,s,t",      MATCH_VLSTW, MASK_VLSTW,  0 }, | 
|  | +{"vlstwu",    "#d,s,t",      MATCH_VLSTWU, MASK_VLSTWU,  0 }, | 
|  | +{"vlsth",     "#d,s,t",      MATCH_VLSTH, MASK_VLSTH,  0 }, | 
|  | +{"vlsthu",    "#d,s,t",      MATCH_VLSTHU, MASK_VLSTHU,  0 }, | 
|  | +{"vlstb",     "#d,s,t",      MATCH_VLSTB, MASK_VLSTB,  0 }, | 
|  | +{"vlstbu",    "#d,s,t",      MATCH_VLSTBU, MASK_VLSTBU,  0 }, | 
|  | +/* floads */ | 
|  | +{"vflstd",    "#D,s,t",      MATCH_VFLSTD, MASK_VFLSTD,  0 }, | 
|  | +{"vflstw",    "#D,s,t",      MATCH_VFLSTW, MASK_VFLSTW,  0 }, | 
|  | + | 
|  | +/* segment */ | 
|  | +/* xloads */ | 
|  | +{"vlsegd",    "#d,s,#n",     MATCH_VLSEGD, MASK_VLSEGD,  0 }, | 
|  | +{"vlsegw",    "#d,s,#n",     MATCH_VLSEGW, MASK_VLSEGW,  0 }, | 
|  | +{"vlsegwu",   "#d,s,#n",     MATCH_VLSEGWU, MASK_VLSEGWU,  0 }, | 
|  | +{"vlsegh",    "#d,s,#n",     MATCH_VLSEGH, MASK_VLSEGH,  0 }, | 
|  | +{"vlseghu",   "#d,s,#n",     MATCH_VLSEGHU, MASK_VLSEGHU,  0 }, | 
|  | +{"vlsegb",    "#d,s,#n",     MATCH_VLSEGB, MASK_VLSEGB,  0 }, | 
|  | +{"vlsegbu",   "#d,s,#n",     MATCH_VLSEGBU, MASK_VLSEGBU,  0 }, | 
|  | +/* floads */ | 
|  | +{"vflsegd",   "#D,s,#n",     MATCH_VFLSEGD, MASK_VFLSEGD,  0 }, | 
|  | +{"vflsegw",   "#D,s,#n",     MATCH_VFLSEGW, MASK_VFLSEGW,  0 }, | 
|  | + | 
|  | +/* stride segment */ | 
|  | +/* xloads */ | 
|  | +{"vlsegstd",  "#d,s,t,#m",   MATCH_VLSEGSTD, MASK_VLSEGSTD,  0 }, | 
|  | +{"vlsegstw",  "#d,s,t,#m",   MATCH_VLSEGSTW, MASK_VLSEGSTW,  0 }, | 
|  | +{"vlsegstwu", "#d,s,t,#m",   MATCH_VLSEGSTWU, MASK_VLSEGSTWU,  0 }, | 
|  | +{"vlsegsth",  "#d,s,t,#m",   MATCH_VLSEGSTH, MASK_VLSEGSTH,  0 }, | 
|  | +{"vlsegsthu", "#d,s,t,#m",   MATCH_VLSEGSTHU, MASK_VLSEGSTHU,  0 }, | 
|  | +{"vlsegstb",  "#d,s,t,#m",   MATCH_VLSEGSTB, MASK_VLSEGSTB,  0 }, | 
|  | +{"vlsegstbu", "#d,s,t,#m",   MATCH_VLSEGSTBU, MASK_VLSEGSTBU,  0 }, | 
|  | +/* floads */ | 
|  | +{"vflsegstd", "#D,s,t,#m",   MATCH_VFLSEGSTD, MASK_VFLSEGSTD,  0 }, | 
|  | +{"vflsegstw", "#D,s,t,#m",   MATCH_VFLSEGSTW, MASK_VFLSEGSTW,  0 }, | 
|  | + | 
|  | +/* unit stride */ | 
|  | +/* xstores */ | 
|  | +{"vsd",       "#d,s",        MATCH_VSD, MASK_VSD,  0 }, | 
|  | +{"vsw",       "#d,s",        MATCH_VSW, MASK_VSW,  0 }, | 
|  | +{"vsh",       "#d,s",        MATCH_VSH, MASK_VSH,  0 }, | 
|  | +{"vsb",       "#d,s",        MATCH_VSB, MASK_VSB,  0 }, | 
|  | +/* fstores */ | 
|  | +{"vfsd",      "#D,s",        MATCH_VFSD, MASK_VFSD,  0 }, | 
|  | +{"vfsw",      "#D,s",        MATCH_VFSW, MASK_VFSW,  0 }, | 
|  | + | 
|  | +/* stride */ | 
|  | +/* xstores */ | 
|  | +{"vsstd",     "#d,s,t",      MATCH_VSSTD, MASK_VSSTD,  0 }, | 
|  | +{"vsstw",     "#d,s,t",      MATCH_VSSTW, MASK_VSSTW,  0 }, | 
|  | +{"vssth",     "#d,s,t",      MATCH_VSSTH, MASK_VSSTH,  0 }, | 
|  | +{"vsstb",     "#d,s,t",      MATCH_VSSTB, MASK_VSSTB,  0 }, | 
|  | +/* fstores */ | 
|  | +{"vfsstd",    "#D,s,t",      MATCH_VFSSTD, MASK_VFSSTD,  0 }, | 
|  | +{"vfsstw",    "#D,s,t",      MATCH_VFSSTW, MASK_VFSSTW,  0 }, | 
|  | + | 
|  | +/* segment */ | 
|  | +/* xstores */ | 
|  | +{"vssegd",    "#d,s,#n",     MATCH_VSSEGD, MASK_VSSEGD,  0 }, | 
|  | +{"vssegw",    "#d,s,#n",     MATCH_VSSEGW, MASK_VSSEGW,  0 }, | 
|  | +{"vssegh",    "#d,s,#n",     MATCH_VSSEGH, MASK_VSSEGH,  0 }, | 
|  | +{"vssegb",    "#d,s,#n",     MATCH_VSSEGB, MASK_VSSEGB,  0 }, | 
|  | +/* fstores */ | 
|  | +{"vfssegd",   "#D,s,#n",     MATCH_VFSSEGD, MASK_VFSSEGD,  0 }, | 
|  | +{"vfssegw",   "#D,s,#n",     MATCH_VFSSEGW, MASK_VFSSEGW,  0 }, | 
|  | + | 
|  | +/* stride segment */ | 
|  | +/* xsegstores */ | 
|  | +{"vssegstd",  "#d,s,t,#m",   MATCH_VSSEGSTD, MASK_VSSEGSTD,  0 }, | 
|  | +{"vssegstw",  "#d,s,t,#m",   MATCH_VSSEGSTW, MASK_VSSEGSTW,  0 }, | 
|  | +{"vssegsth",  "#d,s,t,#m",   MATCH_VSSEGSTH, MASK_VSSEGSTH,  0 }, | 
|  | +{"vssegstb",  "#d,s,t,#m",   MATCH_VSSEGSTB, MASK_VSSEGSTB,  0 }, | 
|  | +/* fsegstores */ | 
|  | +{"vfssegstd", "#D,s,t,#m",   MATCH_VFSSEGSTD, MASK_VFSSEGSTD,  0 }, | 
|  | +{"vfssegstw", "#D,s,t,#m",   MATCH_VFSSEGSTW, MASK_VFSSEGSTW,  0 }, | 
|  | + | 
|  | +{"vsetvl",    "d,s",            MATCH_VSETVL, MASK_VSETVL,  WR_xd|RD_xs1 }, | 
|  | +{"vmvv",      "#d,#s",          MATCH_VMVV, MASK_VMVV,  0 }, | 
|  | +{"vmsv",      "#d,s",           MATCH_VMSV, MASK_VMSV,  0 }, | 
|  | +{"vmst",      "#d,s,t",         MATCH_VMST, MASK_VMST,  0 }, | 
|  | +{"vmts",      "d,#s,t",         MATCH_VMTS, MASK_VMTS,  0 }, | 
|  | +{"vfmvv",     "#D,#S",          MATCH_VFMVV, MASK_VFMVV,  0 }, | 
|  | +{"vfmsv",     "#D,S",           MATCH_VFMSV, MASK_VFMSV,  0 }, | 
|  | +{"vfmst",     "#D,S,T",         MATCH_VFMST, MASK_VFMST,  0 }, | 
|  | +{"vfmts",     "D,#S,T",         MATCH_VFMTS, MASK_VFMTS,  0 }, | 
|  | + | 
|  | +{"vvcfg",     "s,t",            MATCH_VVCFG, MASK_VVCFG, RD_xs1|RD_xs2 }, | 
|  | +{"vtcfg",     "s,t",            MATCH_VTCFG, MASK_VTCFG, RD_xs1|RD_xs2 }, | 
|  | + | 
|  | +{"vvcfgivl",  "d,s,#g,#f",      MATCH_VVCFGIVL, MASK_VVCFGIVL,  0 }, | 
|  | +{"vtcfgivl",  "d,s,#g,#f",      MATCH_VTCFGIVL, MASK_VTCFGIVL,  0 }, | 
|  | +{"vf",        "j(b)",           MATCH_VF, MASK_VF,  0 }, | 
|  | + | 
|  | +{"venqcmd",   "s,t",  MATCH_VENQCMD, MASK_VENQCMD, RD_xs1|RD_xs2 }, | 
|  | +{"venqimm1",  "s,t",  MATCH_VENQIMM1, MASK_VENQIMM1, RD_xs1|RD_xs2 }, | 
|  | +{"venqimm2",  "s,t",  MATCH_VENQIMM2, MASK_VENQIMM2, RD_xs1|RD_xs2 }, | 
|  | +{"venqcnt",   "s,t",  MATCH_VENQCNT, MASK_VENQCNT, RD_xs1|RD_xs2 }, | 
|  | + | 
|  | +{"vxcptsave",   "s",   MATCH_VXCPTSAVE, MASK_VXCPTSAVE, RD_xs1 }, | 
|  | +{"vxcptrestore","s",   MATCH_VXCPTRESTORE, MASK_VXCPTRESTORE, RD_xs1 }, | 
|  | +{"vxcptevac",   "s",   MATCH_VXCPTEVAC, MASK_VXCPTEVAC, RD_xs1 }, | 
|  | +{"vxcptkill",   "",   MATCH_VXCPTKILL, MASK_VXCPTKILL, 0 }, | 
|  | +{"vxcpthold",   "",   MATCH_VXCPTHOLD, MASK_VXCPTHOLD, 0 }, | 
|  | +}; | 
|  | + | 
|  | +#define RISCV_NUM_OPCODES \ | 
|  | +	((sizeof riscv_builtin_opcodes) / (sizeof (riscv_builtin_opcodes[0]))) | 
|  | +const int bfd_riscv_num_builtin_opcodes = RISCV_NUM_OPCODES; | 
|  | + | 
|  | +/* const removed from the following to allow for dynamic extensions to the | 
|  | + * built-in instruction set. */ | 
|  | +struct riscv_opcode *riscv_opcodes = | 
|  | +  (struct riscv_opcode *) riscv_builtin_opcodes; | 
|  | +int bfd_riscv_num_opcodes = RISCV_NUM_OPCODES; | 
|  | +#undef RISCV_NUM_OPCODES |