| /* tc-nds32.c -- Assemble for the nds32 | 
 |    Copyright (C) 2012-2023 Free Software Foundation, Inc. | 
 |    Contributed by Andes Technology Corporation. | 
 |  | 
 |    This file is part of GAS, the GNU Assembler. | 
 |  | 
 |    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 "safe-ctype.h" | 
 | #include "subsegs.h" | 
 | #include "symcat.h" | 
 | #include "dwarf2dbg.h" | 
 | #include "dw2gencfi.h" | 
 | #include "opcodes/nds32-asm.h" | 
 | #include "elf/nds32.h" | 
 | #include "bfd/elf32-nds32.h" | 
 | #include "hash.h" | 
 | #include "sb.h" | 
 | #include "macro.h" | 
 | #include "opcode/nds32.h" | 
 |  | 
 | #include <stdio.h> | 
 | #include <errno.h> | 
 | #include <limits.h> | 
 |  | 
 | /* GAS definitions.  */ | 
 |  | 
 | /* Characters which start a comment.  */ | 
 | const char comment_chars[] = "!"; | 
 | /* Characters which start a comment when they appear at the start of a line.  */ | 
 | const char line_comment_chars[] = "#!"; | 
 | /* Characters which separate lines (null and newline are by default).  */ | 
 | const char line_separator_chars[] = ";"; | 
 | /* Characters which may be used as the exponent character | 
 |    in a floating point number.  */ | 
 | const char EXP_CHARS[] = "eE"; | 
 | /* Characters which may be used to indicate a floating point constant.  */ | 
 | const char FLT_CHARS[] = "dDfF"; | 
 |  | 
 | static int enable_16bit = 1; | 
 | /* Save for md_assemble to distinguish if this instruction is | 
 |    expanded from the pseudo instruction.  */ | 
 | static bool pseudo_opcode = false; | 
 | static struct nds32_relocs_pattern *relocs_list = NULL; | 
 | /* Save instruction relation to inserting relaxation relocation.  */ | 
 | struct nds32_relocs_pattern | 
 | { | 
 |   segT seg; | 
 |   fragS *frag; | 
 |   frchainS *frchain; | 
 |   symbolS *sym; | 
 |   fixS* fixP; | 
 |   struct nds32_opcode *opcode; | 
 |   char *where; | 
 |   struct nds32_relocs_pattern *next; | 
 |   /* Assembled instruction bytes.  */ | 
 |   uint32_t insn; | 
 | }; | 
 |  | 
 | /* Suffix name and relocation.  */ | 
 | struct suffix_name | 
 | { | 
 |   const char *suffix; | 
 |   short unsigned int reloc; | 
 | }; | 
 | static int vec_size = 0; | 
 | /* If the assembly code is generated by compiler, it is supposed to have | 
 |    ".flag verbatim" at beginning of the content.  We have | 
 |    'nds32_flag' to parse it and set this field to be non-zero.  */ | 
 | static int verbatim = 0; | 
 | static htab_t nds32_gprs_hash; | 
 | static htab_t nds32_hint_hash; | 
 | #define TLS_REG "$r27" | 
 | #define GOT_NAME "_GLOBAL_OFFSET_TABLE_" | 
 |  | 
 | /* Generate relocation for relax or not, and the default is true.  */ | 
 | static int enable_relax_relocs = 1; | 
 | /* Save option -O for performance.  */ | 
 | static int optimize = 0; | 
 | /* Save option -Os for code size.  */ | 
 | static int optimize_for_space = 0; | 
 | /* Flag to save label exist.  */ | 
 | static int label_exist = 0; | 
 | /* Flag to save state in omit_fp region.  */ | 
 | static int in_omit_fp = 0; | 
 | /* Tag there is relax relocation having to link.  */ | 
 | static bool relaxing = false; | 
 | /* ICT model.  */ | 
 | enum ict_option { | 
 |   ICT_NONE = 0, | 
 |   ICT_SMALL, | 
 |   ICT_LARGE | 
 | }; | 
 | static enum ict_option ict_flag = ICT_NONE; | 
 |  | 
 |  | 
 | static htab_t nds32_relax_info_hash; | 
 |  | 
 | /* Branch patterns.  */ | 
 | static relax_info_t relax_table[] = | 
 | { | 
 |   { | 
 |     .opcode = "jal", | 
 |     .br_range = BR_RANGE_S16M, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JRAL_TA	/* jral $ta */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 12, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL4}, | 
 | 	{4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bgezal", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	  INSN_BGEZAL	/* bgezal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BGEZAL	/* bgezal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BGEZAL	/* bgezal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BLTZ,	/* bltz $rt, $1 */ | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BLTZ,	/* bltz $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JRAL_TA	/* jral $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bltzal", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	  INSN_BLTZAL	/* bltzal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BLTZAL	/* bltzal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BLTZAL	/* bltzal $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BGEZ,	/* bgez $rt, $1 */ | 
 | 	INSN_JAL	/* jal label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BGEZ,	/* bgez $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JRAL_TA	/* jral $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGCALL6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "j", | 
 |     .br_range = BR_RANGE_S16M, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	(INSN_J8 << 16)	/* j8 label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     . relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 12, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4}, | 
 | 	{4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "j8", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	(INSN_J8 << 16)	/* j8 label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 12, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP4}, | 
 | 	{4, 4, NDS32_HINT | NDS32_FIX, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{8, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beqz", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     /* We do not use beqz38 and beqzs8 here directly because we | 
 |        don't want to check register number for specail condition.  */ | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	  INSN_BEQZ	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 , BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BEQZ	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQZ	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNEZ,	/* bnez $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	/* bnez range is 17 pcrel, but it use 15 pcrel here since link time | 
 | 	   relaxtion.  If 17 pcrel can reach, it do not have to use S16M. | 
 | 	   Therefore, 15 pcrel is just for linker to distinguish LONGJUMP5 | 
 | 	   and LONGJUMP6.  */ | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNEZ,	/* bnez $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bgez", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BGEZ	/* bgez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BGEZ	/* bgez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BGEZ	/* bgez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BLTZ,	/* bltz $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BLTZ,	/* bltz $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bnez", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BNEZ	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BNEZ	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNEZ	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQZ,	/* beqz $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQZ,	/* beqz $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bgtz", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BGTZ	/* bgtz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BGTZ	/* bgtz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BGTZ	/* bgtz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BLEZ,	/* blez $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BLEZ,	/* blez $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "blez", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BLEZ	/* blez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BLEZ	/* blez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BLEZ	/* blez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BGTZ,	/* bgtz $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BGTZ,	/* bgtz $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bltz", | 
 |     .br_range = BR_RANGE_S64K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BLTZ	/* bltz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BLTZ	/* bltz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BLTZ	/* bltz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BGEZ,	/* bgez $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BGEZ,	/* bgez $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false}, | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beq", | 
 |     .br_range = BR_RANGE_S16K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BEQ	/* beq $rt, $ra, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BEQ	/* beq $rt, $ra, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNE,	/* bne $rt, $ra, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNE,	/* bne $rt, $ra, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNE,	/* bne $rt, $ra, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bne", | 
 |     .br_range = BR_RANGE_S16K, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BNE	/* bne $rt, $ra, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BNE	/* bne $rt, $ra, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQ,	/* beq $rt, $ra, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQ,	/* beq $rt, $ra, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQ,	/* beq $rt, $ra, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 15, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beqz38", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BEQZ38 << 16	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BEQZ	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQZ	/* beqz $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNEZ,	/* bnez $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNEZ,	/* bnez $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bnez38", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BNEZ38 << 16	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BNEZ	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNEZ	/* bnez $rt, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQZ,	/* beqz $rt, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQZ,	/* beqz $rt, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beqzs8", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BEQZS8 << 16	/* beqz $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BEQZ_TA	/* beqz $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQZ_TA	/* beqz $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNEZ_TA,	/* bnez $r15, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNEZ_TA,	/* bnez $r15, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bnezs8", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BNEZS8 << 16	/* bnez $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BNEZ_TA	/* bnez $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNEZ_TA	/* bnez $r15, label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_17_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQZ_TA,	/* beqz $r15, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQZ_TA,	/* beqz $r15, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bnes38", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BNES38 << 16	/* bne $rt, $r5, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BNE_R5	/* bne $rt, $r5, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQ_R5,	/* beq $rt, $r5, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQ_R5,	/* beq $rt, $r5, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQ_R5,	/* beq $rt, $r5, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beqs38", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BEQS38 << 16	/* beq $rt, $r5, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 2, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 2, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 2, NDS32_PCREL, BFD_RELOC_NDS32_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_BEQ_R5	/* beq $rt, $r5, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNE_R5,	/* bne $rt, $r5, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNE_R5,	/* bne $rt, $r5, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP5}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{4, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNE_R5,	/* bne $rt, $r5, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP6}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{4, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_FIX | NDS32_HINT, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{8, 4, NDS32_PTR |NDS32_HINT, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_ABS | NDS32_HINT, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_SYM | NDS32_HINT, BFD_RELOC_NDS32_EMPTY}, | 
 | 	{12, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "beqc", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7FF, true}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	INSN_BEQC	/* beqc $rt, imm11s, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_MOVI_TA,	/* movi $ta, imm11s */ | 
 | 	INSN_BEQ_TA	/* beq $rt, $ta, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 0, 0xFFFFF, false}, | 
 | 	{4, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BNEC,	/* bnec $rt, imm11s, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BNEC,	/* bnec $rt, imm11s, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BNEC,	/* bnec $rt, imm11s, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = "bnec", | 
 |     .br_range = BR_RANGE_S256, | 
 |     .cond_field = | 
 |       { | 
 | 	{0, 8, 0x7FF, true}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_seq[BR_RANGE_S256] = | 
 |       { | 
 | 	  INSN_BNEC	/* bnec $rt, imm11s, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S256] = 4, | 
 |     .relax_branch_isize[BR_RANGE_S256] = 4, | 
 |     .relax_fixup[BR_RANGE_S256] = | 
 |       { | 
 | 	{0, 4, NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16K] = | 
 |       { | 
 | 	INSN_MOVI_TA,	/* movi $ta, imm11s */ | 
 | 	INSN_BNE_TA	/* bne $rt, $ta, label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 0, 0xFFFFF, false}, | 
 | 	{4, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16K] = 4, | 
 |     .relax_fixup[BR_RANGE_S16K] = | 
 |       { | 
 | 	{0, 4, NDS32_INSN16 | NDS32_HINT, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 4, NDS32_PTR | NDS32_HINT, BFD_RELOC_NDS32_LONGJUMP7}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_15_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S64K] = | 
 |       { | 
 | 	INSN_BEQC,	/* beqc $rt, imm11s, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S64K] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S64K] = 4, | 
 |     .relax_fixup[BR_RANGE_S64K] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_S16M] = | 
 |       { | 
 | 	INSN_BEQC,	/* beqc $rt, imm11s, $1 */ | 
 | 	INSN_J		/* j label */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_S16M] = 8, | 
 |     .relax_branch_isize[BR_RANGE_S16M] = 4, | 
 |     .relax_fixup[BR_RANGE_S16M] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, NDS32_PCREL, BFD_RELOC_NDS32_25_PCREL}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |  | 
 |     .relax_code_seq[BR_RANGE_U4G] = | 
 |       { | 
 | 	INSN_BEQC,	/* beqc $rt, imm11s, $1 */ | 
 | 	INSN_SETHI_TA,	/* sethi $ta, label */ | 
 | 	INSN_ORI_TA,	/* ori $ta, $ta, label */ | 
 | 	INSN_JR_TA	/* jr $ta */ | 
 |       }, | 
 |     .relax_code_condition[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 8, 0x7FF, false}, | 
 | 	{0, 20, 0x1F, false}, | 
 | 	{0, 0, 0, false} | 
 |       }, | 
 |     .relax_code_size[BR_RANGE_U4G] = 16, | 
 |     .relax_branch_isize[BR_RANGE_U4G] = 4, | 
 |     .relax_fixup[BR_RANGE_U4G] = | 
 |       { | 
 | 	{0, 4, NDS32_CREATE_LABEL | NDS32_PCREL, BFD_RELOC_NDS32_WORD_9_PCREL}, | 
 | 	{4, 4, 0, BFD_RELOC_NDS32_HI20}, | 
 | 	{8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, | 
 | 	{12, 4, NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       }, | 
 |   }, | 
 |   { | 
 |     .opcode = NULL, | 
 |   }, | 
 | }; | 
 |  | 
 |  | 
 | /* GAS definitions for command-line options.  */ | 
 | enum options | 
 | { | 
 |   OPTION_BIG = OPTION_MD_BASE, | 
 |   OPTION_LITTLE, | 
 |   OPTION_TURBO, | 
 |   OPTION_PIC, | 
 |   OPTION_RELAX_FP_AS_GP_OFF, | 
 |   OPTION_RELAX_B2BB_ON, | 
 |   OPTION_RELAX_ALL_OFF, | 
 |   OPTION_OPTIMIZE, | 
 |   OPTION_OPTIMIZE_SPACE | 
 | }; | 
 |  | 
 | const char *md_shortopts = "m:O:"; | 
 | struct option md_longopts[] = | 
 | { | 
 |   {"O1", no_argument, NULL, OPTION_OPTIMIZE}, | 
 |   {"Os", no_argument, NULL, OPTION_OPTIMIZE_SPACE}, | 
 |   {"big", no_argument, NULL, OPTION_BIG}, | 
 |   {"little", no_argument, NULL, OPTION_LITTLE}, | 
 |   {"EB", no_argument, NULL, OPTION_BIG}, | 
 |   {"EL", no_argument, NULL, OPTION_LITTLE}, | 
 |   {"meb", no_argument, NULL, OPTION_BIG}, | 
 |   {"mel", no_argument, NULL, OPTION_LITTLE}, | 
 |   {"mall-ext", no_argument, NULL, OPTION_TURBO}, | 
 |   {"mext-all", no_argument, NULL, OPTION_TURBO}, | 
 |   {"mpic", no_argument, NULL, OPTION_PIC}, | 
 |   /* Relaxation related options.  */ | 
 |   {"mno-fp-as-gp-relax", no_argument, NULL, OPTION_RELAX_FP_AS_GP_OFF}, | 
 |   {"mb2bb", no_argument, NULL, OPTION_RELAX_B2BB_ON}, | 
 |   {"mno-all-relax", no_argument, NULL, OPTION_RELAX_ALL_OFF}, | 
 |   {NULL, no_argument, NULL, 0} | 
 | }; | 
 |  | 
 | size_t md_longopts_size = sizeof (md_longopts); | 
 |  | 
 | struct nds32_parse_option_table | 
 | { | 
 |   const char *name;		/* Option string.  */ | 
 |   const char *help;			/* Help description.  */ | 
 |   int (*func) (const char *arg);	/* How to parse it.  */ | 
 | }; | 
 |  | 
 |  | 
 | /* The value `-1' represents this option has *NOT* been set.  */ | 
 | #ifdef NDS32_DEFAULT_ARCH_NAME | 
 | static const char* nds32_arch_name = NDS32_DEFAULT_ARCH_NAME; | 
 | #else | 
 | static const char* nds32_arch_name = "v3"; | 
 | #endif | 
 | static int nds32_baseline = -1; | 
 | static int nds32_gpr16 = -1; | 
 | static int nds32_fpu_sp_ext = -1; | 
 | static int nds32_fpu_dp_ext = -1; | 
 | static int nds32_freg = -1; | 
 | static int nds32_abi = -1; | 
 |  | 
 | /* Record ELF flags */ | 
 | static int nds32_elf_flags = 0; | 
 | static int nds32_fpu_com = 0; | 
 |  | 
 | static int nds32_parse_arch (const char *str); | 
 | static int nds32_parse_baseline (const char *str); | 
 | static int nds32_parse_freg (const char *str); | 
 | static int nds32_parse_abi (const char *str); | 
 | static void add_mapping_symbol (enum mstate state, | 
 | 				unsigned int padding_byte, | 
 | 				unsigned int align); | 
 |  | 
 | static struct nds32_parse_option_table parse_opts [] = | 
 | { | 
 |   {"arch=", N_("<arch name>\t  Assemble for architecture <arch name>\n\ | 
 | 			  <arch name> could be\n\ | 
 | 			  v3, v3j, v3m, v3f, v3s, "\ | 
 | 			  "v2, v2j, v2f, v2s"), nds32_parse_arch}, | 
 |   {"baseline=", N_("<baseline>\t  Assemble for baseline <baseline>\n\ | 
 | 			  <baseline> could be v2, v3, v3m"), | 
 | 		  nds32_parse_baseline}, | 
 |   {"fpu-freg=", N_("<freg>\t  Specify a FPU configuration\n\ | 
 | 			  <freg>\n\ | 
 | 			  0:     8 SP /  4 DP registers\n\ | 
 | 			  1:    16 SP /  8 DP registers\n\ | 
 | 			  2:    32 SP / 16 DP registers\n\ | 
 | 			  3:    32 SP / 32 DP registers"), nds32_parse_freg}, | 
 |   {"abi=", N_("<abi>\t          Specify a abi version\n\ | 
 | 			  <abi> could be v1, v2, v2fp, v2fpp"), nds32_parse_abi}, | 
 |   {NULL, NULL, NULL} | 
 | }; | 
 |  | 
 | static int nds32_mac = 1; | 
 | static int nds32_div = 1; | 
 | static int nds32_16bit_ext = 1; | 
 | static int nds32_dx_regs = NDS32_DEFAULT_DX_REGS; | 
 | static int nds32_perf_ext = NDS32_DEFAULT_PERF_EXT; | 
 | static int nds32_perf_ext2 = NDS32_DEFAULT_PERF_EXT2; | 
 | static int nds32_string_ext = NDS32_DEFAULT_STRING_EXT; | 
 | static int nds32_audio_ext = NDS32_DEFAULT_AUDIO_EXT; | 
 | static int nds32_dsp_ext = NDS32_DEFAULT_DSP_EXT; | 
 | static int nds32_zol_ext = NDS32_DEFAULT_ZOL_EXT; | 
 | static int nds32_fpu_fma = 0; | 
 | static int nds32_pic = 0; | 
 | static int nds32_relax_fp_as_gp = 1; | 
 | static int nds32_relax_b2bb = 0; | 
 | static int nds32_relax_all = 1; | 
 | struct nds32_set_option_table | 
 | { | 
 |   const char *name;		/* Option string.  */ | 
 |   const char *help;			/* Help description.  */ | 
 |   int *var;			/* Variable to be set.  */ | 
 |   int value;			/* Value to set.  */ | 
 | }; | 
 |  | 
 | /* The option in this group has both Enable/Disable settings. | 
 |    Just list on here.  */ | 
 |  | 
 | static struct nds32_set_option_table toggle_opts [] = | 
 | { | 
 |   {"mac", N_("Multiply instructions support"), &nds32_mac, 1}, | 
 |   {"div", N_("Divide instructions support"), &nds32_div, 1}, | 
 |   {"16bit-ext", N_("16-bit extension"), &nds32_16bit_ext, 1}, | 
 |   {"dx-regs", N_("d0/d1 registers"), &nds32_dx_regs, 1}, | 
 |   {"perf-ext", N_("Performance extension"), &nds32_perf_ext, 1}, | 
 |   {"perf2-ext", N_("Performance extension 2"), &nds32_perf_ext2, 1}, | 
 |   {"string-ext", N_("String extension"), &nds32_string_ext, 1}, | 
 |   {"reduced-regs", N_("Reduced Register configuration (GPR16) option"), &nds32_gpr16, 1}, | 
 |   {"audio-isa-ext", N_("AUDIO ISA extension"), &nds32_audio_ext, 1}, | 
 |   {"fpu-sp-ext", N_("FPU SP extension"), &nds32_fpu_sp_ext, 1}, | 
 |   {"fpu-dp-ext", N_("FPU DP extension"), &nds32_fpu_dp_ext, 1}, | 
 |   {"fpu-fma", N_("FPU fused-multiply-add instructions"), &nds32_fpu_fma, 1}, | 
 |   {"dsp-ext", N_("DSP extension"), &nds32_dsp_ext, 1}, | 
 |   {"zol-ext", N_("hardware loop extension"), &nds32_zol_ext, 1}, | 
 |   {NULL, NULL, NULL, 0} | 
 | }; | 
 |  | 
 |  | 
 | /* GAS declarations.  */ | 
 |  | 
 | /* This is the callback for nds32-asm.c to parse operands.  */ | 
 | int | 
 | nds32_asm_parse_operand (struct nds32_asm_desc *pdesc, | 
 | 			 struct nds32_asm_insn *pinsn, | 
 | 			 char **pstr, int64_t *value); | 
 |  | 
 |  | 
 | static struct nds32_asm_desc asm_desc; | 
 |  | 
 | /* md_after_parse_args () | 
 |  | 
 |    GAS will call md_after_parse_args whenever it is defined. | 
 |    This function checks any conflicting options specified.  */ | 
 |  | 
 | void | 
 | nds32_after_parse_args (void) | 
 | { | 
 |   /* If -march option is not used in command-line, set the value of option | 
 |      variable according to NDS32_DEFAULT_ARCH_NAME.  */ | 
 |   nds32_parse_arch (nds32_arch_name); | 
 | } | 
 |  | 
 | /* This function is called when printing usage message (--help).  */ | 
 |  | 
 | void | 
 | md_show_usage (FILE *stream) | 
 | { | 
 |   struct nds32_parse_option_table *coarse_tune; | 
 |   struct nds32_set_option_table *fine_tune; | 
 |  | 
 |   fprintf (stream, _("\n NDS32-specific assembler options:\n")); | 
 |   fprintf (stream, _("\ | 
 |   -O1,			  Optimize for performance\n\ | 
 |   -Os			  Optimize for space\n")); | 
 |   fprintf (stream, _("\ | 
 |   -EL, -mel or -little    Produce little endian output\n\ | 
 |   -EB, -meb or -big       Produce big endian output\n\ | 
 |   -mpic			  Generate PIC\n\ | 
 |   -mno-fp-as-gp-relax	  Suppress fp-as-gp relaxation for this file\n\ | 
 |   -mb2bb-relax		  Back-to-back branch optimization\n\ | 
 |   -mno-all-relax	  Suppress all relaxation for this file\n")); | 
 |  | 
 |   for (coarse_tune = parse_opts; coarse_tune->name != NULL; coarse_tune++) | 
 |     { | 
 |       if (coarse_tune->help != NULL) | 
 | 	fprintf (stream, _("  -m%s%s\n"), | 
 | 		 coarse_tune->name, _(coarse_tune->help)); | 
 |     } | 
 |  | 
 |   for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) | 
 |     { | 
 |       if (fine_tune->help != NULL) | 
 | 	fprintf (stream, _("  -m[no-]%-17sEnable/Disable %s\n"), | 
 | 		 fine_tune->name, _(fine_tune->help)); | 
 |     } | 
 |  | 
 |   fprintf (stream, _("\ | 
 |   -mall-ext		  Turn on all extensions and instructions support\n")); | 
 | } | 
 |  | 
 | void | 
 | nds32_frag_init (fragS *fragp) | 
 | { | 
 |   fragp->tc_frag_data.flag = 0; | 
 |   fragp->tc_frag_data.opcode = NULL; | 
 |   fragp->tc_frag_data.fixup = NULL; | 
 | } | 
 |  | 
 |  | 
 |  | 
 | /* This function reads an expression from a C string and returns a pointer past | 
 |    the end of the expression.  */ | 
 |  | 
 | static char * | 
 | parse_expression (char *str, expressionS *exp) | 
 | { | 
 |   char *s; | 
 |   char *tmp; | 
 |  | 
 |   tmp = input_line_pointer;	/* Save line pointer.  */ | 
 |   input_line_pointer = str; | 
 |   expression (exp); | 
 |   s = input_line_pointer; | 
 |   input_line_pointer = tmp;	/* Restore line pointer.  */ | 
 |  | 
 |   return s;			/* Return pointer to where parsing stopped.  */ | 
 | } | 
 |  | 
 | void | 
 | nds32_start_line_hook (void) | 
 | { | 
 | } | 
 |  | 
 | /* | 
 |  * Pseudo opcodes | 
 |  */ | 
 |  | 
 | typedef void (*nds32_pseudo_opcode_func) (int argc, char *argv[], unsigned int pv); | 
 | struct nds32_pseudo_opcode | 
 | { | 
 |   const char *opcode; | 
 |   int argc; | 
 |   nds32_pseudo_opcode_func proc; | 
 |   unsigned int pseudo_val; | 
 |  | 
 |   /* Some instructions are not pseudo opcode, but they might still be | 
 |      expanded or changed with other instruction combination for some | 
 |      conditions.  We also apply this structure to assist such work. | 
 |  | 
 |      For example, if the distance of branch target '.L0' is larger than | 
 |      imm8s<<1 range, | 
 |  | 
 |      the instruction: | 
 |  | 
 |          beqzs8 .L0 | 
 |  | 
 |      will be transformed into: | 
 |  | 
 |          bnezs8  .LCB0 | 
 |          j  .L0 | 
 |        .LCB0: | 
 |  | 
 |      However, sometimes we do not want assembler to do such changes | 
 |      because compiler knows how to generate corresponding instruction sequence. | 
 |      Use this field to indicate that this opcode is also a physical instruction. | 
 |      If the flag 'verbatim' is nozero and this opcode | 
 |      is a physical instruction, we should not expand it.  */ | 
 |   int physical_op; | 
 | }; | 
 | #define PV_DONT_CARE 0 | 
 |  | 
 | static htab_t nds32_pseudo_opcode_hash = NULL; | 
 |  | 
 | static int | 
 | builtin_isreg (const char *s, const char *x ATTRIBUTE_UNUSED) | 
 | { | 
 |   if (s [0] == '$' && str_hash_find (nds32_gprs_hash, (s + 1))) | 
 |     return 1; | 
 |   return 0; | 
 | } | 
 |  | 
 | static int | 
 | builtin_regnum (const char *s, const char *x ATTRIBUTE_UNUSED) | 
 | { | 
 |   struct nds32_keyword *k; | 
 |   if (*s != '$') | 
 |     return -1; | 
 |   s++; | 
 |   k = str_hash_find (nds32_gprs_hash, s); | 
 |  | 
 |   if (k == NULL) | 
 |     return -1; | 
 |  | 
 |   return k->value; | 
 | } | 
 |  | 
 | static int | 
 | builtin_addend (const char *s, char *x ATTRIBUTE_UNUSED) | 
 | { | 
 |   const char *ptr = s; | 
 |  | 
 |   while (*ptr != '+' && *ptr != '-' && *ptr) | 
 |     ++ptr; | 
 |  | 
 |   if (*ptr == 0) | 
 |     return 0; | 
 |   else | 
 |     return strtol (ptr, NULL, 0); | 
 | } | 
 |  | 
 | static void | 
 | md_assemblef (const char *format, ...) | 
 | { | 
 |   /* FIXME: hope this is long enough.  */ | 
 |   char line[1024]; | 
 |   va_list ap; | 
 |   unsigned int r; | 
 |  | 
 |   va_start (ap, format); | 
 |   r = vsnprintf (line, sizeof (line), format, ap); | 
 |   md_assemble (line); | 
 |  | 
 |   gas_assert (r < sizeof (line)); | 
 | } | 
 |  | 
 | /* Some prototypes here, since some op may use another op.  */ | 
 | static void do_pseudo_li_internal (const char *rt, int imm32s); | 
 | static void do_pseudo_move_reg_internal (char *dst, char *src); | 
 |  | 
 | static void | 
 | do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	     unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *arg_label = argv[0]; | 
 |   relaxing = true; | 
 |   /* b   label */ | 
 |   if (nds32_pic) | 
 |     { | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); | 
 |       md_assemble  ((char *) "add $ta,$ta,$gp"); | 
 |       md_assemble  ((char *) "jr $ta"); | 
 |     } | 
 |   else | 
 |     { | 
 |       md_assemblef ("j %s", arg_label); | 
 |     } | 
 |   relaxing = false; | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *arg_label = argv[0]; | 
 |   relaxing = true; | 
 |   /* bal|call  label */ | 
 |   if (nds32_pic) | 
 |     { | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); | 
 |       md_assemble ((char *) "add $ta,$ta,$gp"); | 
 |       md_assemble ((char *) "jral $ta"); | 
 |     } | 
 |   else | 
 |     { | 
 |       md_assemblef ("jal %s", arg_label); | 
 |     } | 
 |   relaxing = false; | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bge (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* rt5, ra5, label */ | 
 |   md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]); | 
 |   md_assemblef ("beqz $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bges (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* rt5, ra5, label */ | 
 |   md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]); | 
 |   md_assemblef ("beqz $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bgt (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* bgt rt5, ra5, label */ | 
 |   md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]); | 
 |   md_assemblef ("bnez $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bgts (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* bgt rt5, ra5, label */ | 
 |   md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]); | 
 |   md_assemblef ("bnez $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_ble (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* bgt rt5, ra5, label */ | 
 |   md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]); | 
 |   md_assemblef ("beqz $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bles (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* bgt rt5, ra5, label */ | 
 |   md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]); | 
 |   md_assemblef ("beqz $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_blt (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* rt5, ra5, label */ | 
 |   md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]); | 
 |   md_assemblef ("bnez $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_blts (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* rt5, ra5, label */ | 
 |   md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]); | 
 |   md_assemblef ("bnez $ta,%s", argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_br (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	      unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   md_assemblef ("jr %s", argv[0]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_bral (int argc, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   if (argc == 1) | 
 |     md_assemblef ("jral $lp,%s", argv[0]); | 
 |   else | 
 |     md_assemblef ("jral %s,%s", argv[0], argv[1]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_la_internal (const char *arg_reg, char *arg_label, | 
 | 		       const char *line) | 
 | { | 
 |   expressionS exp; | 
 |  | 
 |   parse_expression (arg_label, &exp); | 
 |   if (exp.X_op != O_symbol) | 
 |     { | 
 |       as_bad (_("la must use with symbol. '%s'"), line); | 
 |       return; | 
 |     } | 
 |  | 
 |   relaxing = true; | 
 |   /* rt, label */ | 
 |   if (!nds32_pic && !strstr (arg_label, "@")) | 
 |     { | 
 |       md_assemblef ("sethi %s,hi20(%s)", arg_reg, arg_label); | 
 |       md_assemblef ("ori %s,%s,lo12(%s)", arg_reg, arg_reg, arg_label); | 
 |     } | 
 |   else if (strstr (arg_label, "@TPOFF")) | 
 |     { | 
 |       /* la $rt, sym@TPOFF  */ | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); | 
 |       md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG); | 
 |     } | 
 |   else if (strstr(arg_label, "@GOTTPOFF")) | 
 |     { | 
 |       /* la $rt, sym@GOTTPOFF*/ | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("lwi $ta,[$ta+lo12(%s)]", arg_label); | 
 |       md_assemblef ("add %s,$ta,%s", arg_reg, TLS_REG); | 
 |     } | 
 |   else if (nds32_pic && ((strstr (arg_label, "@PLT") | 
 | 			  || strstr (arg_label, "@GOTOFF")))) | 
 |     { | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); | 
 |       md_assemblef ("add %s,$ta,$gp", arg_reg); | 
 |     } | 
 |   else if (nds32_pic && strstr (arg_label, "@GOT")) | 
 |     { | 
 |       long addend = builtin_addend (arg_label, NULL); | 
 |  | 
 |       md_assemblef ("sethi $ta,hi20(%s)", arg_label); | 
 |       md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); | 
 |       md_assemblef ("lw %s,[$gp+$ta]", arg_reg); | 
 |       if (addend != 0) | 
 | 	{ | 
 | 	  if (addend < 0x4000 && addend >= -0x4000) | 
 | 	    { | 
 | 	      md_assemblef ("addi %s,%s,%d", arg_reg, arg_reg, addend); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      do_pseudo_li_internal ("$ta", addend); | 
 | 	      md_assemblef ("add %s,$ta,%s", arg_reg, arg_reg); | 
 | 	    } | 
 | 	} | 
 |     } | 
 |    else | 
 |       as_bad (_("need PIC qualifier with symbol. '%s'"), line); | 
 |   relaxing = false; | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_la (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	      unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   do_pseudo_la_internal (argv[0], argv[1], argv[argc]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_li_internal (const char *rt, int imm32s) | 
 | { | 
 |   if (enable_16bit && imm32s <= 0xf && imm32s >= -0x10) | 
 |     md_assemblef ("movi55 %s,%d", rt, imm32s); | 
 |   else if (imm32s <= 0x7ffff && imm32s >= -0x80000) | 
 |     md_assemblef ("movi %s,%d", rt, imm32s); | 
 |   else if ((imm32s & 0xfff) == 0) | 
 |     md_assemblef ("sethi %s,hi20(%d)", rt, imm32s); | 
 |   else | 
 |     { | 
 |       md_assemblef ("sethi %s,hi20(%d)", rt, imm32s); | 
 |       md_assemblef ("ori %s,%s,lo12(%d)", rt, rt, imm32s); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_li (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	      unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Validate argv[1] for constant expression.  */ | 
 |   expressionS exp; | 
 |  | 
 |   parse_expression (argv[1], &exp); | 
 |   if (exp.X_op != O_constant) | 
 |     { | 
 |       as_bad (_("Operand is not a constant. `%s'"), argv[argc]); | 
 |       return; | 
 |     } | 
 |  | 
 |   do_pseudo_li_internal (argv[0], exp.X_add_number); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		  unsigned int pv) | 
 | { | 
 |   char ls = 'r'; | 
 |   char size = 'x'; | 
 |   const char *sign = ""; | 
 |  | 
 |   /* Prepare arguments for various load/store.  */ | 
 |   sign = (pv & 0x10) ? "s" : ""; | 
 |   ls = (pv & 0x80000000) ? 's' : 'l'; | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (ls == 's' || size == 'w') | 
 |     sign = ""; | 
 |  | 
 |   if (builtin_isreg (argv[1], NULL)) | 
 |     { | 
 |       /* lwi */ | 
 |       md_assemblef ("%c%ci %s,[%s]", ls, size, argv[0], argv[1]); | 
 |     } | 
 |   else if (!nds32_pic) | 
 |     { | 
 |       relaxing = true; | 
 |       if (strstr (argv[1], "@TPOFF")) | 
 | 	{ | 
 | 	  /* ls.w $rt, sym@TPOFF  */ | 
 | 	  md_assemblef ("sethi $ta,hi20(%s)", argv[1]); | 
 | 	  md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); | 
 | 	  md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG); | 
 | 	} | 
 |       else if (strstr (argv[1], "@GOTTPOFF")) | 
 | 	{ | 
 | 	  /* ls.w $rt, sym@GOTTPOFF  */ | 
 | 	  md_assemblef ("sethi $ta,hi20(%s)", argv[1]); | 
 | 	  md_assemblef ("lwi $ta,[$ta+lo12(%s)]", argv[1]); | 
 | 	  md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], TLS_REG); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* lwi */ | 
 | 	  md_assemblef ("sethi $ta,hi20(%s)", argv[1]); | 
 | 	  md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]); | 
 | 	} | 
 |       relaxing = false; | 
 |     } | 
 |   else | 
 |     { | 
 |       relaxing = true; | 
 |       /* PIC code.  */ | 
 |       if (strstr (argv[1], "@GOTOFF")) | 
 | 	{ | 
 | 	  /* lw */ | 
 | 	  md_assemblef ("sethi $ta,hi20(%s)", argv[1]); | 
 | 	  md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); | 
 | 	  md_assemblef ("%c%c%s %s,[$ta+$gp]", ls, size, sign, argv[0]); | 
 | 	} | 
 |       else if (strstr (argv[1], "@GOT")) | 
 | 	{ | 
 | 	  long addend = builtin_addend (argv[1], NULL); | 
 | 	  /* lw */ | 
 | 	  md_assemblef ("sethi $ta,hi20(%s)", argv[1]); | 
 | 	  md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); | 
 | 	  md_assemble ((char *) "lw $ta,[$gp+$ta]");	/* Load address word.  */ | 
 | 	  if (addend < 0x10000 && addend >= -0x10000) | 
 | 	    { | 
 | 	      md_assemblef ("%c%c%si %s,[$ta+(%d)]", ls, size, sign, argv[0], addend); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      /* lw */ | 
 | 	      do_pseudo_li_internal (argv[0], addend); | 
 | 	      md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], argv[0]); | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  as_bad (_("needs @GOT or @GOTOFF. %s"), argv[argc]); | 
 | 	} | 
 |       relaxing = false; | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_ls_bhwp (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		   unsigned int pv) | 
 | { | 
 |   char *arg_rt = argv[0]; | 
 |   char *arg_label = argv[1]; | 
 |   char *arg_inc = argv[2]; | 
 |   char ls = 'r'; | 
 |   char size = 'x'; | 
 |   const char *sign = ""; | 
 |  | 
 |   /* Prepare arguments for various load/store.  */ | 
 |   sign = (pv & 0x10) ? "s" : ""; | 
 |   ls = (pv & 0x80000000) ? 's' : 'l'; | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (ls == 's' || size == 'w') | 
 |     sign = ""; | 
 |  | 
 |   do_pseudo_la_internal ("$ta", arg_label, argv[argc]); | 
 |   md_assemblef ("%c%c%si.bi %s,[$ta],%s", ls, size, sign, arg_rt, arg_inc); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		    unsigned int pv) | 
 | { | 
 |   char *arg_rt = argv[0]; | 
 |   char *arg_inc = argv[1]; | 
 |   char ls = 'r'; | 
 |   char size = 'x'; | 
 |   const char *sign = ""; | 
 |  | 
 |   /* Prepare arguments for various load/store.  */ | 
 |   sign = (pv & 0x10) ? "s" : ""; | 
 |   ls = (pv & 0x80000000) ? 's' : 'l'; | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (ls == 's' || size == 'w') | 
 |     sign = ""; | 
 |  | 
 |   md_assemblef ("%c%c%si.bi %s,[$ta],%s", ls, size, sign, arg_rt, arg_inc); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_ls_bhwi (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		   unsigned int pv) | 
 | { | 
 |   char ls = 'r'; | 
 |   char size = 'x'; | 
 |   const char *sign = ""; | 
 |  | 
 |   /* Prepare arguments for various load/store.  */ | 
 |   sign = (pv & 0x10) ? "s" : ""; | 
 |   ls = (pv & 0x80000000) ? 's' : 'l'; | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (ls == 's' || size == 'w') | 
 |     sign = ""; | 
 |  | 
 |   md_assemblef ("%c%c%si.bi %s,%s,%s", | 
 | 		ls, size, sign, argv[0], argv[1], argv[2]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_move_reg_internal (char *dst, char *src) | 
 | { | 
 |   if (enable_16bit) | 
 |     md_assemblef ("mov55 %s,%s", dst, src); | 
 |   else | 
 |     md_assemblef ("ori %s,%s,0", dst, src); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   expressionS exp; | 
 |  | 
 |   if (builtin_isreg (argv[1], NULL)) | 
 |     do_pseudo_move_reg_internal (argv[0], argv[1]); | 
 |   else | 
 |     { | 
 |       parse_expression (argv[1], &exp); | 
 |       if (exp.X_op == O_constant) | 
 | 	/* move $rt, imm  -> li $rt, imm  */ | 
 | 	do_pseudo_li_internal (argv[0], exp.X_add_number); | 
 |       else | 
 | 	/* l.w $rt, var  -> l.w $rt, var  */ | 
 | 	do_pseudo_ls_bhw (argc, argv, 2); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_neg (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Instead of "subri".  */ | 
 |   md_assemblef ("subri %s,%s,0", argv[0], argv[1]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_not (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 	       unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   md_assemblef ("nor %s,%s,%s", argv[0], argv[1], argv[1]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_pushpopm (int argc, char *argv[], | 
 | 		    unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* posh/pop $ra, $rb */ | 
 |   /* SMW.{b | a}{i | d}{m?} Rb, [Ra], Re, Enable4 */ | 
 |   int rb, re, ra, en4; | 
 |   int i; | 
 |   const char *opc = "pushpopm"; | 
 |  | 
 |   if (argc == 3) | 
 |     as_bad ("'pushm/popm $ra5, $rb5, $label' is deprecated.  " | 
 | 	    "Only 'pushm/popm $ra5' is supported now. %s", argv[argc]); | 
 |   else if (argc == 1) | 
 |     as_bad ("'pushm/popm $ra5, $rb5'. %s\n", argv[argc]); | 
 |  | 
 |   if (strstr (argv[argc], "pop") == argv[argc]) | 
 |     opc = "lmw.bim"; | 
 |   else if (strstr (argv[argc], "push") == argv[argc]) | 
 |     opc = "smw.adm"; | 
 |   else | 
 |     as_fatal ("nds32-as internal error. %s", argv[argc]); | 
 |  | 
 |   rb = builtin_regnum (argv[0], NULL); | 
 |   re = builtin_regnum (argv[1], NULL); | 
 |  | 
 |   if (re < rb) | 
 |     { | 
 |       as_warn ("$rb should not be smaller than $ra. %s", argv[argc]); | 
 |       /* Swap to right order.  */ | 
 |       ra = re; | 
 |       re = rb; | 
 |       rb = ra; | 
 |     } | 
 |  | 
 |   /* Build enable4 mask.  */ | 
 |   en4 = 0; | 
 |   if (re >= 28 || rb >= 28) | 
 |     { | 
 |       for (i = (rb >= 28? rb: 28); i <= re; i++) | 
 | 	en4 |= 1 << (3 - (i - 28)); | 
 |     } | 
 |  | 
 |   /* Adjust $re, $rb.  */ | 
 |   if (rb >= 28) | 
 |     rb = re = 31; | 
 |   else if (nds32_gpr16 != 1 && re >= 28) | 
 |     re = 27; | 
 |  | 
 |   /* Reduce register.  */ | 
 |   if (nds32_gpr16 && re > 10 && !(rb == 31 && re == 31)) | 
 |     { | 
 |       if (re >= 15 && strstr (opc, "smw") != NULL) | 
 | 	md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4); | 
 |       if (rb <= 10) | 
 | 	md_assemblef ("%s $r%d,[$sp],$r10, 0x0", opc, rb); | 
 |       if (re >= 15 && strstr (opc, "lmw") != NULL) | 
 | 	md_assemblef ("%s $r15,[$sp],$r15,%d", opc, en4); | 
 |     } | 
 |   else | 
 |     md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_pushpop (int argc, char *argv[], | 
 | 		   unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* push/pop $ra5, $label=$sp */ | 
 |   char *argvm[3]; | 
 |  | 
 |   if (argc == 2) | 
 |     as_bad ("'push/pop $ra5, rb5' is deprecated.  " | 
 | 	    "Only 'push/pop $ra5' is supported now. %s", argv[argc]); | 
 |  | 
 |   argvm[0] = argv[0]; | 
 |   argvm[1] = argv[0]; | 
 |   argvm[2] = argv[argc]; | 
 |   do_pseudo_pushpopm (2, argvm, PV_DONT_CARE); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_v3push (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		  unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   md_assemblef ("push25 %s,%s", argv[0], argv[1]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_v3pop (int argc ATTRIBUTE_UNUSED, char *argv[],  | 
 | 		 unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   md_assemblef ("pop25 %s,%s", argv[0], argv[1]); | 
 | } | 
 |  | 
 | /* pv == 0, parsing "push.s" pseudo instruction operands. | 
 |    pv != 0, parsing "pop.s" pseudo instruction operands.  */ | 
 |  | 
 | static void | 
 | do_pseudo_pushpop_stack (int argc, char *argv[], | 
 | 			 unsigned int pv) | 
 | { | 
 |   /* push.s Rb,Re,{$fp $gp $lp $sp}  ==>  smw.adm Rb,[$sp],Re,Eable4  */ | 
 |   /* pop.s Rb,Re,{$fp $gp $lp $sp}   ==>  lmw.bim Rb,[$sp],Re,Eable4  */ | 
 |  | 
 |   int rb, re; | 
 |   int en4; | 
 |   int last_arg_index; | 
 |   const char *opc = (pv == 0) ? "smw.adm" : "lmw.bim"; | 
 |  | 
 |   rb = re = 0; | 
 |  | 
 |   if (argc == 1) | 
 |     { | 
 |       /* argc=1, operands pattern: { $fp $gp $lp $sp }  */ | 
 |  | 
 |       /* Set register number Rb = Re = $sp = $r31.  */ | 
 |       rb = re = 31; | 
 |     } | 
 |   else if (argc == 2 || argc == 3) | 
 |     { | 
 |       /* argc=2, operands pattern: Rb, Re  */ | 
 |       /* argc=3, operands pattern: Rb, Re, { $fp $gp $lp $sp }  */ | 
 |  | 
 |       /* Get register number in integer.  */ | 
 |       rb = builtin_regnum (argv[0], NULL); | 
 |       re = builtin_regnum (argv[1], NULL); | 
 |  | 
 |       /* Rb should be equal/less than Re.  */ | 
 |       if (rb > re) | 
 | 	as_bad ("The first operand (%s) should be equal to or smaller than " | 
 | 		"second operand (%s).", argv[0], argv[1]); | 
 |  | 
 |       /* forbid using $fp|$gp|$lp|$sp in Rb or Re | 
 | 		      r28 r29 r30 r31  */ | 
 |       if (rb >= 28) | 
 | 	as_bad ("Cannot use $fp, $gp, $lp, or $sp at first operand !!"); | 
 |       if (re >= 28) | 
 | 	as_bad ("Cannot use $fp, $gp, $lp, or $sp at second operand !!"); | 
 |     } | 
 |   else | 
 |     { | 
 |       as_bad ("Invalid operands pattern !!"); | 
 |     } | 
 |  | 
 |   /* Build Enable4 mask.  */ | 
 |   /* Using last_arg_index for argc=1|2|3 is safe, because $fp, $gp, $lp, | 
 |      and $sp only appear in argc=1 or argc=3 if argc=2, en4 remains 0, | 
 |      which is also valid for code generation.  */ | 
 |   en4 = 0; | 
 |   last_arg_index = argc - 1; | 
 |   if (strstr (argv[last_arg_index], "$fp")) | 
 |     en4 |= 8; | 
 |   if (strstr (argv[last_arg_index], "$gp")) | 
 |     en4 |= 4; | 
 |   if (strstr (argv[last_arg_index], "$lp")) | 
 |     en4 |= 2; | 
 |   if (strstr (argv[last_arg_index], "$sp")) | 
 |     en4 |= 1; | 
 |  | 
 |   md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_push_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		     unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   char size = 'x'; | 
 |   /* If users omit push location, use $sp as default value.  */ | 
 |   char location[8] = "$sp";  /* 8 is enough for register name.  */ | 
 |  | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     case 3: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (argc == 2) | 
 |     { | 
 |       strncpy (location, argv[1], sizeof (location) - 1); | 
 |       location[sizeof (location) - 1] = '\0'; | 
 |     } | 
 |  | 
 |   md_assemblef ("l.%c $ta,%s", size, argv[0]); | 
 |   md_assemblef ("smw.adm $ta,[%s],$ta", location); | 
 |  | 
 |   if ((pv & 0x3) == 0x3) /* double-word */ | 
 |     { | 
 |       md_assemblef ("l.w $ta,%s+4", argv[0]); | 
 |       md_assemblef ("smw.adm $ta,[%s],$ta", location); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_pop_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		    unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   char size = 'x'; | 
 |   /* If users omit pop location, use $sp as default value.  */ | 
 |   char location[8] = "$sp";  /* 8 is enough for register name.  */ | 
 |  | 
 |   switch (pv & 0x3) | 
 |     { | 
 |     case 0: size = 'b'; break; | 
 |     case 1: size = 'h'; break; | 
 |     case 2: size = 'w'; break; | 
 |     case 3: size = 'w'; break; | 
 |     } | 
 |  | 
 |   if (argc == 3) | 
 |     { | 
 |       strncpy (location, argv[2], sizeof (location) - 1); | 
 |       location[sizeof (location) - 1] = '\0'; | 
 |     } | 
 |  | 
 |   if ((pv & 0x3) == 0x3) /* double-word */ | 
 |     { | 
 |       md_assemblef ("lmw.bim %s,[%s],%s", argv[1], location, argv[1]); | 
 |       md_assemblef ("s.w %s,%s+4", argv[1], argv[0]); | 
 |     } | 
 |  | 
 |   md_assemblef ("lmw.bim %s,[%s],%s", argv[1], location, argv[1]); | 
 |   md_assemblef ("s.%c %s,%s", size, argv[1], argv[0]); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_pusha (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		 unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* If users omit push location, use $sp as default value.  */ | 
 |   char location[8] = "$sp";  /* 8 is enough for register name.  */ | 
 |  | 
 |   if (argc == 2) | 
 |     { | 
 |       strncpy (location, argv[1], sizeof (location) - 1); | 
 |       location[sizeof (location) - 1] = '\0'; | 
 |     } | 
 |  | 
 |   md_assemblef ("la $ta,%s", argv[0]); | 
 |   md_assemblef ("smw.adm $ta,[%s],$ta", location); | 
 | } | 
 |  | 
 | static void | 
 | do_pseudo_pushi (int argc ATTRIBUTE_UNUSED, char *argv[], | 
 | 		 unsigned int pv ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* If users omit push location, use $sp as default value.  */ | 
 |   char location[8] = "$sp";  /* 8 is enough for register name.  */ | 
 |  | 
 |   if (argc == 2) | 
 |     { | 
 |       strncpy (location, argv[1], sizeof (location) - 1); | 
 |       location[sizeof (location) - 1] = '\0'; | 
 |     } | 
 |  | 
 |   md_assemblef ("li $ta,%s", argv[0]); | 
 |   md_assemblef ("smw.adm $ta,[%s],$ta", location); | 
 | } | 
 |  | 
 | static struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] = | 
 | { | 
 |   {"b",      1, do_pseudo_b,      0, 0}, | 
 |   {"bal",    1, do_pseudo_bal,    0, 0}, | 
 |  | 
 |   {"bge",    3, do_pseudo_bge,    0, 0}, | 
 |   {"bges",   3, do_pseudo_bges,   0, 0}, | 
 |  | 
 |   {"bgt",    3, do_pseudo_bgt,    0, 0}, | 
 |   {"bgts",   3, do_pseudo_bgts,   0, 0}, | 
 |  | 
 |   {"ble",    3, do_pseudo_ble,    0, 0}, | 
 |   {"bles",   3, do_pseudo_bles,   0, 0}, | 
 |  | 
 |   {"blt",    3, do_pseudo_blt,    0, 0}, | 
 |   {"blts",   3, do_pseudo_blts,   0, 0}, | 
 |  | 
 |   {"br",     1, do_pseudo_br,     0, 0}, | 
 |   {"bral",   1, do_pseudo_bral,   0, 0}, | 
 |  | 
 |   {"call",   1, do_pseudo_bal,    0, 0}, | 
 |  | 
 |   {"la",     2, do_pseudo_la, 0, 0}, | 
 |   {"li",     2, do_pseudo_li, 0, 0}, | 
 |  | 
 |   {"l.b",    2, do_pseudo_ls_bhw, 0, 0}, | 
 |   {"l.h",    2, do_pseudo_ls_bhw, 1, 0}, | 
 |   {"l.w",    2, do_pseudo_ls_bhw, 2, 0}, | 
 |   {"l.bs",   2, do_pseudo_ls_bhw, 0 | 0x10, 0}, | 
 |   {"l.hs",   2, do_pseudo_ls_bhw, 1 | 0x10, 0}, | 
 |   {"s.b",    2, do_pseudo_ls_bhw, 0 | 0x80000000, 0}, | 
 |   {"s.h",    2, do_pseudo_ls_bhw, 1 | 0x80000000, 0}, | 
 |   {"s.w",    2, do_pseudo_ls_bhw, 2 | 0x80000000, 0}, | 
 |  | 
 |   {"l.bp",   3, do_pseudo_ls_bhwp, 0, 0}, | 
 |   {"l.bpc",  3, do_pseudo_ls_bhwpc, 0, 0}, | 
 |   {"l.hp",   3, do_pseudo_ls_bhwp, 1, 0}, | 
 |   {"l.hpc",  3, do_pseudo_ls_bhwpc, 1, 0}, | 
 |   {"l.wp",   3, do_pseudo_ls_bhwp, 2, 0}, | 
 |   {"l.wpc",  3, do_pseudo_ls_bhwpc, 2, 0}, | 
 |   {"l.bsp",  3, do_pseudo_ls_bhwp, 0 | 0x10, 0}, | 
 |   {"l.bspc", 3, do_pseudo_ls_bhwpc, 0 | 0x10, 0}, | 
 |   {"l.hsp",  3, do_pseudo_ls_bhwp, 1 | 0x10, 0}, | 
 |   {"l.hspc", 3, do_pseudo_ls_bhwpc, 1 | 0x10, 0}, | 
 |   {"s.bp",   3, do_pseudo_ls_bhwp, 0 | 0x80000000, 0}, | 
 |   {"s.bpc",   3, do_pseudo_ls_bhwpc, 0 | 0x80000000, 0}, | 
 |   {"s.hp",   3, do_pseudo_ls_bhwp, 1 | 0x80000000, 0}, | 
 |   {"s.hpc",   3, do_pseudo_ls_bhwpc, 1 | 0x80000000, 0}, | 
 |   {"s.wp",   3, do_pseudo_ls_bhwp, 2 | 0x80000000, 0}, | 
 |   {"s.wpc",   3, do_pseudo_ls_bhwpc, 2 | 0x80000000, 0}, | 
 |   {"s.bsp",  3, do_pseudo_ls_bhwp, 0 | 0x80000000 | 0x10, 0}, | 
 |   {"s.hsp",  3, do_pseudo_ls_bhwp, 1 | 0x80000000 | 0x10, 0}, | 
 |  | 
 |   {"lbi.p",  3, do_pseudo_ls_bhwi, 0, 0}, | 
 |   {"lhi.p",  3, do_pseudo_ls_bhwi, 1, 0}, | 
 |   {"lwi.p",  3, do_pseudo_ls_bhwi, 2, 0}, | 
 |   {"sbi.p",  3, do_pseudo_ls_bhwi, 0 | 0x80000000, 0}, | 
 |   {"shi.p",  3, do_pseudo_ls_bhwi, 1 | 0x80000000, 0}, | 
 |   {"swi.p",  3, do_pseudo_ls_bhwi, 2 | 0x80000000, 0}, | 
 |   {"lbsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0}, | 
 |   {"lhsi.p", 3, do_pseudo_ls_bhwi, 1 | 0x10, 0}, | 
 |   {"lwsi.p", 3, do_pseudo_ls_bhwi, 2 | 0x10, 0}, | 
 |  | 
 |   {"move",   2, do_pseudo_move, 0, 0}, | 
 |   {"neg",    2, do_pseudo_neg,  0, 0}, | 
 |   {"not",    2, do_pseudo_not,  0, 0}, | 
 |  | 
 |   {"pop",    2, do_pseudo_pushpop,   0, 0}, | 
 |   {"push",   2, do_pseudo_pushpop,   0, 0}, | 
 |   {"popm",   2, do_pseudo_pushpopm,  0, 0}, | 
 |   {"pushm",   3, do_pseudo_pushpopm, 0, 0}, | 
 |  | 
 |   {"v3push", 2, do_pseudo_v3push, 0, 0}, | 
 |   {"v3pop",  2, do_pseudo_v3pop,  0, 0}, | 
 |  | 
 |   /* Support pseudo instructions of pushing/poping registers into/from stack | 
 |      push.s  Rb, Re, { $fp $gp $lp $sp }  ==>  smw.adm  Rb,[$sp],Re,Enable4 | 
 |      pop.s   Rb, Re, { $fp $gp $lp $sp }  ==>  lmw.bim  Rb,[$sp],Re,Enable4 */ | 
 |   { "push.s", 3, do_pseudo_pushpop_stack, 0, 0 }, | 
 |   { "pop.s", 3, do_pseudo_pushpop_stack, 1, 0 }, | 
 |   { "push.b", 2, do_pseudo_push_bhwd, 0, 0 }, | 
 |   { "push.h", 2, do_pseudo_push_bhwd, 1, 0 }, | 
 |   { "push.w", 2, do_pseudo_push_bhwd, 2, 0 }, | 
 |   { "push.d", 2, do_pseudo_push_bhwd, 3, 0 }, | 
 |   { "pop.b", 3, do_pseudo_pop_bhwd, 0, 0 }, | 
 |   { "pop.h", 3, do_pseudo_pop_bhwd, 1, 0 }, | 
 |   { "pop.w", 3, do_pseudo_pop_bhwd, 2, 0 }, | 
 |   { "pop.d", 3, do_pseudo_pop_bhwd, 3, 0 }, | 
 |   { "pusha", 2, do_pseudo_pusha, 0, 0 }, | 
 |   { "pushi", 2, do_pseudo_pushi, 0, 0 }, | 
 |  | 
 |   {NULL, 0, NULL, 0, 0} | 
 | }; | 
 |  | 
 | static void | 
 | nds32_init_nds32_pseudo_opcodes (void) | 
 | { | 
 |   struct nds32_pseudo_opcode *opcode; | 
 |  | 
 |   nds32_pseudo_opcode_hash = str_htab_create (); | 
 |   for (opcode = nds32_pseudo_opcode_table; opcode->opcode; opcode++) | 
 |     if (str_hash_insert (nds32_pseudo_opcode_hash, opcode->opcode, opcode, 0)) | 
 |       as_fatal (_("duplicate %s"), opcode->opcode); | 
 | } | 
 |  | 
 | static struct nds32_pseudo_opcode * | 
 | nds32_lookup_pseudo_opcode (const char *str) | 
 | { | 
 |   struct nds32_pseudo_opcode *result; | 
 |   int i = 0; | 
 |  | 
 |   /* (*op) is the first word of current source line (*str)  */ | 
 |   int maxlen = strlen (str); | 
 |   char *op = xmalloc (maxlen + 1); | 
 |  | 
 |   for (i = 0; i < maxlen; i++) | 
 |     { | 
 |       if (ISSPACE (op[i] = str[i])) | 
 | 	break; | 
 |     } | 
 |   op[i] = '\0'; | 
 |  | 
 |   result = str_hash_find (nds32_pseudo_opcode_hash, op); | 
 |   free (op); | 
 |   return result; | 
 | } | 
 |  | 
 | static void | 
 | nds32_pseudo_opcode_wrapper (char *line, struct nds32_pseudo_opcode *opcode) | 
 | { | 
 |   int argc = 0; | 
 |   char *argv[8] = {NULL}; | 
 |   char *s; | 
 |   char *str = xstrdup (line); | 
 |  | 
 |   /* Parse arguments for opcode.  */ | 
 |   s = str + strlen (opcode->opcode); | 
 |  | 
 |   if (!s[0]) | 
 |     goto end; | 
 |  | 
 |   /* Dummy comma to ease separate arguments as below.  */ | 
 |   s[0] = ','; | 
 |   do | 
 |     { | 
 |       if (s[0] == ',') | 
 | 	{ | 
 | 	  if (argc >= opcode->argc | 
 | 	      || (argc >= (int)ARRAY_SIZE (argv) - 1)) | 
 | 	    as_bad (_("Too many argument. `%s'"), line); | 
 |  | 
 | 	  argv[argc] = s + 1; | 
 | 	  argc ++; | 
 | 	  s[0] = '\0'; | 
 | 	} | 
 |       ++s; | 
 |     } while (s[0] != '\0'); | 
 |  end: | 
 |   /* Put the origin line for debugging.  */ | 
 |   argv[argc] = line; | 
 |   opcode->proc (argc, argv, opcode->pseudo_val); | 
 |   free (str); | 
 | } | 
 |  | 
 | /* This function will be invoked from function `nds32_after_parse_args'. | 
 |    Thus, if the value of option has been set, keep the value the way it is.  */ | 
 |  | 
 | static int | 
 | nds32_parse_arch (const char *str) | 
 | { | 
 |   static const struct nds32_arch | 
 |   { | 
 |     const char *name; | 
 |     int baseline; | 
 |     int reduced_reg; | 
 |     int fpu_sp_ext; | 
 |     int fpu_dp_ext; | 
 |     int fpu_freg; | 
 |     int abi; | 
 |   } archs[] = | 
 |   { | 
 |     {"v3m", ISA_V3M, 1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, | 
 |     {"v3j", ISA_V3,  1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, | 
 |     {"v3s", ISA_V3,  0, 1, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, | 
 |     {"v3f", ISA_V3,  0, 1, 1, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, | 
 |     {"v3",  ISA_V3,  0, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, | 
 |     {"v2j", ISA_V2,  1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, | 
 |     {"v2s", ISA_V2,  0, 1, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, | 
 |     {"v2f", ISA_V2,  0, 1, 1, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, | 
 |     {"v2",  ISA_V2,  0, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, | 
 |   }; | 
 |   size_t i; | 
 |  | 
 |   for (i = 0; i < ARRAY_SIZE (archs); i++) | 
 |     { | 
 |       if (strcmp (str, archs[i].name) != 0) | 
 | 	continue; | 
 |  | 
 |       /* The value `-1' represents this option has *NOT* been set.  */ | 
 |       nds32_baseline = (-1 != nds32_baseline) ? nds32_baseline : archs[i].baseline; | 
 |       nds32_gpr16 = (-1 != nds32_gpr16) ? nds32_gpr16 : archs[i].reduced_reg; | 
 |       nds32_fpu_sp_ext = (-1 != nds32_fpu_sp_ext) ? nds32_fpu_sp_ext : archs[i].fpu_sp_ext; | 
 |       nds32_fpu_dp_ext = (-1 != nds32_fpu_dp_ext) ? nds32_fpu_dp_ext : archs[i].fpu_dp_ext; | 
 |       nds32_freg = (-1 != nds32_freg) ? nds32_freg : archs[i].fpu_freg; | 
 |       nds32_abi = (-1 != nds32_abi) ? nds32_abi : archs[i].abi; | 
 |  | 
 |       return 1; | 
 |     } | 
 |  | 
 |   /* Logic here rejects the input arch name.  */ | 
 |   as_bad (_("unknown arch name `%s'\n"), str); | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* This function parses "baseline" specified.  */ | 
 |  | 
 | static int | 
 | nds32_parse_baseline (const char *str) | 
 | { | 
 |   if (strcmp (str, "v3") == 0) | 
 |     nds32_baseline = ISA_V3; | 
 |   else if (strcmp (str, "v3m") == 0) | 
 |     nds32_baseline = ISA_V3M; | 
 |   else if (strcmp (str, "v2") == 0) | 
 |     nds32_baseline = ISA_V2; | 
 |   else | 
 |     { | 
 |       /* Logic here rejects the input baseline.  */ | 
 |       as_bad (_("unknown baseline `%s'\n"), str); | 
 |       return 0; | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* This function parses "fpu-freg" specified.  */ | 
 |  | 
 | static int | 
 | nds32_parse_freg (const char *str) | 
 | { | 
 |   if (strcmp (str, "2") == 0) | 
 |     nds32_freg = E_NDS32_FPU_REG_32SP_16DP; | 
 |   else if (strcmp (str, "3") == 0) | 
 |     nds32_freg = E_NDS32_FPU_REG_32SP_32DP; | 
 |   else if (strcmp (str, "1") == 0) | 
 |     nds32_freg = E_NDS32_FPU_REG_16SP_8DP; | 
 |   else if (strcmp (str, "0") == 0) | 
 |     nds32_freg = E_NDS32_FPU_REG_8SP_4DP; | 
 |   else | 
 |     { | 
 |       /* Logic here rejects the input FPU configuration.  */ | 
 |       as_bad (_("unknown FPU configuration `%s'\n"), str); | 
 |       return 0; | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* This function parse "abi=" specified.  */ | 
 |  | 
 | static int | 
 | nds32_parse_abi (const char *str) | 
 | { | 
 |   if (strcmp (str, "v2") == 0) | 
 |     nds32_abi = E_NDS_ABI_AABI; | 
 |   /* Obsolete.  */ | 
 |   else if (strcmp (str, "v2fp") == 0) | 
 |     nds32_abi = E_NDS_ABI_V2FP; | 
 |   else if (strcmp (str, "v1") == 0) | 
 |     nds32_abi = E_NDS_ABI_V1; | 
 |   else if (strcmp (str,"v2fpp") == 0) | 
 |     nds32_abi = E_NDS_ABI_V2FP_PLUS; | 
 |   else | 
 |     { | 
 |       /* Logic here rejects the input abi version.  */ | 
 |       as_bad (_("unknown ABI version`%s'\n"), str); | 
 |       return 0; | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* This function turn on all extensions and instructions support.  */ | 
 |  | 
 | static int | 
 | nds32_all_ext (void) | 
 | { | 
 |   nds32_mac = 1; | 
 |   nds32_div = 1; | 
 |   nds32_dx_regs = 1; | 
 |   nds32_16bit_ext = 1; | 
 |   nds32_perf_ext = 1; | 
 |   nds32_perf_ext2 = 1; | 
 |   nds32_string_ext = 1; | 
 |   nds32_audio_ext = 1; | 
 |   nds32_fpu_fma = 1; | 
 |   nds32_fpu_sp_ext = 1; | 
 |   nds32_fpu_dp_ext = 1; | 
 |   nds32_dsp_ext = 1; | 
 |   nds32_zol_ext = 1; | 
 |   /* Turn off reduced register.  */ | 
 |   nds32_gpr16 = 0; | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* GAS will call md_parse_option whenever getopt returns an unrecognized code, | 
 |    presumably indicating a special code value which appears in md_longopts. | 
 |    This function should return non-zero if it handled the option and zero | 
 |    otherwise.  There is no need to print a message about an option not being | 
 |    recognized.  This will be handled by the generic code.  */ | 
 |  | 
 | int | 
 | nds32_parse_option (int c, const char *arg) | 
 | { | 
 |   struct nds32_parse_option_table *coarse_tune; | 
 |   struct nds32_set_option_table *fine_tune; | 
 |   const char *ptr_arg = NULL; | 
 |  | 
 |   switch (c) | 
 |     { | 
 |     case OPTION_OPTIMIZE: | 
 |       optimize = 1; | 
 |       optimize_for_space = 0; | 
 |       break; | 
 |     case OPTION_OPTIMIZE_SPACE: | 
 |       optimize = 0; | 
 |       optimize_for_space = 1; | 
 |       break; | 
 |     case OPTION_BIG: | 
 |       target_big_endian = 1; | 
 |       break; | 
 |     case OPTION_LITTLE: | 
 |       target_big_endian = 0; | 
 |       break; | 
 |     case OPTION_TURBO: | 
 |       nds32_all_ext (); | 
 |       break; | 
 |     case OPTION_PIC: | 
 |       nds32_pic = 1; | 
 |       break; | 
 |     case OPTION_RELAX_FP_AS_GP_OFF: | 
 |       nds32_relax_fp_as_gp = 0; | 
 |       break; | 
 |     case OPTION_RELAX_B2BB_ON: | 
 |       nds32_relax_b2bb = 1; | 
 |       break; | 
 |     case OPTION_RELAX_ALL_OFF: | 
 |       nds32_relax_all = 0; | 
 |       break; | 
 |     default: | 
 |       /* Determination of which option table to search for to save time.  */ | 
 |       if (!arg) | 
 | 	return 0; | 
 |  | 
 |       ptr_arg = strchr (arg, '='); | 
 |  | 
 |       if (ptr_arg) | 
 | 	{ | 
 | 	  /* Find the value after '='.  */ | 
 | 	  if (ptr_arg != NULL) | 
 | 	    ptr_arg++; | 
 | 	  for (coarse_tune = parse_opts; coarse_tune->name != NULL; coarse_tune++) | 
 | 	    { | 
 | 	      if (strncmp (arg, coarse_tune->name, (ptr_arg - arg)) == 0) | 
 | 		{ | 
 | 		  coarse_tune->func (ptr_arg); | 
 | 		  return 1; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  int disable = 0; | 
 |  | 
 | 	  /* Filter out the Disable option first.  */ | 
 | 	  if (startswith (arg, "no-")) | 
 | 	    { | 
 | 	      disable = 1; | 
 | 	      arg += 3; | 
 | 	    } | 
 |  | 
 | 	  for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) | 
 | 	    { | 
 | 	      if (strcmp (arg, fine_tune->name) == 0) | 
 | 		{ | 
 | 		  if (fine_tune->var != NULL) | 
 | 		    *fine_tune->var = (disable) ? 0 : 1; | 
 | 		  return 1; | 
 | 		} | 
 | 	    } | 
 | 	} | 
 |       /* Nothing match.  */ | 
 |       return 0; | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* tc_check_label  */ | 
 |  | 
 | void | 
 | nds32_check_label (symbolS *label ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* The code used to create BB is move to frob_label. | 
 |      They should go there.  */ | 
 | } | 
 |  | 
 | static void | 
 | set_endian_little (int on) | 
 | { | 
 |   target_big_endian = !on; | 
 | } | 
 |  | 
 | /* These functions toggles the generation of 16-bit.  First encounter signals | 
 |    the beginning of not generating 16-bit instructions and next encounter | 
 |    signals the restoring back to default behavior.  */ | 
 |  | 
 | static void | 
 | trigger_16bit (int trigger) | 
 | { | 
 |   enable_16bit = trigger; | 
 | } | 
 |  | 
 | static int backup_16bit_mode; | 
 | static void | 
 | restore_16bit (int no_use ATTRIBUTE_UNUSED) | 
 | { | 
 |   enable_16bit = backup_16bit_mode; | 
 | } | 
 |  | 
 | static void | 
 | off_16bit (int no_use ATTRIBUTE_UNUSED) | 
 | { | 
 |   backup_16bit_mode = enable_16bit; | 
 |   enable_16bit = 0; | 
 | } | 
 |  | 
 | /* Built-in segments for small object.  */ | 
 | typedef struct nds32_seg_entryT | 
 | { | 
 |   segT s; | 
 |   const char *name; | 
 |   flagword flags; | 
 | } nds32_seg_entry; | 
 |  | 
 | nds32_seg_entry nds32_seg_table[] = | 
 | { | 
 |   {NULL, ".sdata_f", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | 
 | 		     | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, | 
 |   {NULL, ".sdata_b", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | 
 | 		     | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, | 
 |   {NULL, ".sdata_h", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | 
 | 		     | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, | 
 |   {NULL, ".sdata_w", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | 
 | 		     | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, | 
 |   {NULL, ".sdata_d", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA | 
 | 		     | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, | 
 |   {NULL, ".sbss_f", SEC_ALLOC | SEC_SMALL_DATA}, | 
 |   {NULL, ".sbss_b", SEC_ALLOC | SEC_SMALL_DATA}, | 
 |   {NULL, ".sbss_h", SEC_ALLOC | SEC_SMALL_DATA}, | 
 |   {NULL, ".sbss_w", SEC_ALLOC | SEC_SMALL_DATA}, | 
 |   {NULL, ".sbss_d", SEC_ALLOC | SEC_SMALL_DATA} | 
 | }; | 
 |  | 
 | /* Indexes to nds32_seg_table[].  */ | 
 | enum NDS32_SECTIONS_ENUM | 
 | { | 
 |   SDATA_F_SECTION = 0, | 
 |   SDATA_B_SECTION = 1, | 
 |   SDATA_H_SECTION = 2, | 
 |   SDATA_W_SECTION = 3, | 
 |   SDATA_D_SECTION = 4, | 
 |   SBSS_F_SECTION = 5, | 
 |   SBSS_B_SECTION = 6, | 
 |   SBSS_H_SECTION = 7, | 
 |   SBSS_W_SECTION = 8, | 
 |   SBSS_D_SECTION = 9 | 
 | }; | 
 |  | 
 | /* The following code is borrowed from v850_seg.  Revise this is needed.  */ | 
 |  | 
 | static void | 
 | do_nds32_seg (int i, subsegT sub) | 
 | { | 
 |   nds32_seg_entry *seg = nds32_seg_table + i; | 
 |  | 
 |   obj_elf_section_change_hook (); | 
 |  | 
 |   if (seg->s != NULL) | 
 |     subseg_set (seg->s, sub); | 
 |   else | 
 |     { | 
 |       seg->s = subseg_new (seg->name, sub); | 
 |       if (OUTPUT_FLAVOR == bfd_target_elf_flavour) | 
 | 	{ | 
 | 	  bfd_set_section_flags (seg->s, seg->flags); | 
 | 	  if ((seg->flags & SEC_LOAD) == 0) | 
 | 	    seg_info (seg->s)->bss = 1; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | nds32_seg (int i) | 
 | { | 
 |   subsegT sub = get_absolute_expression (); | 
 |  | 
 |   do_nds32_seg (i, sub); | 
 |   demand_empty_rest_of_line (); | 
 | } | 
 |  | 
 | /* Set if label adjustment is needed.  I should not adjust .xbyte in dwarf.  */ | 
 | static symbolS *nds32_last_label;	/* Last label for alignment.  */ | 
 |  | 
 | static void | 
 | add_mapping_symbol_for_align (int shift, valueT addr, int is_data_align) | 
 | { | 
 |   if ((shift > 1) && (addr & 1)) | 
 |     { | 
 |       int n = (1 << shift) - 1; | 
 |       if (!is_data_align) | 
 | 	add_mapping_symbol (MAP_CODE, 1, 0); | 
 |       else if ((int) (addr & n) != n) | 
 | 	add_mapping_symbol (MAP_CODE, 1, 0); | 
 |     } | 
 |   else if ((shift > 1) && ((int) (addr & 1) == 0)) | 
 |     add_mapping_symbol (MAP_CODE, 0, 0); | 
 | } | 
 |  | 
 | /* This code is referred from D30V for adjust label to be with pending | 
 |    alignment.  For example, | 
 |      LBYTE: .byte	0x12 | 
 |      LHALF: .half	0x12 | 
 |      LWORD: .word	0x12 | 
 |    Without this, the above label will not attach to incoming data.  */ | 
 |  | 
 | static void | 
 | nds32_adjust_label (int n) | 
 | { | 
 |   /* FIXME: I think adjust label and alignment is | 
 |      the programmer's obligation.  Sadly, VLSI team doesn't | 
 |      properly use .align for their test cases. | 
 |      So I re-implement cons_align and auto adjust labels, again. | 
 |  | 
 |      I think d30v's implementation is simple and good enough.  */ | 
 |  | 
 |   symbolS *label = nds32_last_label; | 
 |   nds32_last_label = NULL; | 
 |  | 
 |   /* SEC_ALLOC is used to eliminate .debug_ sections. | 
 |      SEC_CODE is used to include section for ILM.  */ | 
 |   if (((now_seg->flags & SEC_ALLOC) == 0 && (now_seg->flags & SEC_CODE) == 0) | 
 |       || strcmp (now_seg->name, ".eh_frame") == 0 | 
 |       || strcmp (now_seg->name, ".gcc_except_table") == 0) | 
 |     return; | 
 |  | 
 |   /* Only frag by alignment when needed. | 
 |      Otherwise, it will fail to optimize labels on 4-byte boundary.  (bug8454) | 
 |      See md_convert_frag () and RELAX_SET_RELAXABLE (frag) for details.  */ | 
 |   if (frag_now_fix () & ((1 << n) -1 )) | 
 |     { | 
 |       if (subseg_text_p (now_seg)) | 
 | 	{ | 
 | 	  add_mapping_symbol_for_align (n, frag_now_fix (), 1); | 
 | 	  frag_align_code (n, 0); | 
 | 	} | 
 |       else | 
 | 	frag_align (n, 0, 0); | 
 |  | 
 |       /* Record the minimum alignment for this segment.  */ | 
 |       record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); | 
 |     } | 
 |  | 
 |   if (label != NULL) | 
 |     { | 
 |       symbolS *sym; | 
 |       int label_seen = false; | 
 |       struct frag *old_frag; | 
 |       valueT old_value, new_value; | 
 |  | 
 |       gas_assert (S_GET_SEGMENT (label) == now_seg); | 
 |  | 
 |       old_frag  = symbol_get_frag (label); | 
 |       old_value = S_GET_VALUE (label); | 
 |       new_value = (valueT) frag_now_fix (); | 
 |  | 
 |       /* Multiple labels may be on the same address.  And the last symbol | 
 | 	 may not be a label at all, e.g., register name, external function names, | 
 | 	 so I have to track the last label in tc_frob_label instead of | 
 | 	 just using symbol_lastP.  */ | 
 |       for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym)) | 
 | 	{ | 
 | 	  if (symbol_get_frag (sym) == old_frag | 
 | 	      && S_GET_VALUE (sym) == old_value) | 
 | 	    { | 
 | 	      /* Warning HERE! */ | 
 | 	      label_seen = true; | 
 | 	      symbol_set_frag (sym, frag_now); | 
 | 	      S_SET_VALUE (sym, new_value); | 
 | 	    } | 
 | 	  else if (label_seen && symbol_get_frag (sym) != old_frag) | 
 | 	    break; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | nds32_cons_align (int size ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Do nothing here. | 
 |      This is called before `md_flush_pending_output' is called by `cons'. | 
 |  | 
 |      There are two things should be done for auto-adjust-label. | 
 |      1. Align data/instructions and adjust label to be attached to them. | 
 |      2. Clear auto-adjust state, so incoming data/instructions will not | 
 | 	adjust the label. | 
 |  | 
 |      For example, | 
 | 	  .byte 0x1 | 
 | 	.L0: | 
 | 	  .word 0x2 | 
 | 	  .word 0x3 | 
 |      in this case, '.word 0x2' will adjust the label, .L0, but '.word 0x3' should not. | 
 |  | 
 |      I think `md_flush_pending_output' is a good place to clear the auto-adjust state, | 
 |      but it is also called by `cons' before this function. | 
 |      To simplify the code, instead of overriding .zero, .fill, .space, etc, | 
 |      I think we should just adjust label in `nds32_aligned_X_cons' instead of here.  */ | 
 | } | 
 |  | 
 | static void | 
 | make_mapping_symbol (enum mstate state, valueT value, fragS * frag, unsigned int align) | 
 | { | 
 |   symbolS *symbol_p = NULL; | 
 |   const char *symbol_name = NULL; | 
 |   switch (state) | 
 |     { | 
 |     case MAP_DATA: | 
 |       if (align == 0) | 
 | 	symbol_name = "$d0"; | 
 |       else if (align == 1) | 
 | 	symbol_name = "$d1"; | 
 |       else if (align == 2) | 
 | 	symbol_name = "$d2"; | 
 |       else if (align == 3) | 
 | 	symbol_name = "$d3"; | 
 |       else if (align == 4) | 
 | 	symbol_name = "$d4"; | 
 |       break; | 
 |     case MAP_CODE: | 
 |       symbol_name = "$c"; | 
 |       break; | 
 |     default: | 
 |       abort (); | 
 |     } | 
 |  | 
 |   symbol_p = symbol_new (symbol_name, now_seg, frag, value); | 
 |   /* local scope attribute  */ | 
 |   symbol_get_bfdsym (symbol_p)->flags |= BSF_NO_FLAGS | BSF_LOCAL; | 
 | } | 
 |  | 
 | static void | 
 | add_mapping_symbol (enum mstate state, unsigned int padding_byte, | 
 | 		    unsigned int align) | 
 | { | 
 |   enum mstate current_mapping_state = | 
 |     seg_info (now_seg)->tc_segment_info_data.mapstate; | 
 |  | 
 |   if (state == MAP_CODE | 
 |       && current_mapping_state == state) | 
 |     return; | 
 |  | 
 |   if (!SEG_NORMAL (now_seg) | 
 |       || !subseg_text_p (now_seg)) | 
 |     return; | 
 |  | 
 |   /* start adding mapping symbol  */ | 
 |   seg_info (now_seg)->tc_segment_info_data.mapstate = state; | 
 |   make_mapping_symbol (state, (valueT) frag_now_fix () + padding_byte, | 
 | 		       frag_now, align); | 
 | } | 
 |  | 
 | static void | 
 | nds32_aligned_cons (int idx) | 
 | { | 
 |   nds32_adjust_label (idx); | 
 |   add_mapping_symbol (MAP_DATA, 0, idx); | 
 |   /* Call default handler.  */ | 
 |   cons (1 << idx); | 
 |   if (now_seg->flags & SEC_CODE | 
 |       && now_seg->flags & SEC_ALLOC && now_seg->flags & SEC_RELOC) | 
 |     { | 
 |       /* Use BFD_RELOC_NDS32_DATA to avoid linker | 
 | 	 optimization replacing data.  */ | 
 |       expressionS exp; | 
 |  | 
 |       exp.X_add_number = 0; | 
 |       exp.X_op = O_constant; | 
 |       fix_new_exp (frag_now, frag_now_fix () - (1 << idx), 1 << idx, | 
 | 		   &exp, 0, BFD_RELOC_NDS32_DATA); | 
 |     } | 
 | } | 
 |  | 
 | /* `.double' directive.  */ | 
 |  | 
 | static void | 
 | nds32_aligned_float_cons (int type) | 
 | { | 
 |   switch (type) | 
 |     { | 
 |     case 'f': | 
 |     case 'F': | 
 |     case 's': | 
 |     case 'S': | 
 |       nds32_adjust_label (2); | 
 |       break; | 
 |     case 'd': | 
 |     case 'D': | 
 |     case 'r': | 
 |     case 'R': | 
 |       nds32_adjust_label (4); | 
 |       break; | 
 |     default: | 
 |       as_bad ("Unrecognized float type, %c\n", (char)type); | 
 |     } | 
 |   /* Call default handler.  */ | 
 |   float_cons (type); | 
 | } | 
 |  | 
 | static void | 
 | nds32_enable_pic (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Another way to do -mpic. | 
 |      This is for GCC internal use and should always be first line | 
 |      of code, otherwise, the effect is not determined.  */ | 
 |   nds32_pic = 1; | 
 | } | 
 |  | 
 | static void | 
 | nds32_set_abi (int ver) | 
 | { | 
 |   nds32_abi = ver; | 
 | } | 
 |  | 
 | /* Relax directive to set relocation R_NDS32_RELAX_ENTRY value.  */ | 
 |  | 
 | static void | 
 | nds32_relax_relocs (int relax) | 
 | { | 
 |   char saved_char; | 
 |   char *name; | 
 |   int i; | 
 |   const char *subtype_relax[] = | 
 |     {"", "",}; | 
 |  | 
 |   name = input_line_pointer; | 
 |   while (*input_line_pointer && !ISSPACE (*input_line_pointer)) | 
 |     input_line_pointer++; | 
 |   saved_char = *input_line_pointer; | 
 |   *input_line_pointer = 0; | 
 |  | 
 |   for (i = 0; i < (int) ARRAY_SIZE (subtype_relax); i++) | 
 |     { | 
 |       if (strcmp (name, subtype_relax[i]) == 0) | 
 | 	{ | 
 | 	  switch (i) | 
 | 	    { | 
 | 	    case 0: | 
 | 	    case 1: | 
 | 	      enable_relax_relocs = relax & enable_relax_relocs; | 
 | 	      break; | 
 | 	    default: | 
 | 	      break; | 
 | 	    } | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |   *input_line_pointer = saved_char; | 
 |   ignore_rest_of_line (); | 
 | } | 
 |  | 
 | /* Record which arguments register($r0 ~ $r5) is not used in callee. | 
 |    bit[i] for $ri  */ | 
 |  | 
 | static void | 
 | nds32_set_hint_func_args (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   ignore_rest_of_line (); | 
 | } | 
 |  | 
 | /* Insert relocations to mark the begin and end of a fp-omitted function, | 
 |    for further relaxation use. | 
 |    bit[i] for $ri  */ | 
 |  | 
 | static void | 
 | nds32_omit_fp_begin (int mode) | 
 | { | 
 |   expressionS exp; | 
 |  | 
 |   if (nds32_relax_fp_as_gp == 0) | 
 |     return; | 
 |   exp.X_op = O_symbol; | 
 |   exp.X_add_symbol = abs_section_sym; | 
 |   if (mode == 1) | 
 |     { | 
 |       in_omit_fp = 1; | 
 |       exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; | 
 |       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, | 
 | 		   BFD_RELOC_NDS32_RELAX_REGION_BEGIN); | 
 |     } | 
 |   else | 
 |     { | 
 |       in_omit_fp = 0; | 
 |       exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; | 
 |       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, | 
 | 		   BFD_RELOC_NDS32_RELAX_REGION_END); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | nds32_loop_begin (int mode) | 
 | { | 
 |   /* Insert loop region relocation here.  */ | 
 |   expressionS exp; | 
 |  | 
 |   exp.X_op = O_symbol; | 
 |   exp.X_add_symbol = abs_section_sym; | 
 |   if (mode == 1) | 
 |     { | 
 |       exp.X_add_number = R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG; | 
 |       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, | 
 | 		   BFD_RELOC_NDS32_RELAX_REGION_BEGIN); | 
 |     } | 
 |   else | 
 |     { | 
 |       exp.X_add_number = R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG; | 
 |       fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, | 
 | 		   BFD_RELOC_NDS32_RELAX_REGION_END); | 
 |     } | 
 | } | 
 |  | 
 | struct nds32_relocs_group | 
 | { | 
 |   struct nds32_relocs_pattern *pattern; | 
 |   struct nds32_relocs_group *next; | 
 | }; | 
 |  | 
 | static struct nds32_relocs_group *nds32_relax_hint_current = NULL; | 
 | /* Used to reorder the id for ".relax_hint id".  */ | 
 | static int relax_hint_bias = 0; | 
 | /* Record current relax hint id.  */ | 
 | static int relax_hint_id_current = -1; | 
 | int reset_bias = 0; | 
 | /* If ".relax_hint begin" is triggered?  */ | 
 | int relax_hint_begin = 0; | 
 |  | 
 | /* Record the reordered relax hint id.  */ | 
 |  | 
 | struct relax_hint_id | 
 | { | 
 |   int old_id; | 
 |   int new_id; | 
 |   struct relax_hint_id *next; | 
 | }; | 
 |  | 
 | /* FIXME: Need to find somewhere to free the list.  */ | 
 | struct relax_hint_id *record_id_head = NULL; | 
 |  | 
 | /* Is the buffer large enough?  */ | 
 | #define MAX_BUFFER 12 | 
 |  | 
 | static char *nds_itoa (int n); | 
 |  | 
 | static char * | 
 | nds_itoa (int n) | 
 | { | 
 |   char *buf = xmalloc (MAX_BUFFER * sizeof (char)); | 
 |   snprintf (buf, MAX_BUFFER, "%d", n); | 
 |   return buf; | 
 | } | 
 |  | 
 | /* Insert a relax hint.  */ | 
 |  | 
 | static void | 
 | nds32_relax_hint (int mode ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *name = NULL; | 
 |   char saved_char; | 
 |   struct nds32_relocs_pattern *relocs = NULL; | 
 |   struct nds32_relocs_group *group, *new; | 
 |   struct relax_hint_id *record_id; | 
 |  | 
 |   name = input_line_pointer; | 
 |   while (*input_line_pointer && !ISSPACE (*input_line_pointer)) | 
 |     input_line_pointer++; | 
 |   saved_char = *input_line_pointer; | 
 |   *input_line_pointer = 0; | 
 |   name = strdup (name); | 
 |  | 
 |   if (name && strcmp (name, "begin") == 0) | 
 |     { | 
 |       if (relax_hint_id_current == -1) | 
 | 	reset_bias = 1; | 
 |       relax_hint_bias++; | 
 |       relax_hint_id_current++; | 
 |       relax_hint_begin = 1; | 
 |     } | 
 |  | 
 |   /* Original case ".relax_hint id".  It's id may need to be reordered. */ | 
 |   if (!relax_hint_begin) | 
 |     { | 
 |       int tmp = strtol (name, NULL, 10); | 
 |       record_id = record_id_head; | 
 |       while (record_id) | 
 | 	{ | 
 | 	  if (record_id->old_id == tmp) | 
 | 	    { | 
 | 	      name = nds_itoa (record_id->new_id); | 
 | 	      goto reordered_id; | 
 | 	    } | 
 | 	  record_id = record_id->next; | 
 | 	} | 
 |       if (reset_bias) | 
 | 	{ | 
 | 	  relax_hint_bias = relax_hint_id_current - atoi (name) + 1; | 
 | 	  reset_bias = 0; | 
 | 	} | 
 |       relax_hint_id_current = tmp + relax_hint_bias; | 
 |  | 
 |       /* Insert the element to the head of the link list.  */ | 
 |       struct relax_hint_id *tmp_id = malloc (sizeof (struct relax_hint_id)); | 
 |       tmp_id->old_id = tmp; | 
 |       tmp_id->new_id = relax_hint_id_current; | 
 |       tmp_id->next = record_id_head; | 
 |       record_id_head = tmp_id; | 
 |     } | 
 |  | 
 |   if (name && strcmp (name, "end") == 0) | 
 |     relax_hint_begin = 0; | 
 |   name = nds_itoa (relax_hint_id_current); | 
 |  | 
 |  reordered_id: | 
 |  | 
 |   /* Find relax hint entry for next instruction, and all member will be | 
 |      initialized at that time.  */ | 
 |   relocs = str_hash_find (nds32_hint_hash, name); | 
 |   if (relocs == NULL) | 
 |     { | 
 |       relocs = notes_calloc (1, sizeof (*relocs)); | 
 |       str_hash_insert (nds32_hint_hash, name, relocs, 0); | 
 |     } | 
 |   else | 
 |     { | 
 |       while (relocs->next) | 
 | 	relocs = relocs->next; | 
 |       relocs->next = notes_calloc (1, sizeof (*relocs)); | 
 |       relocs = relocs->next; | 
 |     } | 
 |  | 
 |   *input_line_pointer = saved_char; | 
 |   ignore_rest_of_line (); | 
 |  | 
 |   /* Get the final one of relax hint series.  */ | 
 |  | 
 |   /* It has to build this list because there are maybe more than one | 
 |      instructions relative to the same instruction.  It to connect to | 
 |      next instruction after md_assemble.  */ | 
 |   new = XNEW (struct nds32_relocs_group); | 
 |   memset (new, 0, sizeof (struct nds32_relocs_group)); | 
 |   new->pattern = relocs; | 
 |   new->next = NULL; | 
 |   group = nds32_relax_hint_current; | 
 |   if (!group) | 
 |     nds32_relax_hint_current = new; | 
 |   else | 
 |     { | 
 |       while (group->next != NULL) | 
 | 	group = group->next; | 
 |       group->next = new; | 
 |     } | 
 |   relaxing = true; | 
 | } | 
 |  | 
 | /* Decide the size of vector entries, only accepts 4 or 16 now.  */ | 
 |  | 
 | static void | 
 | nds32_vec_size (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   expressionS exp; | 
 |  | 
 |   expression (&exp); | 
 |  | 
 |   if (exp.X_op == O_constant) | 
 |     { | 
 |       if (exp.X_add_number == 4 || exp.X_add_number == 16) | 
 | 	{ | 
 | 	  if (vec_size == 0) | 
 | 	    vec_size = exp.X_add_number; | 
 | 	  else if (vec_size != exp.X_add_number) | 
 | 	    as_warn (_("Different arguments of .vec_size are found, " | 
 | 		       "previous %d, current %d"), | 
 | 		     (int) vec_size, (int) exp.X_add_number); | 
 | 	} | 
 |       else | 
 | 	as_warn (_("Argument of .vec_size is expected 4 or 16, actual: %d."), | 
 | 		 (int) exp.X_add_number); | 
 |     } | 
 |   else | 
 |     as_warn (_("Argument of .vec_size is not a constant.")); | 
 | } | 
 |  | 
 | /* The behavior of ".flag" directive varies depending on the target. | 
 |    In nds32 target, we use it to recognize whether this assembly content is | 
 |    generated by compiler.  Other features can also be added in this function | 
 |    in the future.  */ | 
 |  | 
 | static void | 
 | nds32_flag (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *name; | 
 |   char saved_char; | 
 |   int i; | 
 |   const char *possible_flags[] = { "verbatim" }; | 
 |  | 
 |   /* Skip whitespaces.  */ | 
 |   name = input_line_pointer; | 
 |   while (*input_line_pointer && !ISSPACE (*input_line_pointer)) | 
 |     input_line_pointer++; | 
 |   saved_char = *input_line_pointer; | 
 |   *input_line_pointer = 0; | 
 |  | 
 |   for (i = 0; i < (int) ARRAY_SIZE (possible_flags); i++) | 
 |     { | 
 |       if (strcmp (name, possible_flags[i]) == 0) | 
 | 	{ | 
 | 	  switch (i) | 
 | 	    { | 
 | 	    case 0: | 
 | 	      /* flag: verbatim */ | 
 | 	      verbatim = 1; | 
 | 	      break; | 
 | 	    default: | 
 | 	      break; | 
 | 	    } | 
 | 	  /* Already found the flag, no need to continue next loop.   */ | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   *input_line_pointer = saved_char; | 
 |   ignore_rest_of_line (); | 
 | } | 
 |  | 
 | static void | 
 | ict_model (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *name; | 
 |   char saved_char; | 
 |   int i; | 
 |   const char *possible_flags[] = { "small", "large" }; | 
 |  | 
 |   /* Skip whitespaces.  */ | 
 |   name = input_line_pointer; | 
 |   while (*input_line_pointer && !ISSPACE (*input_line_pointer)) | 
 |     input_line_pointer++; | 
 |   saved_char = *input_line_pointer; | 
 |   *input_line_pointer = 0; | 
 |  | 
 |   for (i = 0; i < (int) ARRAY_SIZE (possible_flags); i++) | 
 |     { | 
 |       if (strcmp (name, possible_flags[i]) == 0) | 
 | 	{ | 
 | 	  switch (i) | 
 | 	    { | 
 | 	    case 0: | 
 | 	      /* flag: verbatim  */ | 
 | 	      ict_flag = ICT_SMALL; | 
 | 	      break; | 
 | 	    case 1: | 
 | 	      ict_flag = ICT_LARGE; | 
 | 	      break; | 
 | 	    default: | 
 | 	      break; | 
 | 	    } | 
 | 	  /* Already found the flag, no need to continue next loop.   */ | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   *input_line_pointer = saved_char; | 
 |   ignore_rest_of_line (); | 
 | } | 
 |  | 
 | static void | 
 | nds32_n12hc (int ignore ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* N1213HC core is used.  */ | 
 | } | 
 |  | 
 |  | 
 | /* The target specific pseudo-ops which we support.  */ | 
 | const pseudo_typeS md_pseudo_table[] = | 
 | { | 
 |   /* Forced alignment if declared these ways.  */ | 
 |   {"ascii", stringer, 8 + 0}, | 
 |   {"asciz", stringer, 8 + 1}, | 
 |   {"double", nds32_aligned_float_cons, 'd'}, | 
 |   {"dword", nds32_aligned_cons, 3}, | 
 |   {"float", nds32_aligned_float_cons, 'f'}, | 
 |   {"half", nds32_aligned_cons, 1}, | 
 |   {"hword", nds32_aligned_cons, 1}, | 
 |   {"int", nds32_aligned_cons, 2}, | 
 |   {"long", nds32_aligned_cons, 2}, | 
 |   {"octa", nds32_aligned_cons, 4}, | 
 |   {"quad", nds32_aligned_cons, 3}, | 
 |   {"qword", nds32_aligned_cons, 4}, | 
 |   {"short", nds32_aligned_cons, 1}, | 
 |   {"byte", nds32_aligned_cons, 0}, | 
 |   {"single", nds32_aligned_float_cons, 'f'}, | 
 |   {"string", stringer, 8 + 1}, | 
 |   {"word", nds32_aligned_cons, 2}, | 
 |  | 
 |   {"little", set_endian_little, 1}, | 
 |   {"big", set_endian_little, 0}, | 
 |   {"16bit_on", trigger_16bit, 1}, | 
 |   {"16bit_off", trigger_16bit, 0}, | 
 |   {"restore_16bit", restore_16bit, 0}, | 
 |   {"off_16bit", off_16bit, 0}, | 
 |  | 
 |   {"sdata_d", nds32_seg, SDATA_D_SECTION}, | 
 |   {"sdata_w", nds32_seg, SDATA_W_SECTION}, | 
 |   {"sdata_h", nds32_seg, SDATA_H_SECTION}, | 
 |   {"sdata_b", nds32_seg, SDATA_B_SECTION}, | 
 |   {"sdata_f", nds32_seg, SDATA_F_SECTION}, | 
 |  | 
 |   {"sbss_d", nds32_seg, SBSS_D_SECTION}, | 
 |   {"sbss_w", nds32_seg, SBSS_W_SECTION}, | 
 |   {"sbss_h", nds32_seg, SBSS_H_SECTION}, | 
 |   {"sbss_b", nds32_seg, SBSS_B_SECTION}, | 
 |   {"sbss_f", nds32_seg, SBSS_F_SECTION}, | 
 |  | 
 |   {"pic", nds32_enable_pic, 0}, | 
 |   {"n12_hc", nds32_n12hc, 0}, | 
 |   {"abi_1", nds32_set_abi, E_NDS_ABI_V1}, | 
 |   {"abi_2", nds32_set_abi, E_NDS_ABI_AABI}, | 
 |   /* Obsolete.  */ | 
 |   {"abi_2fp", nds32_set_abi, E_NDS_ABI_V2FP}, | 
 |   {"abi_2fp_plus", nds32_set_abi, E_NDS_ABI_V2FP_PLUS}, | 
 |   {"relax", nds32_relax_relocs, 1}, | 
 |   {"no_relax", nds32_relax_relocs, 0}, | 
 |   {"hint_func_args", nds32_set_hint_func_args, 0}, /* Abandon??  */ | 
 |   {"omit_fp_begin", nds32_omit_fp_begin, 1}, | 
 |   {"omit_fp_end", nds32_omit_fp_begin, 0}, | 
 |   {"vec_size", nds32_vec_size, 0}, | 
 |   {"flag", nds32_flag, 0}, | 
 |   {"innermost_loop_begin", nds32_loop_begin, 1}, | 
 |   {"innermost_loop_end", nds32_loop_begin, 0}, | 
 |   {"relax_hint", nds32_relax_hint, 0}, | 
 |   {"ict_model", ict_model, 0}, | 
 |   {NULL, NULL, 0} | 
 | }; | 
 |  | 
 | void | 
 | nds32_pre_do_align (int n, char *fill, int len, int max) | 
 | { | 
 |   /* Only make a frag if we HAVE to...  */ | 
 |   fragS *fragP; | 
 |   if (n != 0 && !need_pass_2) | 
 |     { | 
 |       if (fill == NULL) | 
 | 	{ | 
 | 	  if (subseg_text_p (now_seg)) | 
 | 	    { | 
 | 	      dwarf2_emit_insn (0); | 
 | 	      fragP = frag_now; | 
 | 	      add_mapping_symbol_for_align (n, frag_now_fix (), 0); | 
 | 	      frag_align_code (n, max); | 
 |  | 
 | 	      /* Tag this alignment when there is a label before it.  */ | 
 | 	      if (label_exist) | 
 | 		{ | 
 | 		  fragP->tc_frag_data.flag = NDS32_FRAG_LABEL; | 
 | 		  label_exist = 0; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    frag_align (n, 0, max); | 
 | 	} | 
 |       else if (len <= 1) | 
 | 	frag_align (n, *fill, max); | 
 |       else | 
 | 	frag_align_pattern (n, fill, len, max); | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | nds32_do_align (int n) | 
 | { | 
 |   /* Optimize for space and label exists.  */ | 
 |   expressionS exp; | 
 |  | 
 |   /* FIXME:I think this will break debug info sections and except_table.  */ | 
 |   if (!enable_relax_relocs || !subseg_text_p (now_seg)) | 
 |     return; | 
 |  | 
 |   /* Create and attach a BFD_RELOC_NDS32_LABEL fixup | 
 |      the size of instruction may not be correct because | 
 |      it could be relaxable.  */ | 
 |   exp.X_op = O_symbol; | 
 |   exp.X_add_symbol = section_symbol (now_seg); | 
 |   exp.X_add_number = n; | 
 |   fix_new_exp (frag_now, | 
 | 	       frag_now_fix (), 0, &exp, 0, BFD_RELOC_NDS32_LABEL); | 
 | } | 
 |  | 
 | /* Supported Andes machines.  */ | 
 | struct nds32_machs | 
 | { | 
 |   enum bfd_architecture bfd_mach; | 
 |   int mach_flags; | 
 | }; | 
 |  | 
 | /* This is the callback for nds32-asm.c to parse operands.  */ | 
 |  | 
 | int | 
 | nds32_asm_parse_operand (struct nds32_asm_desc *pdesc ATTRIBUTE_UNUSED, | 
 | 			 struct nds32_asm_insn *pinsn, | 
 | 			 char **pstr, int64_t *value) | 
 | { | 
 |   char *hold; | 
 |   expressionS *pexp = pinsn->info; | 
 |  | 
 |   hold = input_line_pointer; | 
 |   input_line_pointer = *pstr; | 
 |   expression (pexp); | 
 |   *pstr = input_line_pointer; | 
 |   input_line_pointer = hold; | 
 |  | 
 |   switch (pexp->X_op) | 
 |     { | 
 |     case O_symbol: | 
 |       *value = 0; | 
 |       return NASM_R_SYMBOL; | 
 |     case O_constant: | 
 |       *value = pexp->X_add_number; | 
 |       return NASM_R_CONST; | 
 |     case O_illegal: | 
 |     case O_absent: | 
 |     case O_register: | 
 |     default: | 
 |       return NASM_R_ILLEGAL; | 
 |     } | 
 | } | 
 |  | 
 | /* GAS will call this function at the start of the assembly, after the command | 
 |    line arguments have been parsed and all the machine independent | 
 |    initializations have been completed.  */ | 
 |  | 
 | void | 
 | md_begin (void) | 
 | { | 
 |   const struct nds32_keyword *k; | 
 |   relax_info_t *relax_info; | 
 |   int flags = 0; | 
 |  | 
 |   bfd_set_arch_mach (stdoutput, TARGET_ARCH, nds32_baseline); | 
 |  | 
 |   nds32_init_nds32_pseudo_opcodes (); | 
 |   asm_desc.parse_operand = nds32_asm_parse_operand; | 
 |   if (nds32_gpr16) | 
 |     flags |= NASM_OPEN_REDUCED_REG; | 
 |   nds32_asm_init (&asm_desc, flags); | 
 |  | 
 |   /* Initial general purpose registers hash table.  */ | 
 |   nds32_gprs_hash = str_htab_create (); | 
 |   for (k = nds32_keyword_gpr; k->name; k++) | 
 |     str_hash_insert (nds32_gprs_hash, k->name, k, 0); | 
 |  | 
 |   /* Initial branch hash table.  */ | 
 |   nds32_relax_info_hash = str_htab_create (); | 
 |   for (relax_info = relax_table; relax_info->opcode; relax_info++) | 
 |     str_hash_insert (nds32_relax_info_hash, relax_info->opcode, relax_info, 0); | 
 |  | 
 |   /* Initial relax hint hash table.  */ | 
 |   nds32_hint_hash = str_htab_create (); | 
 |   enable_16bit = nds32_16bit_ext; | 
 | } | 
 |  | 
 | /* HANDLE_ALIGN in write.c.  */ | 
 |  | 
 | void | 
 | nds32_handle_align (fragS *fragp) | 
 | { | 
 |   static const unsigned char nop16[] = { 0x92, 0x00 }; | 
 |   static const unsigned char nop32[] = { 0x40, 0x00, 0x00, 0x09 }; | 
 |   int bytes; | 
 |   char *p; | 
 |  | 
 |   if (fragp->fr_type != rs_align_code) | 
 |     return; | 
 |  | 
 |   bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; | 
 |   p = fragp->fr_literal + fragp->fr_fix; | 
 |  | 
 |   if (bytes & 1) | 
 |     { | 
 |       *p++ = 0; | 
 |       bytes--; | 
 |     } | 
 |  | 
 |   if (bytes & 2) | 
 |     { | 
 |       expressionS exp_t; | 
 |       exp_t.X_op = O_symbol; | 
 |       exp_t.X_add_symbol = abs_section_sym; | 
 |       exp_t.X_add_number = R_NDS32_INSN16_CONVERT_FLAG; | 
 |       fix_new_exp (fragp, fragp->fr_fix, 2, &exp_t, 0, | 
 | 		   BFD_RELOC_NDS32_INSN16); | 
 |       memcpy (p, nop16, 2); | 
 |       p += 2; | 
 |       bytes -= 2; | 
 |     } | 
 |  | 
 |   while (bytes >= 4) | 
 |     { | 
 |       memcpy (p, nop32, 4); | 
 |       p += 4; | 
 |       bytes -= 4; | 
 |     } | 
 |  | 
 |   bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; | 
 |   fragp->fr_fix += bytes; | 
 | } | 
 |  | 
 | /* md_flush_pending_output  */ | 
 |  | 
 | void | 
 | nds32_flush_pending_output (void) | 
 | { | 
 |   nds32_last_label = NULL; | 
 | } | 
 |  | 
 | void | 
 | nds32_frob_label (symbolS *label) | 
 | { | 
 |   dwarf2_emit_label (label); | 
 | } | 
 |  | 
 | /* TC_START_LABEL  */ | 
 |  | 
 | int | 
 | nds32_start_label (int asmdone ATTRIBUTE_UNUSED, int secdone ATTRIBUTE_UNUSED) | 
 | { | 
 |   if (optimize && subseg_text_p (now_seg)) | 
 |     label_exist = 1; | 
 |   return 1; | 
 | } | 
 |  | 
 | /* TARGET_FORMAT  */ | 
 |  | 
 | const char * | 
 | nds32_target_format (void) | 
 | { | 
 | #ifdef TE_LINUX | 
 |   if (target_big_endian) | 
 |     return "elf32-nds32be-linux"; | 
 |   else | 
 |     return "elf32-nds32le-linux"; | 
 | #else | 
 |   if (target_big_endian) | 
 |     return "elf32-nds32be"; | 
 |   else | 
 |     return "elf32-nds32le"; | 
 | #endif | 
 | } | 
 |  | 
 | static enum nds32_br_range | 
 | get_range_type (const struct nds32_field *field) | 
 | { | 
 |   gas_assert (field != NULL); | 
 |  | 
 |   if (field->bitpos != 0) | 
 |     return BR_RANGE_U4G; | 
 |  | 
 |   if (field->bitsize == 24 && field->shift == 1) | 
 |     return BR_RANGE_S16M; | 
 |   else if (field->bitsize == 16 && field->shift == 1) | 
 |     return BR_RANGE_S64K; | 
 |   else if (field->bitsize == 14 && field->shift == 1) | 
 |     return BR_RANGE_S16K; | 
 |   else if (field->bitsize == 8 && field->shift == 1) | 
 |     return BR_RANGE_S256; | 
 |   else | 
 |     return BR_RANGE_U4G; | 
 | } | 
 |  | 
 | /* Save pseudo instruction relocation list.  */ | 
 |  | 
 | static struct nds32_relocs_pattern* | 
 | nds32_elf_save_pseudo_pattern (fixS* fixP, struct nds32_asm_insn *insn, | 
 | 			       char *out, symbolS *sym, | 
 | 			       struct nds32_relocs_pattern *reloc_ptr, | 
 | 			       fragS *fragP) | 
 | { | 
 |   struct nds32_opcode *opcode = insn->opcode; | 
 |   if (!reloc_ptr) | 
 |     reloc_ptr = XNEW (struct nds32_relocs_pattern); | 
 |   reloc_ptr->seg = now_seg; | 
 |   reloc_ptr->sym = sym; | 
 |   reloc_ptr->frag = fragP; | 
 |   reloc_ptr->frchain = frchain_now; | 
 |   reloc_ptr->fixP = fixP; | 
 |   reloc_ptr->opcode = opcode; | 
 |   reloc_ptr->where = out; | 
 |   reloc_ptr->insn = insn->insn; | 
 |   reloc_ptr->next = NULL; | 
 |   return reloc_ptr; | 
 | } | 
 |  | 
 | /* Check X_md to transform relocation.  */ | 
 |  | 
 | static fixS* | 
 | nds32_elf_record_fixup_exp (fragS *fragP, const char *str, | 
 | 			    const struct nds32_field *fld, | 
 | 			    expressionS *pexp, char* out, | 
 | 			    struct nds32_asm_insn *insn) | 
 | { | 
 |   int reloc = -1; | 
 |   expressionS exp; | 
 |   fixS *fixP = NULL; | 
 |  | 
 |   /* Handle instruction relocation.  */ | 
 |   if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_HI20)) | 
 |     { | 
 |       /* Relocation for hi20 modifier.  */ | 
 |       switch (pexp->X_md) | 
 | 	{ | 
 | 	case BFD_RELOC_NDS32_GOTOFF:	/* @GOTOFF */ | 
 | 	  reloc = BFD_RELOC_NDS32_GOTOFF_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_GOT20:	/* @GOT */ | 
 | 	  reloc = BFD_RELOC_NDS32_GOT_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_25_PLTREL:	/* @PLT */ | 
 | 	  if (!nds32_pic) | 
 | 	    as_bad (_("Invalid PIC expression.")); | 
 | 	  else | 
 | 	    reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_GOTPC20:	/* _GLOBAL_OFFSET_TABLE_ */ | 
 | 	  reloc = BFD_RELOC_NDS32_GOTPC_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_TPOFF:	/* @TPOFF */ | 
 | 	  reloc = BFD_RELOC_NDS32_TLS_LE_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_GOTTPOFF:	/* @GOTTPOFF */ | 
 | 	  reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_HI20 : BFD_RELOC_NDS32_TLS_IE_HI20; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_TLS_DESC:	/* @TLSDESC */ | 
 | 	  reloc = BFD_RELOC_NDS32_TLS_DESC_HI20; | 
 | 	  break; | 
 | 	default:	/* No suffix */ | 
 | 	  if (nds32_pic) | 
 | 	    /* When the file is pic, the address must be offset to gp. | 
 | 	       It may define another relocation or use GOTOFF.  */ | 
 | 	    reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20; | 
 | 	  else | 
 | 	    reloc = BFD_RELOC_NDS32_HI20; | 
 | 	  break; | 
 | 	} | 
 |       fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, | 
 | 			  insn->info, 0 /* pcrel */, reloc); | 
 |     } | 
 |   else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_LO12)) | 
 |     { | 
 |       /* Relocation for lo12 modifier.  */ | 
 |       if (fld->bitsize == 15 && fld->shift == 0) | 
 | 	{ | 
 | 	  /* [ls]bi || ori */ | 
 | 	  switch (pexp->X_md) | 
 | 	    { | 
 | 	    case BFD_RELOC_NDS32_GOTOFF:	/* @GOTOFF */ | 
 | 	      reloc = BFD_RELOC_NDS32_GOTOFF_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_GOT20:		/* @GOT */ | 
 | 	      reloc = BFD_RELOC_NDS32_GOT_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_25_PLTREL:	/* @PLT */ | 
 | 	      if (!nds32_pic) | 
 | 		as_bad (_("Invalid PIC expression.")); | 
 | 	      else | 
 | 		reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_GOTPC20:	/* _GLOBAL_OFFSET_TABLE_ */ | 
 | 	      reloc = BFD_RELOC_NDS32_GOTPC_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_TPOFF:		/* @TPOFF */ | 
 | 	      reloc = BFD_RELOC_NDS32_TLS_LE_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_GOTTPOFF:	/* @GOTTPOFF */ | 
 | 	      reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_LO12 : BFD_RELOC_NDS32_TLS_IE_LO12; | 
 | 	      break; | 
 | 	    case BFD_RELOC_NDS32_TLS_DESC:	/* @TLSDESC */ | 
 | 	      reloc = BFD_RELOC_NDS32_TLS_DESC_LO12; | 
 | 	      break; | 
 | 	    default:	/* No suffix */ | 
 | 	      if (nds32_pic) | 
 | 		/* When the file is pic, the address must be offset to gp. | 
 | 		   It may define another relocation or use GOTOFF.  */ | 
 | 		reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12; | 
 | 	      else | 
 | 		reloc = BFD_RELOC_NDS32_LO12S0; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |       else if (fld->bitsize == 15 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_LO12S1;		/* [ls]hi */ | 
 |       else if (fld->bitsize == 15 && fld->shift == 2) | 
 | 	{ | 
 | 	  /* [ls]wi */ | 
 | 	  switch (pexp->X_md) | 
 | 	    { | 
 | 	    case BFD_RELOC_NDS32_GOTTPOFF:	/* @GOTTPOFF */ | 
 | 	      reloc = nds32_pic ? BFD_RELOC_NDS32_TLS_IEGP_LO12S2 : BFD_RELOC_NDS32_TLS_IE_LO12S2; | 
 | 	      break; | 
 | 	    default:	/* No suffix */ | 
 | 	      reloc = BFD_RELOC_NDS32_LO12S2; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |       else if (fld->bitsize == 15 && fld->shift == 3) | 
 | 	reloc = BFD_RELOC_NDS32_LO12S3;		/* [ls]di */ | 
 |       else if (fld->bitsize == 12 && fld->shift == 2) | 
 | 	reloc = BFD_RELOC_NDS32_LO12S2_SP;	/* f[ls][sd]i */ | 
 |  | 
 |       fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, | 
 | 			  insn->info, 0 /* pcrel */, reloc); | 
 |     } | 
 |   else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 | 
 | 	   && (insn->attr & NASM_ATTR_PCREL)) | 
 |     { | 
 |       /* Relocation for 32-bit branch instructions.  */ | 
 |       if (fld->bitsize == 24 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_25_PCREL; | 
 |       else if (fld->bitsize == 16 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_17_PCREL; | 
 |       else if (fld->bitsize == 14 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_15_PCREL; | 
 |       else if (fld->bitsize == 8 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_WORD_9_PCREL; | 
 |       else | 
 | 	abort (); | 
 |  | 
 |       fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, | 
 | 		   insn->info, 1 /* pcrel */, reloc); | 
 |     } | 
 |   else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 | 
 | 	   && (insn->attr & NASM_ATTR_GPREL)) | 
 |     { | 
 |       /* Relocation for 32-bit gp-relative instructions.  */ | 
 |       if (fld->bitsize == 19 && fld->shift == 0) | 
 | 	reloc = BFD_RELOC_NDS32_SDA19S0; | 
 |       else if (fld->bitsize == 18 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_SDA18S1; | 
 |       else if (fld->bitsize == 17 && fld->shift == 2) | 
 | 	reloc = BFD_RELOC_NDS32_SDA17S2; | 
 |       else | 
 | 	abort (); | 
 |  | 
 |       fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, | 
 | 		   insn->info, 0 /* pcrel */, reloc); | 
 |       /* Insert INSN16 for converting fp_as_gp.  */ | 
 |       exp.X_op = O_symbol; | 
 |       exp.X_add_symbol = abs_section_sym; | 
 |       exp.X_add_number = 0; | 
 |       if (in_omit_fp && reloc == BFD_RELOC_NDS32_SDA17S2) | 
 | 	fix_new_exp (fragP, out - fragP->fr_literal, | 
 | 		     insn->opcode->isize, &exp, 0 /* pcrel */, | 
 | 		     BFD_RELOC_NDS32_INSN16); | 
 |     } | 
 |   else if (fld && fld->bitpos == 0 && insn->opcode->isize == 2 | 
 | 	   && (insn->attr & NASM_ATTR_PCREL)) | 
 |     { | 
 |       /* Relocation for 16-bit branch instructions.  */ | 
 |       if (fld->bitsize == 8 && fld->shift == 1) | 
 | 	reloc = BFD_RELOC_NDS32_9_PCREL; | 
 |       else | 
 | 	abort (); | 
 |  | 
 |       fixP = fix_new_exp (fragP, out - fragP->fr_literal, insn->opcode->isize, | 
 | 		   insn->info, 1 /* pcrel */, reloc); | 
 |     } | 
 |   else if (fld) | 
 |     as_bad (_("Don't know how to handle this field. %s"), str); | 
 |  | 
 |   return fixP; | 
 | } | 
 |  | 
 | /* Build instruction pattern to relax.  There are two type group pattern | 
 |    including pseudo instruction and relax hint.  */ | 
 |  | 
 | static void | 
 | nds32_elf_build_relax_relation (fixS *fixP, expressionS *pexp, char* out, | 
 | 				struct nds32_asm_insn *insn, fragS *fragP, | 
 | 				const struct nds32_field *fld, | 
 | 				bool pseudo_hint) | 
 | { | 
 |   struct nds32_relocs_pattern *reloc_ptr; | 
 |   struct nds32_relocs_group *group; | 
 |   symbolS *sym = NULL; | 
 |  | 
 |   /* The expression may be used uninitialized.  */ | 
 |   if (fld) | 
 |     sym = pexp->X_add_symbol; | 
 |  | 
 |   if (pseudo_hint) | 
 |     { | 
 |       /* We cannot know how many instructions will be expanded for | 
 | 	 the pseudo instruction here.  The first expanded instruction fills | 
 | 	 the memory created by relax_hint.  The follower will created and link | 
 | 	 here.  */ | 
 |       group = nds32_relax_hint_current; | 
 |       while (group) | 
 | 	{ | 
 | 	  if (group->pattern->opcode == NULL) | 
 | 	    nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, | 
 | 					   group->pattern, fragP); | 
 | 	  else | 
 | 	    { | 
 | 	      group->pattern->next = | 
 | 		nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, | 
 | 					       NULL, fragP); | 
 | 	      group->pattern = group->pattern->next; | 
 | 	    } | 
 | 	  group = group->next; | 
 | 	} | 
 |     } | 
 |   else if (pseudo_opcode) | 
 |     { | 
 |       /* Save instruction relation for pseudo instruction expanding pattern.  */ | 
 |       reloc_ptr = nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, | 
 | 						 NULL, fragP); | 
 |       if (!relocs_list) | 
 | 	relocs_list = reloc_ptr; | 
 |       else | 
 | 	{ | 
 | 	  struct nds32_relocs_pattern *temp = relocs_list; | 
 | 	  while (temp->next) | 
 | 	    temp = temp->next; | 
 | 	  temp->next = reloc_ptr; | 
 | 	} | 
 |     } | 
 |   else if (nds32_relax_hint_current) | 
 |     { | 
 |       /* Save instruction relation by relax hint.  */ | 
 |       group = nds32_relax_hint_current; | 
 |       while (group) | 
 | 	{ | 
 | 	  nds32_elf_save_pseudo_pattern (fixP, insn, out, sym, | 
 | 					 group->pattern, fragP); | 
 | 	  group = group->next; | 
 | 	  free (nds32_relax_hint_current); | 
 | 	  nds32_relax_hint_current = group; | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Set relaxing false only for relax_hint trigger it.  */ | 
 |   if (!pseudo_opcode) | 
 |     relaxing = false; | 
 | } | 
 |  | 
 | #define N32_MEM_EXT(insn) ((N32_OP6_MEM << 25) | insn) | 
 |  | 
 | /* Relax pattern for link time relaxation.  */ | 
 | /* Relaxation types only! relocation types are not necessary.  */ | 
 | /* Refer to nds32_elf_record_fixup_exp ().  */ | 
 |  | 
 | static struct nds32_relax_hint_table relax_ls_table[] = | 
 | { | 
 |   { | 
 |     /* LA and Floating LSI.  */ | 
 |     .main_type = NDS32_RELAX_HINT_LA_FLSI, | 
 |     .relax_code_size = 12, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (LBI), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, | 
 | 	{4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_LSI}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* Load Address / Load-Store (LALS).  */ | 
 |     .main_type = NDS32_RELAX_HINT_LALS, | 
 |     .relax_code_size = 12, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (LBI), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{8, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* B(AL) symbol@PLT  */ | 
 |     .main_type = NDS32_RELAX_HINT_LA_PLT, | 
 |     .relax_code_size = 16, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (ALU1), | 
 | 	OP6 (JREG), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, | 
 | 	{12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PLT_GOT_SUFF}, | 
 | 	{12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* LA (@GOT).  */ | 
 |     .main_type = NDS32_RELAX_HINT_LA_GOT, | 
 |     .relax_code_size = 12, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (MEM), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOT_SUFF}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* LA (@GOTOFF).  */ | 
 |     .main_type = NDS32_RELAX_HINT_LA_GOTOFF, | 
 |     .relax_code_size = 16, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (ALU1), | 
 | 	OP6 (MEM), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF}, | 
 | 	{12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_GOTOFF_SUFF}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* TLS LE LS|LA */ | 
 |     .main_type = NDS32_RELAX_HINT_TLS_LE_LS, | 
 |     .relax_code_size = 16, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6(SETHI), | 
 | 	OP6(ORI), | 
 | 	OP6(MEM), | 
 | 	OP6(ALU1), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR_MULTIPLE, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_LE_LS}, | 
 | 	{12, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{12, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_LE_ADD}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* TLS IE LA */ | 
 |     .main_type = NDS32_RELAX_HINT_TLS_IE_LA, | 
 |     .relax_code_size = 8, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6(SETHI), | 
 | 	OP6(LBI), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_INSN16, BFD_RELOC_NDS32_INSN16}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* TLS IEGP LA */ | 
 |     .main_type = NDS32_RELAX_HINT_TLS_IEGP_LA, | 
 |     .relax_code_size = 12, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (MEM), | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR_PATTERN, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_IEGP_LW}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     /* TLS DESC LS:  */ | 
 |     .main_type = NDS32_RELAX_HINT_TLS_DESC_LS, | 
 |     .relax_code_size = 24, | 
 |     .relax_code_seq = | 
 |       { | 
 | 	OP6 (SETHI), | 
 | 	OP6 (ORI), | 
 | 	OP6 (ALU1), | 
 | 	OP6 (LBI),	/* load argument */ | 
 | 	OP6 (JREG), | 
 | 	OP6 (MEM),	/* load/store variable or load argument */ | 
 |       }, | 
 |     .relax_fixup = | 
 |       { | 
 | 	{0, 4, NDS32_HINT | NDS32_ADDEND, BFD_RELOC_NDS32_LOADSTORE}, | 
 | 	{4, 4, NDS32_HINT | NDS32_PTR_PATTERN, BFD_RELOC_NDS32_PTR}, | 
 | 	{8, 4, NDS32_HINT | NDS32_ABS, BFD_RELOC_NDS32_PTR_RESOLVED}, | 
 | 	{8, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_ADD}, | 
 | 	{12, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_FUNC}, | 
 | 	{16, 4, NDS32_HINT | NDS32_SYM, BFD_RELOC_NDS32_TLS_DESC_CALL}, | 
 | 	{20, 4, NDS32_HINT | NDS32_SYM_DESC_MEM, BFD_RELOC_NDS32_TLS_DESC_MEM}, | 
 | 	{0, 0, 0, 0} | 
 |       } | 
 |   }, | 
 |   { | 
 |     .main_type = 0, | 
 |     .relax_code_seq = {0}, | 
 |     .relax_fixup = {{0, 0 , 0, 0}} | 
 |   } | 
 | }; | 
 |  | 
 | /* Since sethi loadstore relocation has to using next instruction to determine | 
 |    elimination itself or not, we have to return the next instruction range.  */ | 
 |  | 
 | static int | 
 | nds32_elf_sethi_range (struct nds32_relocs_pattern *pattern) | 
 | { | 
 |   int range = 0; | 
 |   while (pattern) | 
 |     { | 
 |       switch (pattern->opcode->value) | 
 | 	{ | 
 | 	case INSN_LBI: | 
 | 	case INSN_SBI: | 
 | 	case INSN_LBSI: | 
 | 	case N32_MEM_EXT (N32_MEM_LB): | 
 | 	case N32_MEM_EXT (N32_MEM_LBS): | 
 | 	case N32_MEM_EXT (N32_MEM_SB): | 
 | 	  range = NDS32_LOADSTORE_BYTE; | 
 | 	  break; | 
 | 	case INSN_LHI: | 
 | 	case INSN_SHI: | 
 | 	case INSN_LHSI: | 
 | 	case N32_MEM_EXT (N32_MEM_LH): | 
 | 	case N32_MEM_EXT (N32_MEM_LHS): | 
 | 	case N32_MEM_EXT (N32_MEM_SH): | 
 | 	  range = NDS32_LOADSTORE_HALF; | 
 | 	  break; | 
 | 	case INSN_LWI: | 
 | 	case INSN_SWI: | 
 | 	case N32_MEM_EXT (N32_MEM_LW): | 
 | 	case N32_MEM_EXT (N32_MEM_SW): | 
 | 	  range = NDS32_LOADSTORE_WORD; | 
 | 	  break; | 
 | 	case INSN_FLSI: | 
 | 	case INSN_FSSI: | 
 | 	  range = NDS32_LOADSTORE_FLOAT_S; | 
 | 	  break; | 
 | 	case INSN_FLDI: | 
 | 	case INSN_FSDI: | 
 | 	  range = NDS32_LOADSTORE_FLOAT_D; | 
 | 	  break; | 
 | 	case INSN_ORI: | 
 | 	  range = NDS32_LOADSTORE_IMM; | 
 | 	  break; | 
 | 	default: | 
 | 	  range = NDS32_LOADSTORE_NONE; | 
 | 	  break; | 
 | 	} | 
 |       if (range != NDS32_LOADSTORE_NONE) | 
 | 	break; | 
 |       pattern = pattern->next; | 
 |     } | 
 |   return range; | 
 | } | 
 |  | 
 | /* The args means: instruction size, the 1st instruction is converted to 16 or | 
 |    not, optimize option, 16 bit instruction is enable.  */ | 
 |  | 
 | #define SET_ADDEND(size, convertible, optimize, insn16_on) \ | 
 |   (((size) & 0xff) | ((convertible) ? 1u << 31 : 0) \ | 
 |    | ((optimize) ? 1 << 30 : 0) | (insn16_on ? 1 << 29 : 0)) | 
 | #define MAC_COMBO (E_NDS32_HAS_FPU_MAC_INST|E_NDS32_HAS_MAC_DX_INST) | 
 |  | 
 | static void | 
 | nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn) | 
 | { | 
 |   static int skip_flags = NASM_ATTR_FPU_FMA | 
 |     | NASM_ATTR_BRANCH | NASM_ATTR_SATURATION_EXT | 
 |     | NASM_ATTR_GPREL | NASM_ATTR_DXREG | 
 |     | NASM_ATTR_ISA_V1 | NASM_ATTR_ISA_V2 | 
 |     | NASM_ATTR_ISA_V3 | NASM_ATTR_ISA_V3M | 
 |     | NASM_ATTR_PCREL; | 
 |  | 
 |   int new_flags = insn->opcode->attr & ~skip_flags; | 
 |   while (new_flags) | 
 |     { | 
 |       int next = 1 << (ffs (new_flags) - 1); | 
 |       new_flags &= ~next; | 
 |       switch (next) | 
 | 	{ | 
 | 	case NASM_ATTR_PERF_EXT: | 
 | 	  { | 
 | 	    if (nds32_perf_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_EXT_INST; | 
 | 		skip_flags |= NASM_ATTR_PERF_EXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling performance " | 
 | 			"extension"), insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_PERF2_EXT: | 
 | 	  { | 
 | 	    if (nds32_perf_ext2) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_EXT2_INST; | 
 | 		skip_flags |= NASM_ATTR_PERF2_EXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling performance " | 
 | 			"extension II"), insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_AUDIO_ISAEXT: | 
 | 	  { | 
 | 	    if (nds32_audio_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_AUDIO_INST; | 
 | 		skip_flags |= NASM_ATTR_AUDIO_ISAEXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling AUDIO extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_STR_EXT: | 
 | 	  { | 
 | 	    if (nds32_string_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_STRING_INST; | 
 | 		skip_flags |= NASM_ATTR_STR_EXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling STRING extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_DIV: | 
 | 	  { | 
 | 	    if (insn->opcode->attr & NASM_ATTR_DXREG) | 
 | 	      { | 
 | 		if (nds32_div && nds32_dx_regs) | 
 | 		  { | 
 | 		    nds32_elf_flags |= E_NDS32_HAS_DIV_DX_INST; | 
 | 		    skip_flags |= NASM_ATTR_DIV; | 
 | 		  } | 
 | 		else | 
 | 		  as_bad (_("instruction %s requires enabling DIV & DX_REGS " | 
 | 			    "extension"), insn->opcode->opcode); | 
 | 	      } | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_FPU: | 
 | 	  { | 
 | 	    if (nds32_fpu_sp_ext || nds32_fpu_dp_ext) | 
 | 	      { | 
 | 		if (!(nds32_elf_flags | 
 | 		      & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST))) | 
 | 		  nds32_fpu_com = 1; | 
 | 		skip_flags |= NASM_ATTR_FPU; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling FPU extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_FPU_SP_EXT: | 
 | 	  { | 
 | 	    if (nds32_fpu_sp_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_FPU_INST; | 
 | 		skip_flags |= NASM_ATTR_FPU_SP_EXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling FPU_SP extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_FPU_DP_EXT: | 
 | 	  { | 
 | 	    if (nds32_fpu_dp_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST; | 
 | 		skip_flags |= NASM_ATTR_FPU_DP_EXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling FPU_DP extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_MAC: | 
 | 	  { | 
 | 	    if (insn->opcode->attr & NASM_ATTR_FPU_SP_EXT) | 
 | 	      { | 
 | 		if (nds32_fpu_sp_ext && nds32_mac) | 
 | 		  nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST; | 
 | 		else | 
 | 		  as_bad (_("instruction %s requires enabling FPU_MAC " | 
 | 			    "extension"), insn->opcode->opcode); | 
 | 	      } | 
 | 	    else if (insn->opcode->attr & NASM_ATTR_FPU_DP_EXT) | 
 | 	      { | 
 | 		if (nds32_fpu_dp_ext && nds32_mac) | 
 | 		  nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST; | 
 | 		else | 
 | 		  as_bad (_("instruction %s requires enabling FPU_MAC " | 
 | 			    "extension"), insn->opcode->opcode); | 
 | 	      } | 
 | 	    else if (insn->opcode->attr & NASM_ATTR_DXREG) | 
 | 	      { | 
 | 		if (nds32_dx_regs && nds32_mac) | 
 | 		  nds32_elf_flags |= E_NDS32_HAS_MAC_DX_INST; | 
 | 		else | 
 | 		  as_bad (_("instruction %s requires enabling DX_REGS " | 
 | 			    "extension"), insn->opcode->opcode); | 
 | 	      } | 
 |  | 
 | 	    if (MAC_COMBO == (MAC_COMBO & nds32_elf_flags)) | 
 | 	      skip_flags |= NASM_ATTR_MAC; | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_DSP_ISAEXT: | 
 | 	  { | 
 | 	    if (nds32_dsp_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_DSP_INST; | 
 | 		skip_flags |= NASM_ATTR_DSP_ISAEXT; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling dsp extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	case NASM_ATTR_ZOL: | 
 | 	  { | 
 | 	    if (nds32_zol_ext) | 
 | 	      { | 
 | 		nds32_elf_flags |= E_NDS32_HAS_ZOL; | 
 | 		skip_flags |= NASM_ATTR_ZOL; | 
 | 	      } | 
 | 	    else | 
 | 	      as_bad (_("instruction %s requires enabling zol extension"), | 
 | 		      insn->opcode->opcode); | 
 | 	  } | 
 | 	  break; | 
 | 	default: | 
 | 	  as_bad (_("internal error: unknown instruction attribute: 0x%08x"), | 
 | 		  next); | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Flag for analysis relaxation type.  */ | 
 |  | 
 | enum nds32_insn_type | 
 | { | 
 |   N32_RELAX_SETHI = 1, | 
 |   N32_RELAX_BR = (1 << 1), | 
 |   N32_RELAX_LSI = (1 << 2), | 
 |   N32_RELAX_JUMP = (1 << 3), | 
 |   N32_RELAX_CALL = (1 << 4), | 
 |   N32_RELAX_ORI = (1 << 5), | 
 |   N32_RELAX_MEM = (1 << 6), | 
 |   N32_RELAX_MOVI = (1 << 7), | 
 |   N32_RELAX_ALU1 = (1 << 8), | 
 |   N32_RELAX_16BIT = (1 << 9), | 
 | }; | 
 |  | 
 | struct nds32_hint_map | 
 | { | 
 |   /* the preamble relocation */ | 
 |   bfd_reloc_code_real_type hi_type; | 
 |   /* mnemonic */ | 
 |   const char *opc; | 
 |   /* relax pattern ID */ | 
 |   enum nds32_relax_hint_type hint_type; | 
 |   /* range */ | 
 |   enum nds32_br_range range; | 
 |   /* pattern character flags */ | 
 |   enum nds32_insn_type insn_list; | 
 |   /* optional pattern character flags */ | 
 |   enum nds32_insn_type option_list; | 
 | }; | 
 |  | 
 | /* Table to match instructions with hint and relax pattern.  */ | 
 |  | 
 | static struct nds32_hint_map hint_map [] = | 
 | { | 
 |   { | 
 |     /* LONGCALL4.  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     "jal", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGCALL5.  */ | 
 |     _dummy_first_bfd_reloc_code_real, | 
 |     "bgezal", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_S16M, | 
 |     N32_RELAX_BR | N32_RELAX_CALL, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGCALL6.  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     "bgezal", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_BR | N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_CALL, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGJUMP4.  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     "j", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_JUMP, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGJUMP5.  */ | 
 |     /* There is two kinds of variation of LONGJUMP5.  One of them | 
 |        generate EMPTY relocation for converted INSN16 if needed. | 
 |        But we don't distinguish them here.  */ | 
 |     _dummy_first_bfd_reloc_code_real, | 
 |     "beq", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_S16M, | 
 |     N32_RELAX_BR | N32_RELAX_JUMP, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGJUMP6.  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     "beq", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_BR | N32_RELAX_JUMP, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGJUMP7.  */ | 
 |     _dummy_first_bfd_reloc_code_real, | 
 |     "beqc", | 
 |     NDS32_RELAX_HINT_NONE, | 
 |     BR_RANGE_S16K, | 
 |     N32_RELAX_MOVI | N32_RELAX_BR, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* LONGCALL (BAL|JR|LA symbol@PLT).  */ | 
 |     BFD_RELOC_NDS32_PLT_GOTREL_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LA_PLT, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI, | 
 |     N32_RELAX_ALU1 | N32_RELAX_CALL | N32_RELAX_JUMP, | 
 |   }, | 
 |   /* relative issue: #12566 */ | 
 |   { | 
 |     /* LA and Floating LSI.  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LA_FLSI, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_LSI, | 
 |     0, | 
 |   }, | 
 |   /* relative issue: #11685 #11602 */ | 
 |   { | 
 |     /* load address / load-store (LALS).  */ | 
 |     BFD_RELOC_NDS32_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LALS, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI, | 
 |     N32_RELAX_ORI | N32_RELAX_LSI, | 
 |   }, | 
 |   { | 
 |     /* setup $GP (_GLOBAL_OFFSET_TABLE_)  */ | 
 |     BFD_RELOC_NDS32_GOTPC_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LALS, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* GOT LA/LS (symbol@GOT)  */ | 
 |     BFD_RELOC_NDS32_GOT_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LA_GOT, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI, | 
 |     N32_RELAX_MEM, | 
 |   }, | 
 |   { | 
 |     /* GOTOFF LA/LS (symbol@GOTOFF)  */ | 
 |     BFD_RELOC_NDS32_GOTOFF_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_LA_GOTOFF, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI, | 
 |     N32_RELAX_ALU1  | N32_RELAX_MEM, /* | N32_RELAX_LSI, */ | 
 |   }, | 
 |   { | 
 |     /* TLS LE LA|LS (@TPOFF)  */ | 
 |     BFD_RELOC_NDS32_TLS_LE_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_TLS_LE_LS, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI, | 
 |     N32_RELAX_ALU1 | N32_RELAX_MEM, | 
 |   }, | 
 |   { | 
 |     /* TLS IE LA */ | 
 |     BFD_RELOC_NDS32_TLS_IE_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_TLS_IE_LA, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_LSI, | 
 |     0, | 
 |   }, | 
 | { | 
 |     /* TLS IE LS */ | 
 |     BFD_RELOC_NDS32_TLS_IE_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_TLS_IE_LS, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_LSI | N32_RELAX_MEM, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* TLS IEGP LA */ | 
 |     BFD_RELOC_NDS32_TLS_IEGP_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_TLS_IEGP_LA, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_MEM, | 
 |     0, | 
 |   }, | 
 |   { | 
 |     /* TLS DESC LS */ | 
 |     BFD_RELOC_NDS32_TLS_DESC_HI20, | 
 |     NULL, | 
 |     NDS32_RELAX_HINT_TLS_DESC_LS, | 
 |     BR_RANGE_U4G, | 
 |     N32_RELAX_SETHI | N32_RELAX_ORI | N32_RELAX_ALU1 | N32_RELAX_CALL, | 
 |     N32_RELAX_LSI | N32_RELAX_MEM, | 
 |   }, | 
 |   /* last one */ | 
 |   {0, NULL, 0, 0 ,0, 0} | 
 | }; | 
 |  | 
 | /* Find the relaxation pattern according to instructions.  */ | 
 |  | 
 | static bool | 
 | nds32_find_reloc_table (struct nds32_relocs_pattern *relocs_pattern, | 
 | 			struct nds32_relax_hint_table *hint_info) | 
 | { | 
 |   unsigned int opcode, seq_size; | 
 |   enum nds32_br_range range; | 
 |   struct nds32_relocs_pattern *pattern, *hi_pattern = NULL; | 
 |   const char *opc = NULL; | 
 |   relax_info_t *relax_info = NULL; | 
 |   nds32_relax_fixup_info_t *fixup_info, *hint_fixup; | 
 |   enum nds32_relax_hint_type hint_type = NDS32_RELAX_HINT_NONE; | 
 |   struct nds32_relax_hint_table *table_ptr; | 
 |   uint32_t *code_seq, *hint_code; | 
 |   enum nds32_insn_type relax_type = 0; | 
 |   struct nds32_hint_map *map_ptr = hint_map; | 
 |   unsigned int i; | 
 |   const char *check_insn[] = | 
 |     { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8" }; | 
 |  | 
 |   /* TODO: PLT GOT.  */ | 
 |   /* Traverse all pattern instruction and set flag.  */ | 
 |   pattern = relocs_pattern; | 
 |   while (pattern) | 
 |     { | 
 |       if (pattern->opcode->isize == 4) | 
 | 	{ | 
 | 	  /* 4 byte instruction.  */ | 
 | 	  opcode = N32_OP6 (pattern->opcode->value); | 
 | 	  switch (opcode) | 
 | 	    { | 
 | 	    case N32_OP6_SETHI: | 
 | 	      hi_pattern = pattern; | 
 | 	      relax_type |= N32_RELAX_SETHI; | 
 | 	      break; | 
 | 	    case N32_OP6_MEM: | 
 | 	      relax_type |= N32_RELAX_MEM; | 
 | 	      break; | 
 | 	    case N32_OP6_ALU1: | 
 | 	      relax_type |= N32_RELAX_ALU1; | 
 | 	      break; | 
 | 	    case N32_OP6_ORI: | 
 | 	      relax_type |= N32_RELAX_ORI; | 
 | 	      break; | 
 | 	    case N32_OP6_BR1: | 
 | 	    case N32_OP6_BR2: | 
 | 	    case N32_OP6_BR3: | 
 | 	      relax_type |= N32_RELAX_BR; | 
 | 	      break; | 
 | 	    case N32_OP6_MOVI: | 
 | 	      relax_type |= N32_RELAX_MOVI; | 
 | 	      break; | 
 | 	    case N32_OP6_LBI: | 
 | 	    case N32_OP6_SBI: | 
 | 	    case N32_OP6_LBSI: | 
 | 	    case N32_OP6_LHI: | 
 | 	    case N32_OP6_SHI: | 
 | 	    case N32_OP6_LHSI: | 
 | 	    case N32_OP6_LWI: | 
 | 	    case N32_OP6_SWI: | 
 | 	    case N32_OP6_LWC: | 
 | 	    case N32_OP6_SWC: | 
 | 	    case N32_OP6_LDC: | 
 | 	    case N32_OP6_SDC: | 
 | 	      relax_type |= N32_RELAX_LSI; | 
 | 	      break; | 
 | 	    case N32_OP6_JREG: | 
 | 	      if (__GF (pattern->opcode->value, 0, 1) == 1) | 
 | 		relax_type |= N32_RELAX_CALL; | 
 | 	      else | 
 | 		relax_type |= N32_RELAX_JUMP; | 
 | 	      break; | 
 | 	    case N32_OP6_JI: | 
 | 	      if (__GF (pattern->opcode->value, 24, 1) == 1) | 
 | 		relax_type |= N32_RELAX_CALL; | 
 | 	      else | 
 | 		relax_type |= N32_RELAX_JUMP; | 
 | 	      break; | 
 | 	    default: | 
 | 	      as_warn (_("relax hint unrecognized instruction: line %d."), | 
 | 		       pattern->frag->fr_line); | 
 | 	      return false; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* 2 byte instruction.  Compare by opcode name because | 
 | 	     the opcode of 2byte instruction is not regular.  */ | 
 | 	  int is_matched = 0; | 
 | 	  for (i = 0; i < ARRAY_SIZE (check_insn); i++) | 
 | 	    { | 
 | 	      if (strcmp (pattern->opcode->opcode, check_insn[i]) == 0) | 
 | 		{ | 
 | 		  relax_type |= N32_RELAX_BR; | 
 | 		  is_matched += 1; | 
 | 		  break; | 
 | 		} | 
 | 	    } | 
 | 	  if (!is_matched) | 
 | 	    relax_type |= N32_RELAX_16BIT; | 
 | 	} | 
 |       pattern = pattern->next; | 
 |     } | 
 |  | 
 |   /* Analysis instruction flag to choose relaxation table.  */ | 
 |   while (map_ptr->insn_list != 0) | 
 |     { | 
 |       struct nds32_hint_map *hint = map_ptr++; | 
 |       enum nds32_insn_type must = hint->insn_list; | 
 |       enum nds32_insn_type optional = hint->option_list; | 
 |       enum nds32_insn_type extra; | 
 |  | 
 |       if (must != (must & relax_type)) | 
 | 	continue; | 
 |  | 
 |       extra = relax_type ^ must; | 
 |       if (extra != (extra & optional)) | 
 | 	continue; | 
 |  | 
 |       if (!hi_pattern | 
 | 	  || (hi_pattern->fixP | 
 | 	      && hi_pattern->fixP->fx_r_type == hint->hi_type)) | 
 | 	{ | 
 | 	  opc = hint->opc; | 
 | 	  hint_type = hint->hint_type; | 
 | 	  range = hint->range; | 
 | 	  map_ptr = hint; | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   if (map_ptr->insn_list == 0) | 
 |     { | 
 |       if (!nds32_pic) | 
 | 	as_warn (_("Can not find match relax hint.  Line: %d"), | 
 | 		 relocs_pattern->frag->fr_line); | 
 |       return false; | 
 |     } | 
 |  | 
 |   /* Get the match table.  */ | 
 |   if (opc) | 
 |     { | 
 |       /* Branch relax pattern.  */ | 
 |       relax_info = str_hash_find (nds32_relax_info_hash, opc); | 
 |       if (!relax_info) | 
 | 	return false; | 
 |       fixup_info = relax_info->relax_fixup[range]; | 
 |       code_seq = relax_info->relax_code_seq[range]; | 
 |       seq_size = relax_info->relax_code_size[range]; | 
 |     } | 
 |   else if (hint_type) | 
 |     { | 
 |       /* Load-store relax pattern.  */ | 
 |       table_ptr = relax_ls_table; | 
 |       while (table_ptr->main_type != 0) | 
 | 	{ | 
 | 	  if (table_ptr->main_type == hint_type) | 
 | 	    { | 
 | 	      fixup_info = table_ptr->relax_fixup; | 
 | 	      code_seq = table_ptr->relax_code_seq; | 
 | 	      seq_size = table_ptr->relax_code_size; | 
 | 	      break; | 
 | 	    } | 
 | 	  table_ptr++; | 
 | 	} | 
 |       if (table_ptr->main_type == 0) | 
 | 	return false; | 
 |     } | 
 |   else | 
 |     return false; | 
 |  | 
 |   hint_fixup = hint_info->relax_fixup; | 
 |   hint_code = hint_info->relax_code_seq; | 
 |   hint_info->relax_code_size = seq_size; | 
 |  | 
 |   while (fixup_info->size != 0) | 
 |     { | 
 |       if (fixup_info->ramp & NDS32_HINT) | 
 | 	{ | 
 | 	  memcpy (hint_fixup, fixup_info, sizeof (nds32_relax_fixup_info_t)); | 
 | 	  hint_fixup++; | 
 | 	} | 
 |       fixup_info++; | 
 |     } | 
 |   /* Clear final relocation.  */ | 
 |   memset (hint_fixup, 0, sizeof (nds32_relax_fixup_info_t)); | 
 |   /* Copy code sequence.  */ | 
 |   memcpy (hint_code, code_seq, seq_size); | 
 |   return true; | 
 | } | 
 |  | 
 | /* Because there are a lot of variant of load-store, check | 
 |    all these type here.  */ | 
 |  | 
 | #define CLEAN_REG(insn) ((insn) & 0xfe0003ff) | 
 | #define GET_OPCODE(insn) ((insn) & 0xfe000000) | 
 |  | 
 | static bool | 
 | nds32_match_hint_insn (struct nds32_opcode *opcode, uint32_t seq) | 
 | { | 
 |   const char *check_insn[] = | 
 |     { "bnes38", "beqs38", "bnez38", "bnezs8", "beqz38", "beqzs8", "jral5" }; | 
 |   uint32_t insn = opcode->value; | 
 |   unsigned int i; | 
 |  | 
 |   insn = CLEAN_REG (opcode->value); | 
 |   if (insn == seq) | 
 |     return true; | 
 |  | 
 |   switch (seq) | 
 |     { | 
 |     case OP6 (LBI): | 
 |       /* In relocation_table, it regards instruction LBI as representation | 
 | 	 of all the NDS32_RELAX_HINT_LS pattern.  */ | 
 |       if (insn == OP6 (LBI) || insn == OP6 (SBI) || insn == OP6 (LBSI) | 
 | 	  || insn == OP6 (LHI) || insn == OP6 (SHI) || insn == OP6 (LHSI) | 
 | 	  || insn == OP6 (LWI) || insn == OP6 (SWI) | 
 | 	  || insn == OP6 (LWC) || insn == OP6 (SWC) | 
 | 	  || insn == OP6 (LDC) || insn == OP6 (SDC)) | 
 | 	return true; | 
 |       break; | 
 |     case OP6 (BR2): | 
 |       /* This is for LONGCALL5 and LONGCALL6.  */ | 
 |       if (insn == OP6 (BR2)) | 
 | 	return true; | 
 |       break; | 
 |     case OP6 (BR1): | 
 |       /* This is for LONGJUMP5 and LONGJUMP6.  */ | 
 |       if (opcode->isize == 4 | 
 | 	  && (insn == OP6 (BR1) || insn == OP6 (BR2) || insn == OP6 (BR3))) | 
 | 	return true; | 
 |       else if (opcode->isize == 2) | 
 | 	{ | 
 | 	  for (i = 0; i < ARRAY_SIZE (check_insn); i++) | 
 | 	    if (strcmp (opcode->opcode, check_insn[i]) == 0) | 
 | 	      return true; | 
 | 	} | 
 |       break; | 
 |     case OP6 (MOVI): | 
 |       /* This is for LONGJUMP7.  */ | 
 |       if (opcode->isize == 2 && strcmp (opcode->opcode, "movi55") == 0) | 
 | 	return true; | 
 |       break; | 
 |     case OP6 (MEM): | 
 |       if (OP6 (MEM) == GET_OPCODE (insn)) | 
 | 	return true; | 
 |       break; | 
 |     case OP6 (JREG): | 
 |       /* bit 24: N32_JI_JAL  */ /* feed me!  */ | 
 |       if ((insn & ~(N32_BIT (24))) == JREG (JRAL)) | 
 | 	return true; | 
 |       break; | 
 |     default: | 
 |       if (opcode->isize == 2) | 
 | 	{ | 
 | 	  for (i = 0; i < ARRAY_SIZE (check_insn); i++) | 
 | 	    if (strcmp (opcode->opcode, check_insn[i]) == 0) | 
 | 	      return true; | 
 |  | 
 | 	  if ((strcmp (opcode->opcode, "add5.pc") == 0) || | 
 | 	      (strcmp (opcode->opcode, "add45") == 0)) | 
 | 	    return true; | 
 | 	} | 
 |     } | 
 |   return false; | 
 | } | 
 |  | 
 | /* Append relax relocation for link time relaxing.  */ | 
 |  | 
 | static void | 
 | nds32_elf_append_relax_relocs (const char *key, const void *value) | 
 | { | 
 |   struct nds32_relocs_pattern *relocs_pattern = | 
 |     (struct nds32_relocs_pattern *) value; | 
 |   struct nds32_relocs_pattern *pattern_temp, *pattern_now; | 
 |   symbolS *sym, *hi_sym = NULL; | 
 |   expressionS exp; | 
 |   fragS *fragP; | 
 |   segT seg_bak = now_seg; | 
 |   frchainS *frchain_bak = frchain_now; | 
 |   struct nds32_relax_hint_table hint_info; | 
 |   nds32_relax_fixup_info_t *hint_fixup, *fixup_now; | 
 |   size_t fixup_size; | 
 |   offsetT branch_offset, hi_branch_offset = 0; | 
 |   fixS *fixP; | 
 |   int range, offset; | 
 |   unsigned int ptr_offset, hint_count, relax_code_size, count = 0; | 
 |   uint32_t *code_seq, code_insn; | 
 |   char *where; | 
 |   int pcrel; | 
 |  | 
 |   if (!relocs_pattern) | 
 |     return; | 
 |  | 
 |   if (!nds32_find_reloc_table (relocs_pattern, &hint_info)) | 
 |     return; | 
 |  | 
 |   /* Save symbol for some EMPTY relocation using.  */ | 
 |   pattern_now = relocs_pattern; | 
 |   while (pattern_now) | 
 |     { | 
 |       if (pattern_now->opcode->value == OP6 (SETHI)) | 
 | 	{ | 
 | 	  hi_sym = pattern_now->sym; | 
 | 	  hi_branch_offset = pattern_now->fixP->fx_offset; | 
 | 	  break; | 
 | 	} | 
 |       pattern_now = pattern_now->next; | 
 |     } | 
 |  | 
 |   /* Inserting fix up must specify now_seg or frchain_now.  */ | 
 |   now_seg = relocs_pattern->seg; | 
 |   frchain_now = relocs_pattern->frchain; | 
 |   fragP = relocs_pattern->frag; | 
 |   branch_offset = fragP->fr_offset; | 
 |  | 
 |   hint_fixup = hint_info.relax_fixup; | 
 |   code_seq = hint_info.relax_code_seq; | 
 |   relax_code_size = hint_info.relax_code_size; | 
 |   pattern_now = relocs_pattern; | 
 |  | 
 | #ifdef NDS32_LINUX_TOOLCHAIN | 
 |   /* prepare group relocation ID (number).  */ | 
 |   long group_id = 0; | 
 |   if (key) | 
 |     { | 
 |       /* convert .relax_hint key to number */ | 
 |       errno = 0; | 
 |       group_id = strtol (key, NULL, 10); | 
 |       if ((errno == ERANGE && (group_id == LONG_MAX || group_id == LONG_MIN)) | 
 | 	  || (errno != 0 && group_id == 0)) | 
 | 	{ | 
 | 	  as_bad (_("Internal error: .relax_hint KEY is not a number!")); | 
 | 	  goto restore; | 
 | 	} | 
 |     } | 
 | #endif | 
 |  | 
 |   /* Insert relaxation.  */ | 
 |   exp.X_op = O_symbol; | 
 |  | 
 |   /* For each instruction in the hint group.  */ | 
 |   while (pattern_now) | 
 |     { | 
 |       if (count >= relax_code_size / 4) | 
 | 	count = 0; | 
 |  | 
 |       /* Choose the match fixup by instruction.  */ | 
 |       code_insn = CLEAN_REG (*(code_seq + count)); | 
 |       if (!nds32_match_hint_insn (pattern_now->opcode, code_insn)) | 
 | 	{ | 
 | 	  /* Try search from head again */ | 
 | 	  count = 0; | 
 | 	  code_insn = CLEAN_REG (*(code_seq + count)); | 
 |  | 
 | 	  while (!nds32_match_hint_insn (pattern_now->opcode, code_insn)) | 
 | 	    { | 
 | 	      count++; | 
 | 	      if (count >= relax_code_size / 4) | 
 | 		{ | 
 | 		  as_bad (_("Internal error: Relax hint (%s) error. %s: %s (%x)"), | 
 | 			  key, | 
 | 			  now_seg->name, | 
 | 			  pattern_now->opcode->opcode, | 
 | 			  pattern_now->opcode->value); | 
 | 		  goto restore; | 
 | 		} | 
 | 	      code_insn = CLEAN_REG (*(code_seq + count)); | 
 | 	    } | 
 | 	} | 
 |       fragP = pattern_now->frag; | 
 |       sym = pattern_now->sym; | 
 |       branch_offset = fragP->fr_offset; | 
 |       offset = count * 4; | 
 |       where = pattern_now->where; | 
 |       /* Find the instruction map fix.  */ | 
 |       fixup_now = hint_fixup; | 
 |       while (fixup_now->offset != offset) | 
 | 	{ | 
 | 	  fixup_now++; | 
 | 	  if (fixup_now->size == 0) | 
 | 	    break; | 
 | 	} | 
 |       /* This element is without relaxation relocation.  */ | 
 |       if (fixup_now->size == 0) | 
 | 	{ | 
 | 	  pattern_now = pattern_now->next; | 
 | 	  continue; | 
 | 	} | 
 |       fixup_size = fixup_now->size; | 
 |  | 
 |       /* Insert all fixup.  */ | 
 |       pcrel = 0; | 
 |       while (fixup_size != 0 && fixup_now->offset == offset) | 
 | 	{ | 
 | 	  /* Set the real instruction size in element.  */ | 
 | 	  fixup_size = pattern_now->opcode->isize; | 
 | 	  pcrel = ((fixup_now->ramp & NDS32_PCREL) != 0) ? 1 : 0; | 
 | 	  if (fixup_now->ramp & NDS32_FIX) | 
 | 	    { | 
 | 	      /* Convert original relocation.  */ | 
 | 	      pattern_now->fixP->fx_r_type = fixup_now->r_type ; | 
 | 	      fixup_size = 0; | 
 | 	    } | 
 | 	  else if ((fixup_now->ramp & NDS32_PTR) != 0) | 
 | 	    { | 
 | 	      /* This relocation has to point to another instruction.  Make | 
 | 		 sure each resolved relocation has to be pointed.  */ | 
 | 	      pattern_temp = relocs_pattern; | 
 | 	      /* All instruction in relax_table should be 32-bit.  */ | 
 | 	      hint_count = hint_info.relax_code_size / 4; | 
 | 	      code_insn = CLEAN_REG (*(code_seq + hint_count - 1)); | 
 | 	      while (pattern_temp) | 
 | 		{ | 
 | 		  /* Point to every resolved relocation.  */ | 
 | 		  if (nds32_match_hint_insn (pattern_temp->opcode, code_insn)) | 
 | 		    { | 
 | 		      ptr_offset = | 
 | 			pattern_temp->where - pattern_temp->frag->fr_literal; | 
 | 		      exp.X_add_symbol = symbol_temp_new (now_seg, | 
 | 							  pattern_temp->frag, | 
 | 							  ptr_offset); | 
 | 		      exp.X_add_number = 0; | 
 | 		      fixP = | 
 | 			fix_new_exp (fragP, where - fragP->fr_literal, | 
 | 				     fixup_size, &exp, 0, fixup_now->r_type); | 
 | 		      fixP->fx_addnumber = fixP->fx_offset; | 
 | 		    } | 
 | 		  pattern_temp = pattern_temp->next; | 
 | 		} | 
 | 	      fixup_size = 0; | 
 | 	    } | 
 | 	  else if (fixup_now->ramp & NDS32_ADDEND) | 
 | 	    { | 
 | 	      range = nds32_elf_sethi_range (relocs_pattern); | 
 | 	      if (range == NDS32_LOADSTORE_NONE) | 
 | 		{ | 
 | 		  as_bad (_("Internal error: Range error. %s"), now_seg->name); | 
 | 		  return; | 
 | 		} | 
 | 	      exp.X_add_symbol = abs_section_sym; | 
 | 	      exp.X_add_number = SET_ADDEND (4, 0, optimize, enable_16bit); | 
 | 	      exp.X_add_number |= ((range & 0x3f) << 8); | 
 | 	    } | 
 | 	  else if ((fixup_now->ramp & NDS32_ABS) != 0) | 
 | 	    { | 
 | 	      /* This is a tag relocation.  */ | 
 | 	      exp.X_add_symbol = abs_section_sym; | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else if ((fixup_now->ramp & NDS32_INSN16) != 0) | 
 | 	    { | 
 | 	      if (!enable_16bit) | 
 | 		fixup_size = 0; | 
 | 	      /* This is a tag relocation.  */ | 
 | 	      exp.X_add_symbol = abs_section_sym; | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else if ((fixup_now->ramp & NDS32_SYM) != 0) | 
 | 	    { | 
 | 	      /* For EMPTY relocation save the true symbol.  */ | 
 | 	      exp.X_add_symbol = hi_sym; | 
 | 	      exp.X_add_number = hi_branch_offset; | 
 | 	    } | 
 | 	  else if (NDS32_SYM_DESC_MEM & fixup_now->ramp) | 
 | 	    { | 
 | 	      /* Do the same as NDS32_SYM.  */ | 
 | 	      exp.X_add_symbol = hi_sym; | 
 | 	      exp.X_add_number = hi_branch_offset; | 
 |  | 
 | 	      /* Extra to NDS32_SYM.  */ | 
 | 	      /* Detect if DESC_FUNC relax type do apply.  */ | 
 | 	      if ((REG_GP == N32_RA5 (pattern_now->insn)) | 
 | 		  || (REG_GP == N32_RB5 (pattern_now->insn))) | 
 | 		{ | 
 | 		  fixP = fix_new_exp (fragP, where - fragP->fr_literal, | 
 | 				      fixup_size, &exp, pcrel, | 
 | 				      BFD_RELOC_NDS32_TLS_DESC_FUNC); | 
 | 		  fixP->fx_addnumber = fixP->fx_offset; | 
 |  | 
 | 		  fixup_size = 0; | 
 | 		} | 
 | 	      /* Else do as usual.  */ | 
 | 	    } | 
 | 	  else if (fixup_now->ramp & NDS32_PTR_PATTERN) | 
 | 	    { | 
 | 	      /* Find out PTR_RESOLVED code pattern.  */ | 
 | 	      nds32_relax_fixup_info_t *next_fixup = fixup_now + 1; | 
 | 	      uint32_t resolved_pattern = 0; | 
 | 	      while (next_fixup->offset) | 
 | 		{ | 
 | 		  if (next_fixup->r_type == BFD_RELOC_NDS32_PTR_RESOLVED) | 
 | 		    { | 
 | 		      uint32_t new_pattern = code_seq[next_fixup->offset >> 2]; | 
 | 		      if (!resolved_pattern) | 
 | 			resolved_pattern = new_pattern; | 
 | 		      else if (new_pattern != resolved_pattern) | 
 | 			{ | 
 | 			  as_warn (_("Multiple BFD_RELOC_NDS32_PTR_RESOLVED " | 
 | 				     "patterns are not supported yet!")); | 
 | 			  break; | 
 | 			} | 
 | 		    } | 
 | 		  ++next_fixup; | 
 | 		} | 
 |  | 
 | 	      /* Find matched code and insert fix-ups.  */ | 
 | 	      struct nds32_relocs_pattern *next_pattern = pattern_now->next; | 
 | 	      /* This relocation has to point to another instruction. | 
 | 		 Make sure each resolved relocation has to be pointed.  */ | 
 | 	      /* All instruction in relax_table should be 32-bit.  */ | 
 | 	      while (next_pattern) | 
 | 		{ | 
 | 		  uint32_t cur_pattern = GET_OPCODE (next_pattern->opcode->value); | 
 | 		  if (cur_pattern == resolved_pattern) | 
 | 		    { | 
 | 		      ptr_offset = next_pattern->where | 
 | 			- next_pattern->frag->fr_literal; | 
 | 		      exp.X_add_symbol = symbol_temp_new (now_seg, | 
 | 							  next_pattern->frag, | 
 | 							  ptr_offset); | 
 | 		      exp.X_add_number = 0; | 
 | 		      fixP = fix_new_exp (fragP, where - fragP->fr_literal, | 
 | 					  fixup_size, &exp, 0, | 
 | 					  fixup_now->r_type); | 
 | 		      fixP->fx_addnumber = fixP->fx_offset; | 
 | 		    } | 
 | 		  next_pattern = next_pattern->next; | 
 | 		} | 
 |  | 
 | 	      fixup_size = 0; | 
 | 	    } | 
 | 	  else if (fixup_now->ramp & NDS32_PTR_MULTIPLE) | 
 | 	    { | 
 | 	      /* Find each PTR_RESOLVED pattern after PTR.  */ | 
 | 	      nds32_relax_fixup_info_t *next_fixup = fixup_now + 1; | 
 | 	      while (next_fixup->offset) | 
 | 		{ | 
 | 		  if (next_fixup->r_type == BFD_RELOC_NDS32_PTR_RESOLVED) | 
 | 		    { | 
 | 		      uint32_t pattern = code_seq[next_fixup->offset >> 2]; | 
 | 		      /* Find matched code to insert fix-ups.  */ | 
 | 		      struct nds32_relocs_pattern *next_insn = pattern_now->next; | 
 | 		      while (next_insn) | 
 | 			{ | 
 | 			  uint32_t insn_pattern = GET_OPCODE (next_insn->opcode->value); | 
 | 			  if (insn_pattern == pattern) | 
 | 			    { | 
 | 			      ptr_offset = next_insn->where | 
 | 				- next_insn->frag->fr_literal; | 
 | 			      exp.X_add_symbol = symbol_temp_new (now_seg, | 
 | 								  next_insn->frag, | 
 | 								  ptr_offset); | 
 | 			      exp.X_add_number = 0; | 
 | 			      fixP = fix_new_exp (fragP, | 
 | 						  where - fragP->fr_literal, | 
 | 						  fixup_size, &exp, 0, | 
 | 						  fixup_now->r_type); | 
 | 			      fixP->fx_addnumber = fixP->fx_offset; | 
 | 			    } | 
 | 			  next_insn = next_insn->next; | 
 | 			} | 
 | 		    } | 
 | 		  ++next_fixup; | 
 | 		} | 
 | 	      fixup_size = 0; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      exp.X_add_symbol = sym; | 
 | 	      exp.X_add_number = branch_offset; | 
 | 	    } | 
 |  | 
 | 	  if (fixup_size != 0) | 
 | 	    { | 
 | 	      fixP = fix_new_exp (fragP, where - fragP->fr_literal, fixup_size, | 
 | 				  &exp, pcrel, fixup_now->r_type); | 
 | 	      fixP->fx_addnumber = fixP->fx_offset; | 
 | 	    } | 
 | 	  fixup_now++; | 
 | 	  fixup_size = fixup_now->size; | 
 | 	} | 
 |  | 
 | #ifdef NDS32_LINUX_TOOLCHAIN | 
 |       /* Insert group relocation for each relax hint.  */ | 
 |       if (key) | 
 | 	{ | 
 | 	  exp.X_add_symbol = hi_sym; /* for eyes only */ | 
 | 	  exp.X_add_number = group_id; | 
 | 	  fixP = fix_new_exp (fragP, where - fragP->fr_literal, fixup_size, | 
 | 			      &exp, pcrel, BFD_RELOC_NDS32_GROUP); | 
 | 	  fixP->fx_addnumber = fixP->fx_offset; | 
 | 	} | 
 | #endif | 
 |  | 
 |       if (count < relax_code_size / 4) | 
 | 	count++; | 
 |       pattern_now = pattern_now->next; | 
 |     } | 
 |  | 
 |  restore: | 
 |   now_seg = seg_bak; | 
 |   frchain_now = frchain_bak; | 
 | } | 
 |  | 
 | static int | 
 | nds32_elf_append_relax_relocs_traverse (void **slot, void *arg ATTRIBUTE_UNUSED) | 
 | { | 
 |   string_tuple_t *tuple = *((string_tuple_t **) slot); | 
 |   nds32_elf_append_relax_relocs (tuple->key, tuple->value); | 
 |   return 1; | 
 | } | 
 |  | 
 |  | 
 | static void | 
 | nds32_str_tolower (const char *src, char *dest) | 
 | { | 
 |   unsigned int i, len; | 
 |  | 
 |   len = strlen (src); | 
 |  | 
 |   for (i = 0; i < len; i++) | 
 |     *(dest + i) = TOLOWER (*(src + i)); | 
 |  | 
 |   *(dest + i) = '\0'; | 
 | } | 
 |  | 
 | /* Check instruction if it can be used for the baseline.  */ | 
 |  | 
 | static bool | 
 | nds32_check_insn_available (struct nds32_asm_insn insn, const char *str) | 
 | { | 
 |   int attr = insn.attr & ATTR_ALL; | 
 |   static int baseline_isa = 0; | 
 |   char *s; | 
 |  | 
 |   s = xmalloc (strlen (str) + 1); | 
 |   nds32_str_tolower (str, s); | 
 |   if (verbatim | 
 |       && (((insn.opcode->value == ALU2 (MTUSR) | 
 | 	    || insn.opcode->value == ALU2 (MFUSR)) | 
 | 	   && (strstr (s, "lc") | 
 | 	       || strstr (s, "le") | 
 | 	       || strstr (s, "lb"))) | 
 | 	  || (insn.attr & NASM_ATTR_ZOL))) | 
 |     { | 
 |       as_bad (_("Not support instruction %s in verbatim."), str); | 
 |       return false; | 
 |     } | 
 |   free (s); | 
 |  | 
 |   if (!enable_16bit && insn.opcode->isize == 2) | 
 |     { | 
 |       as_bad (_("16-bit instruction is disabled: %s."), str); | 
 |       return false; | 
 |     } | 
 |  | 
 |   /* No isa setting or all isa can use.  */ | 
 |   if (attr == 0 || attr == ATTR_ALL) | 
 |     return true; | 
 |  | 
 |   if (baseline_isa == 0) | 
 |     { | 
 |       /* Map option baseline and instruction attribute.  */ | 
 |       switch (nds32_baseline) | 
 | 	{ | 
 | 	case ISA_V2: | 
 | 	  baseline_isa = ATTR (ISA_V2); | 
 | 	  break; | 
 | 	case ISA_V3: | 
 | 	  baseline_isa = ATTR (ISA_V3); | 
 | 	  break; | 
 | 	case ISA_V3M: | 
 | 	  baseline_isa = ATTR (ISA_V3M); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   if  ((baseline_isa & attr) == 0) | 
 |     { | 
 |       as_bad (_("Instruction %s not supported in the baseline."), str); | 
 |       return false; | 
 |     } | 
 |   return true; | 
 | } | 
 |  | 
 | /* Stub of machine dependent.  */ | 
 |  | 
 | void | 
 | md_assemble (char *str) | 
 | { | 
 |   struct nds32_asm_insn insn; | 
 |   char *out; | 
 |   struct nds32_pseudo_opcode *popcode; | 
 |   const struct nds32_field *fld = NULL; | 
 |   fixS *fixP; | 
 |   uint16_t insn_16; | 
 |   struct nds32_relocs_pattern *relocs_temp; | 
 |   struct nds32_relocs_group *group_temp; | 
 |   fragS *fragP; | 
 |   int label = label_exist; | 
 |   static bool pseudo_hint = false; | 
 |  | 
 |   popcode = nds32_lookup_pseudo_opcode (str); | 
 |   /* Note that we need to check 'verbatim' and | 
 |      'opcode->physical_op'.  If the assembly content is generated by | 
 |      compiler and this opcode is a physical instruction, there is no | 
 |      need to perform pseudo instruction expansion/transformation.  */ | 
 |   if (popcode && !(verbatim && popcode->physical_op)) | 
 |     { | 
 |       /* Pseudo instruction is with relax_hint.  */ | 
 |       if (relaxing) | 
 | 	pseudo_hint = true; | 
 |       pseudo_opcode = true; | 
 |       nds32_pseudo_opcode_wrapper (str, popcode); | 
 |       pseudo_opcode = false; | 
 |       pseudo_hint = false; | 
 |       nds32_elf_append_relax_relocs (NULL, relocs_list); | 
 |  | 
 |       /* Free relax_hint group list.  */ | 
 |       while (nds32_relax_hint_current) | 
 | 	{ | 
 | 	  group_temp = nds32_relax_hint_current->next; | 
 | 	  free (nds32_relax_hint_current); | 
 | 	  nds32_relax_hint_current = group_temp; | 
 | 	} | 
 |  | 
 |       /* Free pseudo list.  */ | 
 |       relocs_temp = relocs_list; | 
 |       while (relocs_temp) | 
 | 	{ | 
 | 	  relocs_list = relocs_list->next; | 
 | 	  free (relocs_temp); | 
 | 	  relocs_temp = relocs_list; | 
 | 	} | 
 |  | 
 |       return; | 
 |     } | 
 |  | 
 |   label_exist = 0; | 
 |   insn.info = XNEW (expressionS); | 
 |   asm_desc.result = NASM_OK; | 
 |   nds32_assemble (&asm_desc, &insn, str); | 
 |  | 
 |   switch (asm_desc.result) | 
 |     { | 
 |     case NASM_ERR_UNKNOWN_OP: | 
 |       as_bad (_("Unrecognized opcode, %s."), str); | 
 |       return; | 
 |     case NASM_ERR_SYNTAX: | 
 |       as_bad (_("Incorrect syntax, %s."), str); | 
 |       return; | 
 |     case NASM_ERR_OPERAND: | 
 |       as_bad (_("Unrecognized operand/register, %s."), str); | 
 |       return; | 
 |     case NASM_ERR_OUT_OF_RANGE: | 
 |       as_bad (_("Operand out of range, %s."), str); | 
 |       return; | 
 |     case NASM_ERR_REG_REDUCED: | 
 |       as_bad (_("Prohibited register used for reduced-register, %s."), str); | 
 |       return; | 
 |     case NASM_ERR_JUNK_EOL: | 
 |       as_bad (_("Junk at end of line, %s."), str); | 
 |       return; | 
 |     } | 
 |  | 
 |   gas_assert (insn.opcode); | 
 |  | 
 |   nds32_set_elf_flags_by_insn (&insn); | 
 |  | 
 |   gas_assert (insn.opcode->isize == 4 || insn.opcode->isize == 2); | 
 |  | 
 |   if (!nds32_check_insn_available (insn, str)) | 
 |     return; | 
 |  | 
 |   /* Make sure the beginning of text being 2-byte align.  */ | 
 |   nds32_adjust_label (1); | 
 |   add_mapping_symbol (MAP_CODE, 0, 0); | 
 |   fld = insn.field; | 
 |   /* Try to allocate the max size to guarantee relaxable same branch | 
 |      instructions in the same fragment.  */ | 
 |   frag_grow (NDS32_MAXCHAR); | 
 |   fragP = frag_now; | 
 |  | 
 |   if (fld && (insn.attr & NASM_ATTR_BRANCH) | 
 |       && (pseudo_opcode || (insn.opcode->value != INSN_JAL | 
 | 			    && insn.opcode->value != INSN_J)) | 
 |       && (!verbatim || pseudo_opcode)) | 
 |     { | 
 |       /* User assembly code branch relax for it.  */ | 
 |       /* If fld is not NULL, it is a symbol.  */ | 
 |       /* Branch must relax to proper pattern in user assembly code exclude | 
 | 	 J and JAL.  Keep these two in original type for users which wants | 
 | 	 to keep their size be fixed.  In general, assembler does not convert | 
 | 	 instruction generated by compiler.  But jump instruction may be | 
 | 	 truncated in text virtual model.  For workaround, compiler generate | 
 | 	 pseudo jump to fix this issue currently.  */ | 
 |  | 
 |       /* Get branch range type.  */ | 
 |       dwarf2_emit_insn (0); | 
 |       enum nds32_br_range range_type; | 
 |       expressionS *pexp = insn.info; | 
 |  | 
 |       range_type = get_range_type (fld); | 
 |  | 
 |       out = frag_var (rs_machine_dependent, NDS32_MAXCHAR, | 
 | 		      0, /* VAR is un-used.  */ | 
 | 		      range_type, /* SUBTYPE is used as range type.  */ | 
 | 		      pexp->X_add_symbol, pexp->X_add_number, 0); | 
 |  | 
 |       fragP->fr_fix += insn.opcode->isize; | 
 |       fragP->tc_frag_data.opcode = insn.opcode; | 
 |       fragP->tc_frag_data.insn = insn.insn; | 
 |       if (insn.opcode->isize == 4) | 
 | 	bfd_putb32 (insn.insn, out); | 
 |       else if (insn.opcode->isize == 2) | 
 | 	bfd_putb16 (insn.insn, out); | 
 |       fragP->tc_frag_data.flag |= NDS32_FRAG_BRANCH; | 
 |  | 
 |       free (insn.info); | 
 |       return; | 
 |       /* md_convert_frag will insert relocations.  */ | 
 |     } | 
 |   else if (!relaxing && enable_16bit && (optimize || optimize_for_space) | 
 | 	   && ((!fld && !verbatim && insn.opcode->isize == 4 | 
 | 		&& nds32_convert_32_to_16 (stdoutput, insn.insn, &insn_16, NULL)) | 
 | 	       || (insn.opcode->isize == 2 | 
 | 		   && nds32_convert_16_to_32 (stdoutput, insn.insn, NULL)))) | 
 |     { | 
 |       /* Record this one is relaxable.  */ | 
 |       expressionS *pexp = insn.info; | 
 |       dwarf2_emit_insn (0); | 
 |       if (fld) | 
 | 	{ | 
 | 	  out = frag_var (rs_machine_dependent, | 
 | 			  4, /* Max size is 32-bit instruction.  */ | 
 | 			  0, /* VAR is un-used.  */ | 
 | 			  0, pexp->X_add_symbol, pexp->X_add_number, 0); | 
 | 	  fragP->tc_frag_data.flag |= NDS32_FRAG_RELAXABLE_BRANCH; | 
 | 	} | 
 |       else | 
 | 	out = frag_var (rs_machine_dependent, | 
 | 			4, /* Max size is 32-bit instruction.  */ | 
 | 			0, /* VAR is un-used.  */ | 
 | 			0, NULL, 0, NULL); | 
 |       fragP->tc_frag_data.flag |= NDS32_FRAG_RELAXABLE; | 
 |       fragP->tc_frag_data.opcode = insn.opcode; | 
 |       fragP->tc_frag_data.insn = insn.insn; | 
 |       fragP->fr_fix += 2; | 
 |  | 
 |       /* In original, we don't relax the instruction with label on it, | 
 | 	 but this may cause some redundant nop16.  Therefore, tag this | 
 | 	 relaxable instruction and relax it carefully.  */ | 
 |       if (label) | 
 | 	fragP->tc_frag_data.flag |= NDS32_FRAG_LABEL; | 
 |  | 
 |       if (insn.opcode->isize == 4) | 
 | 	bfd_putb16 (insn_16, out); | 
 |       else if (insn.opcode->isize == 2) | 
 | 	bfd_putb16 (insn.insn, out); | 
 |  | 
 |       free (insn.info); | 
 |       return; | 
 |     } | 
 |   else if ((verbatim || !relaxing) && optimize && label) | 
 |     { | 
 |       /* This instruction is with label.  */ | 
 |       expressionS exp; | 
 |       out = frag_var (rs_machine_dependent, insn.opcode->isize, | 
 | 		      0, 0, NULL, 0, NULL); | 
 |       /* If this instruction is branch target, it is not relaxable.  */ | 
 |       fragP->tc_frag_data.flag = NDS32_FRAG_LABEL; | 
 |       fragP->tc_frag_data.opcode = insn.opcode; | 
 |       fragP->tc_frag_data.insn = insn.insn; | 
 |       fragP->fr_fix += insn.opcode->isize; | 
 |       if (insn.opcode->isize == 4) | 
 | 	{ | 
 | 	  exp.X_op = O_symbol; | 
 | 	  exp.X_add_symbol = abs_section_sym; | 
 | 	  exp.X_add_number = 0; | 
 | 	  fixP = fix_new_exp (fragP, fragP->fr_fix - 4, 0, &exp, | 
 | 			      0, BFD_RELOC_NDS32_LABEL); | 
 | 	  if (!verbatim) | 
 | 	    fragP->tc_frag_data.flag = NDS32_FRAG_ALIGN; | 
 | 	} | 
 |     } | 
 |   else | 
 |     out = frag_more (insn.opcode->isize); | 
 |  | 
 |   if (insn.opcode->isize == 4) | 
 |     bfd_putb32 (insn.insn, out); | 
 |   else if (insn.opcode->isize == 2) | 
 |     bfd_putb16 (insn.insn, out); | 
 |  | 
 |   dwarf2_emit_insn (insn.opcode->isize); | 
 |  | 
 |   /* Compiler generating code and user assembly pseudo load-store, insert | 
 |      fixup here.  */ | 
 |   expressionS *pexp = insn.info; | 
 |   fixP = nds32_elf_record_fixup_exp (fragP, str, fld, pexp, out, &insn); | 
 |   /* Build relaxation pattern when relaxing is enable.  */ | 
 |   if (relaxing) | 
 |     nds32_elf_build_relax_relation (fixP, pexp, out, &insn, fragP, fld, | 
 | 				    pseudo_hint); | 
 |  | 
 |   free (insn.info); | 
 | } | 
 |  | 
 | /* md_macro_start  */ | 
 |  | 
 | void | 
 | nds32_macro_start (void) | 
 | { | 
 | } | 
 |  | 
 | /* md_macro_info  */ | 
 |  | 
 | void | 
 | nds32_macro_info (void *info ATTRIBUTE_UNUSED) | 
 | { | 
 | } | 
 |  | 
 | /* md_macro_end  */ | 
 |  | 
 | void | 
 | nds32_macro_end (void) | 
 | { | 
 | } | 
 |  | 
 | /* GAS will call this function with one argument, an expressionS pointer, for | 
 |    any expression that can not be recognized.  When the function is called, | 
 |    input_line_pointer will point to the start of the expression.  */ | 
 |  | 
 | void | 
 | md_operand (expressionS *expressionP) | 
 | { | 
 |   if (*input_line_pointer == '#') | 
 |     { | 
 |       input_line_pointer++; | 
 |       expression (expressionP); | 
 |     } | 
 | } | 
 |  | 
 | /* GAS will call this function for each section at the end of the assembly, to | 
 |    permit the CPU back end to adjust the alignment of a section.  The function | 
 |    must take two arguments, a segT for the section and a valueT for the size of | 
 |    the section, and return a valueT for the rounded size.  */ | 
 |  | 
 | valueT | 
 | md_section_align (segT segment, valueT size) | 
 | { | 
 |   int align = bfd_section_alignment (segment); | 
 |  | 
 |   return ((size + (1 << align) - 1) & ((valueT) -1 << align)); | 
 | } | 
 |  | 
 | /* GAS will call this function when a symbol table lookup fails, before it | 
 |    creates a new symbol.  Typically this would be used to supply symbols whose | 
 |    name or value changes dynamically, possibly in a context sensitive way. | 
 |    Predefined symbols with fixed values, such as register names or condition | 
 |    codes, are typically entered directly into the symbol table when md_begin | 
 |    is called.  One argument is passed, a char * for the symbol.  */ | 
 |  | 
 | symbolS * | 
 | md_undefined_symbol (char *name ATTRIBUTE_UNUSED) | 
 | { | 
 |   return NULL; | 
 | } | 
 |  | 
 | static long | 
 | nds32_calc_branch_offset (segT segment, fragS *fragP, | 
 | 			  long stretch ATTRIBUTE_UNUSED, | 
 | 			  relax_info_t *relax_info, | 
 | 			  enum nds32_br_range branch_range_type) | 
 | { | 
 |   struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; | 
 |   symbolS *branch_symbol = fragP->fr_symbol; | 
 |   offsetT branch_offset = fragP->fr_offset; | 
 |   offsetT branch_target_address; | 
 |   offsetT branch_insn_address; | 
 |   long offset = 0; | 
 |  | 
 |   if ((S_GET_SEGMENT (branch_symbol) != segment) | 
 |       || S_IS_WEAK (branch_symbol)) | 
 |     { | 
 |       /* The symbol is not in the SEGMENT.  It could be far far away.  */ | 
 |       offset = 0x80000000; | 
 |     } | 
 |   else | 
 |     { | 
 |       /* Calculate symbol-to-instruction offset.  */ | 
 |       branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; | 
 |       /* If the destination symbol is beyond current frag address, | 
 | 	 STRETCH will take effect to symbol's position.  */ | 
 |       if (S_GET_VALUE (branch_symbol) > fragP->fr_address) | 
 | 	branch_target_address += stretch; | 
 |  | 
 |       branch_insn_address = fragP->fr_address + fragP->fr_fix; | 
 |       branch_insn_address -= opcode->isize; | 
 |  | 
 |       /* Update BRANCH_INSN_ADDRESS to relaxed position.  */ | 
 |       branch_insn_address += (relax_info->relax_code_size[branch_range_type] | 
 | 			      - relax_info->relax_branch_isize[branch_range_type]); | 
 |  | 
 |       offset = branch_target_address - branch_insn_address; | 
 |     } | 
 |  | 
 |   return offset; | 
 | } | 
 |  | 
 | static enum nds32_br_range | 
 | nds32_convert_to_range_type (long offset) | 
 | { | 
 |   enum nds32_br_range range_type; | 
 |  | 
 |   if (-(0x100) <= offset && offset < 0x100) /* 256 bytes */ | 
 |     range_type = BR_RANGE_S256; | 
 |   else if (-(0x4000) <= offset && offset < 0x4000) /* 16K bytes */ | 
 |     range_type = BR_RANGE_S16K; | 
 |   else if (-(0x10000) <= offset && offset < 0x10000) /* 64K bytes */ | 
 |     range_type = BR_RANGE_S64K; | 
 |   else if (-(0x1000000) <= offset && offset < 0x1000000) /* 16M bytes */ | 
 |     range_type = BR_RANGE_S16M; | 
 |   else /* 4G bytes */ | 
 |     range_type = BR_RANGE_U4G; | 
 |  | 
 |   return range_type; | 
 | } | 
 |  | 
 | /* Set instruction register mask.  */ | 
 |  | 
 | static void | 
 | nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn, | 
 | 			uint32_t ori_insn, int range) | 
 | { | 
 |   nds32_cond_field_t *cond_fields = relax_info->cond_field; | 
 |   nds32_cond_field_t *code_seq_cond = relax_info->relax_code_condition[range]; | 
 |   uint32_t mask; | 
 |   int i = 0; | 
 |  | 
 |   /* The instruction has conditions.  Collect condition values.  */ | 
 |   while (code_seq_cond[i].bitmask != 0) | 
 |     { | 
 |       if (offset == code_seq_cond[i].offset) | 
 | 	{ | 
 | 	  mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask; | 
 | 	  /* Sign extend.  */ | 
 | 	  if (cond_fields[i].signed_extend) | 
 | 	    mask = (mask ^ ((cond_fields[i].bitmask + 1) >> 1)) - | 
 | 	      ((cond_fields[i].bitmask + 1) >> 1); | 
 | 	  *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos; | 
 | 	} | 
 |       i++; | 
 |     } | 
 | } | 
 |  | 
 | static int | 
 | nds32_relax_branch_instructions (segT segment, fragS *fragP, | 
 | 				 long stretch ATTRIBUTE_UNUSED, | 
 | 				 int init) | 
 | { | 
 |   enum nds32_br_range branch_range_type; | 
 |   struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; | 
 |   long offset = 0; | 
 |   enum nds32_br_range real_range_type; | 
 |   int adjust = 0; | 
 |   relax_info_t *relax_info; | 
 |   int diff = 0; | 
 |   int i, j, k; | 
 |   int code_seq_size; | 
 |   uint32_t *code_seq; | 
 |   uint32_t insn; | 
 |   int insn_size; | 
 |   int code_seq_offset; | 
 |  | 
 |   /* Replace with gas_assert (fragP->fr_symbol != NULL); */ | 
 |   if (fragP->fr_symbol == NULL) | 
 |     return adjust; | 
 |  | 
 |   /* If frag_var is not enough room, the previous frag is fr_full and with | 
 |      opcode.  The new one is rs_dependent but without opcode.  */ | 
 |   if (opcode == NULL) | 
 |     return adjust; | 
 |  | 
 |   /* Use U4G mode for b and bal in verbatim mode because lto may combine | 
 |      functions into a file.  And order the file in the last when linking. | 
 |      Once there is multiple definition, the same function will be kicked. | 
 |      This may cause relocation truncated error.  */ | 
 |   if (verbatim && !nds32_pic | 
 |       && (strcmp (opcode->opcode, "j") == 0 | 
 | 	  || strcmp (opcode->opcode, "jal") == 0)) | 
 |     { | 
 |       fragP->fr_subtype = BR_RANGE_U4G; | 
 |       if (init) | 
 | 	return 8; | 
 |       else | 
 | 	return 0; | 
 |     } | 
 |  | 
 |   relax_info = str_hash_find (nds32_relax_info_hash, opcode->opcode); | 
 |  | 
 |   if (relax_info == NULL) | 
 |     return adjust; | 
 |  | 
 |   if (init) | 
 |     { | 
 |       branch_range_type = relax_info->br_range; | 
 |       i = BR_RANGE_S256; | 
 |     } | 
 |   else | 
 |     { | 
 |       branch_range_type = fragP->fr_subtype; | 
 |       i = branch_range_type; | 
 |     } | 
 |  | 
 |   offset = nds32_calc_branch_offset (segment, fragP, stretch, | 
 | 				     relax_info, branch_range_type); | 
 |  | 
 |   real_range_type = nds32_convert_to_range_type (offset); | 
 |  | 
 |   /* If actual range is equal to instruction jump range, do nothing.  */ | 
 |   if (real_range_type == branch_range_type) | 
 |     { | 
 |       fragP->fr_subtype = real_range_type; | 
 |       return adjust; | 
 |     } | 
 |  | 
 |   /* Find out proper relaxation code sequence.  */ | 
 |   for (; i < BR_RANGE_NUM; i++) | 
 |     { | 
 |       if (real_range_type <= (unsigned int) i) | 
 | 	{ | 
 | 	  if (init) | 
 | 	    diff = relax_info->relax_code_size[i] - opcode->isize; | 
 | 	  else if (real_range_type < (unsigned int) i) | 
 | 	    diff = relax_info->relax_code_size[real_range_type] | 
 | 	      - relax_info->relax_code_size[branch_range_type]; | 
 | 	  else | 
 | 	    diff = relax_info->relax_code_size[i] | 
 | 	      - relax_info->relax_code_size[branch_range_type]; | 
 |  | 
 | 	  /* If the instruction could be converted to 16-bits, | 
 | 	     minus the difference.  */ | 
 | 	  code_seq_offset = 0; | 
 | 	  j = 0; | 
 | 	  k = 0; | 
 | 	  code_seq_size = relax_info->relax_code_size[i]; | 
 | 	  code_seq = relax_info->relax_code_seq[i]; | 
 | 	  while (code_seq_offset < code_seq_size) | 
 | 	    { | 
 | 	      insn = code_seq[j]; | 
 | 	      if (insn & 0x80000000) /* 16-bits instruction.  */ | 
 | 		{ | 
 | 		  insn_size = 2; | 
 | 		} | 
 | 	      else /* 32-bits instruction.  */ | 
 | 		{ | 
 | 		  insn_size = 4; | 
 |  | 
 | 		  while (relax_info->relax_fixup[i][k].size !=0 | 
 | 			 && relax_info->relax_fixup[i][k].offset < code_seq_offset) | 
 | 		    k++; | 
 | 		} | 
 |  | 
 | 	      code_seq_offset += insn_size; | 
 | 	      j++; | 
 | 	    } | 
 |  | 
 | 	  /* Update fr_subtype to new NDS32_BR_RANGE.  */ | 
 | 	  fragP->fr_subtype = real_range_type; | 
 | 	  break; | 
 | 	} | 
 |     } | 
 |  | 
 |   return diff + adjust; | 
 | } | 
 |  | 
 | /* Adjust relaxable frag till current frag.  */ | 
 |  | 
 | static int | 
 | nds32_adjust_relaxable_frag (fragS *startP, fragS *fragP) | 
 | { | 
 |   int adj; | 
 |   if (startP->tc_frag_data.flag & NDS32_FRAG_RELAXED) | 
 |     adj = -2; | 
 |   else | 
 |     adj = 2; | 
 |  | 
 |   startP->tc_frag_data.flag ^= NDS32_FRAG_RELAXED; | 
 |  | 
 |   while (startP) | 
 |     { | 
 |       startP = startP->fr_next; | 
 |       if (startP) | 
 | 	{ | 
 | 	  startP->fr_address += adj; | 
 | 	  if (startP == fragP) | 
 | 	    break; | 
 | 	} | 
 |     } | 
 |   return adj; | 
 | } | 
 |  | 
 | static addressT | 
 | nds32_get_align (addressT address, int align) | 
 | { | 
 |   addressT mask, new_address; | 
 |  | 
 |   mask = ~((addressT) (~0) << align); | 
 |   new_address = (address + mask) & (~mask); | 
 |   return (new_address - address); | 
 | } | 
 |  | 
 | /* Check the prev_frag is legal.  */ | 
 | static void | 
 | invalid_prev_frag (fragS * fragP, fragS **prev_frag, bool relax) | 
 | { | 
 |   addressT address; | 
 |   fragS *frag_start = *prev_frag; | 
 |  | 
 |   if (!frag_start || !relax) | 
 |     return; | 
 |  | 
 |   if (frag_start->last_fr_address >= fragP->last_fr_address) | 
 |     { | 
 |       *prev_frag = NULL; | 
 |       return; | 
 |     } | 
 |  | 
 |   fragS *frag_t = *prev_frag; | 
 |   while (frag_t != fragP) | 
 |     { | 
 |       if (frag_t->fr_type == rs_align | 
 | 	  || frag_t->fr_type == rs_align_code | 
 | 	  || frag_t->fr_type == rs_align_test) | 
 | 	{ | 
 | 	  /* Relax instruction can not walk across label.  */ | 
 | 	  if (frag_t->tc_frag_data.flag & NDS32_FRAG_LABEL) | 
 | 	    { | 
 | 	      prev_frag = NULL; | 
 | 	      return; | 
 | 	    } | 
 | 	  /* Relax previous relaxable to align rs_align frag.  */ | 
 | 	  address = frag_t->fr_address + frag_t->fr_fix; | 
 | 	  addressT offset = nds32_get_align (address, (int) frag_t->fr_offset); | 
 | 	  if (offset & 0x2) | 
 | 	    { | 
 | 	      /* If there is label on the prev_frag, check if it is aligned.  */ | 
 | 	      if (!((*prev_frag)->tc_frag_data.flag & NDS32_FRAG_LABEL) | 
 | 		  || (((*prev_frag)->fr_address + (*prev_frag)->fr_fix  - 2 ) | 
 | 		      & 0x2) == 0) | 
 | 		nds32_adjust_relaxable_frag (*prev_frag, frag_t); | 
 | 	    } | 
 | 	  *prev_frag = NULL; | 
 | 	  return; | 
 | 	} | 
 |       frag_t = frag_t->fr_next; | 
 |     } | 
 |  | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_ALIGN) | 
 |     { | 
 |       address = fragP->fr_address; | 
 |       addressT offset = nds32_get_align (address, 2); | 
 |       if (offset & 0x2) | 
 | 	{ | 
 | 	  /* If there is label on the prev_frag, check if it is aligned.  */ | 
 | 	  if (!((*prev_frag)->tc_frag_data.flag & NDS32_FRAG_LABEL) | 
 | 	      || (((*prev_frag)->fr_address + (*prev_frag)->fr_fix  - 2 ) | 
 | 		  & 0x2) == 0) | 
 | 	    nds32_adjust_relaxable_frag (*prev_frag, fragP); | 
 | 	} | 
 |       *prev_frag = NULL; | 
 |       return; | 
 |     } | 
 | } | 
 |  | 
 | /* md_relax_frag  */ | 
 |  | 
 | int | 
 | nds32_relax_frag (segT segment, fragS *fragP, long stretch ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Currently, there are two kinds of relaxation in nds32 assembler. | 
 |      1. relax for branch | 
 |      2. relax for 32-bits to 16-bits  */ | 
 |  | 
 |   static fragS *prev_frag = NULL; | 
 |   int adjust = 0; | 
 |  | 
 |   invalid_prev_frag (fragP, &prev_frag, true); | 
 |  | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH) | 
 |     adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0); | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL) | 
 |     prev_frag = NULL; | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE | 
 |       && (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) == 0) | 
 |     /* Here is considered relaxed case originally.  But it may cause | 
 |        an endless loop when relaxing.  Once the instruction is relaxed, | 
 |        it can not be undone.  */ | 
 |     prev_frag = fragP; | 
 |  | 
 |   return adjust; | 
 | } | 
 |  | 
 | /* This function returns an initial guess of the length by which a fragment | 
 |    must grow to hold a branch to reach its destination.  Also updates | 
 |    fr_type/fr_subtype as necessary. | 
 |  | 
 |    It is called just before doing relaxation.  Any symbol that is now undefined | 
 |    will not become defined.  The guess for fr_var is ACTUALLY the growth beyond | 
 |    fr_fix.  Whatever we do to grow fr_fix or fr_var contributes to our returned | 
 |    value.  Although it may not be explicit in the frag, pretend fr_var starts | 
 |    with a 0 value.  */ | 
 |  | 
 | int | 
 | md_estimate_size_before_relax (fragS *fragP, segT segment) | 
 | { | 
 |   /* Currently, there are two kinds of relaxation in nds32 assembler. | 
 |      1. relax for branch | 
 |      2. relax for 32-bits to 16-bits  */ | 
 |  | 
 |   /* Save previous relaxable frag.  */ | 
 |   static fragS *prev_frag = NULL; | 
 |   int adjust = 0; | 
 |  | 
 |   invalid_prev_frag (fragP, &prev_frag, false); | 
 |  | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH) | 
 |     adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1); | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_LABEL) | 
 |     prev_frag = NULL; | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) | 
 |     adjust = 2; | 
 |   else if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE) | 
 |     prev_frag = fragP; | 
 |  | 
 |   return adjust; | 
 | } | 
 |  | 
 | /* GAS will call this for each rs_machine_dependent fragment.  The instruction | 
 |    is completed using the data from the relaxation pass.  It may also create any | 
 |    necessary relocations. | 
 |  | 
 |    *FRAGP has been relaxed to its final size, and now needs to have the bytes | 
 |    inside it modified to conform to the new size.  It is called after relaxation | 
 |    is finished. | 
 |  | 
 |    fragP->fr_type == rs_machine_dependent. | 
 |    fragP->fr_subtype is the subtype of what the address relaxed to.  */ | 
 |  | 
 | void | 
 | md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP) | 
 | { | 
 |   /* Convert branch relaxation instructions.  */ | 
 |   symbolS *branch_symbol = fragP->fr_symbol; | 
 |   offsetT branch_offset = fragP->fr_offset; | 
 |   enum nds32_br_range branch_range_type = fragP->fr_subtype; | 
 |   struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; | 
 |   uint32_t origin_insn = fragP->tc_frag_data.insn; | 
 |   relax_info_t *relax_info; | 
 |   char *fr_buffer; | 
 |   int fr_where; | 
 |   int addend ATTRIBUTE_UNUSED; | 
 |   offsetT branch_target_address, branch_insn_address; | 
 |   expressionS exp; | 
 |   fixS *fixP; | 
 |   uint32_t *code_seq; | 
 |   uint32_t insn; | 
 |   int code_size, insn_size, offset, fixup_size; | 
 |   int buf_offset, pcrel; | 
 |   int i, k; | 
 |   uint16_t insn_16; | 
 |   nds32_relax_fixup_info_t fixup_info[MAX_RELAX_FIX]; | 
 |   /* Save the 1st instruction is converted to 16 bit or not.  */ | 
 |   unsigned int branch_size; | 
 |   enum bfd_reloc_code_real final_r_type; | 
 |  | 
 |   /* Replace with gas_assert (branch_symbol != NULL); */ | 
 |   if (branch_symbol == NULL && !(fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED)) | 
 |     return; | 
 |  | 
 |   /* If frag_var is not enough room, the previous frag is fr_full and with | 
 |      opcode.  The new one is rs_dependent but without opcode.  */ | 
 |   if (opcode == NULL) | 
 |     return; | 
 |  | 
 |   if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXABLE_BRANCH) | 
 |     { | 
 |       relax_info = str_hash_find (nds32_relax_info_hash, opcode->opcode); | 
 |  | 
 |       if (relax_info == NULL) | 
 | 	return; | 
 |  | 
 |       i = BR_RANGE_S256; | 
 |       while (i < BR_RANGE_NUM | 
 | 	     && relax_info->relax_code_size[i] | 
 | 	     != (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED ? 4 : 2)) | 
 | 	i++; | 
 |  | 
 |       if (i >= BR_RANGE_NUM) | 
 | 	as_bad ("Internal error: Cannot find relocation of" | 
 | 		"relaxable branch."); | 
 |  | 
 |       exp.X_op = O_symbol; | 
 |       exp.X_add_symbol = branch_symbol; | 
 |       exp.X_add_number = branch_offset; | 
 |       pcrel = ((relax_info->relax_fixup[i][0].ramp & NDS32_PCREL) != 0) ? 1 : 0; | 
 |       fr_where = fragP->fr_fix - 2; | 
 |       fixP = fix_new_exp (fragP, fr_where, relax_info->relax_fixup[i][0].size, | 
 | 			  &exp, pcrel, relax_info->relax_fixup[i][0].r_type); | 
 |       fixP->fx_addnumber = fixP->fx_offset; | 
 |  | 
 |       if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) | 
 | 	{ | 
 | 	  insn_16 = fragP->tc_frag_data.insn; | 
 | 	  nds32_convert_16_to_32 (stdoutput, insn_16, &insn); | 
 | 	  fr_buffer = fragP->fr_literal + fr_where; | 
 | 	  fragP->fr_fix += 2; | 
 | 	  exp.X_op = O_symbol; | 
 | 	  exp.X_add_symbol = abs_section_sym; | 
 | 	  exp.X_add_number = 0; | 
 | 	  fix_new_exp (fragP, fr_where, 4, | 
 | 		       &exp, 0, BFD_RELOC_NDS32_INSN16); | 
 | 	  number_to_chars_bigendian (fr_buffer, insn, 4); | 
 | 	} | 
 |     } | 
 |   else if (fragP->tc_frag_data.flag & NDS32_FRAG_RELAXED) | 
 |     { | 
 |       if (fragP->tc_frag_data.opcode->isize == 2) | 
 | 	{ | 
 | 	  insn_16 = fragP->tc_frag_data.insn; | 
 | 	  nds32_convert_16_to_32 (stdoutput, insn_16, &insn); | 
 | 	} | 
 |       else | 
 | 	insn = fragP->tc_frag_data.insn; | 
 |       fragP->fr_fix += 2; | 
 |       fr_where = fragP->fr_fix - 4; | 
 |       fr_buffer = fragP->fr_literal + fr_where; | 
 |       exp.X_op = O_symbol; | 
 |       exp.X_add_symbol = abs_section_sym; | 
 |       exp.X_add_number = 0; | 
 |       fix_new_exp (fragP, fr_where, 4, &exp, 0, | 
 | 		   BFD_RELOC_NDS32_INSN16); | 
 |       number_to_chars_bigendian (fr_buffer, insn, 4); | 
 |     } | 
 |   else if (fragP->tc_frag_data.flag & NDS32_FRAG_BRANCH) | 
 |     { | 
 |       /* Branch instruction adjust and append relocations.  */ | 
 |       relax_info = str_hash_find (nds32_relax_info_hash, opcode->opcode); | 
 |  | 
 |       if (relax_info == NULL) | 
 | 	return; | 
 |  | 
 |       fr_where = fragP->fr_fix - opcode->isize; | 
 |       fr_buffer = fragP->fr_literal + fr_where; | 
 |  | 
 |       if ((S_GET_SEGMENT (branch_symbol) != sec) | 
 | 	  || S_IS_WEAK (branch_symbol)) | 
 | 	{ | 
 | 	  if (fragP->fr_offset & 3) | 
 | 	    as_warn (_("Addend to unresolved symbol is not on word boundary.")); | 
 | 	  addend = 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Calculate symbol-to-instruction offset.  */ | 
 | 	  branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; | 
 | 	  branch_insn_address = fragP->fr_address + fr_where; | 
 | 	  addend = (branch_target_address - branch_insn_address) >> 1; | 
 | 	} | 
 |  | 
 |       code_size = relax_info->relax_code_size[branch_range_type]; | 
 |       code_seq = relax_info->relax_code_seq[branch_range_type]; | 
 |  | 
 |       memcpy (fixup_info, relax_info->relax_fixup[branch_range_type], | 
 | 	      sizeof (fixup_info)); | 
 |  | 
 |       /* Fill in frag.  */ | 
 |       i = 0; | 
 |       k = 0; | 
 |       offset = 0; /* code_seq offset */ | 
 |       buf_offset = 0; /* fr_buffer offset */ | 
 |       while (offset < code_size) | 
 | 	{ | 
 | 	  insn = code_seq[i]; | 
 | 	  if (insn & 0x80000000) /* 16-bits instruction.  */ | 
 | 	    { | 
 | 	      insn = (insn >> 16) & 0xFFFF; | 
 | 	      insn_size = 2; | 
 | 	    } | 
 | 	  else /* 32-bits instruction.  */ | 
 | 	    { | 
 | 	      insn_size = 4; | 
 | 	    } | 
 |  | 
 | 	  nds32_elf_get_set_cond (relax_info, offset, &insn, | 
 | 				  origin_insn, branch_range_type); | 
 |  | 
 | 	  /* Try to convert to 16-bits instruction.  Currently, only the first | 
 | 	     instruction in pattern can be converted.  EX: bnez sethi ori jr, | 
 | 	     only bnez can be converted to 16 bit and ori can't.  */ | 
 |  | 
 | 	  while (fixup_info[k].size != 0 | 
 | 		 && relax_info->relax_fixup[branch_range_type][k].offset < offset) | 
 | 	    k++; | 
 |  | 
 | 	  number_to_chars_bigendian (fr_buffer + buf_offset, insn, insn_size); | 
 | 	  buf_offset += insn_size; | 
 |  | 
 | 	  offset += insn_size; | 
 | 	  i++; | 
 | 	} | 
 |  | 
 |       /* Set up fixup.  */ | 
 |       exp.X_op = O_symbol; | 
 |  | 
 |       for (i = 0; fixup_info[i].size != 0; i++) | 
 | 	{ | 
 | 	  fixup_size = fixup_info[i].size; | 
 | 	  pcrel = ((fixup_info[i].ramp & NDS32_PCREL) != 0) ? 1 : 0; | 
 |  | 
 | 	  if ((fixup_info[i].ramp & NDS32_CREATE_LABEL) != 0) | 
 | 	    { | 
 | 	      /* This is a reverse branch.  */ | 
 | 	      exp.X_add_symbol = symbol_temp_new (sec, fragP->fr_next, 0); | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else if ((fixup_info[i].ramp & NDS32_PTR) != 0) | 
 | 	    { | 
 | 	      /* This relocation has to point to another instruction.  */ | 
 | 	      branch_size = fr_where + code_size - 4; | 
 | 	      exp.X_add_symbol = symbol_temp_new (sec, fragP, branch_size); | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else if ((fixup_info[i].ramp & NDS32_ABS) != 0) | 
 | 	    { | 
 | 	      /* This is a tag relocation.  */ | 
 | 	      exp.X_add_symbol = abs_section_sym; | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else if ((fixup_info[i].ramp & NDS32_INSN16) != 0) | 
 | 	    { | 
 | 	      if (!enable_16bit) | 
 | 		continue; | 
 | 	      /* This is a tag relocation.  */ | 
 | 	      exp.X_add_symbol = abs_section_sym; | 
 | 	      exp.X_add_number = 0; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      exp.X_add_symbol = branch_symbol; | 
 | 	      exp.X_add_number = branch_offset; | 
 | 	    } | 
 |  | 
 | 	  if (fixup_info[i].r_type != 0) | 
 | 	    { | 
 | 	      final_r_type = fixup_info[i].r_type; | 
 | 	      fixP = fix_new_exp (fragP, fr_where + fixup_info[i].offset, | 
 | 				  fixup_size, &exp, pcrel, | 
 | 				  final_r_type); | 
 | 	      fixP->fx_addnumber = fixP->fx_offset; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       fragP->fr_fix = fr_where + buf_offset; | 
 |     } | 
 | } | 
 |  | 
 | /* tc_frob_file_before_fix  */ | 
 |  | 
 | void | 
 | nds32_frob_file_before_fix (void) | 
 | { | 
 | } | 
 |  | 
 | static bool | 
 | nds32_relaxable_section (asection *sec) | 
 | { | 
 |   return ((sec->flags & SEC_DEBUGGING) == 0 | 
 | 	  && strcmp (sec->name, ".eh_frame") != 0); | 
 | } | 
 |  | 
 | /* TC_FORCE_RELOCATION */ | 
 | int | 
 | nds32_force_relocation (fixS * fix) | 
 | { | 
 |   switch (fix->fx_r_type) | 
 |     { | 
 |     case BFD_RELOC_NDS32_INSN16: | 
 |     case BFD_RELOC_NDS32_LABEL: | 
 |     case BFD_RELOC_NDS32_LONGCALL1: | 
 |     case BFD_RELOC_NDS32_LONGCALL2: | 
 |     case BFD_RELOC_NDS32_LONGCALL3: | 
 |     case BFD_RELOC_NDS32_LONGJUMP1: | 
 |     case BFD_RELOC_NDS32_LONGJUMP2: | 
 |     case BFD_RELOC_NDS32_LONGJUMP3: | 
 |     case BFD_RELOC_NDS32_LOADSTORE: | 
 |     case BFD_RELOC_NDS32_9_FIXED: | 
 |     case BFD_RELOC_NDS32_15_FIXED: | 
 |     case BFD_RELOC_NDS32_17_FIXED: | 
 |     case BFD_RELOC_NDS32_25_FIXED: | 
 |     case BFD_RELOC_NDS32_9_PCREL: | 
 |     case BFD_RELOC_NDS32_15_PCREL: | 
 |     case BFD_RELOC_NDS32_17_PCREL: | 
 |     case BFD_RELOC_NDS32_WORD_9_PCREL: | 
 |     case BFD_RELOC_NDS32_10_UPCREL: | 
 |     case BFD_RELOC_NDS32_25_PCREL: | 
 |     case BFD_RELOC_NDS32_MINUEND: | 
 |     case BFD_RELOC_NDS32_SUBTRAHEND: | 
 |       return 1; | 
 |  | 
 |     case BFD_RELOC_8: | 
 |     case BFD_RELOC_16: | 
 |     case BFD_RELOC_32: | 
 |     case BFD_RELOC_NDS32_DIFF_ULEB128: | 
 |       /* Linker should handle difference between two symbol.  */ | 
 |       return fix->fx_subsy != NULL | 
 | 	&& nds32_relaxable_section (S_GET_SEGMENT (fix->fx_addsy)); | 
 |     case BFD_RELOC_64: | 
 |       if (fix->fx_subsy) | 
 | 	as_bad ("Double word for difference between two symbols " | 
 | 		"is not supported across relaxation."); | 
 |     default: | 
 |       ; | 
 |     } | 
 |  | 
 |   if (generic_force_reloc (fix)) | 
 |     return 1; | 
 |  | 
 |   return fix->fx_pcrel; | 
 | } | 
 |  | 
 | /* TC_VALIDATE_FIX_SUB  */ | 
 |  | 
 | int | 
 | nds32_validate_fix_sub (fixS *fix, segT add_symbol_segment) | 
 | { | 
 |   segT sub_symbol_segment; | 
 |  | 
 |   /* This code is referred from Xtensa.  Check their implementation for | 
 |      details.  */ | 
 |  | 
 |   /* Make sure both symbols are in the same segment, and that segment is | 
 |      "normal" and relaxable.  */ | 
 |   sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy); | 
 |   return (sub_symbol_segment == add_symbol_segment | 
 | 	  && add_symbol_segment != undefined_section); | 
 | } | 
 |  | 
 | 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); | 
 | } | 
 |  | 
 | /* This function is called to convert an ASCII string into a floating point | 
 |    value in format used by the CPU.  */ | 
 |  | 
 | const char * | 
 | md_atof (int type, char *litP, int *sizeP) | 
 | { | 
 |   int i; | 
 |   int prec; | 
 |   LITTLENUM_TYPE words[MAX_LITTLENUMS]; | 
 |   char *t; | 
 |  | 
 |   switch (type) | 
 |     { | 
 |     case 'f': | 
 |     case 'F': | 
 |     case 's': | 
 |     case 'S': | 
 |       prec = 2; | 
 |       break; | 
 |     case 'd': | 
 |     case 'D': | 
 |     case 'r': | 
 |     case 'R': | 
 |       prec = 4; | 
 |       break; | 
 |     default: | 
 |       *sizeP = 0; | 
 |       return _("Bad call to md_atof()"); | 
 |     } | 
 |  | 
 |   t = atof_ieee (input_line_pointer, type, words); | 
 |   if (t) | 
 |     input_line_pointer = t; | 
 |   *sizeP = prec * sizeof (LITTLENUM_TYPE); | 
 |  | 
 |   if (target_big_endian) | 
 |     { | 
 |       for (i = 0; i < prec; i++) | 
 | 	{ | 
 | 	  md_number_to_chars (litP, (valueT) words[i], | 
 | 			      sizeof (LITTLENUM_TYPE)); | 
 | 	  litP += sizeof (LITTLENUM_TYPE); | 
 | 	} | 
 |     } | 
 |   else | 
 |     { | 
 |       for (i = prec - 1; i >= 0; i--) | 
 | 	{ | 
 | 	  md_number_to_chars (litP, (valueT) words[i], | 
 | 			      sizeof (LITTLENUM_TYPE)); | 
 | 	  litP += sizeof (LITTLENUM_TYPE); | 
 | 	} | 
 |     } | 
 |  | 
 |   return 0; | 
 | } | 
 |  | 
 | /* md_elf_section_change_hook  */ | 
 |  | 
 | void | 
 | nds32_elf_section_change_hook (void) | 
 | { | 
 | } | 
 |  | 
 | /* md_cleanup  */ | 
 |  | 
 | void | 
 | nds32_cleanup (void) | 
 | { | 
 | } | 
 |  | 
 | /* This function is used to scan leb128 subtraction expressions, | 
 |    and insert fixups for them. | 
 |  | 
 |       e.g., .leb128  .L1 - .L0 | 
 |  | 
 |    These expressions are heavily used in debug information or | 
 |    exception tables.  Because relaxation will change code size, | 
 |    we must resolve them in link time.  */ | 
 |  | 
 | static void | 
 | nds32_insert_leb128_fixes (bfd *abfd ATTRIBUTE_UNUSED, | 
 | 			   asection *sec, void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo = seg_info (sec); | 
 |   struct frag *fragP; | 
 |  | 
 |   subseg_set (sec, 0); | 
 |  | 
 |   for (fragP = seginfo->frchainP->frch_root; | 
 |        fragP; fragP = fragP->fr_next) | 
 |     { | 
 |       expressionS *exp; | 
 |  | 
 |       /* Only unsigned leb128 can be handle.  */ | 
 |       if (fragP->fr_type != rs_leb128 || fragP->fr_subtype != 0 | 
 | 	  || fragP->fr_symbol == NULL) | 
 | 	continue; | 
 |  | 
 |       exp = symbol_get_value_expression (fragP->fr_symbol); | 
 |  | 
 |       if (exp->X_op != O_subtract) | 
 | 	continue; | 
 |  | 
 |       fix_new_exp (fragP, fragP->fr_fix, 0, | 
 | 		   exp, 0, BFD_RELOC_NDS32_DIFF_ULEB128); | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, | 
 | 			  void *xxx ATTRIBUTE_UNUSED) | 
 | { | 
 |   segment_info_type *seginfo; | 
 |   fragS *fragP; | 
 |   fixS *fixP; | 
 |   expressionS exp; | 
 |   fixS *fixp; | 
 |  | 
 |   seginfo = seg_info (sec); | 
 |   if (!seginfo || !symbol_rootP || !subseg_text_p (sec) || sec->size == 0) | 
 |     return; | 
 |  | 
 |   for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) | 
 |     if (!fixp->fx_done) | 
 |       break; | 
 |  | 
 |   if (!fixp && !verbatim && ict_flag == ICT_NONE) | 
 |     return; | 
 |  | 
 |   subseg_change (sec, 0); | 
 |  | 
 |   /* Set RELAX_ENTRY flags for linker.  */ | 
 |   fragP = seginfo->frchainP->frch_root; | 
 |   exp.X_op = O_symbol; | 
 |   exp.X_add_symbol = abs_section_sym; | 
 |   exp.X_add_number = 0; | 
 |   if (!enable_relax_relocs) | 
 |     exp.X_add_number |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG; | 
 |   else | 
 |     { | 
 |       /* These flags are only enabled when global relax is enabled. | 
 | 	 Maybe we can check DISABLE_RELAX_FLAG at link-time, | 
 | 	 so we set them anyway.  */ | 
 |       if (verbatim) | 
 | 	exp.X_add_number |= R_NDS32_RELAX_ENTRY_VERBATIM_FLAG; | 
 |       if (ict_flag == ICT_SMALL) | 
 | 	exp.X_add_number |= R_NDS32_RELAX_ENTRY_ICT_SMALL; | 
 |       else if (ict_flag == ICT_LARGE) | 
 | 	exp.X_add_number |= R_NDS32_RELAX_ENTRY_ICT_LARGE; | 
 |     } | 
 |   if (optimize) | 
 |     exp.X_add_number |= R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG; | 
 |   if (optimize_for_space) | 
 |     exp.X_add_number |= R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG; | 
 |  | 
 |   fixP = fix_new_exp (fragP, 0, 0, &exp, 0, BFD_RELOC_NDS32_RELAX_ENTRY); | 
 |   fixP->fx_no_overflow = 1; | 
 | } | 
 |  | 
 | /* Analysis relax hint and insert suitable relocation pattern.  */ | 
 |  | 
 | static void | 
 | nds32_elf_analysis_relax_hint (void) | 
 | { | 
 |   htab_traverse_noresize (nds32_hint_hash, | 
 | 			  nds32_elf_append_relax_relocs_traverse, NULL); | 
 | } | 
 |  | 
 | static void | 
 | nds32_elf_insert_final_frag (void) | 
 | { | 
 |   struct frchain *frchainP; | 
 |   asection *s; | 
 |   fragS *fragP; | 
 |  | 
 |   if (!optimize) | 
 |     return; | 
 |  | 
 |   for (s = stdoutput->sections; s; s = s->next) | 
 |     { | 
 |       segment_info_type *seginfo = seg_info (s); | 
 |       if (!seginfo) | 
 | 	continue; | 
 |  | 
 |       for (frchainP = seginfo->frchainP; frchainP != NULL; | 
 | 	   frchainP = frchainP->frch_next) | 
 | 	{ | 
 | 	  subseg_set (s, frchainP->frch_subseg); | 
 |  | 
 | 	  if (subseg_text_p (now_seg)) | 
 | 	    { | 
 | 	      fragP = frag_now; | 
 | 	      frag_var (rs_machine_dependent, 2, /* Max size.  */ | 
 | 			0, /* VAR is un-used.  */ 0, NULL, 0, NULL); | 
 | 	      fragP->tc_frag_data.flag |= NDS32_FRAG_FINAL; | 
 | 	    } | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | md_finish (void) | 
 | { | 
 |   nds32_elf_insert_final_frag (); | 
 |   nds32_elf_analysis_relax_hint (); | 
 |   bfd_map_over_sections (stdoutput, nds32_insert_leb128_fixes, NULL); | 
 | } | 
 |  | 
 | /* Implement md_allow_local_subtract.  */ | 
 |  | 
 | bool | 
 | nds32_allow_local_subtract (expressionS *expr_l ATTRIBUTE_UNUSED, | 
 | 			    expressionS *expr_r ATTRIBUTE_UNUSED, | 
 | 			    segT sec ATTRIBUTE_UNUSED) | 
 | { | 
 |   /* Don't allow any subtraction, because relax may change the code.  */ | 
 |   return false; | 
 | } | 
 |  | 
 | long | 
 | nds32_pcrel_from_section (fixS *fixP, segT sec ATTRIBUTE_UNUSED) | 
 | { | 
 |   if (fixP->fx_addsy == NULL || !S_IS_DEFINED (fixP->fx_addsy) | 
 |       || S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)) | 
 |     { | 
 |       /* Let linker resolve undefined symbols.  */ | 
 |       return 0; | 
 |     } | 
 |  | 
 |   return fixP->fx_frag->fr_address + fixP->fx_where; | 
 | } | 
 |  | 
 | /* md_post_relax_hook () | 
 |    Insert relax entry relocation into sections.  */ | 
 |  | 
 | void | 
 | nds32_post_relax_hook (void) | 
 | { | 
 |   bfd_map_over_sections (stdoutput, nds32_insert_relax_entry, NULL); | 
 | } | 
 |  | 
 | /* tc_fix_adjustable () | 
 |  | 
 |    Return whether this symbol (fixup) can be replaced with | 
 |    section symbols.  */ | 
 |  | 
 | bool | 
 | nds32_fix_adjustable (fixS *fixP) | 
 | { | 
 |   switch (fixP->fx_r_type) | 
 |     { | 
 |     case BFD_RELOC_NDS32_WORD_9_PCREL: | 
 |     case BFD_RELOC_NDS32_9_PCREL: | 
 |     case BFD_RELOC_NDS32_15_PCREL: | 
 |     case BFD_RELOC_NDS32_17_PCREL: | 
 |     case BFD_RELOC_NDS32_25_PCREL: | 
 |     case BFD_RELOC_NDS32_HI20: | 
 |     case BFD_RELOC_NDS32_LO12S0: | 
 |     case BFD_RELOC_8: | 
 |     case BFD_RELOC_16: | 
 |     case BFD_RELOC_32: | 
 |     case BFD_RELOC_NDS32_PTR: | 
 |     case BFD_RELOC_NDS32_LONGCALL4: | 
 |     case BFD_RELOC_NDS32_LONGCALL5: | 
 |     case BFD_RELOC_NDS32_LONGCALL6: | 
 |     case BFD_RELOC_NDS32_LONGJUMP4: | 
 |     case BFD_RELOC_NDS32_LONGJUMP5: | 
 |     case BFD_RELOC_NDS32_LONGJUMP6: | 
 |     case BFD_RELOC_NDS32_LONGJUMP7: | 
 |       return 1; | 
 |     default: | 
 |       return 0; | 
 |     } | 
 | } | 
 |  | 
 | /* elf_tc_final_processing  */ | 
 |  | 
 | void | 
 | elf_nds32_final_processing (void) | 
 | { | 
 |   /* An FPU_COM instruction is found without previous non-FPU_COM | 
 |      instruction.  */ | 
 |   if (nds32_fpu_com | 
 |       && !(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST))) | 
 |     { | 
 |       /* Since only FPU_COM instructions are used and no other FPU instructions | 
 | 	 are used.  The nds32_elf_flags will be decided by the enabled options | 
 | 	 by command line or default configuration.  */ | 
 |       if (nds32_fpu_dp_ext || nds32_fpu_sp_ext) | 
 | 	{ | 
 | 	  nds32_elf_flags |= nds32_fpu_dp_ext ? E_NDS32_HAS_FPU_DP_INST : 0; | 
 | 	  nds32_elf_flags |= nds32_fpu_sp_ext ? E_NDS32_HAS_FPU_INST : 0; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Should never here.  */ | 
 | 	  as_bad (_("Used FPU instructions requires enabling FPU extension")); | 
 | 	} | 
 |     } | 
 |  | 
 |   if (nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST)) | 
 |     { | 
 |       /* Single/double FPU has been used, set FPU register config.  */ | 
 |       /* We did not check the actual number of register used.  We may | 
 | 	 want to do it while assemble.  */ | 
 |       nds32_elf_flags &= ~E_NDS32_FPU_REG_CONF; | 
 |       nds32_elf_flags |= (nds32_freg << E_NDS32_FPU_REG_CONF_SHIFT); | 
 |     } | 
 |  | 
 |   if (nds32_pic) | 
 |     nds32_elf_flags |= E_NDS32_HAS_PIC; | 
 |  | 
 |   if (nds32_gpr16) | 
 |     nds32_elf_flags |= E_NDS32_HAS_REDUCED_REGS; | 
 |  | 
 |   nds32_elf_flags |= (E_NDS32_ELF_VER_1_4 | nds32_abi); | 
 |   elf_elfheader (stdoutput)->e_flags |= nds32_elf_flags; | 
 | } | 
 |  | 
 | /* Implement md_apply_fix.  Apply the fix-up or transform the fix-up for | 
 |    later relocation generation.  */ | 
 |  | 
 | void | 
 | nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) | 
 | { | 
 |   char *where = fixP->fx_frag->fr_literal + fixP->fx_where; | 
 |   bfd_vma value = *valP; | 
 |  | 
 |   if (fixP->fx_r_type < BFD_RELOC_UNUSED | 
 |       && fixP->fx_r_type > BFD_RELOC_NONE | 
 |       && fixP->fx_r_type != BFD_RELOC_NDS32_DIFF_ULEB128) | 
 |     { | 
 |       /* In our old nds32 binutils, it must convert relocations which is | 
 | 	 generated by CGEN.  However, it does not have to consider this anymore. | 
 | 	 In current, it only deal with data relocations which enum | 
 | 	 is smaller than BFD_RELOC_NONE and BFD_RELOC_NDS32_DIFF_ULEB128. | 
 | 	 It is believed that we can construct a better mechanism to | 
 | 	 deal with the whole relocation issue in nds32 target | 
 | 	 without using CGEN.  */ | 
 |       fixP->fx_addnumber = value; | 
 |       fixP->tc_fix_data = NULL; | 
 |  | 
 |       /* Transform specific relocations here for later relocation generation. | 
 | 	 Tag tls data for linker.  */ | 
 |       switch (fixP->fx_r_type) | 
 | 	{ | 
 | 	case BFD_RELOC_NDS32_DATA: | 
 | 	  /* This reloc is obselete, we do not need it so far.  */ | 
 | 	  fixP->fx_done = 1; | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_TPOFF: | 
 | 	case BFD_RELOC_NDS32_TLS_LE_HI20: | 
 | 	case BFD_RELOC_NDS32_TLS_LE_LO12: | 
 | 	case BFD_RELOC_NDS32_TLS_LE_ADD: | 
 | 	case BFD_RELOC_NDS32_TLS_LE_LS: | 
 | 	case BFD_RELOC_NDS32_GOTTPOFF: | 
 | 	case BFD_RELOC_NDS32_TLS_IE_HI20: | 
 | 	case BFD_RELOC_NDS32_TLS_IE_LO12S2: | 
 | 	case BFD_RELOC_NDS32_TLS_DESC_HI20: | 
 | 	case BFD_RELOC_NDS32_TLS_DESC_LO12: | 
 | 	case BFD_RELOC_NDS32_TLS_IE_LO12: | 
 | 	case BFD_RELOC_NDS32_TLS_IEGP_HI20: | 
 | 	case BFD_RELOC_NDS32_TLS_IEGP_LO12: | 
 | 	case BFD_RELOC_NDS32_TLS_IEGP_LO12S2: | 
 | 	  S_SET_THREAD_LOCAL (fixP->fx_addsy); | 
 | 	  break; | 
 | 	default: | 
 | 	  break; | 
 | 	} | 
 |       return; | 
 |     } | 
 |  | 
 |   if (fixP->fx_addsy == (symbolS *) NULL) | 
 |     fixP->fx_done = 1; | 
 |  | 
 |   if (fixP->fx_subsy != (symbolS *) NULL) | 
 |     { | 
 |       /* HOW DIFF RELOCATION WORKS. | 
 |  | 
 | 	 First of all, this relocation is used to calculate the distance | 
 | 	 between two symbols in the SAME section.  It is used for  jump- | 
 | 	 table, debug information, exception table, et al.    Therefore, | 
 | 	 it is a unsigned positive value.   It is NOT used for  general- | 
 | 	 purpose arithmetic. | 
 |  | 
 | 	 Consider this example,  the distance between  .LEND and .LBEGIN | 
 | 	 is stored at the address of foo. | 
 |  | 
 | 	 ---- >8 ---- >8 ---- >8 ---- >8 ---- | 
 | 	  .data | 
 | 	  foo: | 
 | 	    .word	.LBEGIN - .LEND | 
 |  | 
 | 	  .text | 
 | 	     [before] | 
 | 	  .LBEGIN | 
 | 			 \ | 
 | 	     [between]    distance | 
 | 			 / | 
 | 	  .LEND | 
 | 	     [after] | 
 | 	 ---- 8< ---- 8< ---- 8< ---- 8< ---- | 
 |  | 
 | 	 We use a single relocation entry for this expression. | 
 | 	 * The initial distance value is stored directly in that location | 
 | 	   specified by r_offset (i.e., foo in this example.) | 
 | 	 * The begin of the region, i.e., .LBEGIN, is specified by | 
 | 	   r_info/R_SYM and r_addend, e.g., .text + 0x32. | 
 | 	 * The end of region, i.e., .LEND, is represented by | 
 | 	   .LBEGIN + distance instead of .LEND, so we only need | 
 | 	   a single relocation entry instead of two. | 
 |  | 
 | 	 When an instruction is relaxed, we adjust the relocation entry | 
 | 	 depending on where the instruction locates.    There are three | 
 | 	 cases, before, after and between the region. | 
 | 	 * between: Distance value is read from r_offset,  adjusted and | 
 | 	   written back into r_offset. | 
 | 	 * before: Only r_addend is adjust. | 
 | 	 * after: We don't care about it. | 
 |  | 
 | 	 Hereby, there are some limitation. | 
 |  | 
 | 	 `(.LEND - 1) - .LBEGIN' and `(.LEND - .LBEGIN) - 1' | 
 | 	 are semantically different, and we cannot handle latter case | 
 | 	 when relaxation. | 
 |  | 
 | 	 The latter expression means subtracting 1 from the distance | 
 | 	 between .LEND and .LBEGIN.  And the former expression means | 
 | 	 the distance between (.LEND - 1) and .LBEGIN. | 
 |  | 
 | 	 The nuance affects whether to adjust distance value when relax | 
 | 	 an instruction.  In another words, whether the instruction | 
 | 	 locates in the region.  Because we use a single relocation entry, | 
 | 	 there is no field left for .LEND and the subtrahend. | 
 |  | 
 | 	 Since GCC-4.5, GCC may produce debug information in such expression | 
 | 	     .long  .L1-1-.L0 | 
 | 	 in order to describe register clobbering during an function-call. | 
 | 	     .L0: | 
 | 		call foo | 
 | 	     .L1: | 
 |  | 
 | 	 Check http://gcc.gnu.org/ml/gcc-patches/2009-06/msg01317.html | 
 | 	 for details.  */ | 
 |  | 
 |       value -= S_GET_VALUE (fixP->fx_subsy); | 
 |       *valP = value; | 
 |       fixP->fx_subsy = NULL; | 
 |       fixP->fx_offset -= value; | 
 |  | 
 |       switch (fixP->fx_r_type) | 
 | 	{ | 
 | 	case BFD_RELOC_8: | 
 | 	  fixP->fx_r_type = BFD_RELOC_NDS32_DIFF8; | 
 | 	  md_number_to_chars (where, value, 1); | 
 | 	  break; | 
 | 	case BFD_RELOC_16: | 
 | 	  fixP->fx_r_type = BFD_RELOC_NDS32_DIFF16; | 
 | 	  md_number_to_chars (where, value, 2); | 
 | 	  break; | 
 | 	case BFD_RELOC_32: | 
 | 	  fixP->fx_r_type = BFD_RELOC_NDS32_DIFF32; | 
 | 	  md_number_to_chars (where, value, 4); | 
 | 	  break; | 
 | 	case BFD_RELOC_NDS32_DIFF_ULEB128: | 
 | 	  /* cvt_frag_to_fill () has called output_leb128 () for us.  */ | 
 | 	  break; | 
 | 	default: | 
 | 	  as_bad_subtract (fixP); | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |   else if (fixP->fx_done) | 
 |     { | 
 |       /* We're finished with this fixup.  Install it because | 
 | 	 bfd_install_relocation won't be called to do it.  */ | 
 |       switch (fixP->fx_r_type) | 
 | 	{ | 
 | 	case BFD_RELOC_8: | 
 | 	  md_number_to_chars (where, value, 1); | 
 | 	  break; | 
 | 	case BFD_RELOC_16: | 
 | 	  md_number_to_chars (where, value, 2); | 
 | 	  break; | 
 | 	case BFD_RELOC_32: | 
 | 	  md_number_to_chars (where, value, 4); | 
 | 	  break; | 
 | 	case BFD_RELOC_64: | 
 | 	  md_number_to_chars (where, value, 8); | 
 | 	  break; | 
 | 	default: | 
 | 	  as_bad_where (fixP->fx_file, fixP->fx_line, | 
 | 			_("Internal error: Unknown fixup type %d (`%s')"), | 
 | 			fixP->fx_r_type, | 
 | 			bfd_get_reloc_code_name (fixP->fx_r_type)); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Implement tc_gen_reloc.  Generate ELF relocation for a fix-up.  */ | 
 |  | 
 | arelent * | 
 | tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) | 
 | { | 
 |   arelent *reloc; | 
 |   bfd_reloc_code_real_type code; | 
 |  | 
 |   reloc = XNEW (arelent); | 
 |  | 
 |   reloc->sym_ptr_ptr = XNEW (asymbol *); | 
 |   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); | 
 |   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; | 
 |  | 
 |   code = fixP->fx_r_type; | 
 |  | 
 |   reloc->howto = bfd_reloc_type_lookup (stdoutput, code); | 
 |   if (reloc->howto == (reloc_howto_type *) NULL) | 
 |     { | 
 |       as_bad_where (fixP->fx_file, fixP->fx_line, | 
 | 		    _("internal error: can't export reloc type %d (`%s')"), | 
 | 		    fixP->fx_r_type, bfd_get_reloc_code_name (code)); | 
 |       return NULL; | 
 |     } | 
 |  | 
 |   /* Add relocation handling here.  */ | 
 |  | 
 |   switch (fixP->fx_r_type) | 
 |     { | 
 |     default: | 
 |       /* In general, addend of a relocation is the offset to the | 
 | 	 associated symbol.  */ | 
 |       reloc->addend = fixP->fx_offset; | 
 |       break; | 
 |  | 
 |     case BFD_RELOC_NDS32_DATA: | 
 |       /* Prevent linker from optimizing data in text sections. | 
 | 	 For example, jump table.  */ | 
 |       reloc->addend = fixP->fx_size; | 
 |       break; | 
 |     } | 
 |  | 
 |   return reloc; | 
 | } | 
 |  | 
 | static struct suffix_name suffix_table[] = | 
 | { | 
 |   {"GOTOFF",	BFD_RELOC_NDS32_GOTOFF}, | 
 |   {"GOT",	BFD_RELOC_NDS32_GOT20}, | 
 |   {"TPOFF",	BFD_RELOC_NDS32_TPOFF}, | 
 |   {"PLT",	BFD_RELOC_NDS32_25_PLTREL}, | 
 |   {"GOTTPOFF",	BFD_RELOC_NDS32_GOTTPOFF}, | 
 |   {"TLSDESC",  BFD_RELOC_NDS32_TLS_DESC}, | 
 | }; | 
 |  | 
 | /* Implement md_parse_name.  */ | 
 |  | 
 | int | 
 | nds32_parse_name (char const *name, expressionS *exprP, | 
 | 		  enum expr_mode mode ATTRIBUTE_UNUSED, | 
 | 		  char *nextcharP ATTRIBUTE_UNUSED) | 
 | { | 
 |   segT segment; | 
 |  | 
 |   exprP->X_op_symbol = NULL; | 
 |   exprP->X_md = BFD_RELOC_UNUSED; | 
 |  | 
 |   exprP->X_add_symbol = symbol_find_or_make (name); | 
 |   exprP->X_op = O_symbol; | 
 |   exprP->X_add_number = 0; | 
 |  | 
 |   /* Check the special name if a symbol.  */ | 
 |   segment = S_GET_SEGMENT (exprP->X_add_symbol); | 
 |   if ((segment != undefined_section) && (*nextcharP != '@')) | 
 |     return 0; | 
 |  | 
 |   if (strcmp (name, GOT_NAME) == 0 && *nextcharP != '@') | 
 |     { | 
 |       /* Set for _GOT_OFFSET_TABLE_.  */ | 
 |       exprP->X_md = BFD_RELOC_NDS32_GOTPC20; | 
 |     } | 
 |   else if (*nextcharP == '@') | 
 |     { | 
 |       size_t i; | 
 |       char *next; | 
 |       for (i = 0; i < ARRAY_SIZE (suffix_table); i++) | 
 | 	{ | 
 | 	  next = input_line_pointer + 1 + strlen (suffix_table[i].suffix); | 
 | 	  if (strncasecmp (input_line_pointer + 1, suffix_table[i].suffix, | 
 | 			   strlen (suffix_table[i].suffix)) == 0 | 
 | 	      && !is_part_of_name (*next)) | 
 | 	    { | 
 | 	      exprP->X_md = suffix_table[i].reloc; | 
 | 	      *input_line_pointer = *nextcharP; | 
 | 	      input_line_pointer = next; | 
 | 	      *nextcharP = *input_line_pointer; | 
 | 	      *input_line_pointer = '\0'; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |     } | 
 |  | 
 |   return 1; | 
 | } | 
 |  | 
 | /* Implement tc_regname_to_dw2regnum.  */ | 
 |  | 
 | int | 
 | tc_nds32_regname_to_dw2regnum (char *regname) | 
 | { | 
 |   struct nds32_keyword *sym = str_hash_find (nds32_gprs_hash, regname); | 
 |  | 
 |   if (!sym) | 
 |     return -1; | 
 |  | 
 |   return sym->value; | 
 | } | 
 |  | 
 | void | 
 | tc_nds32_frame_initial_instructions (void) | 
 | { | 
 |   /* CIE */ | 
 |   /* Default cfa is register-31/sp.  */ | 
 |   cfi_add_CFA_def_cfa (31, 0); | 
 | } |