1440a403fSchristos /* tc-arc.c -- Assembler for the ARC
2*b88e3e88Schristos    Copyright (C) 1994-2020 Free Software Foundation, Inc.
3440a403fSchristos 
4440a403fSchristos    Contributor: Claudiu Zissulescu <claziss@synopsys.com>
5440a403fSchristos 
6440a403fSchristos    This file is part of GAS, the GNU Assembler.
7440a403fSchristos 
8440a403fSchristos    GAS is free software; you can redistribute it and/or modify
9440a403fSchristos    it under the terms of the GNU General Public License as published by
10440a403fSchristos    the Free Software Foundation; either version 3, or (at your option)
11440a403fSchristos    any later version.
12440a403fSchristos 
13440a403fSchristos    GAS is distributed in the hope that it will be useful,
14440a403fSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
15440a403fSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16440a403fSchristos    GNU General Public License for more details.
17440a403fSchristos 
18440a403fSchristos    You should have received a copy of the GNU General Public License
19440a403fSchristos    along with GAS; see the file COPYING.  If not, write to the Free
20440a403fSchristos    Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
21440a403fSchristos    02110-1301, USA.  */
22440a403fSchristos 
23440a403fSchristos #include "as.h"
24440a403fSchristos #include "subsegs.h"
25440a403fSchristos #include "dwarf2dbg.h"
26440a403fSchristos #include "dw2gencfi.h"
27440a403fSchristos #include "safe-ctype.h"
28440a403fSchristos 
29440a403fSchristos #include "opcode/arc.h"
3006324dcfSchristos #include "opcode/arc-attrs.h"
31440a403fSchristos #include "elf/arc.h"
32440a403fSchristos #include "../opcodes/arc-ext.h"
33440a403fSchristos 
34440a403fSchristos /* Defines section.  */
35440a403fSchristos 
36440a403fSchristos #define MAX_INSN_FIXUPS      2
37440a403fSchristos #define MAX_CONSTR_STR       20
38440a403fSchristos #define FRAG_MAX_GROWTH      8
39440a403fSchristos 
40440a403fSchristos #ifdef DEBUG
41440a403fSchristos # define pr_debug(fmt, args...) fprintf (stderr, fmt, ##args)
42440a403fSchristos #else
43440a403fSchristos # define pr_debug(fmt, args...)
44440a403fSchristos #endif
45440a403fSchristos 
46440a403fSchristos #define MAJOR_OPCODE(x)  (((x) & 0xF8000000) >> 27)
47440a403fSchristos #define SUB_OPCODE(x)	 (((x) & 0x003F0000) >> 16)
4806324dcfSchristos #define LP_INSN(x)	 ((MAJOR_OPCODE (x) == 0x4) \
4906324dcfSchristos 			  && (SUB_OPCODE (x) == 0x28))
50440a403fSchristos 
51440a403fSchristos #ifndef TARGET_WITH_CPU
52440a403fSchristos #define TARGET_WITH_CPU "arc700"
53440a403fSchristos #endif /* TARGET_WITH_CPU */
54440a403fSchristos 
5506324dcfSchristos #define ARC_GET_FLAG(s)   	(*symbol_get_tc (s))
5606324dcfSchristos #define ARC_SET_FLAG(s,v) 	(*symbol_get_tc (s) |= (v))
5706324dcfSchristos #define streq(a, b)	      (strcmp (a, b) == 0)
5806324dcfSchristos 
59440a403fSchristos /* Enum used to enumerate the relaxable ins operands.  */
60440a403fSchristos enum rlx_operand_type
61440a403fSchristos {
62440a403fSchristos   EMPTY = 0,
63440a403fSchristos   REGISTER,
64440a403fSchristos   REGISTER_S,     /* Register for short instruction(s).  */
65440a403fSchristos   REGISTER_NO_GP, /* Is a register but not gp register specifically.  */
66440a403fSchristos   REGISTER_DUP,   /* Duplication of previous operand of type register.  */
67440a403fSchristos   IMMEDIATE,
68440a403fSchristos   BRACKET
69440a403fSchristos };
70440a403fSchristos 
71440a403fSchristos enum arc_rlx_types
72440a403fSchristos {
73440a403fSchristos   ARC_RLX_NONE = 0,
74440a403fSchristos   ARC_RLX_BL_S,
75440a403fSchristos   ARC_RLX_BL,
76440a403fSchristos   ARC_RLX_B_S,
77440a403fSchristos   ARC_RLX_B,
78440a403fSchristos   ARC_RLX_ADD_U3,
79440a403fSchristos   ARC_RLX_ADD_U6,
80440a403fSchristos   ARC_RLX_ADD_LIMM,
81440a403fSchristos   ARC_RLX_LD_U7,
82440a403fSchristos   ARC_RLX_LD_S9,
83440a403fSchristos   ARC_RLX_LD_LIMM,
84440a403fSchristos   ARC_RLX_MOV_U8,
85440a403fSchristos   ARC_RLX_MOV_S12,
86440a403fSchristos   ARC_RLX_MOV_LIMM,
87440a403fSchristos   ARC_RLX_SUB_U3,
88440a403fSchristos   ARC_RLX_SUB_U6,
89440a403fSchristos   ARC_RLX_SUB_LIMM,
90440a403fSchristos   ARC_RLX_MPY_U6,
91440a403fSchristos   ARC_RLX_MPY_LIMM,
92440a403fSchristos   ARC_RLX_MOV_RU6,
93440a403fSchristos   ARC_RLX_MOV_RLIMM,
94440a403fSchristos   ARC_RLX_ADD_RRU6,
95440a403fSchristos   ARC_RLX_ADD_RRLIMM,
96440a403fSchristos };
97440a403fSchristos 
98440a403fSchristos /* Macros section.  */
99440a403fSchristos 
100440a403fSchristos #define regno(x)		((x) & 0x3F)
101440a403fSchristos #define is_ir_num(x)		(((x) & ~0x3F) == 0)
102440a403fSchristos #define is_code_density_p(sc)   (((sc) == CD1 || (sc) == CD2))
103440a403fSchristos #define is_spfp_p(op)           (((sc) == SPX))
104440a403fSchristos #define is_dpfp_p(op)           (((sc) == DPX))
105440a403fSchristos #define is_fpuda_p(op)          (((sc) == DPA))
10606324dcfSchristos #define is_br_jmp_insn_p(op)    (((op)->insn_class == BRANCH		\
10706324dcfSchristos 				  || (op)->insn_class == JUMP		\
10806324dcfSchristos 				  || (op)->insn_class == BRCC		\
10906324dcfSchristos 				  || (op)->insn_class == BBIT0		\
11006324dcfSchristos 				  || (op)->insn_class == BBIT1		\
11106324dcfSchristos 				  || (op)->insn_class == BI		\
11206324dcfSchristos 				  || (op)->insn_class == EI		\
11306324dcfSchristos 				  || (op)->insn_class == ENTER		\
11406324dcfSchristos 				  || (op)->insn_class == JLI		\
11506324dcfSchristos 				  || (op)->insn_class == LOOP		\
11606324dcfSchristos 				  || (op)->insn_class == LEAVE		\
11706324dcfSchristos 				  ))
118440a403fSchristos #define is_kernel_insn_p(op)    (((op)->insn_class == KERNEL))
119440a403fSchristos #define is_nps400_p(op)         (((sc) == NPS400))
120440a403fSchristos 
121440a403fSchristos /* Generic assembler global variables which must be defined by all
122440a403fSchristos    targets.  */
123440a403fSchristos 
124440a403fSchristos /* Characters which always start a comment.  */
125440a403fSchristos const char comment_chars[] = "#;";
126440a403fSchristos 
127440a403fSchristos /* Characters which start a comment at the beginning of a line.  */
128440a403fSchristos const char line_comment_chars[] = "#";
129440a403fSchristos 
130440a403fSchristos /* Characters which may be used to separate multiple commands on a
131440a403fSchristos    single line.  */
132440a403fSchristos const char line_separator_chars[] = "`";
133440a403fSchristos 
134440a403fSchristos /* Characters which are used to indicate an exponent in a floating
135440a403fSchristos    point number.  */
136440a403fSchristos const char EXP_CHARS[] = "eE";
137440a403fSchristos 
138440a403fSchristos /* Chars that mean this number is a floating point constant
139440a403fSchristos    As in 0f12.456 or 0d1.2345e12.  */
140440a403fSchristos const char FLT_CHARS[] = "rRsSfFdD";
141440a403fSchristos 
142440a403fSchristos /* Byte order.  */
143440a403fSchristos extern int target_big_endian;
144440a403fSchristos const char *arc_target_format = DEFAULT_TARGET_FORMAT;
145440a403fSchristos static int byte_order = DEFAULT_BYTE_ORDER;
146440a403fSchristos 
147440a403fSchristos /* Arc extension section.  */
148440a403fSchristos static segT arcext_section;
149440a403fSchristos 
150440a403fSchristos /* By default relaxation is disabled.  */
151440a403fSchristos static int relaxation_state = 0;
152440a403fSchristos 
153440a403fSchristos extern int arc_get_mach (char *);
154440a403fSchristos 
155440a403fSchristos /* Forward declarations.  */
156440a403fSchristos static void arc_lcomm (int);
157440a403fSchristos static void arc_option (int);
158440a403fSchristos static void arc_extra_reloc (int);
159440a403fSchristos static void arc_extinsn (int);
160440a403fSchristos static void arc_extcorereg (int);
16106324dcfSchristos static void arc_attribute (int);
162440a403fSchristos 
163440a403fSchristos const pseudo_typeS md_pseudo_table[] =
164440a403fSchristos {
165440a403fSchristos   /* Make sure that .word is 32 bits.  */
166440a403fSchristos   { "word", cons, 4 },
167440a403fSchristos 
168440a403fSchristos   { "align",   s_align_bytes, 0 }, /* Defaulting is invalid (0).  */
169440a403fSchristos   { "lcomm",   arc_lcomm, 0 },
170440a403fSchristos   { "lcommon", arc_lcomm, 0 },
171440a403fSchristos   { "cpu",     arc_option, 0 },
172440a403fSchristos 
17306324dcfSchristos   { "arc_attribute",   arc_attribute, 0 },
174440a403fSchristos   { "extinstruction",  arc_extinsn, 0 },
175440a403fSchristos   { "extcoreregister", arc_extcorereg, EXT_CORE_REGISTER },
176440a403fSchristos   { "extauxregister",  arc_extcorereg, EXT_AUX_REGISTER },
177440a403fSchristos   { "extcondcode",     arc_extcorereg, EXT_COND_CODE },
178440a403fSchristos 
179440a403fSchristos   { "tls_gd_ld",   arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_LD },
180440a403fSchristos   { "tls_gd_call", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_CALL },
181440a403fSchristos 
182440a403fSchristos   { NULL, NULL, 0 }
183440a403fSchristos };
184440a403fSchristos 
185440a403fSchristos const char *md_shortopts = "";
186440a403fSchristos 
187440a403fSchristos enum options
188440a403fSchristos {
189440a403fSchristos   OPTION_EB = OPTION_MD_BASE,
190440a403fSchristos   OPTION_EL,
191440a403fSchristos 
192440a403fSchristos   OPTION_ARC600,
193440a403fSchristos   OPTION_ARC601,
194440a403fSchristos   OPTION_ARC700,
195440a403fSchristos   OPTION_ARCEM,
196440a403fSchristos   OPTION_ARCHS,
197440a403fSchristos 
198440a403fSchristos   OPTION_MCPU,
199440a403fSchristos   OPTION_CD,
200440a403fSchristos   OPTION_RELAX,
201440a403fSchristos   OPTION_NPS400,
202440a403fSchristos 
203440a403fSchristos   OPTION_SPFP,
204440a403fSchristos   OPTION_DPFP,
205440a403fSchristos   OPTION_FPUDA,
206440a403fSchristos 
207440a403fSchristos   /* The following options are deprecated and provided here only for
208440a403fSchristos      compatibility reasons.  */
209440a403fSchristos   OPTION_USER_MODE,
210440a403fSchristos   OPTION_LD_EXT_MASK,
211440a403fSchristos   OPTION_SWAP,
212440a403fSchristos   OPTION_NORM,
213440a403fSchristos   OPTION_BARREL_SHIFT,
214440a403fSchristos   OPTION_MIN_MAX,
215440a403fSchristos   OPTION_NO_MPY,
216440a403fSchristos   OPTION_EA,
217440a403fSchristos   OPTION_MUL64,
218440a403fSchristos   OPTION_SIMD,
219440a403fSchristos   OPTION_XMAC_D16,
220440a403fSchristos   OPTION_XMAC_24,
221440a403fSchristos   OPTION_DSP_PACKA,
222440a403fSchristos   OPTION_CRC,
223440a403fSchristos   OPTION_DVBF,
224440a403fSchristos   OPTION_TELEPHONY,
225440a403fSchristos   OPTION_XYMEMORY,
226440a403fSchristos   OPTION_LOCK,
227440a403fSchristos   OPTION_SWAPE,
228440a403fSchristos   OPTION_RTSC
229440a403fSchristos };
230440a403fSchristos 
231440a403fSchristos struct option md_longopts[] =
232440a403fSchristos {
233440a403fSchristos   { "EB",		no_argument,	   NULL, OPTION_EB },
234440a403fSchristos   { "EL",		no_argument,	   NULL, OPTION_EL },
235440a403fSchristos   { "mcpu",		required_argument, NULL, OPTION_MCPU },
236440a403fSchristos   { "mA6",		no_argument,	   NULL, OPTION_ARC600 },
237440a403fSchristos   { "mARC600",		no_argument,	   NULL, OPTION_ARC600 },
238440a403fSchristos   { "mARC601",		no_argument,	   NULL, OPTION_ARC601 },
239440a403fSchristos   { "mARC700",		no_argument,	   NULL, OPTION_ARC700 },
240440a403fSchristos   { "mA7",		no_argument,	   NULL, OPTION_ARC700 },
241440a403fSchristos   { "mEM",		no_argument,	   NULL, OPTION_ARCEM },
242440a403fSchristos   { "mHS",		no_argument,	   NULL, OPTION_ARCHS },
243440a403fSchristos   { "mcode-density",	no_argument,	   NULL, OPTION_CD },
244440a403fSchristos   { "mrelax",           no_argument,       NULL, OPTION_RELAX },
245440a403fSchristos   { "mnps400",          no_argument,       NULL, OPTION_NPS400 },
246440a403fSchristos 
247440a403fSchristos   /* Floating point options */
248440a403fSchristos   { "mspfp", no_argument, NULL, OPTION_SPFP},
249440a403fSchristos   { "mspfp-compact", no_argument, NULL, OPTION_SPFP},
250440a403fSchristos   { "mspfp_compact", no_argument, NULL, OPTION_SPFP},
251440a403fSchristos   { "mspfp-fast", no_argument, NULL, OPTION_SPFP},
252440a403fSchristos   { "mspfp_fast", no_argument, NULL, OPTION_SPFP},
253440a403fSchristos   { "mdpfp", no_argument, NULL, OPTION_DPFP},
254440a403fSchristos   { "mdpfp-compact", no_argument, NULL, OPTION_DPFP},
255440a403fSchristos   { "mdpfp_compact", no_argument, NULL, OPTION_DPFP},
256440a403fSchristos   { "mdpfp-fast", no_argument, NULL, OPTION_DPFP},
257440a403fSchristos   { "mdpfp_fast", no_argument, NULL, OPTION_DPFP},
258440a403fSchristos   { "mfpuda", no_argument, NULL, OPTION_FPUDA},
259440a403fSchristos 
260440a403fSchristos   /* The following options are deprecated and provided here only for
261440a403fSchristos      compatibility reasons.  */
262440a403fSchristos   { "mav2em", no_argument, NULL, OPTION_ARCEM },
263440a403fSchristos   { "mav2hs", no_argument, NULL, OPTION_ARCHS },
264440a403fSchristos   { "muser-mode-only", no_argument, NULL, OPTION_USER_MODE },
265440a403fSchristos   { "mld-extension-reg-mask", required_argument, NULL, OPTION_LD_EXT_MASK },
266440a403fSchristos   { "mswap", no_argument, NULL, OPTION_SWAP },
267440a403fSchristos   { "mnorm", no_argument, NULL, OPTION_NORM },
268440a403fSchristos   { "mbarrel-shifter", no_argument, NULL, OPTION_BARREL_SHIFT },
269440a403fSchristos   { "mbarrel_shifter", no_argument, NULL, OPTION_BARREL_SHIFT },
270440a403fSchristos   { "mmin-max", no_argument, NULL, OPTION_MIN_MAX },
271440a403fSchristos   { "mmin_max", no_argument, NULL, OPTION_MIN_MAX },
272440a403fSchristos   { "mno-mpy", no_argument, NULL, OPTION_NO_MPY },
273440a403fSchristos   { "mea", no_argument, NULL, OPTION_EA },
274440a403fSchristos   { "mEA", no_argument, NULL, OPTION_EA },
275440a403fSchristos   { "mmul64", no_argument, NULL, OPTION_MUL64 },
276440a403fSchristos   { "msimd", no_argument, NULL, OPTION_SIMD},
277440a403fSchristos   { "mmac-d16", no_argument, NULL, OPTION_XMAC_D16},
278440a403fSchristos   { "mmac_d16", no_argument, NULL, OPTION_XMAC_D16},
279440a403fSchristos   { "mmac-24", no_argument, NULL, OPTION_XMAC_24},
280440a403fSchristos   { "mmac_24", no_argument, NULL, OPTION_XMAC_24},
281440a403fSchristos   { "mdsp-packa", no_argument, NULL, OPTION_DSP_PACKA},
282440a403fSchristos   { "mdsp_packa", no_argument, NULL, OPTION_DSP_PACKA},
283440a403fSchristos   { "mcrc", no_argument, NULL, OPTION_CRC},
284440a403fSchristos   { "mdvbf", no_argument, NULL, OPTION_DVBF},
285440a403fSchristos   { "mtelephony", no_argument, NULL, OPTION_TELEPHONY},
286440a403fSchristos   { "mxy", no_argument, NULL, OPTION_XYMEMORY},
287440a403fSchristos   { "mlock", no_argument, NULL, OPTION_LOCK},
288440a403fSchristos   { "mswape", no_argument, NULL, OPTION_SWAPE},
289440a403fSchristos   { "mrtsc", no_argument, NULL, OPTION_RTSC},
290440a403fSchristos 
291440a403fSchristos   { NULL,		no_argument, NULL, 0 }
292440a403fSchristos };
293440a403fSchristos 
294440a403fSchristos size_t md_longopts_size = sizeof (md_longopts);
295440a403fSchristos 
296440a403fSchristos /* Local data and data types.  */
297440a403fSchristos 
298440a403fSchristos /* Used since new relocation types are introduced in this
299440a403fSchristos    file (DUMMY_RELOC_LITUSE_*).  */
300440a403fSchristos typedef int extended_bfd_reloc_code_real_type;
301440a403fSchristos 
302440a403fSchristos struct arc_fixup
303440a403fSchristos {
304440a403fSchristos   expressionS exp;
305440a403fSchristos 
306440a403fSchristos   extended_bfd_reloc_code_real_type reloc;
307440a403fSchristos 
308440a403fSchristos   /* index into arc_operands.  */
309440a403fSchristos   unsigned int opindex;
310440a403fSchristos 
311440a403fSchristos   /* PC-relative, used by internals fixups.  */
312440a403fSchristos   unsigned char pcrel;
313440a403fSchristos 
314440a403fSchristos   /* TRUE if this fixup is for LIMM operand.  */
315440a403fSchristos   bfd_boolean islong;
316440a403fSchristos };
317440a403fSchristos 
318440a403fSchristos struct arc_insn
319440a403fSchristos {
32006324dcfSchristos   unsigned long long int insn;
321440a403fSchristos   int nfixups;
322440a403fSchristos   struct arc_fixup fixups[MAX_INSN_FIXUPS];
323440a403fSchristos   long limm;
32406324dcfSchristos   unsigned int len;       /* Length of instruction in bytes.  */
325440a403fSchristos   bfd_boolean has_limm;   /* Boolean value: TRUE if limm field is
326440a403fSchristos 			     valid.  */
327440a403fSchristos   bfd_boolean relax;	  /* Boolean value: TRUE if needs
328440a403fSchristos 			     relaxation.  */
329440a403fSchristos };
330440a403fSchristos 
331440a403fSchristos /* Structure to hold any last two instructions.  */
332440a403fSchristos static struct arc_last_insn
333440a403fSchristos {
334440a403fSchristos   /* Saved instruction opcode.  */
335440a403fSchristos   const struct arc_opcode *opcode;
336440a403fSchristos 
337440a403fSchristos   /* Boolean value: TRUE if current insn is short.  */
338440a403fSchristos   bfd_boolean has_limm;
339440a403fSchristos 
340440a403fSchristos   /* Boolean value: TRUE if current insn has delay slot.  */
341440a403fSchristos   bfd_boolean has_delay_slot;
342440a403fSchristos } arc_last_insns[2];
343440a403fSchristos 
344440a403fSchristos /* Extension instruction suffix classes.  */
345440a403fSchristos typedef struct
346440a403fSchristos {
347440a403fSchristos   const char *name;
348440a403fSchristos   int  len;
349440a403fSchristos   int  attr_class;
350440a403fSchristos } attributes_t;
351440a403fSchristos 
352440a403fSchristos static const attributes_t suffixclass[] =
353440a403fSchristos {
354440a403fSchristos   { "SUFFIX_FLAG", 11, ARC_SUFFIX_FLAG },
355440a403fSchristos   { "SUFFIX_COND", 11, ARC_SUFFIX_COND },
356440a403fSchristos   { "SUFFIX_NONE", 11, ARC_SUFFIX_NONE }
357440a403fSchristos };
358440a403fSchristos 
359440a403fSchristos /* Extension instruction syntax classes.  */
360440a403fSchristos static const attributes_t syntaxclass[] =
361440a403fSchristos {
362440a403fSchristos   { "SYNTAX_3OP", 10, ARC_SYNTAX_3OP },
363440a403fSchristos   { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP },
364440a403fSchristos   { "SYNTAX_1OP", 10, ARC_SYNTAX_1OP },
365440a403fSchristos   { "SYNTAX_NOP", 10, ARC_SYNTAX_NOP }
366440a403fSchristos };
367440a403fSchristos 
368440a403fSchristos /* Extension instruction syntax classes modifiers.  */
369440a403fSchristos static const attributes_t syntaxclassmod[] =
370440a403fSchristos {
371440a403fSchristos   { "OP1_IMM_IMPLIED" , 15, ARC_OP1_IMM_IMPLIED },
372440a403fSchristos   { "OP1_MUST_BE_IMM" , 15, ARC_OP1_MUST_BE_IMM }
373440a403fSchristos };
374440a403fSchristos 
375440a403fSchristos /* Extension register type.  */
376440a403fSchristos typedef struct
377440a403fSchristos {
378440a403fSchristos   char *name;
379440a403fSchristos   int  number;
380440a403fSchristos   int  imode;
381440a403fSchristos } extRegister_t;
382440a403fSchristos 
383440a403fSchristos /* A structure to hold the additional conditional codes.  */
384440a403fSchristos static struct
385440a403fSchristos {
386440a403fSchristos   struct arc_flag_operand *arc_ext_condcode;
387440a403fSchristos   int size;
388440a403fSchristos } ext_condcode = { NULL, 0 };
389440a403fSchristos 
390440a403fSchristos /* Structure to hold an entry in ARC_OPCODE_HASH.  */
391440a403fSchristos struct arc_opcode_hash_entry
392440a403fSchristos {
393440a403fSchristos   /* The number of pointers in the OPCODE list.  */
394440a403fSchristos   size_t count;
395440a403fSchristos 
396440a403fSchristos   /* Points to a list of opcode pointers.  */
397440a403fSchristos   const struct arc_opcode **opcode;
398440a403fSchristos };
399440a403fSchristos 
400440a403fSchristos /* Structure used for iterating through an arc_opcode_hash_entry.  */
401440a403fSchristos struct arc_opcode_hash_entry_iterator
402440a403fSchristos {
403440a403fSchristos   /* Index into the OPCODE element of the arc_opcode_hash_entry.  */
404440a403fSchristos   size_t index;
405440a403fSchristos 
406440a403fSchristos   /* The specific ARC_OPCODE from the ARC_OPCODES table that was last
407440a403fSchristos      returned by this iterator.  */
408440a403fSchristos   const struct arc_opcode *opcode;
409440a403fSchristos };
410440a403fSchristos 
411440a403fSchristos /* Forward declaration.  */
412440a403fSchristos static void assemble_insn
413440a403fSchristos   (const struct arc_opcode *, const expressionS *, int,
414440a403fSchristos    const struct arc_flags *, int, struct arc_insn *);
415440a403fSchristos 
41606324dcfSchristos /* The selection of the machine type can come from different sources.  This
41706324dcfSchristos    enum is used to track how the selection was made in order to perform
41806324dcfSchristos    error checks.  */
41906324dcfSchristos enum mach_selection_type
42006324dcfSchristos   {
42106324dcfSchristos     MACH_SELECTION_NONE,
42206324dcfSchristos     MACH_SELECTION_FROM_DEFAULT,
42306324dcfSchristos     MACH_SELECTION_FROM_CPU_DIRECTIVE,
42406324dcfSchristos     MACH_SELECTION_FROM_COMMAND_LINE
42506324dcfSchristos   };
426440a403fSchristos 
42706324dcfSchristos /* How the current machine type was selected.  */
42806324dcfSchristos static enum mach_selection_type mach_selection_mode = MACH_SELECTION_NONE;
429440a403fSchristos 
430440a403fSchristos /* The hash table of instruction opcodes.  */
431440a403fSchristos static struct hash_control *arc_opcode_hash;
432440a403fSchristos 
433440a403fSchristos /* The hash table of register symbols.  */
434440a403fSchristos static struct hash_control *arc_reg_hash;
435440a403fSchristos 
436440a403fSchristos /* The hash table of aux register symbols.  */
437440a403fSchristos static struct hash_control *arc_aux_hash;
438440a403fSchristos 
43906324dcfSchristos /* The hash table of address types.  */
44006324dcfSchristos static struct hash_control *arc_addrtype_hash;
44106324dcfSchristos 
44206324dcfSchristos #define ARC_CPU_TYPE_A6xx(NAME,EXTRA)			\
44306324dcfSchristos   { #NAME, ARC_OPCODE_ARC600, bfd_mach_arc_arc600,	\
44406324dcfSchristos       E_ARC_MACH_ARC600, EXTRA}
44506324dcfSchristos #define ARC_CPU_TYPE_A7xx(NAME,EXTRA)			\
44606324dcfSchristos   { #NAME, ARC_OPCODE_ARC700,  bfd_mach_arc_arc700,	\
44706324dcfSchristos       E_ARC_MACH_ARC700, EXTRA}
44806324dcfSchristos #define ARC_CPU_TYPE_AV2EM(NAME,EXTRA)			\
44906324dcfSchristos   { #NAME,  ARC_OPCODE_ARCv2EM, bfd_mach_arc_arcv2,	\
45006324dcfSchristos       EF_ARC_CPU_ARCV2EM, EXTRA}
45106324dcfSchristos #define ARC_CPU_TYPE_AV2HS(NAME,EXTRA)			\
45206324dcfSchristos   { #NAME,  ARC_OPCODE_ARCv2HS, bfd_mach_arc_arcv2,	\
45306324dcfSchristos       EF_ARC_CPU_ARCV2HS, EXTRA}
45406324dcfSchristos #define ARC_CPU_TYPE_NONE				\
45506324dcfSchristos   { 0, 0, 0, 0, 0 }
45606324dcfSchristos 
457440a403fSchristos /* A table of CPU names and opcode sets.  */
458440a403fSchristos static const struct cpu_type
459440a403fSchristos {
460440a403fSchristos   const char *name;
461440a403fSchristos   unsigned flags;
462440a403fSchristos   int mach;
463440a403fSchristos   unsigned eflags;
464440a403fSchristos   unsigned features;
465440a403fSchristos }
466440a403fSchristos   cpu_types[] =
467440a403fSchristos {
46806324dcfSchristos   #include "elf/arc-cpu.def"
469440a403fSchristos };
470440a403fSchristos 
47106324dcfSchristos /* Information about the cpu/variant we're assembling for.  */
47206324dcfSchristos static struct cpu_type selected_cpu = { 0, 0, 0, E_ARC_OSABI_CURRENT, 0 };
47306324dcfSchristos 
474*b88e3e88Schristos /* TRUE if current assembly code uses RF16 only registers.  */
475*b88e3e88Schristos static bfd_boolean rf16_only = TRUE;
476*b88e3e88Schristos 
47706324dcfSchristos /* MPY option.  */
47806324dcfSchristos static unsigned mpy_option = 0;
47906324dcfSchristos 
48006324dcfSchristos /* Use PIC. */
48106324dcfSchristos static unsigned pic_option = 0;
48206324dcfSchristos 
48306324dcfSchristos /* Use small data.  */
48406324dcfSchristos static unsigned sda_option = 0;
48506324dcfSchristos 
48606324dcfSchristos /* Use TLS.  */
48706324dcfSchristos static unsigned tls_option = 0;
48806324dcfSchristos 
48906324dcfSchristos /* Command line given features.  */
49006324dcfSchristos static unsigned cl_features = 0;
49106324dcfSchristos 
492440a403fSchristos /* Used by the arc_reloc_op table.  Order is important.  */
493440a403fSchristos #define O_gotoff  O_md1     /* @gotoff relocation.  */
494440a403fSchristos #define O_gotpc   O_md2     /* @gotpc relocation.  */
495440a403fSchristos #define O_plt     O_md3     /* @plt relocation.  */
496440a403fSchristos #define O_sda     O_md4     /* @sda relocation.  */
497440a403fSchristos #define O_pcl     O_md5     /* @pcl relocation.  */
498440a403fSchristos #define O_tlsgd   O_md6     /* @tlsgd relocation.  */
499440a403fSchristos #define O_tlsie   O_md7     /* @tlsie relocation.  */
500440a403fSchristos #define O_tpoff9  O_md8     /* @tpoff9 relocation.  */
501440a403fSchristos #define O_tpoff   O_md9     /* @tpoff relocation.  */
502440a403fSchristos #define O_dtpoff9 O_md10    /* @dtpoff9 relocation.  */
503440a403fSchristos #define O_dtpoff  O_md11    /* @dtpoff relocation.  */
504440a403fSchristos #define O_last    O_dtpoff
505440a403fSchristos 
506440a403fSchristos /* Used to define a bracket as operand in tokens.  */
507440a403fSchristos #define O_bracket O_md32
508440a403fSchristos 
50906324dcfSchristos /* Used to define a colon as an operand in tokens.  */
51006324dcfSchristos #define O_colon O_md31
51106324dcfSchristos 
51206324dcfSchristos /* Used to define address types in nps400.  */
51306324dcfSchristos #define O_addrtype O_md30
51406324dcfSchristos 
515440a403fSchristos /* Dummy relocation, to be sorted out.  */
516440a403fSchristos #define DUMMY_RELOC_ARC_ENTRY     (BFD_RELOC_UNUSED + 1)
517440a403fSchristos 
518440a403fSchristos #define USER_RELOC_P(R) ((R) >= O_gotoff && (R) <= O_last)
519440a403fSchristos 
520440a403fSchristos /* A table to map the spelling of a relocation operand into an appropriate
521440a403fSchristos    bfd_reloc_code_real_type type.  The table is assumed to be ordered such
522440a403fSchristos    that op-O_literal indexes into it.  */
523440a403fSchristos #define ARC_RELOC_TABLE(op)				\
524440a403fSchristos   (&arc_reloc_op[ ((!USER_RELOC_P (op))			\
525440a403fSchristos 		   ? (abort (), 0)			\
526440a403fSchristos 		   : (int) (op) - (int) O_gotoff) ])
527440a403fSchristos 
528440a403fSchristos #define DEF(NAME, RELOC, REQ)				\
529440a403fSchristos   { #NAME, sizeof (#NAME)-1, O_##NAME, RELOC, REQ}
530440a403fSchristos 
531440a403fSchristos static const struct arc_reloc_op_tag
532440a403fSchristos {
533440a403fSchristos   /* String to lookup.  */
534440a403fSchristos   const char *name;
535440a403fSchristos   /* Size of the string.  */
536440a403fSchristos   size_t length;
537440a403fSchristos   /* Which operator to use.  */
538440a403fSchristos   operatorT op;
539440a403fSchristos   extended_bfd_reloc_code_real_type reloc;
540440a403fSchristos   /* Allows complex relocation expression like identifier@reloc +
541440a403fSchristos      const.  */
542440a403fSchristos   unsigned int complex_expr : 1;
543440a403fSchristos }
544440a403fSchristos   arc_reloc_op[] =
545440a403fSchristos {
546440a403fSchristos   DEF (gotoff,  BFD_RELOC_ARC_GOTOFF,		1),
547440a403fSchristos   DEF (gotpc,   BFD_RELOC_ARC_GOTPC32,		0),
548440a403fSchristos   DEF (plt,	BFD_RELOC_ARC_PLT32,		0),
549440a403fSchristos   DEF (sda,	DUMMY_RELOC_ARC_ENTRY,		1),
550440a403fSchristos   DEF (pcl,	BFD_RELOC_ARC_PC32,		1),
551440a403fSchristos   DEF (tlsgd,   BFD_RELOC_ARC_TLS_GD_GOT,	0),
552440a403fSchristos   DEF (tlsie,   BFD_RELOC_ARC_TLS_IE_GOT,	0),
553440a403fSchristos   DEF (tpoff9,  BFD_RELOC_ARC_TLS_LE_S9,	0),
554440a403fSchristos   DEF (tpoff,   BFD_RELOC_ARC_TLS_LE_32,	1),
555440a403fSchristos   DEF (dtpoff9, BFD_RELOC_ARC_TLS_DTPOFF_S9,	0),
55606324dcfSchristos   DEF (dtpoff,  BFD_RELOC_ARC_TLS_DTPOFF,	1),
557440a403fSchristos };
558440a403fSchristos 
559440a403fSchristos static const int arc_num_reloc_op
560440a403fSchristos = sizeof (arc_reloc_op) / sizeof (*arc_reloc_op);
561440a403fSchristos 
562440a403fSchristos /* Structure for relaxable instruction that have to be swapped with a
563440a403fSchristos    smaller alternative instruction.  */
564440a403fSchristos struct arc_relaxable_ins
565440a403fSchristos {
566440a403fSchristos   /* Mnemonic that should be checked.  */
567440a403fSchristos   const char *mnemonic_r;
568440a403fSchristos 
569440a403fSchristos   /* Operands that should be checked.
570440a403fSchristos      Indexes of operands from operand array.  */
571440a403fSchristos   enum rlx_operand_type operands[6];
572440a403fSchristos 
573440a403fSchristos   /* Flags that should be checked.  */
574440a403fSchristos   unsigned flag_classes[5];
575440a403fSchristos 
576440a403fSchristos   /* Mnemonic (smaller) alternative to be used later for relaxation.  */
577440a403fSchristos   const char *mnemonic_alt;
578440a403fSchristos 
579440a403fSchristos   /* Index of operand that generic relaxation has to check.  */
580440a403fSchristos   unsigned opcheckidx;
581440a403fSchristos 
582440a403fSchristos   /* Base subtype index used.  */
583440a403fSchristos   enum arc_rlx_types subtype;
584440a403fSchristos };
585440a403fSchristos 
586440a403fSchristos #define RELAX_TABLE_ENTRY(BITS, ISSIGNED, SIZE, NEXT)			\
587440a403fSchristos   { (ISSIGNED) ? ((1 << ((BITS) - 1)) - 1) : ((1 << (BITS)) - 1),	\
588440a403fSchristos       (ISSIGNED) ? -(1 << ((BITS) - 1)) : 0,				\
589440a403fSchristos       (SIZE),								\
590440a403fSchristos       (NEXT) }								\
591440a403fSchristos 
592440a403fSchristos #define RELAX_TABLE_ENTRY_MAX(ISSIGNED, SIZE, NEXT)	\
593440a403fSchristos   { (ISSIGNED) ? 0x7FFFFFFF : 0xFFFFFFFF,		\
594440a403fSchristos       (ISSIGNED) ? -(0x7FFFFFFF) : 0,                   \
595440a403fSchristos       (SIZE),                                           \
596440a403fSchristos       (NEXT) }                                          \
597440a403fSchristos 
598440a403fSchristos 
599440a403fSchristos /* ARC relaxation table.  */
600440a403fSchristos const relax_typeS md_relax_table[] =
601440a403fSchristos {
602440a403fSchristos   /* Fake entry.  */
603440a403fSchristos   {0, 0, 0, 0},
604440a403fSchristos 
605440a403fSchristos   /* BL_S s13 ->
606440a403fSchristos      BL s25.  */
607440a403fSchristos   RELAX_TABLE_ENTRY (13, 1, 2, ARC_RLX_BL),
608440a403fSchristos   RELAX_TABLE_ENTRY (25, 1, 4, ARC_RLX_NONE),
609440a403fSchristos 
610440a403fSchristos   /* B_S s10 ->
611440a403fSchristos      B s25.  */
612440a403fSchristos   RELAX_TABLE_ENTRY (10, 1, 2, ARC_RLX_B),
613440a403fSchristos   RELAX_TABLE_ENTRY (25, 1, 4, ARC_RLX_NONE),
614440a403fSchristos 
615440a403fSchristos   /* ADD_S c,b, u3 ->
616440a403fSchristos      ADD<.f> a,b,u6 ->
617440a403fSchristos      ADD<.f> a,b,limm.  */
618440a403fSchristos   RELAX_TABLE_ENTRY (3, 0, 2, ARC_RLX_ADD_U6),
619440a403fSchristos   RELAX_TABLE_ENTRY (6, 0, 4, ARC_RLX_ADD_LIMM),
620440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
621440a403fSchristos 
622440a403fSchristos   /* LD_S a, [b, u7] ->
623440a403fSchristos      LD<zz><.x><.aa><.di> a, [b, s9] ->
624440a403fSchristos      LD<zz><.x><.aa><.di> a, [b, limm] */
625440a403fSchristos   RELAX_TABLE_ENTRY (7, 0, 2, ARC_RLX_LD_S9),
626440a403fSchristos   RELAX_TABLE_ENTRY (9, 1, 4, ARC_RLX_LD_LIMM),
627440a403fSchristos   RELAX_TABLE_ENTRY_MAX (1, 8, ARC_RLX_NONE),
628440a403fSchristos 
629440a403fSchristos   /* MOV_S b, u8 ->
630440a403fSchristos      MOV<.f> b, s12 ->
631440a403fSchristos      MOV<.f> b, limm.  */
632440a403fSchristos   RELAX_TABLE_ENTRY (8, 0, 2, ARC_RLX_MOV_S12),
633440a403fSchristos   RELAX_TABLE_ENTRY (8, 0, 4, ARC_RLX_MOV_LIMM),
634440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
635440a403fSchristos 
636440a403fSchristos   /* SUB_S c, b, u3 ->
637440a403fSchristos      SUB<.f> a, b, u6 ->
638440a403fSchristos      SUB<.f> a, b, limm.  */
639440a403fSchristos   RELAX_TABLE_ENTRY (3, 0, 2, ARC_RLX_SUB_U6),
640440a403fSchristos   RELAX_TABLE_ENTRY (6, 0, 4, ARC_RLX_SUB_LIMM),
641440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
642440a403fSchristos 
643440a403fSchristos   /* MPY<.f> a, b, u6 ->
644440a403fSchristos      MPY<.f> a, b, limm.  */
645440a403fSchristos   RELAX_TABLE_ENTRY (6, 0, 4, ARC_RLX_MPY_LIMM),
646440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
647440a403fSchristos 
648440a403fSchristos   /* MOV<.f><.cc> b, u6 ->
649440a403fSchristos      MOV<.f><.cc> b, limm.  */
650440a403fSchristos   RELAX_TABLE_ENTRY (6, 0, 4, ARC_RLX_MOV_RLIMM),
651440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
652440a403fSchristos 
653440a403fSchristos   /* ADD<.f><.cc> b, b, u6 ->
654440a403fSchristos      ADD<.f><.cc> b, b, limm.  */
655440a403fSchristos   RELAX_TABLE_ENTRY (6, 0, 4, ARC_RLX_ADD_RRLIMM),
656440a403fSchristos   RELAX_TABLE_ENTRY_MAX (0, 8, ARC_RLX_NONE),
657440a403fSchristos };
658440a403fSchristos 
659440a403fSchristos /* Order of this table's entries matters!  */
660440a403fSchristos const struct arc_relaxable_ins arc_relaxable_insns[] =
661440a403fSchristos {
662440a403fSchristos   { "bl", { IMMEDIATE }, { 0 }, "bl_s", 0, ARC_RLX_BL_S },
663440a403fSchristos   { "b", { IMMEDIATE }, { 0 }, "b_s", 0, ARC_RLX_B_S },
664440a403fSchristos   { "add", { REGISTER, REGISTER_DUP, IMMEDIATE }, { 5, 1, 0 }, "add",
665440a403fSchristos     2, ARC_RLX_ADD_RRU6},
666440a403fSchristos   { "add", { REGISTER_S, REGISTER_S, IMMEDIATE }, { 0 }, "add_s", 2,
667440a403fSchristos     ARC_RLX_ADD_U3 },
668440a403fSchristos   { "add", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "add", 2,
669440a403fSchristos     ARC_RLX_ADD_U6 },
670440a403fSchristos   { "ld", { REGISTER_S, BRACKET, REGISTER_S, IMMEDIATE, BRACKET },
671440a403fSchristos     { 0 }, "ld_s", 3, ARC_RLX_LD_U7 },
672440a403fSchristos   { "ld", { REGISTER, BRACKET, REGISTER_NO_GP, IMMEDIATE, BRACKET },
673440a403fSchristos     { 11, 4, 14, 17, 0 }, "ld", 3, ARC_RLX_LD_S9 },
674440a403fSchristos   { "mov", { REGISTER_S, IMMEDIATE }, { 0 }, "mov_s", 1, ARC_RLX_MOV_U8 },
675440a403fSchristos   { "mov", { REGISTER, IMMEDIATE }, { 5, 0 }, "mov", 1, ARC_RLX_MOV_S12 },
676440a403fSchristos   { "mov", { REGISTER, IMMEDIATE }, { 5, 1, 0 },"mov", 1, ARC_RLX_MOV_RU6 },
677440a403fSchristos   { "sub", { REGISTER_S, REGISTER_S, IMMEDIATE }, { 0 }, "sub_s", 2,
678440a403fSchristos     ARC_RLX_SUB_U3 },
679440a403fSchristos   { "sub", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "sub", 2,
680440a403fSchristos     ARC_RLX_SUB_U6 },
681440a403fSchristos   { "mpy", { REGISTER, REGISTER, IMMEDIATE }, { 5, 0 }, "mpy", 2,
682440a403fSchristos     ARC_RLX_MPY_U6 },
683440a403fSchristos };
684440a403fSchristos 
685440a403fSchristos const unsigned arc_num_relaxable_ins = ARRAY_SIZE (arc_relaxable_insns);
686440a403fSchristos 
687440a403fSchristos /* Pre-defined "_GLOBAL_OFFSET_TABLE_".  */
688440a403fSchristos symbolS * GOT_symbol = 0;
689440a403fSchristos 
690440a403fSchristos /* Set to TRUE when we assemble instructions.  */
691440a403fSchristos static bfd_boolean assembling_insn = FALSE;
692440a403fSchristos 
69306324dcfSchristos /* List with attributes set explicitly.  */
69406324dcfSchristos static bfd_boolean attributes_set_explicitly[NUM_KNOWN_OBJ_ATTRIBUTES];
69506324dcfSchristos 
696440a403fSchristos /* Functions implementation.  */
697440a403fSchristos 
698440a403fSchristos /* Return a pointer to ARC_OPCODE_HASH_ENTRY that identifies all
699440a403fSchristos    ARC_OPCODE entries in ARC_OPCODE_HASH that match NAME, or NULL if there
700440a403fSchristos    are no matching entries in ARC_OPCODE_HASH.  */
701440a403fSchristos 
702440a403fSchristos static const struct arc_opcode_hash_entry *
arc_find_opcode(const char * name)703440a403fSchristos arc_find_opcode (const char *name)
704440a403fSchristos {
705440a403fSchristos   const struct arc_opcode_hash_entry *entry;
706440a403fSchristos 
707440a403fSchristos   entry = hash_find (arc_opcode_hash, name);
708440a403fSchristos   return entry;
709440a403fSchristos }
710440a403fSchristos 
711440a403fSchristos /* Initialise the iterator ITER.  */
712440a403fSchristos 
713440a403fSchristos static void
arc_opcode_hash_entry_iterator_init(struct arc_opcode_hash_entry_iterator * iter)714440a403fSchristos arc_opcode_hash_entry_iterator_init (struct arc_opcode_hash_entry_iterator *iter)
715440a403fSchristos {
716440a403fSchristos   iter->index = 0;
717440a403fSchristos   iter->opcode = NULL;
718440a403fSchristos }
719440a403fSchristos 
720440a403fSchristos /* Return the next ARC_OPCODE from ENTRY, using ITER to hold state between
721440a403fSchristos    calls to this function.  Return NULL when all ARC_OPCODE entries have
722440a403fSchristos    been returned.  */
723440a403fSchristos 
724440a403fSchristos static const struct arc_opcode *
arc_opcode_hash_entry_iterator_next(const struct arc_opcode_hash_entry * entry,struct arc_opcode_hash_entry_iterator * iter)725440a403fSchristos arc_opcode_hash_entry_iterator_next (const struct arc_opcode_hash_entry *entry,
726440a403fSchristos 				     struct arc_opcode_hash_entry_iterator *iter)
727440a403fSchristos {
728440a403fSchristos   if (iter->opcode == NULL && iter->index == 0)
729440a403fSchristos     {
730440a403fSchristos       gas_assert (entry->count > 0);
731440a403fSchristos       iter->opcode = entry->opcode[iter->index];
732440a403fSchristos     }
733440a403fSchristos   else if (iter->opcode != NULL)
734440a403fSchristos     {
735440a403fSchristos       const char *old_name = iter->opcode->name;
736440a403fSchristos 
737440a403fSchristos       iter->opcode++;
738440a403fSchristos       if (iter->opcode->name == NULL
739440a403fSchristos 	  || strcmp (old_name, iter->opcode->name) != 0)
740440a403fSchristos 	{
741440a403fSchristos 	  iter->index++;
742440a403fSchristos 	  if (iter->index == entry->count)
743440a403fSchristos 	    iter->opcode = NULL;
744440a403fSchristos 	  else
745440a403fSchristos 	    iter->opcode = entry->opcode[iter->index];
746440a403fSchristos 	}
747440a403fSchristos     }
748440a403fSchristos 
749440a403fSchristos   return iter->opcode;
750440a403fSchristos }
751440a403fSchristos 
752440a403fSchristos /* Insert an opcode into opcode hash structure.  */
753440a403fSchristos 
754440a403fSchristos static void
arc_insert_opcode(const struct arc_opcode * opcode)755440a403fSchristos arc_insert_opcode (const struct arc_opcode *opcode)
756440a403fSchristos {
757440a403fSchristos   const char *name, *retval;
758440a403fSchristos   struct arc_opcode_hash_entry *entry;
759440a403fSchristos   name = opcode->name;
760440a403fSchristos 
761440a403fSchristos   entry = hash_find (arc_opcode_hash, name);
762440a403fSchristos   if (entry == NULL)
763440a403fSchristos     {
764440a403fSchristos       entry = XNEW (struct arc_opcode_hash_entry);
765440a403fSchristos       entry->count = 0;
766440a403fSchristos       entry->opcode = NULL;
767440a403fSchristos 
768440a403fSchristos       retval = hash_insert (arc_opcode_hash, name, (void *) entry);
769440a403fSchristos       if (retval)
770440a403fSchristos 	as_fatal (_("internal error: can't hash opcode '%s': %s"),
771440a403fSchristos 		  name, retval);
772440a403fSchristos     }
773440a403fSchristos 
774440a403fSchristos   entry->opcode = XRESIZEVEC (const struct arc_opcode *, entry->opcode,
775440a403fSchristos 			      entry->count + 1);
776440a403fSchristos 
777440a403fSchristos   if (entry->opcode == NULL)
778440a403fSchristos     as_fatal (_("Virtual memory exhausted"));
779440a403fSchristos 
780440a403fSchristos   entry->opcode[entry->count] = opcode;
781440a403fSchristos   entry->count++;
782440a403fSchristos }
783440a403fSchristos 
784440a403fSchristos 
78506324dcfSchristos /* Like md_number_to_chars but for middle-endian values.  The 4-byte limm
78606324dcfSchristos    value, is encoded as 'middle-endian' for a little-endian target.  This
78706324dcfSchristos    function is used for regular 4, 6, and 8 byte instructions as well.  */
788440a403fSchristos 
789440a403fSchristos static void
md_number_to_chars_midend(char * buf,unsigned long long val,int n)79006324dcfSchristos md_number_to_chars_midend (char *buf, unsigned long long val, int n)
791440a403fSchristos {
79206324dcfSchristos   switch (n)
793440a403fSchristos     {
79406324dcfSchristos     case 2:
79506324dcfSchristos       md_number_to_chars (buf, val, n);
79606324dcfSchristos       break;
79706324dcfSchristos     case 6:
798*b88e3e88Schristos       md_number_to_chars (buf, (val & 0xffff00000000ull) >> 32, 2);
79906324dcfSchristos       md_number_to_chars_midend (buf + 2, (val & 0xffffffff), 4);
80006324dcfSchristos       break;
80106324dcfSchristos     case 4:
802440a403fSchristos       md_number_to_chars (buf,     (val & 0xffff0000) >> 16, 2);
803440a403fSchristos       md_number_to_chars (buf + 2, (val & 0xffff), 2);
80406324dcfSchristos       break;
80506324dcfSchristos     case 8:
806*b88e3e88Schristos       md_number_to_chars_midend (buf, (val & 0xffffffff00000000ull) >> 32, 4);
80706324dcfSchristos       md_number_to_chars_midend (buf + 4, (val & 0xffffffff), 4);
80806324dcfSchristos       break;
80906324dcfSchristos     default:
81006324dcfSchristos       abort ();
811440a403fSchristos     }
81206324dcfSchristos }
81306324dcfSchristos 
81406324dcfSchristos /* Check if a feature is allowed for a specific CPU.  */
81506324dcfSchristos 
81606324dcfSchristos static void
arc_check_feature(void)81706324dcfSchristos arc_check_feature (void)
818440a403fSchristos {
81906324dcfSchristos   unsigned i;
82006324dcfSchristos 
82106324dcfSchristos   if (!selected_cpu.features
82206324dcfSchristos       || !selected_cpu.name)
82306324dcfSchristos     return;
82406324dcfSchristos 
82506324dcfSchristos   for (i = 0; i < ARRAY_SIZE (feature_list); i++)
82606324dcfSchristos     if ((selected_cpu.features & feature_list[i].feature)
82706324dcfSchristos 	&& !(selected_cpu.flags & feature_list[i].cpus))
82806324dcfSchristos       as_bad (_("invalid %s option for %s cpu"), feature_list[i].name,
82906324dcfSchristos 	      selected_cpu.name);
83006324dcfSchristos 
83106324dcfSchristos   for (i = 0; i < ARRAY_SIZE (conflict_list); i++)
83206324dcfSchristos     if ((selected_cpu.features & conflict_list[i]) == conflict_list[i])
83306324dcfSchristos       as_bad(_("conflicting ISA extension attributes."));
834440a403fSchristos }
835440a403fSchristos 
836440a403fSchristos /* Select an appropriate entry from CPU_TYPES based on ARG and initialise
83706324dcfSchristos    the relevant static global variables.  Parameter SEL describes where
83806324dcfSchristos    this selection originated from.  */
839440a403fSchristos 
840440a403fSchristos static void
arc_select_cpu(const char * arg,enum mach_selection_type sel)84106324dcfSchristos arc_select_cpu (const char *arg, enum mach_selection_type sel)
842440a403fSchristos {
843440a403fSchristos   int i;
844*b88e3e88Schristos   static struct cpu_type old_cpu = { 0, 0, 0, E_ARC_OSABI_CURRENT, 0 };
845440a403fSchristos 
84606324dcfSchristos   /* We should only set a default if we've not made a selection from some
84706324dcfSchristos      other source.  */
84806324dcfSchristos   gas_assert (sel != MACH_SELECTION_FROM_DEFAULT
84906324dcfSchristos               || mach_selection_mode == MACH_SELECTION_NONE);
85006324dcfSchristos 
85106324dcfSchristos   if ((mach_selection_mode == MACH_SELECTION_FROM_CPU_DIRECTIVE)
85206324dcfSchristos       && (sel == MACH_SELECTION_FROM_CPU_DIRECTIVE))
85306324dcfSchristos     as_bad (_("Multiple .cpu directives found"));
85406324dcfSchristos 
85506324dcfSchristos   /* Look for a matching entry in CPU_TYPES array.  */
856440a403fSchristos   for (i = 0; cpu_types[i].name; ++i)
857440a403fSchristos     {
858440a403fSchristos       if (!strcasecmp (cpu_types[i].name, arg))
859440a403fSchristos         {
86006324dcfSchristos           /* If a previous selection was made on the command line, then we
86106324dcfSchristos              allow later selections on the command line to override earlier
86206324dcfSchristos              ones.  However, a selection from a '.cpu NAME' directive must
86306324dcfSchristos              match the command line selection, or we give a warning.  */
86406324dcfSchristos           if (mach_selection_mode == MACH_SELECTION_FROM_COMMAND_LINE)
86506324dcfSchristos             {
86606324dcfSchristos               gas_assert (sel == MACH_SELECTION_FROM_COMMAND_LINE
86706324dcfSchristos                           || sel == MACH_SELECTION_FROM_CPU_DIRECTIVE);
86806324dcfSchristos               if (sel == MACH_SELECTION_FROM_CPU_DIRECTIVE
86906324dcfSchristos                   && selected_cpu.mach != cpu_types[i].mach)
87006324dcfSchristos                 {
87106324dcfSchristos                   as_warn (_("Command-line value overrides \".cpu\" directive"));
87206324dcfSchristos                 }
87306324dcfSchristos 	      return;
87406324dcfSchristos             }
87506324dcfSchristos 	  /* Initialise static global data about selected machine type.  */
87606324dcfSchristos 	  selected_cpu.flags = cpu_types[i].flags;
87706324dcfSchristos 	  selected_cpu.name = cpu_types[i].name;
87806324dcfSchristos 	  selected_cpu.features = cpu_types[i].features | cl_features;
87906324dcfSchristos 	  selected_cpu.mach = cpu_types[i].mach;
88006324dcfSchristos 	  selected_cpu.eflags = ((selected_cpu.eflags & ~EF_ARC_MACH_MSK)
88106324dcfSchristos 				 | cpu_types[i].eflags);
882440a403fSchristos           break;
883440a403fSchristos         }
884440a403fSchristos     }
885440a403fSchristos 
886440a403fSchristos   if (!cpu_types[i].name)
887440a403fSchristos     as_fatal (_("unknown architecture: %s\n"), arg);
88806324dcfSchristos 
88906324dcfSchristos   /* Check if set features are compatible with the chosen CPU.  */
89006324dcfSchristos   arc_check_feature ();
89106324dcfSchristos 
892*b88e3e88Schristos   /* If we change the CPU, we need to re-init the bfd.  */
893*b88e3e88Schristos   if (mach_selection_mode != MACH_SELECTION_NONE
894*b88e3e88Schristos       && (old_cpu.mach != selected_cpu.mach))
895*b88e3e88Schristos     {
896*b88e3e88Schristos       bfd_find_target (arc_target_format, stdoutput);
897*b88e3e88Schristos       if (! bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
898*b88e3e88Schristos 	as_warn (_("Could not set architecture and machine"));
899*b88e3e88Schristos     }
900*b88e3e88Schristos 
90106324dcfSchristos   mach_selection_mode = sel;
902*b88e3e88Schristos   old_cpu = selected_cpu;
903440a403fSchristos }
904440a403fSchristos 
905440a403fSchristos /* Here ends all the ARCompact extension instruction assembling
906440a403fSchristos    stuff.  */
907440a403fSchristos 
908440a403fSchristos static void
arc_extra_reloc(int r_type)909440a403fSchristos arc_extra_reloc (int r_type)
910440a403fSchristos {
911440a403fSchristos   char *sym_name, c;
912440a403fSchristos   symbolS *sym, *lab = NULL;
913440a403fSchristos 
914440a403fSchristos   if (*input_line_pointer == '@')
915440a403fSchristos     input_line_pointer++;
916440a403fSchristos   c = get_symbol_name (&sym_name);
917440a403fSchristos   sym = symbol_find_or_make (sym_name);
918440a403fSchristos   restore_line_pointer (c);
919440a403fSchristos   if (c == ',' && r_type == BFD_RELOC_ARC_TLS_GD_LD)
920440a403fSchristos     {
921440a403fSchristos       ++input_line_pointer;
922440a403fSchristos       char *lab_name;
923440a403fSchristos       c = get_symbol_name (&lab_name);
924440a403fSchristos       lab = symbol_find_or_make (lab_name);
925440a403fSchristos       restore_line_pointer (c);
926440a403fSchristos     }
927440a403fSchristos 
928440a403fSchristos   /* These relocations exist as a mechanism for the compiler to tell the
929440a403fSchristos      linker how to patch the code if the tls model is optimised.  However,
930440a403fSchristos      the relocation itself does not require any space within the assembler
931440a403fSchristos      fragment, and so we pass a size of 0.
932440a403fSchristos 
933440a403fSchristos      The lines that generate these relocations look like this:
934440a403fSchristos 
935440a403fSchristos          .tls_gd_ld @.tdata`bl __tls_get_addr@plt
936440a403fSchristos 
937440a403fSchristos      The '.tls_gd_ld @.tdata' is processed first and generates the
938440a403fSchristos      additional relocation, while the 'bl __tls_get_addr@plt' is processed
939440a403fSchristos      second and generates the additional branch.
940440a403fSchristos 
941440a403fSchristos      It is possible that the additional relocation generated by the
942440a403fSchristos      '.tls_gd_ld @.tdata' will be attached at the very end of one fragment,
943440a403fSchristos      while the 'bl __tls_get_addr@plt' will be generated as the first thing
944440a403fSchristos      in the next fragment.  This will be fine; both relocations will still
945440a403fSchristos      appear to be at the same address in the generated object file.
946440a403fSchristos      However, this only works as the additional relocation is generated
947440a403fSchristos      with size of 0 bytes.  */
948440a403fSchristos   fixS *fixP
949440a403fSchristos     = fix_new (frag_now,	/* Which frag?  */
950440a403fSchristos 	       frag_now_fix (),	/* Where in that frag?  */
951440a403fSchristos 	       0,		/* size: 1, 2, or 4 usually.  */
952440a403fSchristos 	       sym,		/* X_add_symbol.  */
953440a403fSchristos 	       0,		/* X_add_number.  */
954440a403fSchristos 	       FALSE,		/* TRUE if PC-relative relocation.  */
955440a403fSchristos 	       r_type		/* Relocation type.  */);
956440a403fSchristos   fixP->fx_subsy = lab;
957440a403fSchristos }
958440a403fSchristos 
959440a403fSchristos static symbolS *
arc_lcomm_internal(int ignore ATTRIBUTE_UNUSED,symbolS * symbolP,addressT size)960440a403fSchristos arc_lcomm_internal (int ignore ATTRIBUTE_UNUSED,
961440a403fSchristos 		    symbolS *symbolP, addressT size)
962440a403fSchristos {
963440a403fSchristos   addressT align = 0;
964440a403fSchristos   SKIP_WHITESPACE ();
965440a403fSchristos 
966440a403fSchristos   if (*input_line_pointer == ',')
967440a403fSchristos     {
968440a403fSchristos       align = parse_align (1);
969440a403fSchristos 
970440a403fSchristos       if (align == (addressT) -1)
971440a403fSchristos 	return NULL;
972440a403fSchristos     }
973440a403fSchristos   else
974440a403fSchristos     {
975440a403fSchristos       if (size >= 8)
976440a403fSchristos 	align = 3;
977440a403fSchristos       else if (size >= 4)
978440a403fSchristos 	align = 2;
979440a403fSchristos       else if (size >= 2)
980440a403fSchristos 	align = 1;
981440a403fSchristos       else
982440a403fSchristos 	align = 0;
983440a403fSchristos     }
984440a403fSchristos 
985440a403fSchristos   bss_alloc (symbolP, size, align);
986440a403fSchristos   S_CLEAR_EXTERNAL (symbolP);
987440a403fSchristos 
988440a403fSchristos   return symbolP;
989440a403fSchristos }
990440a403fSchristos 
991440a403fSchristos static void
arc_lcomm(int ignore)992440a403fSchristos arc_lcomm (int ignore)
993440a403fSchristos {
994440a403fSchristos   symbolS *symbolP = s_comm_internal (ignore, arc_lcomm_internal);
995440a403fSchristos 
996440a403fSchristos   if (symbolP)
997440a403fSchristos     symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
998440a403fSchristos }
999440a403fSchristos 
1000440a403fSchristos /* Select the cpu we're assembling for.  */
1001440a403fSchristos 
1002440a403fSchristos static void
arc_option(int ignore ATTRIBUTE_UNUSED)1003440a403fSchristos arc_option (int ignore ATTRIBUTE_UNUSED)
1004440a403fSchristos {
1005440a403fSchristos   char c;
1006440a403fSchristos   char *cpu;
100706324dcfSchristos   const char *cpu_name;
1008440a403fSchristos 
1009440a403fSchristos   c = get_symbol_name (&cpu);
1010440a403fSchristos 
101106324dcfSchristos   cpu_name = cpu;
1012440a403fSchristos   if ((!strcmp ("ARC600", cpu))
1013440a403fSchristos       || (!strcmp ("ARC601", cpu))
1014440a403fSchristos       || (!strcmp ("A6", cpu)))
101506324dcfSchristos     cpu_name = "arc600";
1016440a403fSchristos   else if ((!strcmp ("ARC700", cpu))
1017440a403fSchristos            || (!strcmp ("A7", cpu)))
101806324dcfSchristos     cpu_name = "arc700";
1019440a403fSchristos   else if (!strcmp ("EM", cpu))
102006324dcfSchristos     cpu_name = "arcem";
1021440a403fSchristos   else if (!strcmp ("HS", cpu))
102206324dcfSchristos     cpu_name = "archs";
1023440a403fSchristos   else if (!strcmp ("NPS400", cpu))
102406324dcfSchristos     cpu_name = "nps400";
1025440a403fSchristos 
102606324dcfSchristos   arc_select_cpu (cpu_name, MACH_SELECTION_FROM_CPU_DIRECTIVE);
1027440a403fSchristos 
1028440a403fSchristos   restore_line_pointer (c);
1029440a403fSchristos   demand_empty_rest_of_line ();
1030440a403fSchristos }
1031440a403fSchristos 
1032440a403fSchristos /* Smartly print an expression.  */
1033440a403fSchristos 
1034440a403fSchristos static void
debug_exp(expressionS * t)1035440a403fSchristos debug_exp (expressionS *t)
1036440a403fSchristos {
1037440a403fSchristos   const char *name ATTRIBUTE_UNUSED;
1038440a403fSchristos   const char *namemd ATTRIBUTE_UNUSED;
1039440a403fSchristos 
1040440a403fSchristos   pr_debug ("debug_exp: ");
1041440a403fSchristos 
1042440a403fSchristos   switch (t->X_op)
1043440a403fSchristos     {
1044440a403fSchristos     default:			name = "unknown";		break;
1045440a403fSchristos     case O_illegal:		name = "O_illegal";		break;
1046440a403fSchristos     case O_absent:		name = "O_absent";		break;
1047440a403fSchristos     case O_constant:		name = "O_constant";		break;
1048440a403fSchristos     case O_symbol:		name = "O_symbol";		break;
1049440a403fSchristos     case O_symbol_rva:		name = "O_symbol_rva";		break;
1050440a403fSchristos     case O_register:		name = "O_register";		break;
1051440a403fSchristos     case O_big:			name = "O_big";			break;
1052440a403fSchristos     case O_uminus:		name = "O_uminus";		break;
1053440a403fSchristos     case O_bit_not:		name = "O_bit_not";		break;
1054440a403fSchristos     case O_logical_not:		name = "O_logical_not";		break;
1055440a403fSchristos     case O_multiply:		name = "O_multiply";		break;
1056440a403fSchristos     case O_divide:		name = "O_divide";		break;
1057440a403fSchristos     case O_modulus:		name = "O_modulus";		break;
1058440a403fSchristos     case O_left_shift:		name = "O_left_shift";		break;
1059440a403fSchristos     case O_right_shift:		name = "O_right_shift";		break;
1060440a403fSchristos     case O_bit_inclusive_or:	name = "O_bit_inclusive_or";	break;
1061440a403fSchristos     case O_bit_or_not:		name = "O_bit_or_not";		break;
1062440a403fSchristos     case O_bit_exclusive_or:	name = "O_bit_exclusive_or";	break;
1063440a403fSchristos     case O_bit_and:		name = "O_bit_and";		break;
1064440a403fSchristos     case O_add:			name = "O_add";			break;
1065440a403fSchristos     case O_subtract:		name = "O_subtract";		break;
1066440a403fSchristos     case O_eq:			name = "O_eq";			break;
1067440a403fSchristos     case O_ne:			name = "O_ne";			break;
1068440a403fSchristos     case O_lt:			name = "O_lt";			break;
1069440a403fSchristos     case O_le:			name = "O_le";			break;
1070440a403fSchristos     case O_ge:			name = "O_ge";			break;
1071440a403fSchristos     case O_gt:			name = "O_gt";			break;
1072440a403fSchristos     case O_logical_and:		name = "O_logical_and";		break;
1073440a403fSchristos     case O_logical_or:		name = "O_logical_or";		break;
1074440a403fSchristos     case O_index:		name = "O_index";		break;
1075440a403fSchristos     case O_bracket:		name = "O_bracket";		break;
107606324dcfSchristos     case O_colon:		name = "O_colon";               break;
107706324dcfSchristos     case O_addrtype:		name = "O_addrtype";            break;
1078440a403fSchristos     }
1079440a403fSchristos 
1080440a403fSchristos   switch (t->X_md)
1081440a403fSchristos     {
1082440a403fSchristos     default:			namemd = "unknown";		break;
1083440a403fSchristos     case O_gotoff:		namemd = "O_gotoff";		break;
1084440a403fSchristos     case O_gotpc:		namemd = "O_gotpc";		break;
1085440a403fSchristos     case O_plt:			namemd = "O_plt";		break;
1086440a403fSchristos     case O_sda:			namemd = "O_sda";		break;
1087440a403fSchristos     case O_pcl:			namemd = "O_pcl";		break;
1088440a403fSchristos     case O_tlsgd:		namemd = "O_tlsgd";		break;
1089440a403fSchristos     case O_tlsie:		namemd = "O_tlsie";		break;
1090440a403fSchristos     case O_tpoff9:		namemd = "O_tpoff9";		break;
1091440a403fSchristos     case O_tpoff:		namemd = "O_tpoff";		break;
1092440a403fSchristos     case O_dtpoff9:		namemd = "O_dtpoff9";		break;
1093440a403fSchristos     case O_dtpoff:		namemd = "O_dtpoff";		break;
1094440a403fSchristos     }
1095440a403fSchristos 
1096440a403fSchristos   pr_debug ("%s (%s, %s, %d, %s)", name,
1097440a403fSchristos 	    (t->X_add_symbol) ? S_GET_NAME (t->X_add_symbol) : "--",
1098440a403fSchristos 	    (t->X_op_symbol) ? S_GET_NAME (t->X_op_symbol) : "--",
1099440a403fSchristos 	    (int) t->X_add_number,
1100440a403fSchristos 	    (t->X_md) ? namemd : "--");
1101440a403fSchristos   pr_debug ("\n");
1102440a403fSchristos   fflush (stderr);
1103440a403fSchristos }
1104440a403fSchristos 
1105*b88e3e88Schristos /* Helper for parsing an argument, used for sorting out the relocation
1106*b88e3e88Schristos    type.  */
1107*b88e3e88Schristos 
1108*b88e3e88Schristos static void
parse_reloc_symbol(expressionS * resultP)1109*b88e3e88Schristos parse_reloc_symbol (expressionS *resultP)
1110*b88e3e88Schristos {
1111*b88e3e88Schristos   char *reloc_name, c, *sym_name;
1112*b88e3e88Schristos   size_t len;
1113*b88e3e88Schristos   int i;
1114*b88e3e88Schristos   const struct arc_reloc_op_tag *r;
1115*b88e3e88Schristos   expressionS right;
1116*b88e3e88Schristos   symbolS *base;
1117*b88e3e88Schristos 
1118*b88e3e88Schristos   /* A relocation operand has the following form
1119*b88e3e88Schristos      @identifier@relocation_type.  The identifier is already in
1120*b88e3e88Schristos      tok!  */
1121*b88e3e88Schristos   if (resultP->X_op != O_symbol)
1122*b88e3e88Schristos     {
1123*b88e3e88Schristos       as_bad (_("No valid label relocation operand"));
1124*b88e3e88Schristos       resultP->X_op = O_illegal;
1125*b88e3e88Schristos       return;
1126*b88e3e88Schristos     }
1127*b88e3e88Schristos 
1128*b88e3e88Schristos   /* Parse @relocation_type.  */
1129*b88e3e88Schristos   input_line_pointer++;
1130*b88e3e88Schristos   c = get_symbol_name (&reloc_name);
1131*b88e3e88Schristos   len = input_line_pointer - reloc_name;
1132*b88e3e88Schristos   if (len == 0)
1133*b88e3e88Schristos     {
1134*b88e3e88Schristos       as_bad (_("No relocation operand"));
1135*b88e3e88Schristos       resultP->X_op = O_illegal;
1136*b88e3e88Schristos       return;
1137*b88e3e88Schristos     }
1138*b88e3e88Schristos 
1139*b88e3e88Schristos   /* Go through known relocation and try to find a match.  */
1140*b88e3e88Schristos   r = &arc_reloc_op[0];
1141*b88e3e88Schristos   for (i = arc_num_reloc_op - 1; i >= 0; i--, r++)
1142*b88e3e88Schristos     if (len == r->length
1143*b88e3e88Schristos 	&& memcmp (reloc_name, r->name, len) == 0)
1144*b88e3e88Schristos       break;
1145*b88e3e88Schristos   if (i < 0)
1146*b88e3e88Schristos     {
1147*b88e3e88Schristos       as_bad (_("Unknown relocation operand: @%s"), reloc_name);
1148*b88e3e88Schristos       resultP->X_op = O_illegal;
1149*b88e3e88Schristos       return;
1150*b88e3e88Schristos     }
1151*b88e3e88Schristos 
1152*b88e3e88Schristos   *input_line_pointer = c;
1153*b88e3e88Schristos   SKIP_WHITESPACE_AFTER_NAME ();
1154*b88e3e88Schristos   /* Extra check for TLS: base.  */
1155*b88e3e88Schristos   if (*input_line_pointer == '@')
1156*b88e3e88Schristos     {
1157*b88e3e88Schristos       if (resultP->X_op_symbol != NULL
1158*b88e3e88Schristos 	  || resultP->X_op != O_symbol)
1159*b88e3e88Schristos 	{
1160*b88e3e88Schristos 	  as_bad (_("Unable to parse TLS base: %s"),
1161*b88e3e88Schristos 		  input_line_pointer);
1162*b88e3e88Schristos 	  resultP->X_op = O_illegal;
1163*b88e3e88Schristos 	  return;
1164*b88e3e88Schristos 	}
1165*b88e3e88Schristos       input_line_pointer++;
1166*b88e3e88Schristos       c = get_symbol_name (&sym_name);
1167*b88e3e88Schristos       base = symbol_find_or_make (sym_name);
1168*b88e3e88Schristos       resultP->X_op = O_subtract;
1169*b88e3e88Schristos       resultP->X_op_symbol = base;
1170*b88e3e88Schristos       restore_line_pointer (c);
1171*b88e3e88Schristos       right.X_add_number = 0;
1172*b88e3e88Schristos     }
1173*b88e3e88Schristos 
1174*b88e3e88Schristos   if ((*input_line_pointer != '+')
1175*b88e3e88Schristos       && (*input_line_pointer != '-'))
1176*b88e3e88Schristos     right.X_add_number = 0;
1177*b88e3e88Schristos   else
1178*b88e3e88Schristos     {
1179*b88e3e88Schristos       /* Parse the constant of a complex relocation expression
1180*b88e3e88Schristos 	 like @identifier@reloc +/- const.  */
1181*b88e3e88Schristos       if (! r->complex_expr)
1182*b88e3e88Schristos 	{
1183*b88e3e88Schristos 	  as_bad (_("@%s is not a complex relocation."), r->name);
1184*b88e3e88Schristos 	  resultP->X_op = O_illegal;
1185*b88e3e88Schristos 	  return;
1186*b88e3e88Schristos 	}
1187*b88e3e88Schristos       expression (&right);
1188*b88e3e88Schristos       if (right.X_op != O_constant)
1189*b88e3e88Schristos 	{
1190*b88e3e88Schristos 	  as_bad (_("Bad expression: @%s + %s."),
1191*b88e3e88Schristos 		  r->name, input_line_pointer);
1192*b88e3e88Schristos 	  resultP->X_op = O_illegal;
1193*b88e3e88Schristos 	  return;
1194*b88e3e88Schristos 	}
1195*b88e3e88Schristos     }
1196*b88e3e88Schristos 
1197*b88e3e88Schristos   resultP->X_md = r->op;
1198*b88e3e88Schristos   resultP->X_add_number = right.X_add_number;
1199*b88e3e88Schristos }
1200*b88e3e88Schristos 
1201440a403fSchristos /* Parse the arguments to an opcode.  */
1202440a403fSchristos 
1203440a403fSchristos static int
tokenize_arguments(char * str,expressionS * tok,int ntok)1204440a403fSchristos tokenize_arguments (char *str,
1205440a403fSchristos 		    expressionS *tok,
1206440a403fSchristos 		    int ntok)
1207440a403fSchristos {
1208440a403fSchristos   char *old_input_line_pointer;
1209440a403fSchristos   bfd_boolean saw_comma = FALSE;
1210440a403fSchristos   bfd_boolean saw_arg = FALSE;
1211440a403fSchristos   int brk_lvl = 0;
1212440a403fSchristos   int num_args = 0;
1213440a403fSchristos 
1214440a403fSchristos   memset (tok, 0, sizeof (*tok) * ntok);
1215440a403fSchristos 
1216440a403fSchristos   /* Save and restore input_line_pointer around this function.  */
1217440a403fSchristos   old_input_line_pointer = input_line_pointer;
1218440a403fSchristos   input_line_pointer = str;
1219440a403fSchristos 
1220440a403fSchristos   while (*input_line_pointer)
1221440a403fSchristos     {
1222440a403fSchristos       SKIP_WHITESPACE ();
1223440a403fSchristos       switch (*input_line_pointer)
1224440a403fSchristos 	{
1225440a403fSchristos 	case '\0':
1226440a403fSchristos 	  goto fini;
1227440a403fSchristos 
1228440a403fSchristos 	case ',':
1229440a403fSchristos 	  input_line_pointer++;
1230440a403fSchristos 	  if (saw_comma || !saw_arg)
1231440a403fSchristos 	    goto err;
1232440a403fSchristos 	  saw_comma = TRUE;
1233440a403fSchristos 	  break;
1234440a403fSchristos 
1235440a403fSchristos 	case '}':
1236440a403fSchristos 	case ']':
1237440a403fSchristos 	  ++input_line_pointer;
1238440a403fSchristos 	  --brk_lvl;
1239440a403fSchristos 	  if (!saw_arg || num_args == ntok)
1240440a403fSchristos 	    goto err;
1241440a403fSchristos 	  tok->X_op = O_bracket;
1242440a403fSchristos 	  ++tok;
1243440a403fSchristos 	  ++num_args;
1244440a403fSchristos 	  break;
1245440a403fSchristos 
1246440a403fSchristos 	case '{':
1247440a403fSchristos 	case '[':
1248440a403fSchristos 	  input_line_pointer++;
1249440a403fSchristos 	  if (brk_lvl || num_args == ntok)
1250440a403fSchristos 	    goto err;
1251440a403fSchristos 	  ++brk_lvl;
1252440a403fSchristos 	  tok->X_op = O_bracket;
1253440a403fSchristos 	  ++tok;
1254440a403fSchristos 	  ++num_args;
1255440a403fSchristos 	  break;
1256440a403fSchristos 
125706324dcfSchristos         case ':':
125806324dcfSchristos           input_line_pointer++;
125906324dcfSchristos           if (!saw_arg || num_args == ntok)
126006324dcfSchristos             goto err;
126106324dcfSchristos           tok->X_op = O_colon;
126206324dcfSchristos           saw_arg = FALSE;
126306324dcfSchristos           ++tok;
126406324dcfSchristos           ++num_args;
126506324dcfSchristos           break;
126606324dcfSchristos 
1267440a403fSchristos 	case '@':
1268440a403fSchristos 	  /* We have labels, function names and relocations, all
1269440a403fSchristos 	     starting with @ symbol.  Sort them out.  */
1270440a403fSchristos 	  if ((saw_arg && !saw_comma) || num_args == ntok)
1271440a403fSchristos 	    goto err;
1272440a403fSchristos 
1273440a403fSchristos 	  /* Parse @label.  */
1274*b88e3e88Schristos 	  input_line_pointer++;
1275440a403fSchristos 	  tok->X_op = O_symbol;
1276440a403fSchristos 	  tok->X_md = O_absent;
1277440a403fSchristos 	  expression (tok);
1278440a403fSchristos 
1279440a403fSchristos 	  if (*input_line_pointer == '@')
1280*b88e3e88Schristos 	    parse_reloc_symbol (tok);
1281440a403fSchristos 
1282440a403fSchristos 	  debug_exp (tok);
1283440a403fSchristos 
1284*b88e3e88Schristos 	  if (tok->X_op == O_illegal
1285*b88e3e88Schristos               || tok->X_op == O_absent
1286*b88e3e88Schristos               || num_args == ntok)
1287*b88e3e88Schristos 	    goto err;
1288*b88e3e88Schristos 
1289440a403fSchristos 	  saw_comma = FALSE;
1290440a403fSchristos 	  saw_arg = TRUE;
1291440a403fSchristos 	  tok++;
1292440a403fSchristos 	  num_args++;
1293440a403fSchristos 	  break;
1294440a403fSchristos 
1295440a403fSchristos 	case '%':
1296440a403fSchristos 	  /* Can be a register.  */
1297440a403fSchristos 	  ++input_line_pointer;
1298440a403fSchristos 	  /* Fall through.  */
1299440a403fSchristos 	default:
1300440a403fSchristos 
1301440a403fSchristos 	  if ((saw_arg && !saw_comma) || num_args == ntok)
1302440a403fSchristos 	    goto err;
1303440a403fSchristos 
1304440a403fSchristos 	  tok->X_op = O_absent;
1305440a403fSchristos 	  tok->X_md = O_absent;
1306440a403fSchristos 	  expression (tok);
1307440a403fSchristos 
1308440a403fSchristos 	  /* Legacy: There are cases when we have
1309440a403fSchristos 	     identifier@relocation_type, if it is the case parse the
1310440a403fSchristos 	     relocation type as well.  */
1311440a403fSchristos 	  if (*input_line_pointer == '@')
1312*b88e3e88Schristos 	    parse_reloc_symbol (tok);
1313440a403fSchristos 
1314440a403fSchristos 	  debug_exp (tok);
1315440a403fSchristos 
1316440a403fSchristos 	  if (tok->X_op == O_illegal
1317440a403fSchristos               || tok->X_op == O_absent
1318440a403fSchristos               || num_args == ntok)
1319440a403fSchristos 	    goto err;
1320440a403fSchristos 
1321440a403fSchristos 	  saw_comma = FALSE;
1322440a403fSchristos 	  saw_arg = TRUE;
1323440a403fSchristos 	  tok++;
1324440a403fSchristos 	  num_args++;
1325440a403fSchristos 	  break;
1326440a403fSchristos 	}
1327440a403fSchristos     }
1328440a403fSchristos 
1329440a403fSchristos  fini:
1330440a403fSchristos   if (saw_comma || brk_lvl)
1331440a403fSchristos     goto err;
1332440a403fSchristos   input_line_pointer = old_input_line_pointer;
1333440a403fSchristos 
1334440a403fSchristos   return num_args;
1335440a403fSchristos 
1336440a403fSchristos  err:
1337440a403fSchristos   if (brk_lvl)
1338440a403fSchristos     as_bad (_("Brackets in operand field incorrect"));
1339440a403fSchristos   else if (saw_comma)
1340440a403fSchristos     as_bad (_("extra comma"));
1341440a403fSchristos   else if (!saw_arg)
1342440a403fSchristos     as_bad (_("missing argument"));
1343440a403fSchristos   else
1344440a403fSchristos     as_bad (_("missing comma or colon"));
1345440a403fSchristos   input_line_pointer = old_input_line_pointer;
1346440a403fSchristos   return -1;
1347440a403fSchristos }
1348440a403fSchristos 
1349440a403fSchristos /* Parse the flags to a structure.  */
1350440a403fSchristos 
1351440a403fSchristos static int
tokenize_flags(const char * str,struct arc_flags flags[],int nflg)1352440a403fSchristos tokenize_flags (const char *str,
1353440a403fSchristos 		struct arc_flags flags[],
1354440a403fSchristos 		int nflg)
1355440a403fSchristos {
1356440a403fSchristos   char *old_input_line_pointer;
1357440a403fSchristos   bfd_boolean saw_flg = FALSE;
1358440a403fSchristos   bfd_boolean saw_dot = FALSE;
1359440a403fSchristos   int num_flags  = 0;
1360440a403fSchristos   size_t flgnamelen;
1361440a403fSchristos 
1362440a403fSchristos   memset (flags, 0, sizeof (*flags) * nflg);
1363440a403fSchristos 
1364440a403fSchristos   /* Save and restore input_line_pointer around this function.  */
1365440a403fSchristos   old_input_line_pointer = input_line_pointer;
1366440a403fSchristos   input_line_pointer = (char *) str;
1367440a403fSchristos 
1368440a403fSchristos   while (*input_line_pointer)
1369440a403fSchristos     {
1370440a403fSchristos       switch (*input_line_pointer)
1371440a403fSchristos 	{
1372440a403fSchristos 	case ' ':
1373440a403fSchristos 	case '\0':
1374440a403fSchristos 	  goto fini;
1375440a403fSchristos 
1376440a403fSchristos 	case '.':
1377440a403fSchristos 	  input_line_pointer++;
1378440a403fSchristos 	  if (saw_dot)
1379440a403fSchristos 	    goto err;
1380440a403fSchristos 	  saw_dot = TRUE;
1381440a403fSchristos 	  saw_flg = FALSE;
1382440a403fSchristos 	  break;
1383440a403fSchristos 
1384440a403fSchristos 	default:
1385440a403fSchristos 	  if (saw_flg && !saw_dot)
1386440a403fSchristos 	    goto err;
1387440a403fSchristos 
1388440a403fSchristos 	  if (num_flags >= nflg)
1389440a403fSchristos 	    goto err;
1390440a403fSchristos 
1391440a403fSchristos 	  flgnamelen = strspn (input_line_pointer,
1392440a403fSchristos 			       "abcdefghijklmnopqrstuvwxyz0123456789");
1393440a403fSchristos 	  if (flgnamelen > MAX_FLAG_NAME_LENGTH)
1394440a403fSchristos 	    goto err;
1395440a403fSchristos 
1396440a403fSchristos 	  memcpy (flags->name, input_line_pointer, flgnamelen);
1397440a403fSchristos 
1398440a403fSchristos 	  input_line_pointer += flgnamelen;
1399440a403fSchristos 	  flags++;
1400440a403fSchristos 	  saw_dot = FALSE;
1401440a403fSchristos 	  saw_flg = TRUE;
1402440a403fSchristos 	  num_flags++;
1403440a403fSchristos 	  break;
1404440a403fSchristos 	}
1405440a403fSchristos     }
1406440a403fSchristos 
1407440a403fSchristos  fini:
1408440a403fSchristos   input_line_pointer = old_input_line_pointer;
1409440a403fSchristos   return num_flags;
1410440a403fSchristos 
1411440a403fSchristos  err:
1412440a403fSchristos   if (saw_dot)
1413440a403fSchristos     as_bad (_("extra dot"));
1414440a403fSchristos   else if (!saw_flg)
1415440a403fSchristos     as_bad (_("unrecognized flag"));
1416440a403fSchristos   else
1417440a403fSchristos     as_bad (_("failed to parse flags"));
1418440a403fSchristos   input_line_pointer = old_input_line_pointer;
1419440a403fSchristos   return -1;
1420440a403fSchristos }
1421440a403fSchristos 
1422440a403fSchristos /* Apply the fixups in order.  */
1423440a403fSchristos 
1424440a403fSchristos static void
apply_fixups(struct arc_insn * insn,fragS * fragP,int fix)1425440a403fSchristos apply_fixups (struct arc_insn *insn, fragS *fragP, int fix)
1426440a403fSchristos {
1427440a403fSchristos   int i;
1428440a403fSchristos 
1429440a403fSchristos   for (i = 0; i < insn->nfixups; i++)
1430440a403fSchristos     {
1431440a403fSchristos       struct arc_fixup *fixup = &insn->fixups[i];
1432440a403fSchristos       int size, pcrel, offset = 0;
1433440a403fSchristos 
1434440a403fSchristos       /* FIXME! the reloc size is wrong in the BFD file.
1435440a403fSchristos 	 When it is fixed please delete me.  */
143606324dcfSchristos       size = ((insn->len == 2) && !fixup->islong) ? 2 : 4;
1437440a403fSchristos 
1438440a403fSchristos       if (fixup->islong)
143906324dcfSchristos 	offset = insn->len;
1440440a403fSchristos 
1441440a403fSchristos       /* Some fixups are only used internally, thus no howto.  */
1442440a403fSchristos       if ((int) fixup->reloc == 0)
1443440a403fSchristos 	as_fatal (_("Unhandled reloc type"));
1444440a403fSchristos 
1445440a403fSchristos       if ((int) fixup->reloc < 0)
1446440a403fSchristos 	{
1447440a403fSchristos 	  /* FIXME! the reloc size is wrong in the BFD file.
1448440a403fSchristos 	     When it is fixed please enable me.
144906324dcfSchristos 	     size = ((insn->len == 2 && !fixup->islong) ? 2 : 4; */
1450440a403fSchristos 	  pcrel = fixup->pcrel;
1451440a403fSchristos 	}
1452440a403fSchristos       else
1453440a403fSchristos 	{
1454440a403fSchristos 	  reloc_howto_type *reloc_howto =
1455440a403fSchristos 	    bfd_reloc_type_lookup (stdoutput,
1456440a403fSchristos 				   (bfd_reloc_code_real_type) fixup->reloc);
1457440a403fSchristos 	  gas_assert (reloc_howto);
1458440a403fSchristos 
1459440a403fSchristos 	  /* FIXME! the reloc size is wrong in the BFD file.
1460440a403fSchristos 	     When it is fixed please enable me.
1461440a403fSchristos 	     size = bfd_get_reloc_size (reloc_howto); */
1462440a403fSchristos 	  pcrel = reloc_howto->pc_relative;
1463440a403fSchristos 	}
1464440a403fSchristos 
1465440a403fSchristos       pr_debug ("%s:%d: apply_fixups: new %s fixup (PCrel:%s) of size %d @ \
1466440a403fSchristos offset %d + %d\n",
1467440a403fSchristos 		fragP->fr_file, fragP->fr_line,
1468440a403fSchristos 		(fixup->reloc < 0) ? "Internal" :
1469440a403fSchristos 		bfd_get_reloc_code_name (fixup->reloc),
1470440a403fSchristos 		pcrel ? "Y" : "N",
1471440a403fSchristos 		size, fix, offset);
1472440a403fSchristos       fix_new_exp (fragP, fix + offset,
1473440a403fSchristos 		   size, &fixup->exp, pcrel, fixup->reloc);
1474440a403fSchristos 
1475440a403fSchristos       /* Check for ZOLs, and update symbol info if any.  */
1476440a403fSchristos       if (LP_INSN (insn->insn))
1477440a403fSchristos 	{
1478440a403fSchristos 	  gas_assert (fixup->exp.X_add_symbol);
1479440a403fSchristos 	  ARC_SET_FLAG (fixup->exp.X_add_symbol, ARC_FLAG_ZOL);
1480440a403fSchristos 	}
1481440a403fSchristos     }
1482440a403fSchristos }
1483440a403fSchristos 
1484440a403fSchristos /* Actually output an instruction with its fixup.  */
1485440a403fSchristos 
1486440a403fSchristos static void
emit_insn0(struct arc_insn * insn,char * where,bfd_boolean relax)1487440a403fSchristos emit_insn0 (struct arc_insn *insn, char *where, bfd_boolean relax)
1488440a403fSchristos {
1489440a403fSchristos   char *f = where;
149006324dcfSchristos   size_t total_len;
1491440a403fSchristos 
149206324dcfSchristos   pr_debug ("Emit insn : 0x%llx\n", insn->insn);
149306324dcfSchristos   pr_debug ("\tLength  : 0x%d\n", insn->len);
1494440a403fSchristos   pr_debug ("\tLong imm: 0x%lx\n", insn->limm);
1495440a403fSchristos 
1496440a403fSchristos   /* Write out the instruction.  */
149706324dcfSchristos   total_len = insn->len + (insn->has_limm ? 4 : 0);
149806324dcfSchristos   if (!relax)
149906324dcfSchristos     f = frag_more (total_len);
150006324dcfSchristos 
150106324dcfSchristos   md_number_to_chars_midend(f, insn->insn, insn->len);
150206324dcfSchristos 
1503440a403fSchristos   if (insn->has_limm)
150406324dcfSchristos     md_number_to_chars_midend (f + insn->len, insn->limm, 4);
150506324dcfSchristos   dwarf2_emit_insn (total_len);
1506440a403fSchristos 
1507440a403fSchristos   if (!relax)
1508440a403fSchristos     apply_fixups (insn, frag_now, (f - frag_now->fr_literal));
1509440a403fSchristos }
1510440a403fSchristos 
1511440a403fSchristos static void
emit_insn1(struct arc_insn * insn)1512440a403fSchristos emit_insn1 (struct arc_insn *insn)
1513440a403fSchristos {
1514440a403fSchristos   /* How frag_var's args are currently configured:
1515440a403fSchristos      - rs_machine_dependent, to dictate it's a relaxation frag.
1516440a403fSchristos      - FRAG_MAX_GROWTH, maximum size of instruction
1517440a403fSchristos      - 0, variable size that might grow...unused by generic relaxation.
1518440a403fSchristos      - frag_now->fr_subtype, fr_subtype starting value, set previously.
1519440a403fSchristos      - s, opand expression.
1520440a403fSchristos      - 0, offset but it's unused.
1521440a403fSchristos      - 0, opcode but it's unused.  */
1522440a403fSchristos   symbolS *s = make_expr_symbol (&insn->fixups[0].exp);
1523440a403fSchristos   frag_now->tc_frag_data.pcrel = insn->fixups[0].pcrel;
1524440a403fSchristos 
1525440a403fSchristos   if (frag_room () < FRAG_MAX_GROWTH)
1526440a403fSchristos     {
1527440a403fSchristos       /* Handle differently when frag literal memory is exhausted.
1528440a403fSchristos 	 This is used because when there's not enough memory left in
1529440a403fSchristos 	 the current frag, a new frag is created and the information
1530440a403fSchristos 	 we put into frag_now->tc_frag_data is disregarded.  */
1531440a403fSchristos 
1532440a403fSchristos       struct arc_relax_type relax_info_copy;
1533440a403fSchristos       relax_substateT subtype = frag_now->fr_subtype;
1534440a403fSchristos 
1535440a403fSchristos       memcpy (&relax_info_copy, &frag_now->tc_frag_data,
1536440a403fSchristos 	      sizeof (struct arc_relax_type));
1537440a403fSchristos 
1538440a403fSchristos       frag_wane (frag_now);
1539440a403fSchristos       frag_grow (FRAG_MAX_GROWTH);
1540440a403fSchristos 
1541440a403fSchristos       memcpy (&frag_now->tc_frag_data, &relax_info_copy,
1542440a403fSchristos 	      sizeof (struct arc_relax_type));
1543440a403fSchristos 
1544440a403fSchristos       frag_var (rs_machine_dependent, FRAG_MAX_GROWTH, 0,
1545440a403fSchristos 		subtype, s, 0, 0);
1546440a403fSchristos     }
1547440a403fSchristos   else
1548440a403fSchristos     frag_var (rs_machine_dependent, FRAG_MAX_GROWTH, 0,
1549440a403fSchristos 	      frag_now->fr_subtype, s, 0, 0);
1550440a403fSchristos }
1551440a403fSchristos 
1552440a403fSchristos static void
emit_insn(struct arc_insn * insn)1553440a403fSchristos emit_insn (struct arc_insn *insn)
1554440a403fSchristos {
1555440a403fSchristos   if (insn->relax)
1556440a403fSchristos     emit_insn1 (insn);
1557440a403fSchristos   else
1558440a403fSchristos     emit_insn0 (insn, NULL, FALSE);
1559440a403fSchristos }
1560440a403fSchristos 
1561440a403fSchristos /* Check whether a symbol involves a register.  */
1562440a403fSchristos 
1563440a403fSchristos static bfd_boolean
contains_register(symbolS * sym)1564440a403fSchristos contains_register (symbolS *sym)
1565440a403fSchristos {
1566440a403fSchristos   if (sym)
1567440a403fSchristos     {
1568440a403fSchristos       expressionS *ex = symbol_get_value_expression (sym);
1569440a403fSchristos 
1570440a403fSchristos       return ((O_register == ex->X_op)
1571440a403fSchristos 	      && !contains_register (ex->X_add_symbol)
1572440a403fSchristos 	      && !contains_register (ex->X_op_symbol));
1573440a403fSchristos     }
1574440a403fSchristos 
1575440a403fSchristos   return FALSE;
1576440a403fSchristos }
1577440a403fSchristos 
1578440a403fSchristos /* Returns the register number within a symbol.  */
1579440a403fSchristos 
1580440a403fSchristos static int
get_register(symbolS * sym)1581440a403fSchristos get_register (symbolS *sym)
1582440a403fSchristos {
1583440a403fSchristos   if (!contains_register (sym))
1584440a403fSchristos     return -1;
1585440a403fSchristos 
1586440a403fSchristos   expressionS *ex = symbol_get_value_expression (sym);
1587440a403fSchristos   return regno (ex->X_add_number);
1588440a403fSchristos }
1589440a403fSchristos 
1590440a403fSchristos /* Return true if a RELOC is generic.  A generic reloc is PC-rel of a
1591440a403fSchristos    simple ME relocation (e.g. RELOC_ARC_32_ME, BFD_RELOC_ARC_PC32.  */
1592440a403fSchristos 
1593440a403fSchristos static bfd_boolean
generic_reloc_p(extended_bfd_reloc_code_real_type reloc)1594440a403fSchristos generic_reloc_p (extended_bfd_reloc_code_real_type reloc)
1595440a403fSchristos {
1596440a403fSchristos   if (!reloc)
1597440a403fSchristos     return FALSE;
1598440a403fSchristos 
1599440a403fSchristos   switch (reloc)
1600440a403fSchristos     {
1601440a403fSchristos     case BFD_RELOC_ARC_SDA_LDST:
1602440a403fSchristos     case BFD_RELOC_ARC_SDA_LDST1:
1603440a403fSchristos     case BFD_RELOC_ARC_SDA_LDST2:
1604440a403fSchristos     case BFD_RELOC_ARC_SDA16_LD:
1605440a403fSchristos     case BFD_RELOC_ARC_SDA16_LD1:
1606440a403fSchristos     case BFD_RELOC_ARC_SDA16_LD2:
1607440a403fSchristos     case BFD_RELOC_ARC_SDA16_ST2:
1608440a403fSchristos     case BFD_RELOC_ARC_SDA32_ME:
1609440a403fSchristos       return FALSE;
1610440a403fSchristos     default:
1611440a403fSchristos       return TRUE;
1612440a403fSchristos     }
1613440a403fSchristos }
1614440a403fSchristos 
1615440a403fSchristos /* Allocates a tok entry.  */
1616440a403fSchristos 
1617440a403fSchristos static int
allocate_tok(expressionS * tok,int ntok,int cidx)1618440a403fSchristos allocate_tok (expressionS *tok, int ntok, int cidx)
1619440a403fSchristos {
1620440a403fSchristos   if (ntok > MAX_INSN_ARGS - 2)
1621440a403fSchristos     return 0; /* No space left.  */
1622440a403fSchristos 
1623440a403fSchristos   if (cidx > ntok)
162406324dcfSchristos     return 0; /* Incorrect args.  */
1625440a403fSchristos 
1626440a403fSchristos   memcpy (&tok[ntok+1], &tok[ntok], sizeof (*tok));
1627440a403fSchristos 
1628440a403fSchristos   if (cidx == ntok)
1629440a403fSchristos     return 1; /* Success.  */
1630440a403fSchristos   return allocate_tok (tok, ntok - 1, cidx);
1631440a403fSchristos }
1632440a403fSchristos 
1633440a403fSchristos /* Check if an particular ARC feature is enabled.  */
1634440a403fSchristos 
1635440a403fSchristos static bfd_boolean
check_cpu_feature(insn_subclass_t sc)1636440a403fSchristos check_cpu_feature (insn_subclass_t sc)
1637440a403fSchristos {
163806324dcfSchristos   if (is_code_density_p (sc) && !(selected_cpu.features & CD))
1639440a403fSchristos     return FALSE;
1640440a403fSchristos 
164106324dcfSchristos   if (is_spfp_p (sc) && !(selected_cpu.features & SPX))
1642440a403fSchristos     return FALSE;
1643440a403fSchristos 
164406324dcfSchristos   if (is_dpfp_p (sc) && !(selected_cpu.features & DPX))
1645440a403fSchristos     return FALSE;
1646440a403fSchristos 
164706324dcfSchristos   if (is_fpuda_p (sc) && !(selected_cpu.features & DPA))
1648440a403fSchristos     return FALSE;
1649440a403fSchristos 
165006324dcfSchristos   if (is_nps400_p (sc) && !(selected_cpu.features & NPS400))
1651440a403fSchristos     return FALSE;
1652440a403fSchristos 
1653440a403fSchristos   return TRUE;
1654440a403fSchristos }
1655440a403fSchristos 
1656440a403fSchristos /* Parse the flags described by FIRST_PFLAG and NFLGS against the flag
1657440a403fSchristos    operands in OPCODE.  Stores the matching OPCODES into the FIRST_PFLAG
1658440a403fSchristos    array and returns TRUE if the flag operands all match, otherwise,
1659440a403fSchristos    returns FALSE, in which case the FIRST_PFLAG array may have been
1660440a403fSchristos    modified.  */
1661440a403fSchristos 
1662440a403fSchristos static bfd_boolean
parse_opcode_flags(const struct arc_opcode * opcode,int nflgs,struct arc_flags * first_pflag)1663440a403fSchristos parse_opcode_flags (const struct arc_opcode *opcode,
1664440a403fSchristos                     int nflgs,
1665440a403fSchristos                     struct arc_flags *first_pflag)
1666440a403fSchristos {
1667440a403fSchristos   int lnflg, i;
1668440a403fSchristos   const unsigned char *flgidx;
1669440a403fSchristos 
1670440a403fSchristos   lnflg = nflgs;
1671440a403fSchristos   for (i = 0; i < nflgs; i++)
1672440a403fSchristos     first_pflag[i].flgp = NULL;
1673440a403fSchristos 
1674440a403fSchristos   /* Check the flags.  Iterate over the valid flag classes.  */
1675440a403fSchristos   for (flgidx = opcode->flags; *flgidx; ++flgidx)
1676440a403fSchristos     {
1677440a403fSchristos       /* Get a valid flag class.  */
1678440a403fSchristos       const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
1679440a403fSchristos       const unsigned *flgopridx;
1680440a403fSchristos       int cl_matches = 0;
1681440a403fSchristos       struct arc_flags *pflag = NULL;
1682440a403fSchristos 
168306324dcfSchristos       /* Check if opcode has implicit flag classes.  */
168406324dcfSchristos       if (cl_flags->flag_class & F_CLASS_IMPLICIT)
168506324dcfSchristos 	continue;
168606324dcfSchristos 
1687440a403fSchristos       /* Check for extension conditional codes.  */
1688440a403fSchristos       if (ext_condcode.arc_ext_condcode
1689440a403fSchristos           && cl_flags->flag_class & F_CLASS_EXTEND)
1690440a403fSchristos         {
1691440a403fSchristos           struct arc_flag_operand *pf = ext_condcode.arc_ext_condcode;
1692440a403fSchristos           while (pf->name)
1693440a403fSchristos             {
1694440a403fSchristos               pflag = first_pflag;
1695440a403fSchristos               for (i = 0; i < nflgs; i++, pflag++)
1696440a403fSchristos                 {
1697440a403fSchristos                   if (!strcmp (pf->name, pflag->name))
1698440a403fSchristos                     {
1699440a403fSchristos                       if (pflag->flgp != NULL)
1700440a403fSchristos                         return FALSE;
1701440a403fSchristos                       /* Found it.  */
1702440a403fSchristos                       cl_matches++;
1703440a403fSchristos                       pflag->flgp = pf;
1704440a403fSchristos                       lnflg--;
1705440a403fSchristos                       break;
1706440a403fSchristos                     }
1707440a403fSchristos                 }
1708440a403fSchristos               pf++;
1709440a403fSchristos             }
1710440a403fSchristos         }
1711440a403fSchristos 
1712440a403fSchristos       for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
1713440a403fSchristos         {
1714440a403fSchristos           const struct arc_flag_operand *flg_operand;
1715440a403fSchristos 
1716440a403fSchristos           pflag = first_pflag;
1717440a403fSchristos           flg_operand = &arc_flag_operands[*flgopridx];
1718440a403fSchristos           for (i = 0; i < nflgs; i++, pflag++)
1719440a403fSchristos             {
1720440a403fSchristos               /* Match against the parsed flags.  */
1721440a403fSchristos               if (!strcmp (flg_operand->name, pflag->name))
1722440a403fSchristos                 {
1723440a403fSchristos                   if (pflag->flgp != NULL)
1724440a403fSchristos                     return FALSE;
1725440a403fSchristos                   cl_matches++;
1726440a403fSchristos                   pflag->flgp = flg_operand;
1727440a403fSchristos                   lnflg--;
1728440a403fSchristos                   break; /* goto next flag class and parsed flag.  */
1729440a403fSchristos                 }
1730440a403fSchristos             }
1731440a403fSchristos         }
1732440a403fSchristos 
1733440a403fSchristos       if ((cl_flags->flag_class & F_CLASS_REQUIRED) && cl_matches == 0)
1734440a403fSchristos         return FALSE;
1735440a403fSchristos       if ((cl_flags->flag_class & F_CLASS_OPTIONAL) && cl_matches > 1)
1736440a403fSchristos         return FALSE;
1737440a403fSchristos     }
1738440a403fSchristos 
1739440a403fSchristos   /* Did I check all the parsed flags?  */
1740440a403fSchristos   return lnflg ? FALSE : TRUE;
1741440a403fSchristos }
1742440a403fSchristos 
1743440a403fSchristos 
1744440a403fSchristos /* Search forward through all variants of an opcode looking for a
1745440a403fSchristos    syntax match.  */
1746440a403fSchristos 
1747440a403fSchristos static const struct arc_opcode *
find_opcode_match(const struct arc_opcode_hash_entry * entry,expressionS * tok,int * pntok,struct arc_flags * first_pflag,int nflgs,int * pcpumatch,const char ** errmsg)1748440a403fSchristos find_opcode_match (const struct arc_opcode_hash_entry *entry,
1749440a403fSchristos 		   expressionS *tok,
1750440a403fSchristos 		   int *pntok,
1751440a403fSchristos 		   struct arc_flags *first_pflag,
1752440a403fSchristos 		   int nflgs,
175306324dcfSchristos 		   int *pcpumatch,
175406324dcfSchristos 		   const char **errmsg)
1755440a403fSchristos {
1756440a403fSchristos   const struct arc_opcode *opcode;
1757440a403fSchristos   struct arc_opcode_hash_entry_iterator iter;
1758440a403fSchristos   int ntok = *pntok;
1759440a403fSchristos   int got_cpu_match = 0;
1760440a403fSchristos   expressionS bktok[MAX_INSN_ARGS];
1761440a403fSchristos   int bkntok;
1762440a403fSchristos   expressionS emptyE;
1763440a403fSchristos 
1764440a403fSchristos   arc_opcode_hash_entry_iterator_init (&iter);
1765440a403fSchristos   memset (&emptyE, 0, sizeof (emptyE));
1766440a403fSchristos   memcpy (bktok, tok, MAX_INSN_ARGS * sizeof (*tok));
1767440a403fSchristos   bkntok = ntok;
1768440a403fSchristos 
1769440a403fSchristos   for (opcode = arc_opcode_hash_entry_iterator_next (entry, &iter);
1770440a403fSchristos        opcode != NULL;
1771440a403fSchristos        opcode = arc_opcode_hash_entry_iterator_next (entry, &iter))
1772440a403fSchristos     {
1773440a403fSchristos       const unsigned char *opidx;
1774440a403fSchristos       int tokidx = 0;
1775440a403fSchristos       const expressionS *t = &emptyE;
1776440a403fSchristos 
177706324dcfSchristos       pr_debug ("%s:%d: find_opcode_match: trying opcode 0x%08llX ",
1778440a403fSchristos 		frag_now->fr_file, frag_now->fr_line, opcode->opcode);
1779440a403fSchristos 
1780440a403fSchristos       /* Don't match opcodes that don't exist on this
1781440a403fSchristos 	 architecture.  */
178206324dcfSchristos       if (!(opcode->cpu & selected_cpu.flags))
1783440a403fSchristos 	goto match_failed;
1784440a403fSchristos 
1785440a403fSchristos       if (!check_cpu_feature (opcode->subclass))
1786440a403fSchristos 	goto match_failed;
1787440a403fSchristos 
1788440a403fSchristos       got_cpu_match = 1;
1789440a403fSchristos       pr_debug ("cpu ");
1790440a403fSchristos 
1791440a403fSchristos       /* Check the operands.  */
1792440a403fSchristos       for (opidx = opcode->operands; *opidx; ++opidx)
1793440a403fSchristos 	{
1794440a403fSchristos 	  const struct arc_operand *operand = &arc_operands[*opidx];
1795440a403fSchristos 
1796440a403fSchristos 	  /* Only take input from real operands.  */
179706324dcfSchristos 	  if (ARC_OPERAND_IS_FAKE (operand))
1798440a403fSchristos 	    continue;
1799440a403fSchristos 
1800440a403fSchristos 	  /* When we expect input, make sure we have it.  */
1801440a403fSchristos 	  if (tokidx >= ntok)
1802440a403fSchristos 	    goto match_failed;
1803440a403fSchristos 
1804440a403fSchristos 	  /* Match operand type with expression type.  */
1805440a403fSchristos 	  switch (operand->flags & ARC_OPERAND_TYPECHECK_MASK)
1806440a403fSchristos 	    {
180706324dcfSchristos             case ARC_OPERAND_ADDRTYPE:
180806324dcfSchristos 	      {
180906324dcfSchristos 		*errmsg = NULL;
181006324dcfSchristos 
181106324dcfSchristos 		/* Check to be an address type.  */
181206324dcfSchristos 		if (tok[tokidx].X_op != O_addrtype)
181306324dcfSchristos 		  goto match_failed;
181406324dcfSchristos 
181506324dcfSchristos 		/* All address type operands need to have an insert
181606324dcfSchristos 		   method in order to check that we have the correct
181706324dcfSchristos 		   address type.  */
181806324dcfSchristos 		gas_assert (operand->insert != NULL);
181906324dcfSchristos 		(*operand->insert) (0, tok[tokidx].X_add_number,
182006324dcfSchristos 				    errmsg);
182106324dcfSchristos 		if (*errmsg != NULL)
182206324dcfSchristos 		  goto match_failed;
182306324dcfSchristos 	      }
182406324dcfSchristos               break;
182506324dcfSchristos 
1826440a403fSchristos 	    case ARC_OPERAND_IR:
1827440a403fSchristos 	      /* Check to be a register.  */
1828440a403fSchristos 	      if ((tok[tokidx].X_op != O_register
1829440a403fSchristos 		   || !is_ir_num (tok[tokidx].X_add_number))
1830440a403fSchristos 		  && !(operand->flags & ARC_OPERAND_IGNORE))
1831440a403fSchristos 		goto match_failed;
1832440a403fSchristos 
1833440a403fSchristos 	      /* If expect duplicate, make sure it is duplicate.  */
1834440a403fSchristos 	      if (operand->flags & ARC_OPERAND_DUPLICATE)
1835440a403fSchristos 		{
1836440a403fSchristos 		  /* Check for duplicate.  */
1837440a403fSchristos 		  if (t->X_op != O_register
1838440a403fSchristos 		      || !is_ir_num (t->X_add_number)
1839440a403fSchristos 		      || (regno (t->X_add_number) !=
1840440a403fSchristos 			  regno (tok[tokidx].X_add_number)))
1841440a403fSchristos 		    goto match_failed;
1842440a403fSchristos 		}
1843440a403fSchristos 
1844440a403fSchristos 	      /* Special handling?  */
1845440a403fSchristos 	      if (operand->insert)
1846440a403fSchristos 		{
184706324dcfSchristos 		  *errmsg = NULL;
1848440a403fSchristos 		  (*operand->insert)(0,
1849440a403fSchristos 				     regno (tok[tokidx].X_add_number),
185006324dcfSchristos 				     errmsg);
185106324dcfSchristos 		  if (*errmsg)
1852440a403fSchristos 		    {
1853440a403fSchristos 		      if (operand->flags & ARC_OPERAND_IGNORE)
1854440a403fSchristos 			{
1855440a403fSchristos 			  /* Missing argument, create one.  */
1856440a403fSchristos 			  if (!allocate_tok (tok, ntok - 1, tokidx))
1857440a403fSchristos 			    goto match_failed;
1858440a403fSchristos 
1859440a403fSchristos 			  tok[tokidx].X_op = O_absent;
1860440a403fSchristos 			  ++ntok;
1861440a403fSchristos 			}
1862440a403fSchristos 		      else
1863440a403fSchristos 			goto match_failed;
1864440a403fSchristos 		    }
1865440a403fSchristos 		}
1866440a403fSchristos 
1867440a403fSchristos 	      t = &tok[tokidx];
1868440a403fSchristos 	      break;
1869440a403fSchristos 
1870440a403fSchristos 	    case ARC_OPERAND_BRAKET:
1871440a403fSchristos 	      /* Check if bracket is also in opcode table as
1872440a403fSchristos 		 operand.  */
1873440a403fSchristos 	      if (tok[tokidx].X_op != O_bracket)
1874440a403fSchristos 		goto match_failed;
1875440a403fSchristos 	      break;
1876440a403fSchristos 
187706324dcfSchristos             case ARC_OPERAND_COLON:
187806324dcfSchristos               /* Check if colon is also in opcode table as operand.  */
187906324dcfSchristos               if (tok[tokidx].X_op != O_colon)
188006324dcfSchristos                 goto match_failed;
188106324dcfSchristos               break;
188206324dcfSchristos 
1883440a403fSchristos 	    case ARC_OPERAND_LIMM:
1884440a403fSchristos 	    case ARC_OPERAND_SIGNED:
1885440a403fSchristos 	    case ARC_OPERAND_UNSIGNED:
1886440a403fSchristos 	      switch (tok[tokidx].X_op)
1887440a403fSchristos 		{
1888440a403fSchristos 		case O_illegal:
1889440a403fSchristos 		case O_absent:
1890440a403fSchristos 		case O_register:
1891440a403fSchristos 		  goto match_failed;
1892440a403fSchristos 
1893440a403fSchristos 		case O_bracket:
1894440a403fSchristos 		  /* Got an (too) early bracket, check if it is an
1895440a403fSchristos 		     ignored operand.  N.B. This procedure works only
1896440a403fSchristos 		     when bracket is the last operand!  */
1897440a403fSchristos 		  if (!(operand->flags & ARC_OPERAND_IGNORE))
1898440a403fSchristos 		    goto match_failed;
1899440a403fSchristos 		  /* Insert the missing operand.  */
1900440a403fSchristos 		  if (!allocate_tok (tok, ntok - 1, tokidx))
1901440a403fSchristos 		    goto match_failed;
1902440a403fSchristos 
1903440a403fSchristos 		  tok[tokidx].X_op = O_absent;
1904440a403fSchristos 		  ++ntok;
1905440a403fSchristos 		  break;
1906440a403fSchristos 
1907440a403fSchristos 		case O_symbol:
1908440a403fSchristos 		  {
1909440a403fSchristos 		    const char *p;
1910*b88e3e88Schristos 		    char *tmpp, *pp;
1911440a403fSchristos 		    const struct arc_aux_reg *auxr;
1912440a403fSchristos 
1913440a403fSchristos 		    if (opcode->insn_class != AUXREG)
1914440a403fSchristos 		      goto de_fault;
1915440a403fSchristos 		    p = S_GET_NAME (tok[tokidx].X_add_symbol);
1916440a403fSchristos 
1917*b88e3e88Schristos 		    /* For compatibility reasons, an aux register can
1918*b88e3e88Schristos 		       be spelled with upper or lower case
1919*b88e3e88Schristos 		       letters.  */
1920*b88e3e88Schristos 		    tmpp = strdup (p);
1921*b88e3e88Schristos 		    for (pp = tmpp; *pp; ++pp) *pp = TOLOWER (*pp);
1922*b88e3e88Schristos 
1923*b88e3e88Schristos 		    auxr = hash_find (arc_aux_hash, tmpp);
1924440a403fSchristos 		    if (auxr)
1925440a403fSchristos 		      {
1926440a403fSchristos 			/* We modify the token array here, safe in the
1927440a403fSchristos 			   knowledge, that if this was the wrong
1928440a403fSchristos 			   choice then the original contents will be
1929440a403fSchristos 			   restored from BKTOK.  */
1930440a403fSchristos 			tok[tokidx].X_op = O_constant;
1931440a403fSchristos 			tok[tokidx].X_add_number = auxr->address;
1932440a403fSchristos 			ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX);
1933440a403fSchristos 		      }
1934*b88e3e88Schristos 		    free (tmpp);
1935440a403fSchristos 
1936440a403fSchristos 		    if (tok[tokidx].X_op != O_constant)
1937440a403fSchristos 		      goto de_fault;
1938440a403fSchristos 		  }
193906324dcfSchristos 		  /* Fall through.  */
1940440a403fSchristos 		case O_constant:
1941440a403fSchristos 		  /* Check the range.  */
1942440a403fSchristos 		  if (operand->bits != 32
1943440a403fSchristos 		      && !(operand->flags & ARC_OPERAND_NCHK))
1944440a403fSchristos 		    {
1945440a403fSchristos 		      offsetT min, max, val;
1946440a403fSchristos 		      val = tok[tokidx].X_add_number;
1947440a403fSchristos 
1948440a403fSchristos 		      if (operand->flags & ARC_OPERAND_SIGNED)
1949440a403fSchristos 			{
1950440a403fSchristos 			  max = (1 << (operand->bits - 1)) - 1;
1951440a403fSchristos 			  min = -(1 << (operand->bits - 1));
1952440a403fSchristos 			}
1953440a403fSchristos 		      else
1954440a403fSchristos 			{
1955440a403fSchristos 			  max = (1 << operand->bits) - 1;
1956440a403fSchristos 			  min = 0;
1957440a403fSchristos 			}
1958440a403fSchristos 
1959440a403fSchristos 		      if (val < min || val > max)
1960440a403fSchristos 			goto match_failed;
1961440a403fSchristos 
196206324dcfSchristos 		      /* Check alignments.  */
1963440a403fSchristos 		      if ((operand->flags & ARC_OPERAND_ALIGNED32)
1964440a403fSchristos 			  && (val & 0x03))
1965440a403fSchristos 			goto match_failed;
1966440a403fSchristos 
1967440a403fSchristos 		      if ((operand->flags & ARC_OPERAND_ALIGNED16)
1968440a403fSchristos 			  && (val & 0x01))
1969440a403fSchristos 			goto match_failed;
1970440a403fSchristos 		    }
1971440a403fSchristos 		  else if (operand->flags & ARC_OPERAND_NCHK)
1972440a403fSchristos 		    {
1973440a403fSchristos 		      if (operand->insert)
1974440a403fSchristos 			{
197506324dcfSchristos 			  *errmsg = NULL;
1976440a403fSchristos 			  (*operand->insert)(0,
1977440a403fSchristos 					     tok[tokidx].X_add_number,
197806324dcfSchristos 					     errmsg);
197906324dcfSchristos 			  if (*errmsg)
1980440a403fSchristos 			    goto match_failed;
1981440a403fSchristos 			}
1982440a403fSchristos 		      else if (!(operand->flags & ARC_OPERAND_IGNORE))
1983440a403fSchristos 			goto match_failed;
1984440a403fSchristos 		    }
1985440a403fSchristos 		  break;
1986440a403fSchristos 
1987440a403fSchristos 		case O_subtract:
1988440a403fSchristos 		  /* Check if it is register range.  */
1989440a403fSchristos 		  if ((tok[tokidx].X_add_number == 0)
1990440a403fSchristos 		      && contains_register (tok[tokidx].X_add_symbol)
1991440a403fSchristos 		      && contains_register (tok[tokidx].X_op_symbol))
1992440a403fSchristos 		    {
1993440a403fSchristos 		      int regs;
1994440a403fSchristos 
1995440a403fSchristos 		      regs = get_register (tok[tokidx].X_add_symbol);
1996440a403fSchristos 		      regs <<= 16;
1997440a403fSchristos 		      regs |= get_register (tok[tokidx].X_op_symbol);
1998440a403fSchristos 		      if (operand->insert)
1999440a403fSchristos 			{
200006324dcfSchristos 			  *errmsg = NULL;
2001440a403fSchristos 			  (*operand->insert)(0,
2002440a403fSchristos 					     regs,
200306324dcfSchristos 					     errmsg);
200406324dcfSchristos 			  if (*errmsg)
2005440a403fSchristos 			    goto match_failed;
2006440a403fSchristos 			}
2007440a403fSchristos 		      else
2008440a403fSchristos 			goto match_failed;
2009440a403fSchristos 		      break;
2010440a403fSchristos 		    }
201106324dcfSchristos 		  /* Fall through.  */
2012440a403fSchristos 		default:
2013440a403fSchristos 		de_fault:
2014440a403fSchristos 		  if (operand->default_reloc == 0)
2015440a403fSchristos 		    goto match_failed; /* The operand needs relocation.  */
2016440a403fSchristos 
2017440a403fSchristos 		  /* Relocs requiring long immediate.  FIXME! make it
2018440a403fSchristos 		     generic and move it to a function.  */
2019440a403fSchristos 		  switch (tok[tokidx].X_md)
2020440a403fSchristos 		    {
2021440a403fSchristos 		    case O_gotoff:
2022440a403fSchristos 		    case O_gotpc:
2023440a403fSchristos 		    case O_pcl:
2024440a403fSchristos 		    case O_tpoff:
2025440a403fSchristos 		    case O_dtpoff:
2026440a403fSchristos 		    case O_tlsgd:
2027440a403fSchristos 		    case O_tlsie:
2028440a403fSchristos 		      if (!(operand->flags & ARC_OPERAND_LIMM))
2029440a403fSchristos 			goto match_failed;
203006324dcfSchristos 		      /* Fall through.  */
2031440a403fSchristos 		    case O_absent:
2032440a403fSchristos 		      if (!generic_reloc_p (operand->default_reloc))
2033440a403fSchristos 			goto match_failed;
203406324dcfSchristos 		      break;
2035440a403fSchristos 		    default:
2036440a403fSchristos 		      break;
2037440a403fSchristos 		    }
2038440a403fSchristos 		  break;
2039440a403fSchristos 		}
2040440a403fSchristos 	      /* If expect duplicate, make sure it is duplicate.  */
2041440a403fSchristos 	      if (operand->flags & ARC_OPERAND_DUPLICATE)
2042440a403fSchristos 		{
2043440a403fSchristos 		  if (t->X_op == O_illegal
2044440a403fSchristos 		      || t->X_op == O_absent
2045440a403fSchristos 		      || t->X_op == O_register
2046440a403fSchristos 		      || (t->X_add_number != tok[tokidx].X_add_number))
2047440a403fSchristos 		    goto match_failed;
2048440a403fSchristos 		}
2049440a403fSchristos 	      t = &tok[tokidx];
2050440a403fSchristos 	      break;
2051440a403fSchristos 
2052440a403fSchristos 	    default:
2053440a403fSchristos 	      /* Everything else should have been fake.  */
2054440a403fSchristos 	      abort ();
2055440a403fSchristos 	    }
2056440a403fSchristos 
2057440a403fSchristos 	  ++tokidx;
2058440a403fSchristos 	}
2059440a403fSchristos       pr_debug ("opr ");
2060440a403fSchristos 
2061440a403fSchristos       /* Setup ready for flag parsing.  */
2062440a403fSchristos       if (!parse_opcode_flags (opcode, nflgs, first_pflag))
2063440a403fSchristos 	goto match_failed;
2064440a403fSchristos 
2065440a403fSchristos       pr_debug ("flg");
2066440a403fSchristos       /* Possible match -- did we use all of our input?  */
2067440a403fSchristos       if (tokidx == ntok)
2068440a403fSchristos 	{
2069440a403fSchristos 	  *pntok = ntok;
2070440a403fSchristos 	  pr_debug ("\n");
2071440a403fSchristos 	  return opcode;
2072440a403fSchristos 	}
2073440a403fSchristos 
2074440a403fSchristos     match_failed:;
2075440a403fSchristos       pr_debug ("\n");
2076440a403fSchristos       /* Restore the original parameters.  */
2077440a403fSchristos       memcpy (tok, bktok, MAX_INSN_ARGS * sizeof (*tok));
2078440a403fSchristos       ntok = bkntok;
2079440a403fSchristos     }
2080440a403fSchristos 
2081440a403fSchristos   if (*pcpumatch)
2082440a403fSchristos     *pcpumatch = got_cpu_match;
2083440a403fSchristos 
2084440a403fSchristos   return NULL;
2085440a403fSchristos }
2086440a403fSchristos 
2087440a403fSchristos /* Swap operand tokens.  */
2088440a403fSchristos 
2089440a403fSchristos static void
swap_operand(expressionS * operand_array,unsigned source,unsigned destination)2090440a403fSchristos swap_operand (expressionS *operand_array,
2091440a403fSchristos 	      unsigned source,
2092440a403fSchristos 	      unsigned destination)
2093440a403fSchristos {
2094440a403fSchristos   expressionS cpy_operand;
2095440a403fSchristos   expressionS *src_operand;
2096440a403fSchristos   expressionS *dst_operand;
2097440a403fSchristos   size_t size;
2098440a403fSchristos 
2099440a403fSchristos   if (source == destination)
2100440a403fSchristos     return;
2101440a403fSchristos 
2102440a403fSchristos   src_operand = &operand_array[source];
2103440a403fSchristos   dst_operand = &operand_array[destination];
2104440a403fSchristos   size = sizeof (expressionS);
2105440a403fSchristos 
2106440a403fSchristos   /* Make copy of operand to swap with and swap.  */
2107440a403fSchristos   memcpy (&cpy_operand, dst_operand, size);
2108440a403fSchristos   memcpy (dst_operand, src_operand, size);
2109440a403fSchristos   memcpy (src_operand, &cpy_operand, size);
2110440a403fSchristos }
2111440a403fSchristos 
2112440a403fSchristos /* Check if *op matches *tok type.
2113440a403fSchristos    Returns FALSE if they don't match, TRUE if they match.  */
2114440a403fSchristos 
2115440a403fSchristos static bfd_boolean
pseudo_operand_match(const expressionS * tok,const struct arc_operand_operation * op)2116440a403fSchristos pseudo_operand_match (const expressionS *tok,
2117440a403fSchristos 		      const struct arc_operand_operation *op)
2118440a403fSchristos {
2119440a403fSchristos   offsetT min, max, val;
2120440a403fSchristos   bfd_boolean ret;
2121440a403fSchristos   const struct arc_operand *operand_real = &arc_operands[op->operand_idx];
2122440a403fSchristos 
2123440a403fSchristos   ret = FALSE;
2124440a403fSchristos   switch (tok->X_op)
2125440a403fSchristos     {
2126440a403fSchristos     case O_constant:
2127440a403fSchristos       if (operand_real->bits == 32 && (operand_real->flags & ARC_OPERAND_LIMM))
2128440a403fSchristos 	ret = 1;
2129440a403fSchristos       else if (!(operand_real->flags & ARC_OPERAND_IR))
2130440a403fSchristos 	{
2131440a403fSchristos 	  val = tok->X_add_number + op->count;
2132440a403fSchristos 	  if (operand_real->flags & ARC_OPERAND_SIGNED)
2133440a403fSchristos 	    {
2134440a403fSchristos 	      max = (1 << (operand_real->bits - 1)) - 1;
2135440a403fSchristos 	      min = -(1 << (operand_real->bits - 1));
2136440a403fSchristos 	    }
2137440a403fSchristos 	  else
2138440a403fSchristos 	    {
2139440a403fSchristos 	      max = (1 << operand_real->bits) - 1;
2140440a403fSchristos 	      min = 0;
2141440a403fSchristos 	    }
2142440a403fSchristos 	  if (min <= val && val <= max)
2143440a403fSchristos 	    ret = TRUE;
2144440a403fSchristos 	}
2145440a403fSchristos       break;
2146440a403fSchristos 
2147440a403fSchristos     case O_symbol:
2148440a403fSchristos       /* Handle all symbols as long immediates or signed 9.  */
214906324dcfSchristos       if (operand_real->flags & ARC_OPERAND_LIMM
215006324dcfSchristos 	  || ((operand_real->flags & ARC_OPERAND_SIGNED)
215106324dcfSchristos 	      && operand_real->bits == 9))
2152440a403fSchristos 	ret = TRUE;
2153440a403fSchristos       break;
2154440a403fSchristos 
2155440a403fSchristos     case O_register:
2156440a403fSchristos       if (operand_real->flags & ARC_OPERAND_IR)
2157440a403fSchristos 	ret = TRUE;
2158440a403fSchristos       break;
2159440a403fSchristos 
2160440a403fSchristos     case O_bracket:
2161440a403fSchristos       if (operand_real->flags & ARC_OPERAND_BRAKET)
2162440a403fSchristos 	ret = TRUE;
2163440a403fSchristos       break;
2164440a403fSchristos 
2165440a403fSchristos     default:
2166440a403fSchristos       /* Unknown.  */
2167440a403fSchristos       break;
2168440a403fSchristos     }
2169440a403fSchristos   return ret;
2170440a403fSchristos }
2171440a403fSchristos 
2172440a403fSchristos /* Find pseudo instruction in array.  */
2173440a403fSchristos 
2174440a403fSchristos static const struct arc_pseudo_insn *
find_pseudo_insn(const char * opname,int ntok,const expressionS * tok)2175440a403fSchristos find_pseudo_insn (const char *opname,
2176440a403fSchristos 		  int ntok,
2177440a403fSchristos 		  const expressionS *tok)
2178440a403fSchristos {
2179440a403fSchristos   const struct arc_pseudo_insn *pseudo_insn = NULL;
2180440a403fSchristos   const struct arc_operand_operation *op;
2181440a403fSchristos   unsigned int i;
2182440a403fSchristos   int j;
2183440a403fSchristos 
2184440a403fSchristos   for (i = 0; i < arc_num_pseudo_insn; ++i)
2185440a403fSchristos     {
2186440a403fSchristos       pseudo_insn = &arc_pseudo_insns[i];
2187440a403fSchristos       if (strcmp (pseudo_insn->mnemonic_p, opname) == 0)
2188440a403fSchristos 	{
2189440a403fSchristos 	  op = pseudo_insn->operand;
2190440a403fSchristos 	  for (j = 0; j < ntok; ++j)
2191440a403fSchristos 	    if (!pseudo_operand_match (&tok[j], &op[j]))
2192440a403fSchristos 	      break;
2193440a403fSchristos 
2194440a403fSchristos 	  /* Found the right instruction.  */
2195440a403fSchristos 	  if (j == ntok)
2196440a403fSchristos 	    return pseudo_insn;
2197440a403fSchristos 	}
2198440a403fSchristos     }
2199440a403fSchristos   return NULL;
2200440a403fSchristos }
2201440a403fSchristos 
2202440a403fSchristos /* Assumes the expressionS *tok is of sufficient size.  */
2203440a403fSchristos 
2204440a403fSchristos static const struct arc_opcode_hash_entry *
find_special_case_pseudo(const char * opname,int * ntok,expressionS * tok,int * nflgs,struct arc_flags * pflags)2205440a403fSchristos find_special_case_pseudo (const char *opname,
2206440a403fSchristos 			  int *ntok,
2207440a403fSchristos 			  expressionS *tok,
2208440a403fSchristos 			  int *nflgs,
2209440a403fSchristos 			  struct arc_flags *pflags)
2210440a403fSchristos {
2211440a403fSchristos   const struct arc_pseudo_insn *pseudo_insn = NULL;
2212440a403fSchristos   const struct arc_operand_operation *operand_pseudo;
2213440a403fSchristos   const struct arc_operand *operand_real;
2214440a403fSchristos   unsigned i;
2215440a403fSchristos   char construct_operand[MAX_CONSTR_STR];
2216440a403fSchristos 
2217440a403fSchristos   /* Find whether opname is in pseudo instruction array.  */
2218440a403fSchristos   pseudo_insn = find_pseudo_insn (opname, *ntok, tok);
2219440a403fSchristos 
2220440a403fSchristos   if (pseudo_insn == NULL)
2221440a403fSchristos     return NULL;
2222440a403fSchristos 
2223440a403fSchristos   /* Handle flag, Limited to one flag at the moment.  */
2224440a403fSchristos   if (pseudo_insn->flag_r != NULL)
2225440a403fSchristos     *nflgs += tokenize_flags (pseudo_insn->flag_r, &pflags[*nflgs],
2226440a403fSchristos 			      MAX_INSN_FLGS - *nflgs);
2227440a403fSchristos 
2228440a403fSchristos   /* Handle operand operations.  */
2229440a403fSchristos   for (i = 0; i < pseudo_insn->operand_cnt; ++i)
2230440a403fSchristos     {
2231440a403fSchristos       operand_pseudo = &pseudo_insn->operand[i];
2232440a403fSchristos       operand_real = &arc_operands[operand_pseudo->operand_idx];
2233440a403fSchristos 
223406324dcfSchristos       if (operand_real->flags & ARC_OPERAND_BRAKET
223506324dcfSchristos 	  && !operand_pseudo->needs_insert)
2236440a403fSchristos 	continue;
2237440a403fSchristos 
2238440a403fSchristos       /* Has to be inserted (i.e. this token does not exist yet).  */
2239440a403fSchristos       if (operand_pseudo->needs_insert)
2240440a403fSchristos 	{
2241440a403fSchristos 	  if (operand_real->flags & ARC_OPERAND_BRAKET)
2242440a403fSchristos 	    {
2243440a403fSchristos 	      tok[i].X_op = O_bracket;
2244440a403fSchristos 	      ++(*ntok);
2245440a403fSchristos 	      continue;
2246440a403fSchristos 	    }
2247440a403fSchristos 
2248440a403fSchristos 	  /* Check if operand is a register or constant and handle it
2249440a403fSchristos 	     by type.  */
2250440a403fSchristos 	  if (operand_real->flags & ARC_OPERAND_IR)
2251440a403fSchristos 	    snprintf (construct_operand, MAX_CONSTR_STR, "r%d",
2252440a403fSchristos 		      operand_pseudo->count);
2253440a403fSchristos 	  else
2254440a403fSchristos 	    snprintf (construct_operand, MAX_CONSTR_STR, "%d",
2255440a403fSchristos 		      operand_pseudo->count);
2256440a403fSchristos 
2257440a403fSchristos 	  tokenize_arguments (construct_operand, &tok[i], 1);
2258440a403fSchristos 	  ++(*ntok);
2259440a403fSchristos 	}
2260440a403fSchristos 
2261440a403fSchristos       else if (operand_pseudo->count)
2262440a403fSchristos 	{
2263440a403fSchristos 	  /* Operand number has to be adjusted accordingly (by operand
2264440a403fSchristos 	     type).  */
2265440a403fSchristos 	  switch (tok[i].X_op)
2266440a403fSchristos 	    {
2267440a403fSchristos 	    case O_constant:
2268440a403fSchristos 	      tok[i].X_add_number += operand_pseudo->count;
2269440a403fSchristos 	      break;
2270440a403fSchristos 
2271440a403fSchristos 	    case O_symbol:
2272440a403fSchristos 	      break;
2273440a403fSchristos 
2274440a403fSchristos 	    default:
2275440a403fSchristos 	      /* Ignored.  */
2276440a403fSchristos 	      break;
2277440a403fSchristos 	    }
2278440a403fSchristos 	}
2279440a403fSchristos     }
2280440a403fSchristos 
2281440a403fSchristos   /* Swap operands if necessary.  Only supports one swap at the
2282440a403fSchristos      moment.  */
2283440a403fSchristos   for (i = 0; i < pseudo_insn->operand_cnt; ++i)
2284440a403fSchristos     {
2285440a403fSchristos       operand_pseudo = &pseudo_insn->operand[i];
2286440a403fSchristos 
2287440a403fSchristos       if (operand_pseudo->swap_operand_idx == i)
2288440a403fSchristos 	continue;
2289440a403fSchristos 
2290440a403fSchristos       swap_operand (tok, i, operand_pseudo->swap_operand_idx);
2291440a403fSchristos 
2292440a403fSchristos       /* Prevent a swap back later by breaking out.  */
2293440a403fSchristos       break;
2294440a403fSchristos     }
2295440a403fSchristos 
2296440a403fSchristos   return arc_find_opcode (pseudo_insn->mnemonic_r);
2297440a403fSchristos }
2298440a403fSchristos 
2299440a403fSchristos static const struct arc_opcode_hash_entry *
find_special_case_flag(const char * opname,int * nflgs,struct arc_flags * pflags)2300440a403fSchristos find_special_case_flag (const char *opname,
2301440a403fSchristos 			int *nflgs,
2302440a403fSchristos 			struct arc_flags *pflags)
2303440a403fSchristos {
2304440a403fSchristos   unsigned int i;
2305440a403fSchristos   const char *flagnm;
2306440a403fSchristos   unsigned flag_idx, flag_arr_idx;
2307440a403fSchristos   size_t flaglen, oplen;
2308440a403fSchristos   const struct arc_flag_special *arc_flag_special_opcode;
2309440a403fSchristos   const struct arc_opcode_hash_entry *entry;
2310440a403fSchristos 
2311440a403fSchristos   /* Search for special case instruction.  */
2312440a403fSchristos   for (i = 0; i < arc_num_flag_special; i++)
2313440a403fSchristos     {
2314440a403fSchristos       arc_flag_special_opcode = &arc_flag_special_cases[i];
2315440a403fSchristos       oplen = strlen (arc_flag_special_opcode->name);
2316440a403fSchristos 
2317440a403fSchristos       if (strncmp (opname, arc_flag_special_opcode->name, oplen) != 0)
2318440a403fSchristos 	continue;
2319440a403fSchristos 
2320440a403fSchristos       /* Found a potential special case instruction, now test for
2321440a403fSchristos 	 flags.  */
2322440a403fSchristos       for (flag_arr_idx = 0;; ++flag_arr_idx)
2323440a403fSchristos 	{
2324440a403fSchristos 	  flag_idx = arc_flag_special_opcode->flags[flag_arr_idx];
2325440a403fSchristos 	  if (flag_idx == 0)
2326440a403fSchristos 	    break;  /* End of array, nothing found.  */
2327440a403fSchristos 
2328440a403fSchristos 	  flagnm = arc_flag_operands[flag_idx].name;
2329440a403fSchristos 	  flaglen = strlen (flagnm);
2330440a403fSchristos 	  if (strcmp (opname + oplen, flagnm) == 0)
2331440a403fSchristos 	    {
2332440a403fSchristos               entry = arc_find_opcode (arc_flag_special_opcode->name);
2333440a403fSchristos 
2334440a403fSchristos 	      if (*nflgs + 1 > MAX_INSN_FLGS)
2335440a403fSchristos 		break;
2336440a403fSchristos 	      memcpy (pflags[*nflgs].name, flagnm, flaglen);
2337440a403fSchristos 	      pflags[*nflgs].name[flaglen] = '\0';
2338440a403fSchristos 	      (*nflgs)++;
2339440a403fSchristos 	      return entry;
2340440a403fSchristos 	    }
2341440a403fSchristos 	}
2342440a403fSchristos     }
2343440a403fSchristos   return NULL;
2344440a403fSchristos }
2345440a403fSchristos 
2346440a403fSchristos /* Used to find special case opcode.  */
2347440a403fSchristos 
2348440a403fSchristos static const struct arc_opcode_hash_entry *
find_special_case(const char * opname,int * nflgs,struct arc_flags * pflags,expressionS * tok,int * ntok)2349440a403fSchristos find_special_case (const char *opname,
2350440a403fSchristos 		   int *nflgs,
2351440a403fSchristos 		   struct arc_flags *pflags,
2352440a403fSchristos 		   expressionS *tok,
2353440a403fSchristos 		   int *ntok)
2354440a403fSchristos {
2355440a403fSchristos   const struct arc_opcode_hash_entry *entry;
2356440a403fSchristos 
2357440a403fSchristos   entry = find_special_case_pseudo (opname, ntok, tok, nflgs, pflags);
2358440a403fSchristos 
2359440a403fSchristos   if (entry == NULL)
2360440a403fSchristos     entry = find_special_case_flag (opname, nflgs, pflags);
2361440a403fSchristos 
2362440a403fSchristos   return entry;
2363440a403fSchristos }
2364440a403fSchristos 
236506324dcfSchristos /* Autodetect cpu attribute list.  */
236606324dcfSchristos 
236706324dcfSchristos static void
autodetect_attributes(const struct arc_opcode * opcode,const expressionS * tok,int ntok)236806324dcfSchristos autodetect_attributes (const struct arc_opcode *opcode,
236906324dcfSchristos 			 const expressionS *tok,
237006324dcfSchristos 			 int ntok)
237106324dcfSchristos {
237206324dcfSchristos   unsigned i;
237306324dcfSchristos   struct mpy_type
237406324dcfSchristos   {
237506324dcfSchristos     unsigned feature;
237606324dcfSchristos     unsigned encoding;
237706324dcfSchristos   } mpy_list[] = {{ MPY1E, 1 }, { MPY6E, 6 }, { MPY7E, 7 }, { MPY8E, 8 },
237806324dcfSchristos 		 { MPY9E, 9 }};
237906324dcfSchristos 
238006324dcfSchristos   for (i = 0; i < ARRAY_SIZE (feature_list); i++)
238106324dcfSchristos     if (opcode->subclass == feature_list[i].feature)
238206324dcfSchristos       selected_cpu.features |= feature_list[i].feature;
238306324dcfSchristos 
238406324dcfSchristos   for (i = 0; i < ARRAY_SIZE (mpy_list); i++)
238506324dcfSchristos     if (opcode->subclass == mpy_list[i].feature)
238606324dcfSchristos       mpy_option = mpy_list[i].encoding;
238706324dcfSchristos 
238806324dcfSchristos   for (i = 0; i < (unsigned) ntok; i++)
238906324dcfSchristos     {
239006324dcfSchristos       switch (tok[i].X_md)
239106324dcfSchristos 	{
239206324dcfSchristos 	case O_gotoff:
239306324dcfSchristos 	case O_gotpc:
239406324dcfSchristos 	case O_plt:
239506324dcfSchristos 	  pic_option = 2;
239606324dcfSchristos 	  break;
239706324dcfSchristos 	case O_sda:
239806324dcfSchristos 	  sda_option = 2;
239906324dcfSchristos 	  break;
240006324dcfSchristos 	case O_tlsgd:
240106324dcfSchristos 	case O_tlsie:
240206324dcfSchristos 	case O_tpoff9:
240306324dcfSchristos 	case O_tpoff:
240406324dcfSchristos 	case O_dtpoff9:
240506324dcfSchristos 	case O_dtpoff:
240606324dcfSchristos 	  tls_option = 1;
240706324dcfSchristos 	  break;
240806324dcfSchristos 	default:
240906324dcfSchristos 	  break;
241006324dcfSchristos 	}
2411*b88e3e88Schristos 
2412*b88e3e88Schristos       switch (tok[i].X_op)
2413*b88e3e88Schristos 	{
2414*b88e3e88Schristos 	case O_register:
2415*b88e3e88Schristos 	  if ((tok[i].X_add_number >= 4 && tok[i].X_add_number <= 9)
2416*b88e3e88Schristos 	      || (tok[i].X_add_number >= 16 && tok[i].X_add_number <= 25))
2417*b88e3e88Schristos 	    rf16_only = FALSE;
2418*b88e3e88Schristos 	  break;
2419*b88e3e88Schristos 	default:
2420*b88e3e88Schristos 	  break;
2421*b88e3e88Schristos 	}
242206324dcfSchristos     }
242306324dcfSchristos }
242406324dcfSchristos 
2425440a403fSchristos /* Given an opcode name, pre-tockenized set of argumenst and the
2426440a403fSchristos    opcode flags, take it all the way through emission.  */
2427440a403fSchristos 
2428440a403fSchristos static void
assemble_tokens(const char * opname,expressionS * tok,int ntok,struct arc_flags * pflags,int nflgs)2429440a403fSchristos assemble_tokens (const char *opname,
2430440a403fSchristos 		 expressionS *tok,
2431440a403fSchristos 		 int ntok,
2432440a403fSchristos 		 struct arc_flags *pflags,
2433440a403fSchristos 		 int nflgs)
2434440a403fSchristos {
2435440a403fSchristos   bfd_boolean found_something = FALSE;
2436440a403fSchristos   const struct arc_opcode_hash_entry *entry;
2437440a403fSchristos   int cpumatch = 1;
243806324dcfSchristos   const char *errmsg = NULL;
2439440a403fSchristos 
2440440a403fSchristos   /* Search opcodes.  */
2441440a403fSchristos   entry = arc_find_opcode (opname);
2442440a403fSchristos 
2443440a403fSchristos   /* Couldn't find opcode conventional way, try special cases.  */
2444440a403fSchristos   if (entry == NULL)
2445440a403fSchristos     entry = find_special_case (opname, &nflgs, pflags, tok, &ntok);
2446440a403fSchristos 
2447440a403fSchristos   if (entry != NULL)
2448440a403fSchristos     {
2449440a403fSchristos       const struct arc_opcode *opcode;
2450440a403fSchristos 
2451440a403fSchristos       pr_debug ("%s:%d: assemble_tokens: %s\n",
2452440a403fSchristos 		frag_now->fr_file, frag_now->fr_line, opname);
2453440a403fSchristos       found_something = TRUE;
2454440a403fSchristos       opcode = find_opcode_match (entry, tok, &ntok, pflags,
245506324dcfSchristos 				  nflgs, &cpumatch, &errmsg);
2456440a403fSchristos       if (opcode != NULL)
2457440a403fSchristos 	{
2458440a403fSchristos 	  struct arc_insn insn;
2459440a403fSchristos 
246006324dcfSchristos 	  autodetect_attributes (opcode,  tok, ntok);
2461440a403fSchristos 	  assemble_insn (opcode, tok, ntok, pflags, nflgs, &insn);
2462440a403fSchristos 	  emit_insn (&insn);
2463440a403fSchristos 	  return;
2464440a403fSchristos 	}
2465440a403fSchristos     }
2466440a403fSchristos 
2467440a403fSchristos   if (found_something)
2468440a403fSchristos     {
2469440a403fSchristos       if (cpumatch)
247006324dcfSchristos 	if (errmsg)
247106324dcfSchristos 	  as_bad (_("%s for instruction '%s'"), errmsg, opname);
247206324dcfSchristos 	else
2473440a403fSchristos 	  as_bad (_("inappropriate arguments for opcode '%s'"), opname);
2474440a403fSchristos       else
2475440a403fSchristos 	as_bad (_("opcode '%s' not supported for target %s"), opname,
247606324dcfSchristos 		selected_cpu.name);
2477440a403fSchristos     }
2478440a403fSchristos   else
2479440a403fSchristos     as_bad (_("unknown opcode '%s'"), opname);
2480440a403fSchristos }
2481440a403fSchristos 
2482440a403fSchristos /* The public interface to the instruction assembler.  */
2483440a403fSchristos 
2484440a403fSchristos void
md_assemble(char * str)2485440a403fSchristos md_assemble (char *str)
2486440a403fSchristos {
2487440a403fSchristos   char *opname;
2488440a403fSchristos   expressionS tok[MAX_INSN_ARGS];
2489440a403fSchristos   int ntok, nflg;
2490440a403fSchristos   size_t opnamelen;
2491440a403fSchristos   struct arc_flags flags[MAX_INSN_FLGS];
2492440a403fSchristos 
2493440a403fSchristos   /* Split off the opcode.  */
2494440a403fSchristos   opnamelen = strspn (str, "abcdefghijklmnopqrstuvwxyz_0123468");
2495440a403fSchristos   opname = xmemdup0 (str, opnamelen);
2496440a403fSchristos 
249706324dcfSchristos   /* Signalize we are assembling the instructions.  */
2498440a403fSchristos   assembling_insn = TRUE;
2499440a403fSchristos 
2500440a403fSchristos   /* Tokenize the flags.  */
2501440a403fSchristos   if ((nflg = tokenize_flags (str + opnamelen, flags, MAX_INSN_FLGS)) == -1)
2502440a403fSchristos     {
2503440a403fSchristos       as_bad (_("syntax error"));
2504440a403fSchristos       return;
2505440a403fSchristos     }
2506440a403fSchristos 
2507440a403fSchristos   /* Scan up to the end of the mnemonic which must end in space or end
2508440a403fSchristos      of string.  */
2509440a403fSchristos   str += opnamelen;
2510440a403fSchristos   for (; *str != '\0'; str++)
2511440a403fSchristos     if (*str == ' ')
2512440a403fSchristos       break;
2513440a403fSchristos 
2514440a403fSchristos   /* Tokenize the rest of the line.  */
2515440a403fSchristos   if ((ntok = tokenize_arguments (str, tok, MAX_INSN_ARGS)) < 0)
2516440a403fSchristos     {
2517440a403fSchristos       as_bad (_("syntax error"));
2518440a403fSchristos       return;
2519440a403fSchristos     }
2520440a403fSchristos 
2521440a403fSchristos   /* Finish it off.  */
2522440a403fSchristos   assemble_tokens (opname, tok, ntok, flags, nflg);
2523440a403fSchristos   assembling_insn = FALSE;
2524440a403fSchristos }
2525440a403fSchristos 
2526440a403fSchristos /* Callback to insert a register into the hash table.  */
2527440a403fSchristos 
2528440a403fSchristos static void
declare_register(const char * name,int number)2529440a403fSchristos declare_register (const char *name, int number)
2530440a403fSchristos {
2531440a403fSchristos   const char *err;
2532440a403fSchristos   symbolS *regS = symbol_create (name, reg_section,
2533440a403fSchristos 				 number, &zero_address_frag);
2534440a403fSchristos 
2535440a403fSchristos   err = hash_insert (arc_reg_hash, S_GET_NAME (regS), (void *) regS);
2536440a403fSchristos   if (err)
2537440a403fSchristos     as_fatal (_("Inserting \"%s\" into register table failed: %s"),
2538440a403fSchristos 	      name, err);
2539440a403fSchristos }
2540440a403fSchristos 
2541440a403fSchristos /* Construct symbols for each of the general registers.  */
2542440a403fSchristos 
2543440a403fSchristos static void
declare_register_set(void)2544440a403fSchristos declare_register_set (void)
2545440a403fSchristos {
2546440a403fSchristos   int i;
2547440a403fSchristos   for (i = 0; i < 64; ++i)
2548440a403fSchristos     {
2549440a403fSchristos       char name[7];
2550440a403fSchristos 
2551440a403fSchristos       sprintf (name, "r%d", i);
2552440a403fSchristos       declare_register (name, i);
2553440a403fSchristos       if ((i & 0x01) == 0)
2554440a403fSchristos 	{
2555440a403fSchristos 	  sprintf (name, "r%dr%d", i, i+1);
2556440a403fSchristos 	  declare_register (name, i);
2557440a403fSchristos 	}
2558440a403fSchristos     }
2559440a403fSchristos }
2560440a403fSchristos 
256106324dcfSchristos /* Construct a symbol for an address type.  */
256206324dcfSchristos 
256306324dcfSchristos static void
declare_addrtype(const char * name,int number)256406324dcfSchristos declare_addrtype (const char *name, int number)
256506324dcfSchristos {
256606324dcfSchristos   const char *err;
256706324dcfSchristos   symbolS *addrtypeS = symbol_create (name, undefined_section,
256806324dcfSchristos                                       number, &zero_address_frag);
256906324dcfSchristos 
257006324dcfSchristos   err = hash_insert (arc_addrtype_hash, S_GET_NAME (addrtypeS),
257106324dcfSchristos                      (void *) addrtypeS);
257206324dcfSchristos   if (err)
257306324dcfSchristos     as_fatal (_("Inserting \"%s\" into address type table failed: %s"),
257406324dcfSchristos               name, err);
257506324dcfSchristos }
257606324dcfSchristos 
2577440a403fSchristos /* Port-specific assembler initialization.  This function is called
2578440a403fSchristos    once, at assembler startup time.  */
2579440a403fSchristos 
2580440a403fSchristos void
md_begin(void)2581440a403fSchristos md_begin (void)
2582440a403fSchristos {
2583440a403fSchristos   const struct arc_opcode *opcode = arc_opcodes;
2584440a403fSchristos 
258506324dcfSchristos   if (mach_selection_mode == MACH_SELECTION_NONE)
258606324dcfSchristos     arc_select_cpu (TARGET_WITH_CPU, MACH_SELECTION_FROM_DEFAULT);
2587440a403fSchristos 
2588440a403fSchristos   /* The endianness can be chosen "at the factory".  */
2589440a403fSchristos   target_big_endian = byte_order == BIG_ENDIAN;
2590440a403fSchristos 
259106324dcfSchristos   if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
2592440a403fSchristos     as_warn (_("could not set architecture and machine"));
2593440a403fSchristos 
2594440a403fSchristos   /* Set elf header flags.  */
259506324dcfSchristos   bfd_set_private_flags (stdoutput, selected_cpu.eflags);
2596440a403fSchristos 
2597440a403fSchristos   /* Set up a hash table for the instructions.  */
2598440a403fSchristos   arc_opcode_hash = hash_new ();
2599440a403fSchristos   if (arc_opcode_hash == NULL)
2600440a403fSchristos     as_fatal (_("Virtual memory exhausted"));
2601440a403fSchristos 
2602440a403fSchristos   /* Initialize the hash table with the insns.  */
2603440a403fSchristos   do
2604440a403fSchristos     {
2605440a403fSchristos       const char *name = opcode->name;
2606440a403fSchristos 
2607440a403fSchristos       arc_insert_opcode (opcode);
2608440a403fSchristos 
2609440a403fSchristos       while (++opcode && opcode->name
2610440a403fSchristos 	     && (opcode->name == name
2611440a403fSchristos 		 || !strcmp (opcode->name, name)))
2612440a403fSchristos 	continue;
2613440a403fSchristos     }while (opcode->name);
2614440a403fSchristos 
2615440a403fSchristos   /* Register declaration.  */
2616440a403fSchristos   arc_reg_hash = hash_new ();
2617440a403fSchristos   if (arc_reg_hash == NULL)
2618440a403fSchristos     as_fatal (_("Virtual memory exhausted"));
2619440a403fSchristos 
2620440a403fSchristos   declare_register_set ();
2621440a403fSchristos   declare_register ("gp", 26);
2622440a403fSchristos   declare_register ("fp", 27);
2623440a403fSchristos   declare_register ("sp", 28);
2624440a403fSchristos   declare_register ("ilink", 29);
2625440a403fSchristos   declare_register ("ilink1", 29);
2626440a403fSchristos   declare_register ("ilink2", 30);
2627440a403fSchristos   declare_register ("blink", 31);
2628440a403fSchristos 
2629440a403fSchristos   /* XY memory registers.  */
2630440a403fSchristos   declare_register ("x0_u0", 32);
2631440a403fSchristos   declare_register ("x0_u1", 33);
2632440a403fSchristos   declare_register ("x1_u0", 34);
2633440a403fSchristos   declare_register ("x1_u1", 35);
2634440a403fSchristos   declare_register ("x2_u0", 36);
2635440a403fSchristos   declare_register ("x2_u1", 37);
2636440a403fSchristos   declare_register ("x3_u0", 38);
2637440a403fSchristos   declare_register ("x3_u1", 39);
2638440a403fSchristos   declare_register ("y0_u0", 40);
2639440a403fSchristos   declare_register ("y0_u1", 41);
2640440a403fSchristos   declare_register ("y1_u0", 42);
2641440a403fSchristos   declare_register ("y1_u1", 43);
2642440a403fSchristos   declare_register ("y2_u0", 44);
2643440a403fSchristos   declare_register ("y2_u1", 45);
2644440a403fSchristos   declare_register ("y3_u0", 46);
2645440a403fSchristos   declare_register ("y3_u1", 47);
2646440a403fSchristos   declare_register ("x0_nu", 48);
2647440a403fSchristos   declare_register ("x1_nu", 49);
2648440a403fSchristos   declare_register ("x2_nu", 50);
2649440a403fSchristos   declare_register ("x3_nu", 51);
2650440a403fSchristos   declare_register ("y0_nu", 52);
2651440a403fSchristos   declare_register ("y1_nu", 53);
2652440a403fSchristos   declare_register ("y2_nu", 54);
2653440a403fSchristos   declare_register ("y3_nu", 55);
2654440a403fSchristos 
2655440a403fSchristos   declare_register ("mlo", 57);
2656440a403fSchristos   declare_register ("mmid", 58);
2657440a403fSchristos   declare_register ("mhi", 59);
2658440a403fSchristos 
2659440a403fSchristos   declare_register ("acc1", 56);
2660440a403fSchristos   declare_register ("acc2", 57);
2661440a403fSchristos 
2662440a403fSchristos   declare_register ("lp_count", 60);
2663440a403fSchristos   declare_register ("pcl", 63);
2664440a403fSchristos 
2665440a403fSchristos   /* Initialize the last instructions.  */
2666440a403fSchristos   memset (&arc_last_insns[0], 0, sizeof (arc_last_insns));
2667440a403fSchristos 
2668440a403fSchristos   /* Aux register declaration.  */
2669440a403fSchristos   arc_aux_hash = hash_new ();
2670440a403fSchristos   if (arc_aux_hash == NULL)
2671440a403fSchristos     as_fatal (_("Virtual memory exhausted"));
2672440a403fSchristos 
2673440a403fSchristos   const struct arc_aux_reg *auxr = &arc_aux_regs[0];
2674440a403fSchristos   unsigned int i;
2675440a403fSchristos   for (i = 0; i < arc_num_aux_regs; i++, auxr++)
2676440a403fSchristos     {
2677440a403fSchristos       const char *retval;
2678440a403fSchristos 
267906324dcfSchristos       if (!(auxr->cpu & selected_cpu.flags))
2680440a403fSchristos 	continue;
2681440a403fSchristos 
2682440a403fSchristos       if ((auxr->subclass != NONE)
2683440a403fSchristos 	  && !check_cpu_feature (auxr->subclass))
2684440a403fSchristos 	continue;
2685440a403fSchristos 
2686440a403fSchristos       retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
2687440a403fSchristos       if (retval)
2688440a403fSchristos 	as_fatal (_("internal error: can't hash aux register '%s': %s"),
2689440a403fSchristos 		  auxr->name, retval);
2690440a403fSchristos     }
269106324dcfSchristos 
269206324dcfSchristos   /* Address type declaration.  */
269306324dcfSchristos   arc_addrtype_hash = hash_new ();
269406324dcfSchristos   if (arc_addrtype_hash == NULL)
269506324dcfSchristos     as_fatal (_("Virtual memory exhausted"));
269606324dcfSchristos 
269706324dcfSchristos   declare_addrtype ("bd", ARC_NPS400_ADDRTYPE_BD);
269806324dcfSchristos   declare_addrtype ("jid", ARC_NPS400_ADDRTYPE_JID);
269906324dcfSchristos   declare_addrtype ("lbd", ARC_NPS400_ADDRTYPE_LBD);
270006324dcfSchristos   declare_addrtype ("mbd", ARC_NPS400_ADDRTYPE_MBD);
270106324dcfSchristos   declare_addrtype ("sd", ARC_NPS400_ADDRTYPE_SD);
270206324dcfSchristos   declare_addrtype ("sm", ARC_NPS400_ADDRTYPE_SM);
270306324dcfSchristos   declare_addrtype ("xa", ARC_NPS400_ADDRTYPE_XA);
270406324dcfSchristos   declare_addrtype ("xd", ARC_NPS400_ADDRTYPE_XD);
270506324dcfSchristos   declare_addrtype ("cd", ARC_NPS400_ADDRTYPE_CD);
270606324dcfSchristos   declare_addrtype ("cbd", ARC_NPS400_ADDRTYPE_CBD);
270706324dcfSchristos   declare_addrtype ("cjid", ARC_NPS400_ADDRTYPE_CJID);
270806324dcfSchristos   declare_addrtype ("clbd", ARC_NPS400_ADDRTYPE_CLBD);
270906324dcfSchristos   declare_addrtype ("cm", ARC_NPS400_ADDRTYPE_CM);
271006324dcfSchristos   declare_addrtype ("csd", ARC_NPS400_ADDRTYPE_CSD);
271106324dcfSchristos   declare_addrtype ("cxa", ARC_NPS400_ADDRTYPE_CXA);
271206324dcfSchristos   declare_addrtype ("cxd", ARC_NPS400_ADDRTYPE_CXD);
2713440a403fSchristos }
2714440a403fSchristos 
2715440a403fSchristos /* Write a value out to the object file, using the appropriate
2716440a403fSchristos    endianness.  */
2717440a403fSchristos 
2718440a403fSchristos void
md_number_to_chars(char * buf,valueT val,int n)2719440a403fSchristos md_number_to_chars (char *buf,
2720440a403fSchristos 		    valueT val,
2721440a403fSchristos 		    int n)
2722440a403fSchristos {
2723440a403fSchristos   if (target_big_endian)
2724440a403fSchristos     number_to_chars_bigendian (buf, val, n);
2725440a403fSchristos   else
2726440a403fSchristos     number_to_chars_littleendian (buf, val, n);
2727440a403fSchristos }
2728440a403fSchristos 
2729440a403fSchristos /* Round up a section size to the appropriate boundary.  */
2730440a403fSchristos 
2731440a403fSchristos valueT
md_section_align(segT segment,valueT size)2732440a403fSchristos md_section_align (segT segment,
2733440a403fSchristos 		  valueT size)
2734440a403fSchristos {
2735*b88e3e88Schristos   int align = bfd_section_alignment (segment);
2736440a403fSchristos 
2737440a403fSchristos   return ((size + (1 << align) - 1) & (-((valueT) 1 << align)));
2738440a403fSchristos }
2739440a403fSchristos 
2740440a403fSchristos /* The location from which a PC relative jump should be calculated,
2741440a403fSchristos    given a PC relative reloc.  */
2742440a403fSchristos 
2743440a403fSchristos long
md_pcrel_from_section(fixS * fixP,segT sec)2744440a403fSchristos md_pcrel_from_section (fixS *fixP,
2745440a403fSchristos 		       segT sec)
2746440a403fSchristos {
2747440a403fSchristos   offsetT base = fixP->fx_where + fixP->fx_frag->fr_address;
2748440a403fSchristos 
2749440a403fSchristos   pr_debug ("pcrel_from_section, fx_offset = %d\n", (int) fixP->fx_offset);
2750440a403fSchristos 
2751440a403fSchristos   if (fixP->fx_addsy != (symbolS *) NULL
2752440a403fSchristos       && (!S_IS_DEFINED (fixP->fx_addsy)
2753440a403fSchristos 	  || S_GET_SEGMENT (fixP->fx_addsy) != sec))
2754440a403fSchristos     {
2755440a403fSchristos       pr_debug ("Unknown pcrel symbol: %s\n", S_GET_NAME (fixP->fx_addsy));
2756440a403fSchristos 
2757440a403fSchristos       /* The symbol is undefined (or is defined but not in this section).
2758440a403fSchristos 	 Let the linker figure it out.  */
2759440a403fSchristos       return 0;
2760440a403fSchristos     }
2761440a403fSchristos 
2762440a403fSchristos   if ((int) fixP->fx_r_type < 0)
2763440a403fSchristos     {
2764440a403fSchristos       /* These are the "internal" relocations.  Align them to
2765440a403fSchristos 	 32 bit boundary (PCL), for the moment.  */
2766440a403fSchristos       base &= ~3;
2767440a403fSchristos     }
2768440a403fSchristos   else
2769440a403fSchristos     {
2770440a403fSchristos       switch (fixP->fx_r_type)
2771440a403fSchristos 	{
2772440a403fSchristos 	case BFD_RELOC_ARC_PC32:
2773440a403fSchristos 	  /* The hardware calculates relative to the start of the
2774440a403fSchristos 	     insn, but this relocation is relative to location of the
2775440a403fSchristos 	     LIMM, compensate.  The base always needs to be
277606324dcfSchristos 	     subtracted by 4 as we do not support this type of PCrel
2777440a403fSchristos 	     relocation for short instructions.  */
2778440a403fSchristos 	  base -= 4;
2779440a403fSchristos 	  /* Fall through.  */
2780440a403fSchristos 	case BFD_RELOC_ARC_PLT32:
2781440a403fSchristos 	case BFD_RELOC_ARC_S25H_PCREL_PLT:
2782440a403fSchristos 	case BFD_RELOC_ARC_S21H_PCREL_PLT:
2783440a403fSchristos 	case BFD_RELOC_ARC_S25W_PCREL_PLT:
2784440a403fSchristos 	case BFD_RELOC_ARC_S21W_PCREL_PLT:
2785440a403fSchristos 
2786440a403fSchristos 	case BFD_RELOC_ARC_S21H_PCREL:
2787440a403fSchristos 	case BFD_RELOC_ARC_S25H_PCREL:
2788440a403fSchristos 	case BFD_RELOC_ARC_S13_PCREL:
2789440a403fSchristos 	case BFD_RELOC_ARC_S21W_PCREL:
2790440a403fSchristos 	case BFD_RELOC_ARC_S25W_PCREL:
2791440a403fSchristos 	  base &= ~3;
2792440a403fSchristos 	  break;
2793440a403fSchristos 	default:
2794440a403fSchristos 	  as_bad_where (fixP->fx_file, fixP->fx_line,
2795440a403fSchristos 			_("unhandled reloc %s in md_pcrel_from_section"),
2796440a403fSchristos 		  bfd_get_reloc_code_name (fixP->fx_r_type));
2797440a403fSchristos 	  break;
2798440a403fSchristos 	}
2799440a403fSchristos     }
2800440a403fSchristos 
2801440a403fSchristos   pr_debug ("pcrel from %"BFD_VMA_FMT"x + %lx = %"BFD_VMA_FMT"x, "
2802440a403fSchristos 	    "symbol: %s (%"BFD_VMA_FMT"x)\n",
2803440a403fSchristos 	    fixP->fx_frag->fr_address, fixP->fx_where, base,
2804440a403fSchristos 	    fixP->fx_addsy ? S_GET_NAME (fixP->fx_addsy) : "(null)",
2805440a403fSchristos 	    fixP->fx_addsy ? S_GET_VALUE (fixP->fx_addsy) : 0);
2806440a403fSchristos 
2807440a403fSchristos   return base;
2808440a403fSchristos }
2809440a403fSchristos 
281006324dcfSchristos /* Given a BFD relocation find the corresponding operand.  */
2811440a403fSchristos 
2812440a403fSchristos static const struct arc_operand *
find_operand_for_reloc(extended_bfd_reloc_code_real_type reloc)2813440a403fSchristos find_operand_for_reloc (extended_bfd_reloc_code_real_type reloc)
2814440a403fSchristos {
2815440a403fSchristos   unsigned i;
2816440a403fSchristos 
2817440a403fSchristos   for (i = 0; i < arc_num_operands; i++)
2818440a403fSchristos     if (arc_operands[i].default_reloc == reloc)
2819440a403fSchristos       return  &arc_operands[i];
2820440a403fSchristos   return NULL;
2821440a403fSchristos }
2822440a403fSchristos 
2823440a403fSchristos /* Insert an operand value into an instruction.  */
2824440a403fSchristos 
282506324dcfSchristos static unsigned long long
insert_operand(unsigned long long insn,const struct arc_operand * operand,long long val,const char * file,unsigned line)282606324dcfSchristos insert_operand (unsigned long long insn,
2827440a403fSchristos 		const struct arc_operand *operand,
282806324dcfSchristos 		long long val,
2829440a403fSchristos 		const char *file,
2830440a403fSchristos 		unsigned line)
2831440a403fSchristos {
2832440a403fSchristos   offsetT min = 0, max = 0;
2833440a403fSchristos 
2834440a403fSchristos   if (operand->bits != 32
2835440a403fSchristos       && !(operand->flags & ARC_OPERAND_NCHK)
2836440a403fSchristos       && !(operand->flags & ARC_OPERAND_FAKE))
2837440a403fSchristos     {
2838440a403fSchristos       if (operand->flags & ARC_OPERAND_SIGNED)
2839440a403fSchristos 	{
2840440a403fSchristos 	  max = (1 << (operand->bits - 1)) - 1;
2841440a403fSchristos 	  min = -(1 << (operand->bits - 1));
2842440a403fSchristos 	}
2843440a403fSchristos       else
2844440a403fSchristos 	{
2845440a403fSchristos 	  max = (1 << operand->bits) - 1;
2846440a403fSchristos 	  min = 0;
2847440a403fSchristos 	}
2848440a403fSchristos 
2849440a403fSchristos       if (val < min || val > max)
2850440a403fSchristos 	as_bad_value_out_of_range (_("operand"),
2851440a403fSchristos 				   val, min, max, file, line);
2852440a403fSchristos     }
2853440a403fSchristos 
285406324dcfSchristos   pr_debug ("insert field: %ld <= %lld <= %ld in 0x%08llx\n",
2855440a403fSchristos 	    min, val, max, insn);
2856440a403fSchristos 
2857440a403fSchristos   if ((operand->flags & ARC_OPERAND_ALIGNED32)
2858440a403fSchristos       && (val & 0x03))
2859440a403fSchristos     as_bad_where (file, line,
2860440a403fSchristos 		  _("Unaligned operand. Needs to be 32bit aligned"));
2861440a403fSchristos 
2862440a403fSchristos   if ((operand->flags & ARC_OPERAND_ALIGNED16)
2863440a403fSchristos       && (val & 0x01))
2864440a403fSchristos     as_bad_where (file, line,
2865440a403fSchristos 		  _("Unaligned operand. Needs to be 16bit aligned"));
2866440a403fSchristos 
2867440a403fSchristos   if (operand->insert)
2868440a403fSchristos     {
2869440a403fSchristos       const char *errmsg = NULL;
2870440a403fSchristos 
2871440a403fSchristos       insn = (*operand->insert) (insn, val, &errmsg);
2872440a403fSchristos       if (errmsg)
2873440a403fSchristos 	as_warn_where (file, line, "%s", errmsg);
2874440a403fSchristos     }
2875440a403fSchristos   else
2876440a403fSchristos     {
2877440a403fSchristos       if (operand->flags & ARC_OPERAND_TRUNCATE)
2878440a403fSchristos 	{
2879440a403fSchristos 	  if (operand->flags & ARC_OPERAND_ALIGNED32)
2880440a403fSchristos 	    val >>= 2;
2881440a403fSchristos 	  if (operand->flags & ARC_OPERAND_ALIGNED16)
2882440a403fSchristos 	    val >>= 1;
2883440a403fSchristos 	}
2884440a403fSchristos       insn |= ((val & ((1 << operand->bits) - 1)) << operand->shift);
2885440a403fSchristos     }
2886440a403fSchristos   return insn;
2887440a403fSchristos }
2888440a403fSchristos 
2889440a403fSchristos /* Apply a fixup to the object code.  At this point all symbol values
2890440a403fSchristos    should be fully resolved, and we attempt to completely resolve the
2891440a403fSchristos    reloc.  If we can not do that, we determine the correct reloc code
2892440a403fSchristos    and put it back in the fixup.  To indicate that a fixup has been
2893440a403fSchristos    eliminated, set fixP->fx_done.  */
2894440a403fSchristos 
2895440a403fSchristos void
md_apply_fix(fixS * fixP,valueT * valP,segT seg)2896440a403fSchristos md_apply_fix (fixS *fixP,
2897440a403fSchristos 	      valueT *valP,
2898440a403fSchristos 	      segT seg)
2899440a403fSchristos {
2900440a403fSchristos   char * const fixpos = fixP->fx_frag->fr_literal + fixP->fx_where;
2901440a403fSchristos   valueT value = *valP;
2902440a403fSchristos   unsigned insn = 0;
2903440a403fSchristos   symbolS *fx_addsy, *fx_subsy;
2904440a403fSchristos   offsetT fx_offset;
2905440a403fSchristos   segT add_symbol_segment = absolute_section;
2906440a403fSchristos   segT sub_symbol_segment = absolute_section;
2907440a403fSchristos   const struct arc_operand *operand = NULL;
2908440a403fSchristos   extended_bfd_reloc_code_real_type reloc;
2909440a403fSchristos 
2910440a403fSchristos   pr_debug ("%s:%u: apply_fix: r_type=%d (%s) value=0x%lX offset=0x%lX\n",
2911440a403fSchristos 	    fixP->fx_file, fixP->fx_line, fixP->fx_r_type,
2912440a403fSchristos 	    ((int) fixP->fx_r_type < 0) ? "Internal":
2913440a403fSchristos 	    bfd_get_reloc_code_name (fixP->fx_r_type), value,
2914440a403fSchristos 	    fixP->fx_offset);
2915440a403fSchristos 
2916440a403fSchristos   fx_addsy = fixP->fx_addsy;
2917440a403fSchristos   fx_subsy = fixP->fx_subsy;
2918440a403fSchristos   fx_offset = 0;
2919440a403fSchristos 
2920440a403fSchristos   if (fx_addsy)
2921440a403fSchristos     {
2922440a403fSchristos       add_symbol_segment = S_GET_SEGMENT (fx_addsy);
2923440a403fSchristos     }
2924440a403fSchristos 
2925440a403fSchristos   if (fx_subsy
2926440a403fSchristos       && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF
2927440a403fSchristos       && fixP->fx_r_type != BFD_RELOC_ARC_TLS_DTPOFF_S9
2928440a403fSchristos       && fixP->fx_r_type != BFD_RELOC_ARC_TLS_GD_LD)
2929440a403fSchristos     {
2930440a403fSchristos       resolve_symbol_value (fx_subsy);
2931440a403fSchristos       sub_symbol_segment = S_GET_SEGMENT (fx_subsy);
2932440a403fSchristos 
2933440a403fSchristos       if (sub_symbol_segment == absolute_section)
2934440a403fSchristos 	{
2935440a403fSchristos 	  /* The symbol is really a constant.  */
2936440a403fSchristos 	  fx_offset -= S_GET_VALUE (fx_subsy);
2937440a403fSchristos 	  fx_subsy = NULL;
2938440a403fSchristos 	}
2939440a403fSchristos       else
2940440a403fSchristos 	{
2941440a403fSchristos 	  as_bad_where (fixP->fx_file, fixP->fx_line,
2942440a403fSchristos 			_("can't resolve `%s' {%s section} - `%s' {%s section}"),
2943440a403fSchristos 			fx_addsy ? S_GET_NAME (fx_addsy) : "0",
2944440a403fSchristos 			segment_name (add_symbol_segment),
2945440a403fSchristos 			S_GET_NAME (fx_subsy),
2946440a403fSchristos 			segment_name (sub_symbol_segment));
2947440a403fSchristos 	  return;
2948440a403fSchristos 	}
2949440a403fSchristos     }
2950440a403fSchristos 
2951440a403fSchristos   if (fx_addsy
2952440a403fSchristos       && !S_IS_WEAK (fx_addsy))
2953440a403fSchristos     {
2954440a403fSchristos       if (add_symbol_segment == seg
2955440a403fSchristos 	  && fixP->fx_pcrel)
2956440a403fSchristos 	{
2957440a403fSchristos 	  value += S_GET_VALUE (fx_addsy);
2958440a403fSchristos 	  value -= md_pcrel_from_section (fixP, seg);
2959440a403fSchristos 	  fx_addsy = NULL;
2960440a403fSchristos 	  fixP->fx_pcrel = FALSE;
2961440a403fSchristos 	}
2962440a403fSchristos       else if (add_symbol_segment == absolute_section)
2963440a403fSchristos 	{
2964440a403fSchristos 	  value = fixP->fx_offset;
2965440a403fSchristos 	  fx_offset += S_GET_VALUE (fixP->fx_addsy);
2966440a403fSchristos 	  fx_addsy = NULL;
2967440a403fSchristos 	  fixP->fx_pcrel = FALSE;
2968440a403fSchristos 	}
2969440a403fSchristos     }
2970440a403fSchristos 
2971440a403fSchristos   if (!fx_addsy)
2972440a403fSchristos     fixP->fx_done = TRUE;
2973440a403fSchristos 
2974440a403fSchristos   if (fixP->fx_pcrel)
2975440a403fSchristos     {
2976440a403fSchristos       if (fx_addsy
2977440a403fSchristos 	  && ((S_IS_DEFINED (fx_addsy)
2978440a403fSchristos 	       && S_GET_SEGMENT (fx_addsy) != seg)
2979440a403fSchristos 	      || S_IS_WEAK (fx_addsy)))
2980440a403fSchristos 	value += md_pcrel_from_section (fixP, seg);
2981440a403fSchristos 
2982440a403fSchristos       switch (fixP->fx_r_type)
2983440a403fSchristos 	{
2984440a403fSchristos 	case BFD_RELOC_ARC_32_ME:
2985440a403fSchristos 	  /* This is a pc-relative value in a LIMM.  Adjust it to the
2986440a403fSchristos 	     address of the instruction not to the address of the
298706324dcfSchristos 	     LIMM.  Note: it is not any longer valid this affirmation as
2988440a403fSchristos 	     the linker consider ARC_PC32 a fixup to entire 64 bit
2989440a403fSchristos 	     insn.  */
2990440a403fSchristos 	  fixP->fx_offset += fixP->fx_frag->fr_address;
2991440a403fSchristos 	  /* Fall through.  */
2992440a403fSchristos 	case BFD_RELOC_32:
2993440a403fSchristos 	  fixP->fx_r_type = BFD_RELOC_ARC_PC32;
2994440a403fSchristos 	  /* Fall through.  */
2995440a403fSchristos 	case BFD_RELOC_ARC_PC32:
2996440a403fSchristos 	  /* fixP->fx_offset += fixP->fx_where - fixP->fx_dot_value; */
2997440a403fSchristos 	  break;
2998440a403fSchristos 	default:
2999440a403fSchristos 	  if ((int) fixP->fx_r_type < 0)
300006324dcfSchristos 	    as_bad_where (fixP->fx_file, fixP->fx_line,
300106324dcfSchristos 			  _("PC relative relocation not allowed for (internal)"
300206324dcfSchristos 			    " type %d"),
3003440a403fSchristos 			  fixP->fx_r_type);
3004440a403fSchristos 	  break;
3005440a403fSchristos 	}
3006440a403fSchristos     }
3007440a403fSchristos 
3008440a403fSchristos   pr_debug ("%s:%u: apply_fix: r_type=%d (%s) value=0x%lX offset=0x%lX\n",
3009440a403fSchristos 	    fixP->fx_file, fixP->fx_line, fixP->fx_r_type,
3010440a403fSchristos 	    ((int) fixP->fx_r_type < 0) ? "Internal":
3011440a403fSchristos 	    bfd_get_reloc_code_name (fixP->fx_r_type), value,
3012440a403fSchristos 	    fixP->fx_offset);
3013440a403fSchristos 
3014440a403fSchristos 
3015440a403fSchristos   /* Now check for TLS relocations.  */
3016440a403fSchristos   reloc = fixP->fx_r_type;
3017440a403fSchristos   switch (reloc)
3018440a403fSchristos     {
3019440a403fSchristos     case BFD_RELOC_ARC_TLS_DTPOFF:
3020440a403fSchristos     case BFD_RELOC_ARC_TLS_LE_32:
3021440a403fSchristos       if (fixP->fx_done)
3022440a403fSchristos 	break;
3023440a403fSchristos       /* Fall through.  */
3024440a403fSchristos     case BFD_RELOC_ARC_TLS_GD_GOT:
3025440a403fSchristos     case BFD_RELOC_ARC_TLS_IE_GOT:
3026440a403fSchristos       S_SET_THREAD_LOCAL (fixP->fx_addsy);
3027440a403fSchristos       break;
3028440a403fSchristos 
3029440a403fSchristos     case BFD_RELOC_ARC_TLS_GD_LD:
3030440a403fSchristos       gas_assert (!fixP->fx_offset);
3031440a403fSchristos       if (fixP->fx_subsy)
3032440a403fSchristos 	fixP->fx_offset
3033440a403fSchristos 	  = (S_GET_VALUE (fixP->fx_subsy)
3034440a403fSchristos 	     - fixP->fx_frag->fr_address- fixP->fx_where);
3035440a403fSchristos       fixP->fx_subsy = NULL;
3036440a403fSchristos       /* Fall through.  */
3037440a403fSchristos     case BFD_RELOC_ARC_TLS_GD_CALL:
3038440a403fSchristos       /* These two relocs are there just to allow ld to change the tls
3039440a403fSchristos 	 model for this symbol, by patching the code.  The offset -
3040440a403fSchristos 	 and scale, if any - will be installed by the linker.  */
3041440a403fSchristos       S_SET_THREAD_LOCAL (fixP->fx_addsy);
3042440a403fSchristos       break;
3043440a403fSchristos 
3044440a403fSchristos     case BFD_RELOC_ARC_TLS_LE_S9:
3045440a403fSchristos     case BFD_RELOC_ARC_TLS_DTPOFF_S9:
3046440a403fSchristos       as_bad (_("TLS_*_S9 relocs are not supported yet"));
3047440a403fSchristos       break;
3048440a403fSchristos 
3049440a403fSchristos     default:
3050440a403fSchristos       break;
3051440a403fSchristos     }
3052440a403fSchristos 
3053440a403fSchristos   if (!fixP->fx_done)
3054440a403fSchristos     {
3055440a403fSchristos       return;
3056440a403fSchristos     }
3057440a403fSchristos 
305806324dcfSchristos   /* Adjust the value if we have a constant.  */
3059440a403fSchristos   value += fx_offset;
3060440a403fSchristos 
3061440a403fSchristos   /* For hosts with longs bigger than 32-bits make sure that the top
3062440a403fSchristos      bits of a 32-bit negative value read in by the parser are set,
3063440a403fSchristos      so that the correct comparisons are made.  */
3064440a403fSchristos   if (value & 0x80000000)
3065440a403fSchristos     value |= (-1UL << 31);
3066440a403fSchristos 
3067440a403fSchristos   reloc = fixP->fx_r_type;
3068440a403fSchristos   switch (reloc)
3069440a403fSchristos     {
3070440a403fSchristos     case BFD_RELOC_8:
3071440a403fSchristos     case BFD_RELOC_16:
3072440a403fSchristos     case BFD_RELOC_24:
3073440a403fSchristos     case BFD_RELOC_32:
3074440a403fSchristos     case BFD_RELOC_64:
3075440a403fSchristos     case BFD_RELOC_ARC_32_PCREL:
3076440a403fSchristos       md_number_to_chars (fixpos, value, fixP->fx_size);
3077440a403fSchristos       return;
3078440a403fSchristos 
3079440a403fSchristos     case BFD_RELOC_ARC_GOTPC32:
3080440a403fSchristos       /* I cannot fix an GOTPC relocation because I need to relax it
3081440a403fSchristos 	 from ld rx,[pcl,@sym@gotpc] to add rx,pcl,@sym@gotpc.  */
3082440a403fSchristos       as_bad (_("Unsupported operation on reloc"));
3083440a403fSchristos       return;
3084440a403fSchristos 
3085440a403fSchristos     case BFD_RELOC_ARC_TLS_DTPOFF:
3086440a403fSchristos     case BFD_RELOC_ARC_TLS_LE_32:
3087440a403fSchristos       gas_assert (!fixP->fx_addsy);
3088440a403fSchristos       gas_assert (!fixP->fx_subsy);
308906324dcfSchristos       /* Fall through.  */
3090440a403fSchristos 
3091440a403fSchristos     case BFD_RELOC_ARC_GOTOFF:
3092440a403fSchristos     case BFD_RELOC_ARC_32_ME:
3093440a403fSchristos     case BFD_RELOC_ARC_PC32:
3094440a403fSchristos       md_number_to_chars_midend (fixpos, value, fixP->fx_size);
3095440a403fSchristos       return;
3096440a403fSchristos 
3097440a403fSchristos     case BFD_RELOC_ARC_PLT32:
3098440a403fSchristos       md_number_to_chars_midend (fixpos, value, fixP->fx_size);
3099440a403fSchristos       return;
3100440a403fSchristos 
3101440a403fSchristos     case BFD_RELOC_ARC_S25H_PCREL_PLT:
3102440a403fSchristos       reloc = BFD_RELOC_ARC_S25W_PCREL;
3103440a403fSchristos       goto solve_plt;
3104440a403fSchristos 
3105440a403fSchristos     case BFD_RELOC_ARC_S21H_PCREL_PLT:
3106440a403fSchristos       reloc = BFD_RELOC_ARC_S21H_PCREL;
3107440a403fSchristos       goto solve_plt;
3108440a403fSchristos 
3109440a403fSchristos     case BFD_RELOC_ARC_S25W_PCREL_PLT:
3110440a403fSchristos       reloc = BFD_RELOC_ARC_S25W_PCREL;
3111440a403fSchristos       goto solve_plt;
3112440a403fSchristos 
3113440a403fSchristos     case BFD_RELOC_ARC_S21W_PCREL_PLT:
3114440a403fSchristos       reloc = BFD_RELOC_ARC_S21W_PCREL;
311506324dcfSchristos       /* Fall through.  */
3116440a403fSchristos 
3117440a403fSchristos     case BFD_RELOC_ARC_S25W_PCREL:
3118440a403fSchristos     case BFD_RELOC_ARC_S21W_PCREL:
3119440a403fSchristos     case BFD_RELOC_ARC_S21H_PCREL:
3120440a403fSchristos     case BFD_RELOC_ARC_S25H_PCREL:
3121440a403fSchristos     case BFD_RELOC_ARC_S13_PCREL:
3122440a403fSchristos     solve_plt:
3123440a403fSchristos       operand = find_operand_for_reloc (reloc);
3124440a403fSchristos       gas_assert (operand);
3125440a403fSchristos       break;
3126440a403fSchristos 
3127440a403fSchristos     default:
3128440a403fSchristos       {
3129440a403fSchristos 	if ((int) fixP->fx_r_type >= 0)
3130440a403fSchristos 	  as_fatal (_("unhandled relocation type %s"),
3131440a403fSchristos 		    bfd_get_reloc_code_name (fixP->fx_r_type));
3132440a403fSchristos 
3133440a403fSchristos 	/* The rest of these fixups needs to be completely resolved as
3134440a403fSchristos 	   constants.  */
3135440a403fSchristos 	if (fixP->fx_addsy != 0
3136440a403fSchristos 	    && S_GET_SEGMENT (fixP->fx_addsy) != absolute_section)
3137440a403fSchristos 	  as_bad_where (fixP->fx_file, fixP->fx_line,
3138440a403fSchristos 			_("non-absolute expression in constant field"));
3139440a403fSchristos 
3140440a403fSchristos 	gas_assert (-(int) fixP->fx_r_type < (int) arc_num_operands);
3141440a403fSchristos 	operand = &arc_operands[-(int) fixP->fx_r_type];
3142440a403fSchristos 	break;
3143440a403fSchristos       }
3144440a403fSchristos     }
3145440a403fSchristos 
3146440a403fSchristos   if (target_big_endian)
3147440a403fSchristos     {
3148440a403fSchristos       switch (fixP->fx_size)
3149440a403fSchristos 	{
3150440a403fSchristos 	case 4:
3151440a403fSchristos 	  insn = bfd_getb32 (fixpos);
3152440a403fSchristos 	  break;
3153440a403fSchristos 	case 2:
3154440a403fSchristos 	  insn = bfd_getb16 (fixpos);
3155440a403fSchristos 	  break;
3156440a403fSchristos 	default:
3157440a403fSchristos 	  as_bad_where (fixP->fx_file, fixP->fx_line,
3158440a403fSchristos 			_("unknown fixup size"));
3159440a403fSchristos 	}
3160440a403fSchristos     }
3161440a403fSchristos   else
3162440a403fSchristos     {
3163440a403fSchristos       insn = 0;
3164440a403fSchristos       switch (fixP->fx_size)
3165440a403fSchristos 	{
3166440a403fSchristos 	case 4:
3167440a403fSchristos 	  insn = bfd_getl16 (fixpos) << 16 | bfd_getl16 (fixpos + 2);
3168440a403fSchristos 	  break;
3169440a403fSchristos 	case 2:
3170440a403fSchristos 	  insn = bfd_getl16 (fixpos);
3171440a403fSchristos 	  break;
3172440a403fSchristos 	default:
3173440a403fSchristos 	  as_bad_where (fixP->fx_file, fixP->fx_line,
3174440a403fSchristos 			_("unknown fixup size"));
3175440a403fSchristos 	}
3176440a403fSchristos     }
3177440a403fSchristos 
3178440a403fSchristos   insn = insert_operand (insn, operand, (offsetT) value,
3179440a403fSchristos 			 fixP->fx_file, fixP->fx_line);
3180440a403fSchristos 
3181440a403fSchristos   md_number_to_chars_midend (fixpos, insn, fixP->fx_size);
3182440a403fSchristos }
3183440a403fSchristos 
3184440a403fSchristos /* Prepare machine-dependent frags for relaxation.
3185440a403fSchristos 
3186440a403fSchristos    Called just before relaxation starts.  Any symbol that is now undefined
3187440a403fSchristos    will not become defined.
3188440a403fSchristos 
3189440a403fSchristos    Return the correct fr_subtype in the frag.
3190440a403fSchristos 
3191440a403fSchristos    Return the initial "guess for fr_var" to caller.  The guess for fr_var
3192440a403fSchristos    is *actually* the growth beyond fr_fix.  Whatever we do to grow fr_fix
3193440a403fSchristos    or fr_var contributes to our returned value.
3194440a403fSchristos 
3195440a403fSchristos    Although it may not be explicit in the frag, pretend
3196440a403fSchristos    fr_var starts with a value.  */
3197440a403fSchristos 
3198440a403fSchristos int
md_estimate_size_before_relax(fragS * fragP,segT segment)3199440a403fSchristos md_estimate_size_before_relax (fragS *fragP,
3200440a403fSchristos 			       segT segment)
3201440a403fSchristos {
3202440a403fSchristos   int growth;
3203440a403fSchristos 
3204440a403fSchristos   /* If the symbol is not located within the same section AND it's not
3205440a403fSchristos      an absolute section, use the maximum.  OR if the symbol is a
3206440a403fSchristos      constant AND the insn is by nature not pc-rel, use the maximum.
3207440a403fSchristos      OR if the symbol is being equated against another symbol, use the
3208440a403fSchristos      maximum.  OR if the symbol is weak use the maximum.  */
3209440a403fSchristos   if ((S_GET_SEGMENT (fragP->fr_symbol) != segment
3210440a403fSchristos        && S_GET_SEGMENT (fragP->fr_symbol) != absolute_section)
3211440a403fSchristos       || (symbol_constant_p (fragP->fr_symbol)
3212440a403fSchristos 	  && !fragP->tc_frag_data.pcrel)
3213440a403fSchristos       || symbol_equated_p (fragP->fr_symbol)
3214440a403fSchristos       || S_IS_WEAK (fragP->fr_symbol))
3215440a403fSchristos     {
3216440a403fSchristos       while (md_relax_table[fragP->fr_subtype].rlx_more != ARC_RLX_NONE)
3217440a403fSchristos 	++fragP->fr_subtype;
3218440a403fSchristos     }
3219440a403fSchristos 
3220440a403fSchristos   growth = md_relax_table[fragP->fr_subtype].rlx_length;
3221440a403fSchristos   fragP->fr_var = growth;
3222440a403fSchristos 
3223440a403fSchristos   pr_debug ("%s:%d: md_estimate_size_before_relax: %d\n",
3224440a403fSchristos 	   fragP->fr_file, fragP->fr_line, growth);
3225440a403fSchristos 
3226440a403fSchristos   return growth;
3227440a403fSchristos }
3228440a403fSchristos 
3229440a403fSchristos /* Translate internal representation of relocation info to BFD target
3230440a403fSchristos    format.  */
3231440a403fSchristos 
3232440a403fSchristos arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixP)3233440a403fSchristos tc_gen_reloc (asection *section ATTRIBUTE_UNUSED,
3234440a403fSchristos 	      fixS *fixP)
3235440a403fSchristos {
3236440a403fSchristos   arelent *reloc;
3237440a403fSchristos   bfd_reloc_code_real_type code;
3238440a403fSchristos 
3239440a403fSchristos   reloc = XNEW (arelent);
3240440a403fSchristos   reloc->sym_ptr_ptr = XNEW (asymbol *);
3241440a403fSchristos   *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
3242440a403fSchristos   reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
3243440a403fSchristos 
3244440a403fSchristos   /* Make sure none of our internal relocations make it this far.
3245440a403fSchristos      They'd better have been fully resolved by this point.  */
3246440a403fSchristos   gas_assert ((int) fixP->fx_r_type > 0);
3247440a403fSchristos 
3248440a403fSchristos   code = fixP->fx_r_type;
3249440a403fSchristos 
3250440a403fSchristos   /* if we have something like add gp, pcl,
3251440a403fSchristos      _GLOBAL_OFFSET_TABLE_@gotpc.  */
3252440a403fSchristos   if (code == BFD_RELOC_ARC_GOTPC32
3253440a403fSchristos       && GOT_symbol
3254440a403fSchristos       && fixP->fx_addsy == GOT_symbol)
3255440a403fSchristos     code = BFD_RELOC_ARC_GOTPC;
3256440a403fSchristos 
3257440a403fSchristos   reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
3258440a403fSchristos   if (reloc->howto == NULL)
3259440a403fSchristos     {
3260440a403fSchristos       as_bad_where (fixP->fx_file, fixP->fx_line,
3261440a403fSchristos 		    _("cannot represent `%s' relocation in object file"),
3262440a403fSchristos 		    bfd_get_reloc_code_name (code));
3263440a403fSchristos       return NULL;
3264440a403fSchristos     }
3265440a403fSchristos 
3266440a403fSchristos   if (!fixP->fx_pcrel != !reloc->howto->pc_relative)
3267440a403fSchristos     as_fatal (_("internal error? cannot generate `%s' relocation"),
3268440a403fSchristos 	      bfd_get_reloc_code_name (code));
3269440a403fSchristos 
3270440a403fSchristos   gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
3271440a403fSchristos 
3272440a403fSchristos   reloc->addend = fixP->fx_offset;
3273440a403fSchristos 
3274440a403fSchristos   return reloc;
3275440a403fSchristos }
3276440a403fSchristos 
3277440a403fSchristos /* Perform post-processing of machine-dependent frags after relaxation.
3278440a403fSchristos    Called after relaxation is finished.
3279440a403fSchristos    In:	Address of frag.
3280440a403fSchristos    fr_type == rs_machine_dependent.
3281440a403fSchristos    fr_subtype is what the address relaxed to.
3282440a403fSchristos 
3283440a403fSchristos    Out: Any fixS:s and constants are set up.  */
3284440a403fSchristos 
3285440a403fSchristos void
md_convert_frag(bfd * abfd ATTRIBUTE_UNUSED,segT segment ATTRIBUTE_UNUSED,fragS * fragP)3286440a403fSchristos md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED,
3287440a403fSchristos 		 segT segment ATTRIBUTE_UNUSED,
3288440a403fSchristos 		 fragS *fragP)
3289440a403fSchristos {
3290440a403fSchristos   const relax_typeS *table_entry;
3291440a403fSchristos   char *dest;
3292440a403fSchristos   const struct arc_opcode *opcode;
3293440a403fSchristos   struct arc_insn insn;
3294440a403fSchristos   int size, fix;
3295440a403fSchristos   struct arc_relax_type *relax_arg = &fragP->tc_frag_data;
3296440a403fSchristos 
3297*b88e3e88Schristos   fix = fragP->fr_fix;
3298440a403fSchristos   dest = fragP->fr_literal + fix;
3299440a403fSchristos   table_entry = TC_GENERIC_RELAX_TABLE + fragP->fr_subtype;
3300440a403fSchristos 
3301440a403fSchristos   pr_debug ("%s:%d: md_convert_frag, subtype: %d, fix: %d, "
3302440a403fSchristos 	    "var: %"BFD_VMA_FMT"d\n",
3303440a403fSchristos 	    fragP->fr_file, fragP->fr_line,
3304440a403fSchristos 	    fragP->fr_subtype, fix, fragP->fr_var);
3305440a403fSchristos 
3306440a403fSchristos   if (fragP->fr_subtype <= 0
3307440a403fSchristos       && fragP->fr_subtype >= arc_num_relax_opcodes)
3308440a403fSchristos     as_fatal (_("no relaxation found for this instruction."));
3309440a403fSchristos 
3310440a403fSchristos   opcode = &arc_relax_opcodes[fragP->fr_subtype];
3311440a403fSchristos 
3312440a403fSchristos   assemble_insn (opcode, relax_arg->tok, relax_arg->ntok, relax_arg->pflags,
3313440a403fSchristos 	relax_arg->nflg, &insn);
3314440a403fSchristos 
3315440a403fSchristos   apply_fixups (&insn, fragP, fix);
3316440a403fSchristos 
331706324dcfSchristos   size = insn.len + (insn.has_limm ? 4 : 0);
3318440a403fSchristos   gas_assert (table_entry->rlx_length == size);
3319440a403fSchristos   emit_insn0 (&insn, dest, TRUE);
3320440a403fSchristos 
3321440a403fSchristos   fragP->fr_fix += table_entry->rlx_length;
3322440a403fSchristos   fragP->fr_var = 0;
3323440a403fSchristos }
3324440a403fSchristos 
3325440a403fSchristos /* We have no need to default values of symbols.  We could catch
3326440a403fSchristos    register names here, but that is handled by inserting them all in
3327440a403fSchristos    the symbol table to begin with.  */
3328440a403fSchristos 
3329440a403fSchristos symbolS *
md_undefined_symbol(char * name)3330440a403fSchristos md_undefined_symbol (char *name)
3331440a403fSchristos {
3332440a403fSchristos   /* The arc abi demands that a GOT[0] should be referencible as
3333440a403fSchristos      [pc+_DYNAMIC@gotpc].  Hence we convert a _DYNAMIC@gotpc to a
3334440a403fSchristos      GOTPC reference to _GLOBAL_OFFSET_TABLE_.  */
3335440a403fSchristos   if (((*name == '_')
3336440a403fSchristos        && (*(name+1) == 'G')
333706324dcfSchristos        && (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0)))
3338440a403fSchristos     {
3339440a403fSchristos       if (!GOT_symbol)
3340440a403fSchristos 	{
3341440a403fSchristos 	  if (symbol_find (name))
3342440a403fSchristos 	    as_bad ("GOT already in symbol table");
3343440a403fSchristos 
3344440a403fSchristos 	  GOT_symbol = symbol_new (GLOBAL_OFFSET_TABLE_NAME, undefined_section,
3345440a403fSchristos 				   (valueT) 0, &zero_address_frag);
3346440a403fSchristos 	};
3347440a403fSchristos       return GOT_symbol;
3348440a403fSchristos     }
3349440a403fSchristos   return NULL;
3350440a403fSchristos }
3351440a403fSchristos 
3352440a403fSchristos /* Turn a string in input_line_pointer into a floating point constant
3353440a403fSchristos    of type type, and store the appropriate bytes in *litP.  The number
3354440a403fSchristos    of LITTLENUMS emitted is stored in *sizeP.  An error message is
3355440a403fSchristos    returned, or NULL on OK.  */
3356440a403fSchristos 
3357440a403fSchristos const char *
md_atof(int type,char * litP,int * sizeP)3358440a403fSchristos md_atof (int type, char *litP, int *sizeP)
3359440a403fSchristos {
3360440a403fSchristos   return ieee_md_atof (type, litP, sizeP, target_big_endian);
3361440a403fSchristos }
3362440a403fSchristos 
3363440a403fSchristos /* Called for any expression that can not be recognized.  When the
3364440a403fSchristos    function is called, `input_line_pointer' will point to the start of
3365*b88e3e88Schristos    the expression.  We use it when we have complex operations like
3366*b88e3e88Schristos    @label1 - @label2.  */
3367440a403fSchristos 
3368440a403fSchristos void
md_operand(expressionS * expressionP)3369*b88e3e88Schristos md_operand (expressionS *expressionP)
3370440a403fSchristos {
3371440a403fSchristos   char *p = input_line_pointer;
3372440a403fSchristos   if (*p == '@')
3373440a403fSchristos     {
3374440a403fSchristos       input_line_pointer++;
3375440a403fSchristos       expressionP->X_op = O_symbol;
3376*b88e3e88Schristos       expressionP->X_md = O_absent;
3377440a403fSchristos       expression (expressionP);
3378440a403fSchristos     }
3379440a403fSchristos }
3380440a403fSchristos 
3381440a403fSchristos /* This function is called from the function 'expression', it attempts
3382440a403fSchristos    to parse special names (in our case register names).  It fills in
3383440a403fSchristos    the expression with the identified register.  It returns TRUE if
3384440a403fSchristos    it is a register and FALSE otherwise.  */
3385440a403fSchristos 
3386440a403fSchristos bfd_boolean
arc_parse_name(const char * name,struct expressionS * e)3387440a403fSchristos arc_parse_name (const char *name,
3388440a403fSchristos 		struct expressionS *e)
3389440a403fSchristos {
3390440a403fSchristos   struct symbol *sym;
3391440a403fSchristos 
3392440a403fSchristos   if (!assembling_insn)
3393440a403fSchristos     return FALSE;
3394440a403fSchristos 
3395*b88e3e88Schristos   if (e->X_op == O_symbol
3396*b88e3e88Schristos       && e->X_md == O_absent)
3397440a403fSchristos     return FALSE;
3398440a403fSchristos 
3399440a403fSchristos   sym = hash_find (arc_reg_hash, name);
3400440a403fSchristos   if (sym)
3401440a403fSchristos     {
3402440a403fSchristos       e->X_op = O_register;
3403440a403fSchristos       e->X_add_number = S_GET_VALUE (sym);
3404440a403fSchristos       return TRUE;
3405440a403fSchristos     }
340606324dcfSchristos 
340706324dcfSchristos   sym = hash_find (arc_addrtype_hash, name);
340806324dcfSchristos   if (sym)
340906324dcfSchristos     {
341006324dcfSchristos       e->X_op = O_addrtype;
341106324dcfSchristos       e->X_add_number = S_GET_VALUE (sym);
341206324dcfSchristos       return TRUE;
341306324dcfSchristos     }
341406324dcfSchristos 
3415440a403fSchristos   return FALSE;
3416440a403fSchristos }
3417440a403fSchristos 
3418440a403fSchristos /* md_parse_option
3419440a403fSchristos    Invocation line includes a switch not recognized by the base assembler.
3420440a403fSchristos    See if it's a processor-specific option.
3421440a403fSchristos 
3422440a403fSchristos    New options (supported) are:
3423440a403fSchristos 
3424440a403fSchristos    -mcpu=<cpu name>		 Assemble for selected processor
3425440a403fSchristos    -EB/-mbig-endian		 Big-endian
3426440a403fSchristos    -EL/-mlittle-endian		 Little-endian
3427440a403fSchristos    -mrelax                       Enable relaxation
3428440a403fSchristos 
3429440a403fSchristos    The following CPU names are recognized:
3430440a403fSchristos    arc600, arc700, arcem, archs, nps400.  */
3431440a403fSchristos 
3432440a403fSchristos int
md_parse_option(int c,const char * arg ATTRIBUTE_UNUSED)3433440a403fSchristos md_parse_option (int c, const char *arg ATTRIBUTE_UNUSED)
3434440a403fSchristos {
3435440a403fSchristos   switch (c)
3436440a403fSchristos     {
3437440a403fSchristos     case OPTION_ARC600:
3438440a403fSchristos     case OPTION_ARC601:
3439440a403fSchristos       return md_parse_option (OPTION_MCPU, "arc600");
3440440a403fSchristos 
3441440a403fSchristos     case OPTION_ARC700:
3442440a403fSchristos       return md_parse_option (OPTION_MCPU, "arc700");
3443440a403fSchristos 
3444440a403fSchristos     case OPTION_ARCEM:
3445440a403fSchristos       return md_parse_option (OPTION_MCPU, "arcem");
3446440a403fSchristos 
3447440a403fSchristos     case OPTION_ARCHS:
3448440a403fSchristos       return md_parse_option (OPTION_MCPU, "archs");
3449440a403fSchristos 
3450440a403fSchristos     case OPTION_MCPU:
3451440a403fSchristos       {
345206324dcfSchristos         arc_select_cpu (arg, MACH_SELECTION_FROM_COMMAND_LINE);
3453440a403fSchristos 	break;
3454440a403fSchristos       }
3455440a403fSchristos 
3456440a403fSchristos     case OPTION_EB:
3457440a403fSchristos       arc_target_format = "elf32-bigarc";
3458440a403fSchristos       byte_order = BIG_ENDIAN;
3459440a403fSchristos       break;
3460440a403fSchristos 
3461440a403fSchristos     case OPTION_EL:
3462440a403fSchristos       arc_target_format = "elf32-littlearc";
3463440a403fSchristos       byte_order = LITTLE_ENDIAN;
3464440a403fSchristos       break;
3465440a403fSchristos 
3466440a403fSchristos     case OPTION_CD:
346706324dcfSchristos       selected_cpu.features |= CD;
346806324dcfSchristos       cl_features |= CD;
346906324dcfSchristos       arc_check_feature ();
3470440a403fSchristos       break;
3471440a403fSchristos 
3472440a403fSchristos     case OPTION_RELAX:
3473440a403fSchristos       relaxation_state = 1;
3474440a403fSchristos       break;
3475440a403fSchristos 
3476440a403fSchristos     case OPTION_NPS400:
347706324dcfSchristos       selected_cpu.features |= NPS400;
347806324dcfSchristos       cl_features |= NPS400;
347906324dcfSchristos       arc_check_feature ();
3480440a403fSchristos       break;
3481440a403fSchristos 
3482440a403fSchristos     case OPTION_SPFP:
348306324dcfSchristos       selected_cpu.features |= SPX;
348406324dcfSchristos       cl_features |= SPX;
348506324dcfSchristos       arc_check_feature ();
3486440a403fSchristos       break;
3487440a403fSchristos 
3488440a403fSchristos     case OPTION_DPFP:
348906324dcfSchristos       selected_cpu.features |= DPX;
349006324dcfSchristos       cl_features |= DPX;
349106324dcfSchristos       arc_check_feature ();
3492440a403fSchristos       break;
3493440a403fSchristos 
3494440a403fSchristos     case OPTION_FPUDA:
349506324dcfSchristos       selected_cpu.features |= DPA;
349606324dcfSchristos       cl_features |= DPA;
349706324dcfSchristos       arc_check_feature ();
3498440a403fSchristos       break;
3499440a403fSchristos 
3500440a403fSchristos     /* Dummy options are accepted but have no effect.  */
3501440a403fSchristos     case OPTION_USER_MODE:
3502440a403fSchristos     case OPTION_LD_EXT_MASK:
3503440a403fSchristos     case OPTION_SWAP:
3504440a403fSchristos     case OPTION_NORM:
3505440a403fSchristos     case OPTION_BARREL_SHIFT:
3506440a403fSchristos     case OPTION_MIN_MAX:
3507440a403fSchristos     case OPTION_NO_MPY:
3508440a403fSchristos     case OPTION_EA:
3509440a403fSchristos     case OPTION_MUL64:
3510440a403fSchristos     case OPTION_SIMD:
3511440a403fSchristos     case OPTION_XMAC_D16:
3512440a403fSchristos     case OPTION_XMAC_24:
3513440a403fSchristos     case OPTION_DSP_PACKA:
3514440a403fSchristos     case OPTION_CRC:
3515440a403fSchristos     case OPTION_DVBF:
3516440a403fSchristos     case OPTION_TELEPHONY:
3517440a403fSchristos     case OPTION_XYMEMORY:
3518440a403fSchristos     case OPTION_LOCK:
3519440a403fSchristos     case OPTION_SWAPE:
3520440a403fSchristos     case OPTION_RTSC:
3521440a403fSchristos       break;
3522440a403fSchristos 
3523440a403fSchristos     default:
3524440a403fSchristos       return 0;
3525440a403fSchristos     }
3526440a403fSchristos 
3527440a403fSchristos   return 1;
3528440a403fSchristos }
3529440a403fSchristos 
353006324dcfSchristos /* Display the list of cpu names for use in the help text.  */
353106324dcfSchristos 
353206324dcfSchristos static void
arc_show_cpu_list(FILE * stream)353306324dcfSchristos arc_show_cpu_list (FILE *stream)
353406324dcfSchristos {
353506324dcfSchristos   int i, offset;
353606324dcfSchristos   static const char *space_buf = "                          ";
353706324dcfSchristos 
353806324dcfSchristos   fprintf (stream, "%s", space_buf);
353906324dcfSchristos   offset = strlen (space_buf);
354006324dcfSchristos   for (i = 0; cpu_types[i].name != NULL; ++i)
354106324dcfSchristos     {
354206324dcfSchristos       bfd_boolean last = (cpu_types[i + 1].name == NULL);
354306324dcfSchristos 
354406324dcfSchristos       /* If displaying the new cpu name string, and the ', ' (for all
354506324dcfSchristos          but the last one) will take us past a target width of 80
354606324dcfSchristos          characters, then it's time for a new line.  */
354706324dcfSchristos       if (offset + strlen (cpu_types[i].name) + (last ? 0 : 2) > 80)
354806324dcfSchristos         {
354906324dcfSchristos           fprintf (stream, "\n%s", space_buf);
355006324dcfSchristos           offset = strlen (space_buf);
355106324dcfSchristos         }
355206324dcfSchristos 
355306324dcfSchristos       fprintf (stream, "%s%s", cpu_types[i].name, (last ? "\n" : ", "));
355406324dcfSchristos       offset += strlen (cpu_types [i].name) + (last ? 0 : 2);
355506324dcfSchristos     }
355606324dcfSchristos }
355706324dcfSchristos 
3558440a403fSchristos void
md_show_usage(FILE * stream)3559440a403fSchristos md_show_usage (FILE *stream)
3560440a403fSchristos {
3561440a403fSchristos   fprintf (stream, _("ARC-specific assembler options:\n"));
3562440a403fSchristos 
356306324dcfSchristos   fprintf (stream, "  -mcpu=<cpu name>\t  (default: %s), assemble for"
356406324dcfSchristos            " CPU <cpu name>, one of:\n", TARGET_WITH_CPU);
356506324dcfSchristos   arc_show_cpu_list (stream);
356606324dcfSchristos   fprintf (stream, "\n");
3567440a403fSchristos   fprintf (stream, "  -mA6/-mARC600/-mARC601  same as -mcpu=arc600\n");
3568440a403fSchristos   fprintf (stream, "  -mA7/-mARC700\t\t  same as -mcpu=arc700\n");
3569440a403fSchristos   fprintf (stream, "  -mEM\t\t\t  same as -mcpu=arcem\n");
3570440a403fSchristos   fprintf (stream, "  -mHS\t\t\t  same as -mcpu=archs\n");
3571440a403fSchristos 
3572440a403fSchristos   fprintf (stream, "  -mnps400\t\t  enable NPS-400 extended instructions\n");
357306324dcfSchristos   fprintf (stream, "  -mspfp\t\t  enable single-precision floating point"
357406324dcfSchristos 	   " instructions\n");
357506324dcfSchristos   fprintf (stream, "  -mdpfp\t\t  enable double-precision floating point"
357606324dcfSchristos 	   " instructions\n");
3577440a403fSchristos   fprintf (stream, "  -mfpuda\t\t  enable double-precision assist floating "
3578440a403fSchristos                    "point\n\t\t\t  instructions for ARC EM\n");
3579440a403fSchristos 
3580440a403fSchristos   fprintf (stream,
3581440a403fSchristos 	   "  -mcode-density\t  enable code density option for ARC EM\n");
3582440a403fSchristos 
3583440a403fSchristos   fprintf (stream, _("\
3584440a403fSchristos   -EB                     assemble code for a big-endian cpu\n"));
3585440a403fSchristos   fprintf (stream, _("\
3586440a403fSchristos   -EL                     assemble code for a little-endian cpu\n"));
3587440a403fSchristos   fprintf (stream, _("\
3588440a403fSchristos   -mrelax                 enable relaxation\n"));
3589440a403fSchristos 
3590440a403fSchristos   fprintf (stream, _("The following ARC-specific assembler options are "
3591440a403fSchristos                      "deprecated and are accepted\nfor compatibility only:\n"));
3592440a403fSchristos 
3593440a403fSchristos   fprintf (stream, _("  -mEA\n"
3594440a403fSchristos                      "  -mbarrel-shifter\n"
3595440a403fSchristos                      "  -mbarrel_shifter\n"
3596440a403fSchristos                      "  -mcrc\n"
3597440a403fSchristos                      "  -mdsp-packa\n"
3598440a403fSchristos                      "  -mdsp_packa\n"
3599440a403fSchristos                      "  -mdvbf\n"
3600440a403fSchristos                      "  -mld-extension-reg-mask\n"
3601440a403fSchristos                      "  -mlock\n"
3602440a403fSchristos                      "  -mmac-24\n"
3603440a403fSchristos                      "  -mmac-d16\n"
3604440a403fSchristos                      "  -mmac_24\n"
3605440a403fSchristos                      "  -mmac_d16\n"
3606440a403fSchristos                      "  -mmin-max\n"
3607440a403fSchristos                      "  -mmin_max\n"
3608440a403fSchristos                      "  -mmul64\n"
3609440a403fSchristos                      "  -mno-mpy\n"
3610440a403fSchristos                      "  -mnorm\n"
3611440a403fSchristos                      "  -mrtsc\n"
3612440a403fSchristos                      "  -msimd\n"
3613440a403fSchristos                      "  -mswap\n"
3614440a403fSchristos                      "  -mswape\n"
3615440a403fSchristos                      "  -mtelephony\n"
3616440a403fSchristos 		     "  -muser-mode-only\n"
3617440a403fSchristos                      "  -mxy\n"));
3618440a403fSchristos }
3619440a403fSchristos 
3620440a403fSchristos /* Find the proper relocation for the given opcode.  */
3621440a403fSchristos 
3622440a403fSchristos static extended_bfd_reloc_code_real_type
find_reloc(const char * name,const char * opcodename,const struct arc_flags * pflags,int nflg,extended_bfd_reloc_code_real_type reloc)3623440a403fSchristos find_reloc (const char *name,
3624440a403fSchristos 	    const char *opcodename,
3625440a403fSchristos 	    const struct arc_flags *pflags,
3626440a403fSchristos 	    int nflg,
3627440a403fSchristos 	    extended_bfd_reloc_code_real_type reloc)
3628440a403fSchristos {
3629440a403fSchristos   unsigned int i;
3630440a403fSchristos   int j;
3631440a403fSchristos   bfd_boolean found_flag, tmp;
3632440a403fSchristos   extended_bfd_reloc_code_real_type ret = BFD_RELOC_UNUSED;
3633440a403fSchristos 
3634440a403fSchristos   for (i = 0; i < arc_num_equiv_tab; i++)
3635440a403fSchristos     {
3636440a403fSchristos       const struct arc_reloc_equiv_tab *r = &arc_reloc_equiv[i];
3637440a403fSchristos 
3638440a403fSchristos       /* Find the entry.  */
3639440a403fSchristos       if (strcmp (name, r->name))
3640440a403fSchristos 	continue;
3641440a403fSchristos       if (r->mnemonic && (strcmp (r->mnemonic, opcodename)))
3642440a403fSchristos 	continue;
3643440a403fSchristos       if (r->flags[0])
3644440a403fSchristos 	{
3645440a403fSchristos 	  if (!nflg)
3646440a403fSchristos 	    continue;
3647440a403fSchristos 	  found_flag = FALSE;
3648440a403fSchristos 	  unsigned * psflg = (unsigned *)r->flags;
3649440a403fSchristos 	  do
3650440a403fSchristos 	    {
3651440a403fSchristos 	      tmp = FALSE;
3652440a403fSchristos 	      for (j = 0; j < nflg; j++)
3653440a403fSchristos 		if (!strcmp (pflags[j].name,
3654440a403fSchristos 			     arc_flag_operands[*psflg].name))
3655440a403fSchristos 		  {
3656440a403fSchristos 		    tmp = TRUE;
3657440a403fSchristos 		    break;
3658440a403fSchristos 		  }
3659440a403fSchristos 	      if (!tmp)
3660440a403fSchristos 		{
3661440a403fSchristos 		  found_flag = FALSE;
3662440a403fSchristos 		  break;
3663440a403fSchristos 		}
3664440a403fSchristos 	      else
3665440a403fSchristos 		{
3666440a403fSchristos 		  found_flag = TRUE;
3667440a403fSchristos 		}
3668440a403fSchristos 	      ++ psflg;
3669440a403fSchristos 	    } while (*psflg);
3670440a403fSchristos 
3671440a403fSchristos 	  if (!found_flag)
3672440a403fSchristos 	    continue;
3673440a403fSchristos 	}
3674440a403fSchristos 
3675440a403fSchristos       if (reloc != r->oldreloc)
3676440a403fSchristos 	continue;
3677440a403fSchristos       /* Found it.  */
3678440a403fSchristos       ret = r->newreloc;
3679440a403fSchristos       break;
3680440a403fSchristos     }
3681440a403fSchristos 
3682440a403fSchristos   if (ret == BFD_RELOC_UNUSED)
3683440a403fSchristos     as_bad (_("Unable to find %s relocation for instruction %s"),
3684440a403fSchristos 	    name, opcodename);
3685440a403fSchristos   return ret;
3686440a403fSchristos }
3687440a403fSchristos 
3688440a403fSchristos /* All the symbol types that are allowed to be used for
3689440a403fSchristos    relaxation.  */
3690440a403fSchristos 
3691440a403fSchristos static bfd_boolean
may_relax_expr(expressionS tok)3692440a403fSchristos may_relax_expr (expressionS tok)
3693440a403fSchristos {
3694440a403fSchristos   /* Check if we have unrelaxable relocs.  */
3695440a403fSchristos   switch (tok.X_md)
3696440a403fSchristos     {
3697440a403fSchristos     default:
3698440a403fSchristos       break;
3699440a403fSchristos     case O_plt:
3700440a403fSchristos       return FALSE;
3701440a403fSchristos     }
3702440a403fSchristos 
3703440a403fSchristos   switch (tok.X_op)
3704440a403fSchristos     {
3705440a403fSchristos     case O_symbol:
3706440a403fSchristos     case O_multiply:
3707440a403fSchristos     case O_divide:
3708440a403fSchristos     case O_modulus:
3709440a403fSchristos     case O_add:
3710440a403fSchristos     case O_subtract:
3711440a403fSchristos       break;
3712440a403fSchristos 
3713440a403fSchristos     default:
3714440a403fSchristos       return FALSE;
3715440a403fSchristos     }
3716440a403fSchristos   return TRUE;
3717440a403fSchristos }
3718440a403fSchristos 
3719440a403fSchristos /* Checks if flags are in line with relaxable insn.  */
3720440a403fSchristos 
3721440a403fSchristos static bfd_boolean
relaxable_flag(const struct arc_relaxable_ins * ins,const struct arc_flags * pflags,int nflgs)3722440a403fSchristos relaxable_flag (const struct arc_relaxable_ins *ins,
3723440a403fSchristos 		const struct arc_flags *pflags,
3724440a403fSchristos 		int nflgs)
3725440a403fSchristos {
3726440a403fSchristos   unsigned flag_class,
3727440a403fSchristos     flag,
3728440a403fSchristos     flag_class_idx = 0,
3729440a403fSchristos     flag_idx = 0;
3730440a403fSchristos 
3731440a403fSchristos   const struct arc_flag_operand *flag_opand;
3732440a403fSchristos   int i, counttrue = 0;
3733440a403fSchristos 
3734440a403fSchristos   /* Iterate through flags classes.  */
3735440a403fSchristos   while ((flag_class = ins->flag_classes[flag_class_idx]) != 0)
3736440a403fSchristos     {
3737440a403fSchristos       /* Iterate through flags in flag class.  */
3738440a403fSchristos       while ((flag = arc_flag_classes[flag_class].flags[flag_idx])
3739440a403fSchristos 	     != 0)
3740440a403fSchristos 	{
3741440a403fSchristos 	  flag_opand = &arc_flag_operands[flag];
3742440a403fSchristos 	  /* Iterate through flags in ins to compare.  */
3743440a403fSchristos 	  for (i = 0; i < nflgs; ++i)
3744440a403fSchristos 	    {
3745440a403fSchristos 	      if (strcmp (flag_opand->name, pflags[i].name) == 0)
3746440a403fSchristos 		++counttrue;
3747440a403fSchristos 	    }
3748440a403fSchristos 
3749440a403fSchristos 	  ++flag_idx;
3750440a403fSchristos 	}
3751440a403fSchristos 
3752440a403fSchristos       ++flag_class_idx;
3753440a403fSchristos       flag_idx = 0;
3754440a403fSchristos     }
3755440a403fSchristos 
3756440a403fSchristos   /* If counttrue == nflgs, then all flags have been found.  */
3757440a403fSchristos   return (counttrue == nflgs ? TRUE : FALSE);
3758440a403fSchristos }
3759440a403fSchristos 
3760440a403fSchristos /* Checks if operands are in line with relaxable insn.  */
3761440a403fSchristos 
3762440a403fSchristos static bfd_boolean
relaxable_operand(const struct arc_relaxable_ins * ins,const expressionS * tok,int ntok)3763440a403fSchristos relaxable_operand (const struct arc_relaxable_ins *ins,
3764440a403fSchristos 		   const expressionS *tok,
3765440a403fSchristos 		   int ntok)
3766440a403fSchristos {
3767440a403fSchristos   const enum rlx_operand_type *operand = &ins->operands[0];
3768440a403fSchristos   int i = 0;
3769440a403fSchristos 
3770440a403fSchristos   while (*operand != EMPTY)
3771440a403fSchristos     {
3772440a403fSchristos       const expressionS *epr = &tok[i];
3773440a403fSchristos 
3774440a403fSchristos       if (i != 0 && i >= ntok)
3775440a403fSchristos 	return FALSE;
3776440a403fSchristos 
3777440a403fSchristos       switch (*operand)
3778440a403fSchristos 	{
3779440a403fSchristos 	case IMMEDIATE:
3780440a403fSchristos 	  if (!(epr->X_op == O_multiply
3781440a403fSchristos 		|| epr->X_op == O_divide
3782440a403fSchristos 		|| epr->X_op == O_modulus
3783440a403fSchristos 		|| epr->X_op == O_add
3784440a403fSchristos 		|| epr->X_op == O_subtract
3785440a403fSchristos 		|| epr->X_op == O_symbol))
3786440a403fSchristos 	    return FALSE;
3787440a403fSchristos 	  break;
3788440a403fSchristos 
3789440a403fSchristos 	case REGISTER_DUP:
3790440a403fSchristos 	  if ((i <= 0)
3791440a403fSchristos 	      || (epr->X_add_number != tok[i - 1].X_add_number))
3792440a403fSchristos 	    return FALSE;
3793440a403fSchristos 	  /* Fall through.  */
3794440a403fSchristos 	case REGISTER:
3795440a403fSchristos 	  if (epr->X_op != O_register)
3796440a403fSchristos 	    return FALSE;
3797440a403fSchristos 	  break;
3798440a403fSchristos 
3799440a403fSchristos 	case REGISTER_S:
3800440a403fSchristos 	  if (epr->X_op != O_register)
3801440a403fSchristos 	    return FALSE;
3802440a403fSchristos 
3803440a403fSchristos 	  switch (epr->X_add_number)
3804440a403fSchristos 	    {
3805440a403fSchristos 	    case 0: case 1: case 2: case 3:
3806440a403fSchristos 	    case 12: case 13: case 14: case 15:
3807440a403fSchristos 	      break;
3808440a403fSchristos 	    default:
3809440a403fSchristos 	      return FALSE;
3810440a403fSchristos 	    }
3811440a403fSchristos 	  break;
3812440a403fSchristos 
3813440a403fSchristos 	case REGISTER_NO_GP:
3814440a403fSchristos 	  if ((epr->X_op != O_register)
3815440a403fSchristos 	      || (epr->X_add_number == 26)) /* 26 is the gp register.  */
3816440a403fSchristos 	    return FALSE;
3817440a403fSchristos 	  break;
3818440a403fSchristos 
3819440a403fSchristos 	case BRACKET:
3820440a403fSchristos 	  if (epr->X_op != O_bracket)
3821440a403fSchristos 	    return FALSE;
3822440a403fSchristos 	  break;
3823440a403fSchristos 
3824440a403fSchristos 	default:
3825440a403fSchristos 	  /* Don't understand, bail out.  */
3826440a403fSchristos 	  return FALSE;
3827440a403fSchristos 	  break;
3828440a403fSchristos 	}
3829440a403fSchristos 
3830440a403fSchristos       ++i;
3831440a403fSchristos       operand = &ins->operands[i];
3832440a403fSchristos     }
3833440a403fSchristos 
3834440a403fSchristos   return (i == ntok ? TRUE : FALSE);
3835440a403fSchristos }
3836440a403fSchristos 
3837440a403fSchristos /* Return TRUE if this OPDCODE is a candidate for relaxation.  */
3838440a403fSchristos 
3839440a403fSchristos static bfd_boolean
relax_insn_p(const struct arc_opcode * opcode,const expressionS * tok,int ntok,const struct arc_flags * pflags,int nflg)3840440a403fSchristos relax_insn_p (const struct arc_opcode *opcode,
3841440a403fSchristos 	      const expressionS *tok,
3842440a403fSchristos 	      int ntok,
3843440a403fSchristos 	      const struct arc_flags *pflags,
3844440a403fSchristos 	      int nflg)
3845440a403fSchristos {
3846440a403fSchristos   unsigned i;
3847440a403fSchristos   bfd_boolean rv = FALSE;
3848440a403fSchristos 
3849440a403fSchristos   /* Check the relaxation table.  */
3850440a403fSchristos   for (i = 0; i < arc_num_relaxable_ins && relaxation_state; ++i)
3851440a403fSchristos     {
3852440a403fSchristos       const struct arc_relaxable_ins *arc_rlx_ins = &arc_relaxable_insns[i];
3853440a403fSchristos 
3854440a403fSchristos       if ((strcmp (opcode->name, arc_rlx_ins->mnemonic_r) == 0)
3855440a403fSchristos 	  && may_relax_expr (tok[arc_rlx_ins->opcheckidx])
3856440a403fSchristos 	  && relaxable_operand (arc_rlx_ins, tok, ntok)
3857440a403fSchristos 	  && relaxable_flag (arc_rlx_ins, pflags, nflg))
3858440a403fSchristos 	{
3859440a403fSchristos 	  rv = TRUE;
3860440a403fSchristos 	  frag_now->fr_subtype = arc_relaxable_insns[i].subtype;
3861440a403fSchristos 	  memcpy (&frag_now->tc_frag_data.tok, tok,
3862440a403fSchristos 		sizeof (expressionS) * ntok);
3863440a403fSchristos 	  memcpy (&frag_now->tc_frag_data.pflags, pflags,
3864440a403fSchristos 		sizeof (struct arc_flags) * nflg);
3865440a403fSchristos 	  frag_now->tc_frag_data.nflg = nflg;
3866440a403fSchristos 	  frag_now->tc_frag_data.ntok = ntok;
3867440a403fSchristos 	  break;
3868440a403fSchristos 	}
3869440a403fSchristos     }
3870440a403fSchristos 
3871440a403fSchristos   return rv;
3872440a403fSchristos }
3873440a403fSchristos 
3874440a403fSchristos /* Turn an opcode description and a set of arguments into
3875440a403fSchristos    an instruction and a fixup.  */
3876440a403fSchristos 
3877440a403fSchristos static void
assemble_insn(const struct arc_opcode * opcode,const expressionS * tok,int ntok,const struct arc_flags * pflags,int nflg,struct arc_insn * insn)3878440a403fSchristos assemble_insn (const struct arc_opcode *opcode,
3879440a403fSchristos 	       const expressionS *tok,
3880440a403fSchristos 	       int ntok,
3881440a403fSchristos 	       const struct arc_flags *pflags,
3882440a403fSchristos 	       int nflg,
3883440a403fSchristos 	       struct arc_insn *insn)
3884440a403fSchristos {
3885440a403fSchristos   const expressionS *reloc_exp = NULL;
388606324dcfSchristos   unsigned long long image;
3887440a403fSchristos   const unsigned char *argidx;
3888440a403fSchristos   int i;
3889440a403fSchristos   int tokidx = 0;
3890440a403fSchristos   unsigned char pcrel = 0;
3891440a403fSchristos   bfd_boolean needGOTSymbol;
3892440a403fSchristos   bfd_boolean has_delay_slot = FALSE;
3893440a403fSchristos   extended_bfd_reloc_code_real_type reloc = BFD_RELOC_UNUSED;
3894440a403fSchristos 
3895440a403fSchristos   memset (insn, 0, sizeof (*insn));
3896440a403fSchristos   image = opcode->opcode;
3897440a403fSchristos 
389806324dcfSchristos   pr_debug ("%s:%d: assemble_insn: %s using opcode %llx\n",
3899440a403fSchristos 	    frag_now->fr_file, frag_now->fr_line, opcode->name,
3900440a403fSchristos 	    opcode->opcode);
3901440a403fSchristos 
3902440a403fSchristos   /* Handle operands.  */
3903440a403fSchristos   for (argidx = opcode->operands; *argidx; ++argidx)
3904440a403fSchristos     {
3905440a403fSchristos       const struct arc_operand *operand = &arc_operands[*argidx];
3906440a403fSchristos       const expressionS *t = (const expressionS *) 0;
3907440a403fSchristos 
390806324dcfSchristos       if (ARC_OPERAND_IS_FAKE (operand))
3909440a403fSchristos 	continue;
3910440a403fSchristos 
3911440a403fSchristos       if (operand->flags & ARC_OPERAND_DUPLICATE)
3912440a403fSchristos 	{
3913440a403fSchristos 	  /* Duplicate operand, already inserted.  */
3914440a403fSchristos 	  tokidx ++;
3915440a403fSchristos 	  continue;
3916440a403fSchristos 	}
3917440a403fSchristos 
3918440a403fSchristos       if (tokidx >= ntok)
3919440a403fSchristos 	{
3920440a403fSchristos 	  abort ();
3921440a403fSchristos 	}
3922440a403fSchristos       else
3923440a403fSchristos 	t = &tok[tokidx++];
3924440a403fSchristos 
3925440a403fSchristos       /* Regardless if we have a reloc or not mark the instruction
3926440a403fSchristos 	 limm if it is the case.  */
3927440a403fSchristos       if (operand->flags & ARC_OPERAND_LIMM)
3928440a403fSchristos 	insn->has_limm = TRUE;
3929440a403fSchristos 
3930440a403fSchristos       switch (t->X_op)
3931440a403fSchristos 	{
3932440a403fSchristos 	case O_register:
3933440a403fSchristos 	  image = insert_operand (image, operand, regno (t->X_add_number),
3934440a403fSchristos 				  NULL, 0);
3935440a403fSchristos 	  break;
3936440a403fSchristos 
3937440a403fSchristos 	case O_constant:
3938440a403fSchristos 	  image = insert_operand (image, operand, t->X_add_number, NULL, 0);
3939440a403fSchristos 	  reloc_exp = t;
3940440a403fSchristos 	  if (operand->flags & ARC_OPERAND_LIMM)
3941440a403fSchristos 	    insn->limm = t->X_add_number;
3942440a403fSchristos 	  break;
3943440a403fSchristos 
3944440a403fSchristos 	case O_bracket:
394506324dcfSchristos         case O_colon:
394606324dcfSchristos         case O_addrtype:
394706324dcfSchristos 	  /* Ignore brackets, colons, and address types.  */
3948440a403fSchristos 	  break;
3949440a403fSchristos 
3950440a403fSchristos 	case O_absent:
3951440a403fSchristos 	  gas_assert (operand->flags & ARC_OPERAND_IGNORE);
3952440a403fSchristos 	  break;
3953440a403fSchristos 
3954440a403fSchristos 	case O_subtract:
3955440a403fSchristos 	  /* Maybe register range.  */
3956440a403fSchristos 	  if ((t->X_add_number == 0)
3957440a403fSchristos 	      && contains_register (t->X_add_symbol)
3958440a403fSchristos 	      && contains_register (t->X_op_symbol))
3959440a403fSchristos 	    {
3960440a403fSchristos 	      int regs;
3961440a403fSchristos 
3962440a403fSchristos 	      regs = get_register (t->X_add_symbol);
3963440a403fSchristos 	      regs <<= 16;
3964440a403fSchristos 	      regs |= get_register (t->X_op_symbol);
3965440a403fSchristos 	      image = insert_operand (image, operand, regs, NULL, 0);
3966440a403fSchristos 	      break;
3967440a403fSchristos 	    }
396806324dcfSchristos 	  /* Fall through.  */
3969440a403fSchristos 
3970440a403fSchristos 	default:
3971440a403fSchristos 	  /* This operand needs a relocation.  */
3972440a403fSchristos 	  needGOTSymbol = FALSE;
3973440a403fSchristos 
3974440a403fSchristos 	  switch (t->X_md)
3975440a403fSchristos 	    {
3976440a403fSchristos 	    case O_plt:
3977440a403fSchristos 	      if (opcode->insn_class == JUMP)
397806324dcfSchristos 		as_bad (_("Unable to use @plt relocation for insn %s"),
3979440a403fSchristos 			opcode->name);
3980440a403fSchristos 	      needGOTSymbol = TRUE;
3981440a403fSchristos 	      reloc = find_reloc ("plt", opcode->name,
3982440a403fSchristos 				  pflags, nflg,
3983440a403fSchristos 				  operand->default_reloc);
3984440a403fSchristos 	      break;
3985440a403fSchristos 
3986440a403fSchristos 	    case O_gotoff:
3987440a403fSchristos 	    case O_gotpc:
3988440a403fSchristos 	      needGOTSymbol = TRUE;
3989440a403fSchristos 	      reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
3990440a403fSchristos 	      break;
3991440a403fSchristos 	    case O_pcl:
399206324dcfSchristos 	      if (operand->flags & ARC_OPERAND_LIMM)
399306324dcfSchristos 		{
3994440a403fSchristos 		  reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
399506324dcfSchristos 		  if (arc_opcode_len (opcode) == 2
399606324dcfSchristos 		      || opcode->insn_class == JUMP)
399706324dcfSchristos 		    as_bad (_("Unable to use @pcl relocation for insn %s"),
3998440a403fSchristos 			    opcode->name);
399906324dcfSchristos 		}
400006324dcfSchristos 	      else
400106324dcfSchristos 		{
400206324dcfSchristos 		  /* This is a relaxed operand which initially was
400306324dcfSchristos 		     limm, choose whatever we have defined in the
400406324dcfSchristos 		     opcode as reloc.  */
400506324dcfSchristos 		  reloc = operand->default_reloc;
400606324dcfSchristos 		}
4007440a403fSchristos 	      break;
4008440a403fSchristos 	    case O_sda:
4009440a403fSchristos 	      reloc = find_reloc ("sda", opcode->name,
4010440a403fSchristos 				  pflags, nflg,
4011440a403fSchristos 				  operand->default_reloc);
4012440a403fSchristos 	      break;
4013440a403fSchristos 	    case O_tlsgd:
4014440a403fSchristos 	    case O_tlsie:
4015440a403fSchristos 	      needGOTSymbol = TRUE;
4016440a403fSchristos 	      /* Fall-through.  */
4017440a403fSchristos 
4018440a403fSchristos 	    case O_tpoff:
4019440a403fSchristos 	    case O_dtpoff:
4020440a403fSchristos 	      reloc = ARC_RELOC_TABLE (t->X_md)->reloc;
4021440a403fSchristos 	      break;
4022440a403fSchristos 
4023440a403fSchristos 	    case O_tpoff9: /*FIXME! Check for the conditionality of
4024440a403fSchristos 			     the insn.  */
4025440a403fSchristos 	    case O_dtpoff9: /*FIXME! Check for the conditionality of
4026440a403fSchristos 			      the insn.  */
4027440a403fSchristos 	      as_bad (_("TLS_*_S9 relocs are not supported yet"));
4028440a403fSchristos 	      break;
4029440a403fSchristos 
4030440a403fSchristos 	    default:
4031440a403fSchristos 	      /* Just consider the default relocation.  */
4032440a403fSchristos 	      reloc = operand->default_reloc;
4033440a403fSchristos 	      break;
4034440a403fSchristos 	    }
4035440a403fSchristos 
4036440a403fSchristos 	  if (needGOTSymbol && (GOT_symbol == NULL))
4037440a403fSchristos 	    GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
4038440a403fSchristos 
4039440a403fSchristos 	  reloc_exp = t;
4040440a403fSchristos 
4041440a403fSchristos #if 0
4042440a403fSchristos 	  if (reloc > 0)
4043440a403fSchristos 	    {
4044440a403fSchristos 	      /* sanity checks.  */
4045440a403fSchristos 	      reloc_howto_type *reloc_howto
4046440a403fSchristos 		= bfd_reloc_type_lookup (stdoutput,
4047440a403fSchristos 					 (bfd_reloc_code_real_type) reloc);
4048440a403fSchristos 	      unsigned reloc_bitsize = reloc_howto->bitsize;
4049440a403fSchristos 	      if (reloc_howto->rightshift)
4050440a403fSchristos 		reloc_bitsize -= reloc_howto->rightshift;
4051440a403fSchristos 	      if (reloc_bitsize != operand->bits)
4052440a403fSchristos 		{
4053440a403fSchristos 		  as_bad (_("invalid relocation %s for field"),
4054440a403fSchristos 			  bfd_get_reloc_code_name (reloc));
4055440a403fSchristos 		  return;
4056440a403fSchristos 		}
4057440a403fSchristos 	    }
4058440a403fSchristos #endif
4059440a403fSchristos 	  if (insn->nfixups >= MAX_INSN_FIXUPS)
4060440a403fSchristos 	    as_fatal (_("too many fixups"));
4061440a403fSchristos 
4062440a403fSchristos 	  struct arc_fixup *fixup;
4063440a403fSchristos 	  fixup = &insn->fixups[insn->nfixups++];
4064440a403fSchristos 	  fixup->exp = *t;
4065440a403fSchristos 	  fixup->reloc = reloc;
406606324dcfSchristos 	  if ((int) reloc < 0)
4067440a403fSchristos 	    pcrel = (operand->flags & ARC_OPERAND_PCREL) ? 1 : 0;
406806324dcfSchristos 	  else
406906324dcfSchristos 	    {
407006324dcfSchristos 	      reloc_howto_type *reloc_howto =
407106324dcfSchristos 		bfd_reloc_type_lookup (stdoutput,
407206324dcfSchristos 				       (bfd_reloc_code_real_type) fixup->reloc);
407306324dcfSchristos 	      pcrel = reloc_howto->pc_relative;
407406324dcfSchristos 	    }
4075440a403fSchristos 	  fixup->pcrel = pcrel;
4076440a403fSchristos 	  fixup->islong = (operand->flags & ARC_OPERAND_LIMM) ?
4077440a403fSchristos 	    TRUE : FALSE;
4078440a403fSchristos 	  break;
4079440a403fSchristos 	}
4080440a403fSchristos     }
4081440a403fSchristos 
4082440a403fSchristos   /* Handle flags.  */
4083440a403fSchristos   for (i = 0; i < nflg; i++)
4084440a403fSchristos     {
4085440a403fSchristos       const struct arc_flag_operand *flg_operand = pflags[i].flgp;
4086440a403fSchristos 
4087440a403fSchristos       /* Check if the instruction has a delay slot.  */
4088440a403fSchristos       if (!strcmp (flg_operand->name, "d"))
4089440a403fSchristos 	has_delay_slot = TRUE;
4090440a403fSchristos 
409106324dcfSchristos       /* There is an exceptional case when we cannot insert a flag just as
409206324dcfSchristos 	 it is.  On ARCv2 the '.t' and '.nt' flags must be handled in
409306324dcfSchristos 	 relation with the relative address.  Unfortunately, some of the
409406324dcfSchristos 	 ARC700 extensions (NPS400) also have a '.nt' flag that should be
409506324dcfSchristos 	 handled in the normal way.
409606324dcfSchristos 
409706324dcfSchristos 	 Flag operands don't have an architecture field, so we can't
409806324dcfSchristos 	 directly validate that FLAG_OPERAND is valid for the current
409906324dcfSchristos 	 architecture, what we do instead is just validate that we're
410006324dcfSchristos 	 assembling for an ARCv2 architecture.  */
410106324dcfSchristos       if ((selected_cpu.flags & ARC_OPCODE_ARCV2)
410206324dcfSchristos 	  && (!strcmp (flg_operand->name, "t")
410306324dcfSchristos 	      || !strcmp (flg_operand->name, "nt")))
4104440a403fSchristos 	{
4105440a403fSchristos 	  unsigned bitYoperand = 0;
4106440a403fSchristos 	  /* FIXME! move selection bbit/brcc in arc-opc.c.  */
4107440a403fSchristos 	  if (!strcmp (flg_operand->name, "t"))
4108440a403fSchristos 	    if (!strcmp (opcode->name, "bbit0")
4109440a403fSchristos 		|| !strcmp (opcode->name, "bbit1"))
4110440a403fSchristos 	      bitYoperand = arc_NToperand;
4111440a403fSchristos 	    else
4112440a403fSchristos 	      bitYoperand = arc_Toperand;
4113440a403fSchristos 	  else
4114440a403fSchristos 	    if (!strcmp (opcode->name, "bbit0")
4115440a403fSchristos 		|| !strcmp (opcode->name, "bbit1"))
4116440a403fSchristos 	      bitYoperand = arc_Toperand;
4117440a403fSchristos 	    else
4118440a403fSchristos 	      bitYoperand = arc_NToperand;
4119440a403fSchristos 
4120440a403fSchristos 	  gas_assert (reloc_exp != NULL);
4121440a403fSchristos 	  if (reloc_exp->X_op == O_constant)
4122440a403fSchristos 	    {
4123440a403fSchristos 	      /* Check if we have a constant and solved it
4124440a403fSchristos 		 immediately.  */
4125440a403fSchristos 	      offsetT val = reloc_exp->X_add_number;
4126440a403fSchristos 	      image |= insert_operand (image, &arc_operands[bitYoperand],
4127440a403fSchristos 				       val, NULL, 0);
4128440a403fSchristos 	    }
4129440a403fSchristos 	  else
4130440a403fSchristos 	    {
4131440a403fSchristos 	      struct arc_fixup *fixup;
4132440a403fSchristos 
4133440a403fSchristos 	      if (insn->nfixups >= MAX_INSN_FIXUPS)
4134440a403fSchristos 		as_fatal (_("too many fixups"));
4135440a403fSchristos 
4136440a403fSchristos 	      fixup = &insn->fixups[insn->nfixups++];
4137440a403fSchristos 	      fixup->exp = *reloc_exp;
4138440a403fSchristos 	      fixup->reloc = -bitYoperand;
4139440a403fSchristos 	      fixup->pcrel = pcrel;
4140440a403fSchristos 	      fixup->islong = FALSE;
4141440a403fSchristos 	    }
4142440a403fSchristos 	}
4143440a403fSchristos       else
4144440a403fSchristos 	image |= (flg_operand->code & ((1 << flg_operand->bits) - 1))
4145440a403fSchristos 	  << flg_operand->shift;
4146440a403fSchristos     }
4147440a403fSchristos 
4148440a403fSchristos   insn->relax = relax_insn_p (opcode, tok, ntok, pflags, nflg);
4149440a403fSchristos 
415006324dcfSchristos   /* Instruction length.  */
415106324dcfSchristos   insn->len = arc_opcode_len (opcode);
4152440a403fSchristos 
4153440a403fSchristos   insn->insn = image;
4154440a403fSchristos 
4155440a403fSchristos   /* Update last insn status.  */
4156440a403fSchristos   arc_last_insns[1]		   = arc_last_insns[0];
4157440a403fSchristos   arc_last_insns[0].opcode	   = opcode;
4158440a403fSchristos   arc_last_insns[0].has_limm	   = insn->has_limm;
4159440a403fSchristos   arc_last_insns[0].has_delay_slot = has_delay_slot;
4160440a403fSchristos 
4161440a403fSchristos   /* Check if the current instruction is legally used.  */
4162440a403fSchristos   if (arc_last_insns[1].has_delay_slot
4163440a403fSchristos       && is_br_jmp_insn_p (arc_last_insns[0].opcode))
416406324dcfSchristos     as_bad (_("Insn %s has a jump/branch instruction %s in its delay slot."),
416506324dcfSchristos 	    arc_last_insns[1].opcode->name,
416606324dcfSchristos 	    arc_last_insns[0].opcode->name);
416706324dcfSchristos   if (arc_last_insns[1].has_delay_slot
416806324dcfSchristos       && arc_last_insns[0].has_limm)
416906324dcfSchristos     as_bad (_("Insn %s has an instruction %s with limm in its delay slot."),
417006324dcfSchristos 	    arc_last_insns[1].opcode->name,
417106324dcfSchristos 	    arc_last_insns[0].opcode->name);
4172440a403fSchristos }
4173440a403fSchristos 
4174440a403fSchristos void
arc_handle_align(fragS * fragP)4175440a403fSchristos arc_handle_align (fragS* fragP)
4176440a403fSchristos {
4177440a403fSchristos   if ((fragP)->fr_type == rs_align_code)
4178440a403fSchristos     {
4179440a403fSchristos       char *dest = (fragP)->fr_literal + (fragP)->fr_fix;
4180440a403fSchristos       valueT count = ((fragP)->fr_next->fr_address
4181440a403fSchristos 		      - (fragP)->fr_address - (fragP)->fr_fix);
4182440a403fSchristos 
4183440a403fSchristos       (fragP)->fr_var = 2;
4184440a403fSchristos 
4185440a403fSchristos       if (count & 1)/* Padding in the gap till the next 2-byte
4186440a403fSchristos 		       boundary with 0s.  */
4187440a403fSchristos 	{
4188440a403fSchristos 	  (fragP)->fr_fix++;
4189440a403fSchristos 	  *dest++ = 0;
4190440a403fSchristos 	}
4191440a403fSchristos       /* Writing nop_s.  */
4192440a403fSchristos       md_number_to_chars (dest, NOP_OPCODE_S, 2);
4193440a403fSchristos     }
4194440a403fSchristos }
4195440a403fSchristos 
4196440a403fSchristos /* Here we decide which fixups can be adjusted to make them relative
4197440a403fSchristos    to the beginning of the section instead of the symbol.  Basically
4198440a403fSchristos    we need to make sure that the dynamic relocations are done
4199440a403fSchristos    correctly, so in some cases we force the original symbol to be
4200440a403fSchristos    used.  */
4201440a403fSchristos 
4202440a403fSchristos int
tc_arc_fix_adjustable(fixS * fixP)4203440a403fSchristos tc_arc_fix_adjustable (fixS *fixP)
4204440a403fSchristos {
4205440a403fSchristos 
4206440a403fSchristos   /* Prevent all adjustments to global symbols.  */
4207440a403fSchristos   if (S_IS_EXTERNAL (fixP->fx_addsy))
4208440a403fSchristos     return 0;
4209440a403fSchristos   if (S_IS_WEAK (fixP->fx_addsy))
4210440a403fSchristos     return 0;
4211440a403fSchristos 
4212440a403fSchristos   /* Adjust_reloc_syms doesn't know about the GOT.  */
4213440a403fSchristos   switch (fixP->fx_r_type)
4214440a403fSchristos     {
4215440a403fSchristos     case BFD_RELOC_ARC_GOTPC32:
4216440a403fSchristos     case BFD_RELOC_ARC_PLT32:
4217440a403fSchristos     case BFD_RELOC_ARC_S25H_PCREL_PLT:
4218440a403fSchristos     case BFD_RELOC_ARC_S21H_PCREL_PLT:
4219440a403fSchristos     case BFD_RELOC_ARC_S25W_PCREL_PLT:
4220440a403fSchristos     case BFD_RELOC_ARC_S21W_PCREL_PLT:
4221440a403fSchristos       return 0;
4222440a403fSchristos 
4223440a403fSchristos     default:
4224440a403fSchristos       break;
4225440a403fSchristos     }
4226440a403fSchristos 
4227440a403fSchristos   return 1;
4228440a403fSchristos }
4229440a403fSchristos 
4230440a403fSchristos /* Compute the reloc type of an expression EXP.  */
4231440a403fSchristos 
4232440a403fSchristos static void
arc_check_reloc(expressionS * exp,bfd_reloc_code_real_type * r_type_p)4233440a403fSchristos arc_check_reloc (expressionS *exp,
4234440a403fSchristos 		 bfd_reloc_code_real_type *r_type_p)
4235440a403fSchristos {
4236440a403fSchristos   if (*r_type_p == BFD_RELOC_32
4237440a403fSchristos       && exp->X_op == O_subtract
4238440a403fSchristos       && exp->X_op_symbol != NULL
4239*b88e3e88Schristos       && S_GET_SEGMENT (exp->X_op_symbol) == now_seg)
4240440a403fSchristos     *r_type_p = BFD_RELOC_ARC_32_PCREL;
4241440a403fSchristos }
4242440a403fSchristos 
4243440a403fSchristos 
4244440a403fSchristos /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG.  */
4245440a403fSchristos 
4246440a403fSchristos void
arc_cons_fix_new(fragS * frag,int off,int size,expressionS * exp,bfd_reloc_code_real_type r_type)4247440a403fSchristos arc_cons_fix_new (fragS *frag,
4248440a403fSchristos 		  int off,
4249440a403fSchristos 		  int size,
4250440a403fSchristos 		  expressionS *exp,
4251440a403fSchristos 		  bfd_reloc_code_real_type r_type)
4252440a403fSchristos {
4253440a403fSchristos   r_type = BFD_RELOC_UNUSED;
4254440a403fSchristos 
4255440a403fSchristos   switch (size)
4256440a403fSchristos     {
4257440a403fSchristos     case 1:
4258440a403fSchristos       r_type = BFD_RELOC_8;
4259440a403fSchristos       break;
4260440a403fSchristos 
4261440a403fSchristos     case 2:
4262440a403fSchristos       r_type = BFD_RELOC_16;
4263440a403fSchristos       break;
4264440a403fSchristos 
4265440a403fSchristos     case 3:
4266440a403fSchristos       r_type = BFD_RELOC_24;
4267440a403fSchristos       break;
4268440a403fSchristos 
4269440a403fSchristos     case 4:
4270440a403fSchristos       r_type = BFD_RELOC_32;
4271440a403fSchristos       arc_check_reloc (exp, &r_type);
4272440a403fSchristos       break;
4273440a403fSchristos 
4274440a403fSchristos     case 8:
4275440a403fSchristos       r_type = BFD_RELOC_64;
4276440a403fSchristos       break;
4277440a403fSchristos 
4278440a403fSchristos     default:
4279440a403fSchristos       as_bad (_("unsupported BFD relocation size %u"), size);
4280440a403fSchristos       r_type = BFD_RELOC_UNUSED;
4281440a403fSchristos     }
4282440a403fSchristos 
4283440a403fSchristos   fix_new_exp (frag, off, size, exp, 0, r_type);
4284440a403fSchristos }
4285440a403fSchristos 
4286440a403fSchristos /* The actual routine that checks the ZOL conditions.  */
4287440a403fSchristos 
4288440a403fSchristos static void
check_zol(symbolS * s)4289440a403fSchristos check_zol (symbolS *s)
4290440a403fSchristos {
429106324dcfSchristos   switch (selected_cpu.mach)
4292440a403fSchristos     {
4293440a403fSchristos     case bfd_mach_arc_arcv2:
429406324dcfSchristos       if (selected_cpu.flags & ARC_OPCODE_ARCv2EM)
4295440a403fSchristos 	return;
4296440a403fSchristos 
4297440a403fSchristos       if (is_br_jmp_insn_p (arc_last_insns[0].opcode)
4298440a403fSchristos 	  || arc_last_insns[1].has_delay_slot)
4299440a403fSchristos 	as_bad (_("Jump/Branch instruction detected at the end of the ZOL label @%s"),
4300440a403fSchristos 		S_GET_NAME (s));
4301440a403fSchristos 
4302440a403fSchristos       break;
4303440a403fSchristos     case bfd_mach_arc_arc600:
4304440a403fSchristos 
4305440a403fSchristos       if (is_kernel_insn_p (arc_last_insns[0].opcode))
4306440a403fSchristos 	as_bad (_("Kernel instruction detected at the end of the ZOL label @%s"),
4307440a403fSchristos 		S_GET_NAME (s));
4308440a403fSchristos 
4309440a403fSchristos       if (arc_last_insns[0].has_limm
4310440a403fSchristos 	  && is_br_jmp_insn_p (arc_last_insns[0].opcode))
4311440a403fSchristos 	as_bad (_("A jump instruction with long immediate detected at the \
4312440a403fSchristos end of the ZOL label @%s"), S_GET_NAME (s));
4313440a403fSchristos 
4314440a403fSchristos       /* Fall through.  */
4315440a403fSchristos     case bfd_mach_arc_arc700:
4316440a403fSchristos       if (arc_last_insns[0].has_delay_slot)
4317440a403fSchristos 	as_bad (_("An illegal use of delay slot detected at the end of the ZOL label @%s"),
4318440a403fSchristos 		S_GET_NAME (s));
4319440a403fSchristos 
4320440a403fSchristos       break;
4321440a403fSchristos     default:
4322440a403fSchristos       break;
4323440a403fSchristos     }
4324440a403fSchristos }
4325440a403fSchristos 
4326440a403fSchristos /* If ZOL end check the last two instruction for illegals.  */
4327440a403fSchristos void
arc_frob_label(symbolS * sym)4328440a403fSchristos arc_frob_label (symbolS * sym)
4329440a403fSchristos {
4330440a403fSchristos   if (ARC_GET_FLAG (sym) & ARC_FLAG_ZOL)
4331440a403fSchristos     check_zol (sym);
4332440a403fSchristos 
4333440a403fSchristos   dwarf2_emit_label (sym);
4334440a403fSchristos }
4335440a403fSchristos 
4336440a403fSchristos /* Used because generic relaxation assumes a pc-rel value whilst we
4337440a403fSchristos    also relax instructions that use an absolute value resolved out of
4338440a403fSchristos    relative values (if that makes any sense).  An example: 'add r1,
4339440a403fSchristos    r2, @.L2 - .'  The symbols . and @.L2 are relative to the section
4340440a403fSchristos    but if they're in the same section we can subtract the section
4341440a403fSchristos    offset relocation which ends up in a resolved value.  So if @.L2 is
4342440a403fSchristos    .text + 0x50 and . is .text + 0x10, we can say that .text + 0x50 -
4343440a403fSchristos    .text + 0x40 = 0x10.  */
4344440a403fSchristos int
arc_pcrel_adjust(fragS * fragP)4345440a403fSchristos arc_pcrel_adjust (fragS *fragP)
4346440a403fSchristos {
434706324dcfSchristos   pr_debug ("arc_pcrel_adjust: address=%ld, fix=%ld, PCrel %s\n",
434806324dcfSchristos 	    fragP->fr_address, fragP->fr_fix,
434906324dcfSchristos 	    fragP->tc_frag_data.pcrel ? "Y" : "N");
435006324dcfSchristos 
4351440a403fSchristos   if (!fragP->tc_frag_data.pcrel)
4352440a403fSchristos     return fragP->fr_address + fragP->fr_fix;
4353440a403fSchristos 
435406324dcfSchristos   /* Take into account the PCL rounding.  */
435506324dcfSchristos   return (fragP->fr_address + fragP->fr_fix) & 0x03;
4356440a403fSchristos }
4357440a403fSchristos 
4358440a403fSchristos /* Initialize the DWARF-2 unwind information for this procedure.  */
4359440a403fSchristos 
4360440a403fSchristos void
tc_arc_frame_initial_instructions(void)4361440a403fSchristos tc_arc_frame_initial_instructions (void)
4362440a403fSchristos {
4363440a403fSchristos   /* Stack pointer is register 28.  */
4364440a403fSchristos   cfi_add_CFA_def_cfa (28, 0);
4365440a403fSchristos }
4366440a403fSchristos 
4367440a403fSchristos int
tc_arc_regname_to_dw2regnum(char * regname)4368440a403fSchristos tc_arc_regname_to_dw2regnum (char *regname)
4369440a403fSchristos {
4370440a403fSchristos   struct symbol *sym;
4371440a403fSchristos 
4372440a403fSchristos   sym = hash_find (arc_reg_hash, regname);
4373440a403fSchristos   if (sym)
4374440a403fSchristos     return S_GET_VALUE (sym);
4375440a403fSchristos 
4376440a403fSchristos   return -1;
4377440a403fSchristos }
4378440a403fSchristos 
4379440a403fSchristos /* Adjust the symbol table.  Delete found AUX register symbols.  */
4380440a403fSchristos 
4381440a403fSchristos void
arc_adjust_symtab(void)4382440a403fSchristos arc_adjust_symtab (void)
4383440a403fSchristos {
4384440a403fSchristos   symbolS * sym;
4385440a403fSchristos 
4386440a403fSchristos   for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
4387440a403fSchristos     {
4388440a403fSchristos       /* I've created a symbol during parsing process.  Now, remove
4389440a403fSchristos 	 the symbol as it is found to be an AUX register.  */
4390440a403fSchristos       if (ARC_GET_FLAG (sym) & ARC_FLAG_AUX)
4391440a403fSchristos 	symbol_remove (sym, &symbol_rootP, &symbol_lastP);
4392440a403fSchristos     }
4393440a403fSchristos 
4394440a403fSchristos   /* Now do generic ELF adjustments.  */
4395440a403fSchristos   elf_adjust_symtab ();
4396440a403fSchristos }
4397440a403fSchristos 
4398440a403fSchristos static void
tokenize_extinsn(extInstruction_t * einsn)4399440a403fSchristos tokenize_extinsn (extInstruction_t *einsn)
4400440a403fSchristos {
4401440a403fSchristos   char *p, c;
4402440a403fSchristos   char *insn_name;
4403440a403fSchristos   unsigned char major_opcode;
4404440a403fSchristos   unsigned char sub_opcode;
4405440a403fSchristos   unsigned char syntax_class = 0;
4406440a403fSchristos   unsigned char syntax_class_modifiers = 0;
4407440a403fSchristos   unsigned char suffix_class = 0;
4408440a403fSchristos   unsigned int i;
4409440a403fSchristos 
4410440a403fSchristos   SKIP_WHITESPACE ();
4411440a403fSchristos 
4412440a403fSchristos   /* 1st: get instruction name.  */
4413440a403fSchristos   p = input_line_pointer;
4414440a403fSchristos   c = get_symbol_name (&p);
4415440a403fSchristos 
4416440a403fSchristos   insn_name = xstrdup (p);
4417440a403fSchristos   restore_line_pointer (c);
4418440a403fSchristos 
4419*b88e3e88Schristos   /* Convert to lower case.  */
4420*b88e3e88Schristos   for (p = insn_name; *p; ++p)
4421*b88e3e88Schristos     *p = TOLOWER (*p);
4422*b88e3e88Schristos 
4423440a403fSchristos   /* 2nd: get major opcode.  */
4424440a403fSchristos   if (*input_line_pointer != ',')
4425440a403fSchristos     {
4426440a403fSchristos       as_bad (_("expected comma after instruction name"));
4427440a403fSchristos       ignore_rest_of_line ();
4428440a403fSchristos       return;
4429440a403fSchristos     }
4430440a403fSchristos   input_line_pointer++;
4431440a403fSchristos   major_opcode = get_absolute_expression ();
4432440a403fSchristos 
4433440a403fSchristos   /* 3rd: get sub-opcode.  */
4434440a403fSchristos   SKIP_WHITESPACE ();
4435440a403fSchristos 
4436440a403fSchristos   if (*input_line_pointer != ',')
4437440a403fSchristos     {
4438440a403fSchristos       as_bad (_("expected comma after major opcode"));
4439440a403fSchristos       ignore_rest_of_line ();
4440440a403fSchristos       return;
4441440a403fSchristos     }
4442440a403fSchristos   input_line_pointer++;
4443440a403fSchristos   sub_opcode = get_absolute_expression ();
4444440a403fSchristos 
4445440a403fSchristos   /* 4th: get suffix class.  */
4446440a403fSchristos   SKIP_WHITESPACE ();
4447440a403fSchristos 
4448440a403fSchristos   if (*input_line_pointer != ',')
4449440a403fSchristos     {
4450440a403fSchristos       as_bad ("expected comma after sub opcode");
4451440a403fSchristos       ignore_rest_of_line ();
4452440a403fSchristos       return;
4453440a403fSchristos     }
4454440a403fSchristos   input_line_pointer++;
4455440a403fSchristos 
4456440a403fSchristos   while (1)
4457440a403fSchristos     {
4458440a403fSchristos       SKIP_WHITESPACE ();
4459440a403fSchristos 
4460440a403fSchristos       for (i = 0; i < ARRAY_SIZE (suffixclass); i++)
4461440a403fSchristos 	{
4462440a403fSchristos 	  if (!strncmp (suffixclass[i].name, input_line_pointer,
4463440a403fSchristos 			suffixclass[i].len))
4464440a403fSchristos 	    {
4465440a403fSchristos 	      suffix_class |= suffixclass[i].attr_class;
4466440a403fSchristos 	      input_line_pointer += suffixclass[i].len;
4467440a403fSchristos 	      break;
4468440a403fSchristos 	    }
4469440a403fSchristos 	}
4470440a403fSchristos 
4471440a403fSchristos       if (i == ARRAY_SIZE (suffixclass))
4472440a403fSchristos 	{
4473440a403fSchristos 	  as_bad ("invalid suffix class");
4474440a403fSchristos 	  ignore_rest_of_line ();
4475440a403fSchristos 	  return;
4476440a403fSchristos 	}
4477440a403fSchristos 
4478440a403fSchristos       SKIP_WHITESPACE ();
4479440a403fSchristos 
4480440a403fSchristos       if (*input_line_pointer == '|')
4481440a403fSchristos 	input_line_pointer++;
4482440a403fSchristos       else
4483440a403fSchristos 	break;
4484440a403fSchristos     }
4485440a403fSchristos 
4486440a403fSchristos   /* 5th: get syntax class and syntax class modifiers.  */
4487440a403fSchristos   if (*input_line_pointer != ',')
4488440a403fSchristos     {
4489440a403fSchristos       as_bad ("expected comma after suffix class");
4490440a403fSchristos       ignore_rest_of_line ();
4491440a403fSchristos       return;
4492440a403fSchristos     }
4493440a403fSchristos   input_line_pointer++;
4494440a403fSchristos 
4495440a403fSchristos   while (1)
4496440a403fSchristos     {
4497440a403fSchristos       SKIP_WHITESPACE ();
4498440a403fSchristos 
4499440a403fSchristos       for (i = 0; i < ARRAY_SIZE (syntaxclassmod); i++)
4500440a403fSchristos 	{
4501440a403fSchristos 	  if (!strncmp (syntaxclassmod[i].name,
4502440a403fSchristos 			input_line_pointer,
4503440a403fSchristos 			syntaxclassmod[i].len))
4504440a403fSchristos 	    {
4505440a403fSchristos 	      syntax_class_modifiers |= syntaxclassmod[i].attr_class;
4506440a403fSchristos 	      input_line_pointer += syntaxclassmod[i].len;
4507440a403fSchristos 	      break;
4508440a403fSchristos 	    }
4509440a403fSchristos 	}
4510440a403fSchristos 
4511440a403fSchristos       if (i == ARRAY_SIZE (syntaxclassmod))
4512440a403fSchristos 	{
4513440a403fSchristos 	  for (i = 0; i < ARRAY_SIZE (syntaxclass); i++)
4514440a403fSchristos 	    {
4515440a403fSchristos 	      if (!strncmp (syntaxclass[i].name,
4516440a403fSchristos 			    input_line_pointer,
4517440a403fSchristos 			    syntaxclass[i].len))
4518440a403fSchristos 		{
4519440a403fSchristos 		  syntax_class |= syntaxclass[i].attr_class;
4520440a403fSchristos 		  input_line_pointer += syntaxclass[i].len;
4521440a403fSchristos 		  break;
4522440a403fSchristos 		}
4523440a403fSchristos 	    }
4524440a403fSchristos 
4525440a403fSchristos 	  if (i == ARRAY_SIZE (syntaxclass))
4526440a403fSchristos 	    {
4527440a403fSchristos 	      as_bad ("missing syntax class");
4528440a403fSchristos 	      ignore_rest_of_line ();
4529440a403fSchristos 	      return;
4530440a403fSchristos 	    }
4531440a403fSchristos 	}
4532440a403fSchristos 
4533440a403fSchristos       SKIP_WHITESPACE ();
4534440a403fSchristos 
4535440a403fSchristos       if (*input_line_pointer == '|')
4536440a403fSchristos 	input_line_pointer++;
4537440a403fSchristos       else
4538440a403fSchristos 	break;
4539440a403fSchristos     }
4540440a403fSchristos 
4541440a403fSchristos   demand_empty_rest_of_line ();
4542440a403fSchristos 
4543440a403fSchristos   einsn->name   = insn_name;
4544440a403fSchristos   einsn->major  = major_opcode;
4545440a403fSchristos   einsn->minor  = sub_opcode;
4546440a403fSchristos   einsn->syntax = syntax_class;
4547440a403fSchristos   einsn->modsyn = syntax_class_modifiers;
4548440a403fSchristos   einsn->suffix = suffix_class;
4549440a403fSchristos   einsn->flags  = syntax_class
4550440a403fSchristos     | (syntax_class_modifiers & ARC_OP1_IMM_IMPLIED ? 0x10 : 0);
4551440a403fSchristos }
4552440a403fSchristos 
4553440a403fSchristos /* Generate an extension section.  */
4554440a403fSchristos 
4555440a403fSchristos static int
arc_set_ext_seg(void)4556440a403fSchristos arc_set_ext_seg (void)
4557440a403fSchristos {
4558440a403fSchristos   if (!arcext_section)
4559440a403fSchristos     {
4560440a403fSchristos       arcext_section = subseg_new (".arcextmap", 0);
4561*b88e3e88Schristos       bfd_set_section_flags (arcext_section, SEC_READONLY | SEC_HAS_CONTENTS);
4562440a403fSchristos     }
4563440a403fSchristos   else
4564440a403fSchristos     subseg_set (arcext_section, 0);
4565440a403fSchristos   return 1;
4566440a403fSchristos }
4567440a403fSchristos 
4568440a403fSchristos /* Create an extension instruction description in the arc extension
4569440a403fSchristos    section of the output file.
4570440a403fSchristos    The structure for an instruction is like this:
4571440a403fSchristos    [0]: Length of the record.
4572440a403fSchristos    [1]: Type of the record.
4573440a403fSchristos 
4574440a403fSchristos    [2]: Major opcode.
4575440a403fSchristos    [3]: Sub-opcode.
4576440a403fSchristos    [4]: Syntax (flags).
4577440a403fSchristos    [5]+ Name instruction.
4578440a403fSchristos 
4579440a403fSchristos    The sequence is terminated by an empty entry.  */
4580440a403fSchristos 
4581440a403fSchristos static void
create_extinst_section(extInstruction_t * einsn)4582440a403fSchristos create_extinst_section (extInstruction_t *einsn)
4583440a403fSchristos {
4584440a403fSchristos 
4585440a403fSchristos   segT old_sec    = now_seg;
4586440a403fSchristos   int old_subsec  = now_subseg;
4587440a403fSchristos   char *p;
4588440a403fSchristos   int name_len    = strlen (einsn->name);
4589440a403fSchristos 
4590440a403fSchristos   arc_set_ext_seg ();
4591440a403fSchristos 
4592440a403fSchristos   p = frag_more (1);
4593440a403fSchristos   *p = 5 + name_len + 1;
4594440a403fSchristos   p = frag_more (1);
4595440a403fSchristos   *p = EXT_INSTRUCTION;
4596440a403fSchristos   p = frag_more (1);
4597440a403fSchristos   *p = einsn->major;
4598440a403fSchristos   p = frag_more (1);
4599440a403fSchristos   *p = einsn->minor;
4600440a403fSchristos   p = frag_more (1);
4601440a403fSchristos   *p = einsn->flags;
4602440a403fSchristos   p = frag_more (name_len + 1);
4603440a403fSchristos   strcpy (p, einsn->name);
4604440a403fSchristos 
4605440a403fSchristos   subseg_set (old_sec, old_subsec);
4606440a403fSchristos }
4607440a403fSchristos 
4608440a403fSchristos /* Handler .extinstruction pseudo-op.  */
4609440a403fSchristos 
4610440a403fSchristos static void
arc_extinsn(int ignore ATTRIBUTE_UNUSED)4611440a403fSchristos arc_extinsn (int ignore ATTRIBUTE_UNUSED)
4612440a403fSchristos {
4613440a403fSchristos   extInstruction_t einsn;
4614440a403fSchristos   struct arc_opcode *arc_ext_opcodes;
4615440a403fSchristos   const char *errmsg = NULL;
4616440a403fSchristos   unsigned char moplow, mophigh;
4617440a403fSchristos 
4618440a403fSchristos   memset (&einsn, 0, sizeof (einsn));
4619440a403fSchristos   tokenize_extinsn (&einsn);
4620440a403fSchristos 
4621440a403fSchristos   /* Check if the name is already used.  */
4622440a403fSchristos   if (arc_find_opcode (einsn.name))
4623440a403fSchristos     as_warn (_("Pseudocode already used %s"), einsn.name);
4624440a403fSchristos 
4625440a403fSchristos   /* Check the opcode ranges.  */
4626440a403fSchristos   moplow = 0x05;
462706324dcfSchristos   mophigh = (selected_cpu.flags & (ARC_OPCODE_ARCv2EM
4628440a403fSchristos                                    | ARC_OPCODE_ARCv2HS)) ? 0x07 : 0x0a;
4629440a403fSchristos 
4630440a403fSchristos   if ((einsn.major > mophigh) || (einsn.major < moplow))
4631440a403fSchristos     as_fatal (_("major opcode not in range [0x%02x - 0x%02x]"), moplow, mophigh);
4632440a403fSchristos 
4633440a403fSchristos   if ((einsn.minor > 0x3f) && (einsn.major != 0x0a)
4634440a403fSchristos       && (einsn.major != 5) && (einsn.major != 9))
4635440a403fSchristos     as_fatal (_("minor opcode not in range [0x00 - 0x3f]"));
4636440a403fSchristos 
4637440a403fSchristos   switch (einsn.syntax & ARC_SYNTAX_MASK)
4638440a403fSchristos     {
4639440a403fSchristos     case ARC_SYNTAX_3OP:
4640440a403fSchristos       if (einsn.modsyn & ARC_OP1_IMM_IMPLIED)
4641440a403fSchristos 	as_fatal (_("Improper use of OP1_IMM_IMPLIED"));
4642440a403fSchristos       break;
4643440a403fSchristos     case ARC_SYNTAX_2OP:
4644440a403fSchristos     case ARC_SYNTAX_1OP:
4645440a403fSchristos     case ARC_SYNTAX_NOP:
4646440a403fSchristos       if (einsn.modsyn & ARC_OP1_MUST_BE_IMM)
4647440a403fSchristos 	as_fatal (_("Improper use of OP1_MUST_BE_IMM"));
4648440a403fSchristos       break;
4649440a403fSchristos     default:
4650440a403fSchristos       break;
4651440a403fSchristos     }
4652440a403fSchristos 
465306324dcfSchristos   arc_ext_opcodes = arcExtMap_genOpcode (&einsn, selected_cpu.flags, &errmsg);
4654440a403fSchristos   if (arc_ext_opcodes == NULL)
4655440a403fSchristos     {
4656440a403fSchristos       if (errmsg)
4657440a403fSchristos 	as_fatal ("%s", errmsg);
4658440a403fSchristos       else
4659440a403fSchristos 	as_fatal (_("Couldn't generate extension instruction opcodes"));
4660440a403fSchristos     }
4661440a403fSchristos   else if (errmsg)
4662440a403fSchristos     as_warn ("%s", errmsg);
4663440a403fSchristos 
4664440a403fSchristos   /* Insert the extension instruction.  */
4665440a403fSchristos   arc_insert_opcode ((const struct arc_opcode *) arc_ext_opcodes);
4666440a403fSchristos 
4667440a403fSchristos   create_extinst_section (&einsn);
4668440a403fSchristos }
4669440a403fSchristos 
467006324dcfSchristos static bfd_boolean
tokenize_extregister(extRegister_t * ereg,int opertype)4671440a403fSchristos tokenize_extregister (extRegister_t *ereg, int opertype)
4672440a403fSchristos {
4673440a403fSchristos   char *name;
4674440a403fSchristos   char *mode;
4675440a403fSchristos   char c;
4676440a403fSchristos   char *p;
4677440a403fSchristos   int number, imode = 0;
4678440a403fSchristos   bfd_boolean isCore_p = (opertype == EXT_CORE_REGISTER) ? TRUE : FALSE;
4679440a403fSchristos   bfd_boolean isReg_p  = (opertype == EXT_CORE_REGISTER
4680440a403fSchristos 			  || opertype == EXT_AUX_REGISTER) ? TRUE : FALSE;
4681440a403fSchristos 
4682440a403fSchristos   /* 1st: get register name.  */
4683440a403fSchristos   SKIP_WHITESPACE ();
4684440a403fSchristos   p = input_line_pointer;
4685440a403fSchristos   c = get_symbol_name (&p);
4686440a403fSchristos 
4687440a403fSchristos   name = xstrdup (p);
4688440a403fSchristos   restore_line_pointer (c);
4689440a403fSchristos 
4690440a403fSchristos   /* 2nd: get register number.  */
4691440a403fSchristos   SKIP_WHITESPACE ();
4692440a403fSchristos 
4693440a403fSchristos   if (*input_line_pointer != ',')
4694440a403fSchristos     {
469506324dcfSchristos       as_bad (_("expected comma after name"));
4696440a403fSchristos       ignore_rest_of_line ();
4697440a403fSchristos       free (name);
469806324dcfSchristos       return FALSE;
4699440a403fSchristos     }
4700440a403fSchristos   input_line_pointer++;
4701440a403fSchristos   number = get_absolute_expression ();
4702440a403fSchristos 
470306324dcfSchristos   if ((number < 0)
470406324dcfSchristos       && (opertype != EXT_AUX_REGISTER))
4705440a403fSchristos     {
470606324dcfSchristos       as_bad (_("%s second argument cannot be a negative number %d"),
470706324dcfSchristos 	      isCore_p ? "extCoreRegister's" : "extCondCode's",
470806324dcfSchristos 	      number);
4709440a403fSchristos       ignore_rest_of_line ();
4710440a403fSchristos       free (name);
471106324dcfSchristos       return FALSE;
4712440a403fSchristos     }
4713440a403fSchristos 
4714440a403fSchristos   if (isReg_p)
4715440a403fSchristos     {
4716440a403fSchristos       /* 3rd: get register mode.  */
4717440a403fSchristos       SKIP_WHITESPACE ();
4718440a403fSchristos 
4719440a403fSchristos       if (*input_line_pointer != ',')
4720440a403fSchristos 	{
4721440a403fSchristos 	  as_bad (_("expected comma after register number"));
4722440a403fSchristos 	  ignore_rest_of_line ();
4723440a403fSchristos 	  free (name);
472406324dcfSchristos 	  return FALSE;
4725440a403fSchristos 	}
4726440a403fSchristos 
4727440a403fSchristos       input_line_pointer++;
4728440a403fSchristos       mode = input_line_pointer;
4729440a403fSchristos 
4730440a403fSchristos       if (!strncmp (mode, "r|w", 3))
4731440a403fSchristos 	{
4732440a403fSchristos 	  imode = 0;
4733440a403fSchristos 	  input_line_pointer += 3;
4734440a403fSchristos 	}
4735440a403fSchristos       else if (!strncmp (mode, "r", 1))
4736440a403fSchristos 	{
4737440a403fSchristos 	  imode = ARC_REGISTER_READONLY;
4738440a403fSchristos 	  input_line_pointer += 1;
4739440a403fSchristos 	}
4740440a403fSchristos       else if (strncmp (mode, "w", 1))
4741440a403fSchristos 	{
4742440a403fSchristos 	  as_bad (_("invalid mode"));
4743440a403fSchristos 	  ignore_rest_of_line ();
4744440a403fSchristos 	  free (name);
474506324dcfSchristos 	  return FALSE;
4746440a403fSchristos 	}
4747440a403fSchristos       else
4748440a403fSchristos 	{
4749440a403fSchristos 	  imode = ARC_REGISTER_WRITEONLY;
4750440a403fSchristos 	  input_line_pointer += 1;
4751440a403fSchristos 	}
4752440a403fSchristos     }
4753440a403fSchristos 
4754440a403fSchristos   if (isCore_p)
4755440a403fSchristos     {
4756440a403fSchristos       /* 4th: get core register shortcut.  */
4757440a403fSchristos       SKIP_WHITESPACE ();
4758440a403fSchristos       if (*input_line_pointer != ',')
4759440a403fSchristos 	{
4760440a403fSchristos 	  as_bad (_("expected comma after register mode"));
4761440a403fSchristos 	  ignore_rest_of_line ();
4762440a403fSchristos 	  free (name);
476306324dcfSchristos 	  return FALSE;
4764440a403fSchristos 	}
4765440a403fSchristos 
4766440a403fSchristos       input_line_pointer++;
4767440a403fSchristos 
4768440a403fSchristos       if (!strncmp (input_line_pointer, "cannot_shortcut", 15))
4769440a403fSchristos 	{
4770440a403fSchristos 	  imode |= ARC_REGISTER_NOSHORT_CUT;
4771440a403fSchristos 	  input_line_pointer += 15;
4772440a403fSchristos 	}
4773440a403fSchristos       else if (strncmp (input_line_pointer, "can_shortcut", 12))
4774440a403fSchristos 	{
4775440a403fSchristos 	  as_bad (_("shortcut designator invalid"));
4776440a403fSchristos 	  ignore_rest_of_line ();
4777440a403fSchristos 	  free (name);
477806324dcfSchristos 	  return FALSE;
4779440a403fSchristos 	}
4780440a403fSchristos       else
4781440a403fSchristos 	{
4782440a403fSchristos 	  input_line_pointer += 12;
4783440a403fSchristos 	}
4784440a403fSchristos     }
4785440a403fSchristos   demand_empty_rest_of_line ();
4786440a403fSchristos 
4787440a403fSchristos   ereg->name = name;
4788440a403fSchristos   ereg->number = number;
4789440a403fSchristos   ereg->imode  = imode;
479006324dcfSchristos   return TRUE;
4791440a403fSchristos }
4792440a403fSchristos 
4793440a403fSchristos /* Create an extension register/condition description in the arc
4794440a403fSchristos    extension section of the output file.
4795440a403fSchristos 
4796440a403fSchristos    The structure for an instruction is like this:
4797440a403fSchristos    [0]: Length of the record.
4798440a403fSchristos    [1]: Type of the record.
4799440a403fSchristos 
4800440a403fSchristos    For core regs and condition codes:
4801440a403fSchristos    [2]: Value.
4802440a403fSchristos    [3]+ Name.
4803440a403fSchristos 
480406324dcfSchristos    For auxiliary registers:
4805440a403fSchristos    [2..5]: Value.
4806440a403fSchristos    [6]+ Name
4807440a403fSchristos 
4808440a403fSchristos    The sequence is terminated by an empty entry.  */
4809440a403fSchristos 
4810440a403fSchristos static void
create_extcore_section(extRegister_t * ereg,int opertype)4811440a403fSchristos create_extcore_section (extRegister_t *ereg, int opertype)
4812440a403fSchristos {
4813440a403fSchristos   segT old_sec   = now_seg;
4814440a403fSchristos   int old_subsec = now_subseg;
4815440a403fSchristos   char *p;
4816440a403fSchristos   int name_len   = strlen (ereg->name);
4817440a403fSchristos 
4818440a403fSchristos   arc_set_ext_seg ();
4819440a403fSchristos 
4820440a403fSchristos   switch (opertype)
4821440a403fSchristos     {
4822440a403fSchristos     case EXT_COND_CODE:
4823440a403fSchristos     case EXT_CORE_REGISTER:
4824440a403fSchristos       p = frag_more (1);
4825440a403fSchristos       *p = 3 + name_len + 1;
4826440a403fSchristos       p = frag_more (1);
4827440a403fSchristos       *p = opertype;
4828440a403fSchristos       p = frag_more (1);
4829440a403fSchristos       *p = ereg->number;
4830440a403fSchristos       break;
4831440a403fSchristos     case EXT_AUX_REGISTER:
4832440a403fSchristos       p = frag_more (1);
4833440a403fSchristos       *p = 6 + name_len + 1;
4834440a403fSchristos       p = frag_more (1);
4835440a403fSchristos       *p = EXT_AUX_REGISTER;
4836440a403fSchristos       p = frag_more (1);
4837440a403fSchristos       *p = (ereg->number >> 24) & 0xff;
4838440a403fSchristos       p = frag_more (1);
4839440a403fSchristos       *p = (ereg->number >> 16) & 0xff;
4840440a403fSchristos       p = frag_more (1);
4841440a403fSchristos       *p = (ereg->number >>  8) & 0xff;
4842440a403fSchristos       p = frag_more (1);
4843440a403fSchristos       *p = (ereg->number)       & 0xff;
4844440a403fSchristos       break;
4845440a403fSchristos     default:
4846440a403fSchristos       break;
4847440a403fSchristos     }
4848440a403fSchristos 
4849440a403fSchristos   p = frag_more (name_len + 1);
4850440a403fSchristos   strcpy (p, ereg->name);
4851440a403fSchristos 
4852440a403fSchristos   subseg_set (old_sec, old_subsec);
4853440a403fSchristos }
4854440a403fSchristos 
4855440a403fSchristos /* Handler .extCoreRegister pseudo-op.  */
4856440a403fSchristos 
4857440a403fSchristos static void
arc_extcorereg(int opertype)4858440a403fSchristos arc_extcorereg (int opertype)
4859440a403fSchristos {
4860440a403fSchristos   extRegister_t ereg;
4861440a403fSchristos   struct arc_aux_reg *auxr;
4862440a403fSchristos   const char *retval;
4863440a403fSchristos   struct arc_flag_operand *ccode;
4864440a403fSchristos 
4865440a403fSchristos   memset (&ereg, 0, sizeof (ereg));
486606324dcfSchristos   if (!tokenize_extregister (&ereg, opertype))
486706324dcfSchristos     return;
4868440a403fSchristos 
4869440a403fSchristos   switch (opertype)
4870440a403fSchristos     {
4871440a403fSchristos     case EXT_CORE_REGISTER:
4872440a403fSchristos       /* Core register.  */
4873440a403fSchristos       if (ereg.number > 60)
4874440a403fSchristos 	as_bad (_("core register %s value (%d) too large"), ereg.name,
4875440a403fSchristos 		ereg.number);
4876440a403fSchristos       declare_register (ereg.name, ereg.number);
4877440a403fSchristos       break;
4878440a403fSchristos     case EXT_AUX_REGISTER:
4879440a403fSchristos       /* Auxiliary register.  */
4880440a403fSchristos       auxr = XNEW (struct arc_aux_reg);
4881440a403fSchristos       auxr->name = ereg.name;
488206324dcfSchristos       auxr->cpu = selected_cpu.flags;
4883440a403fSchristos       auxr->subclass = NONE;
4884440a403fSchristos       auxr->address = ereg.number;
4885440a403fSchristos       retval = hash_insert (arc_aux_hash, auxr->name, (void *) auxr);
4886440a403fSchristos       if (retval)
4887440a403fSchristos 	as_fatal (_("internal error: can't hash aux register '%s': %s"),
4888440a403fSchristos 		  auxr->name, retval);
4889440a403fSchristos       break;
4890440a403fSchristos     case EXT_COND_CODE:
4891440a403fSchristos       /* Condition code.  */
4892440a403fSchristos       if (ereg.number > 31)
4893440a403fSchristos 	as_bad (_("condition code %s value (%d) too large"), ereg.name,
4894440a403fSchristos 		ereg.number);
4895440a403fSchristos       ext_condcode.size ++;
4896440a403fSchristos       ext_condcode.arc_ext_condcode =
4897440a403fSchristos 	XRESIZEVEC (struct arc_flag_operand, ext_condcode.arc_ext_condcode,
4898440a403fSchristos 		    ext_condcode.size + 1);
4899440a403fSchristos       if (ext_condcode.arc_ext_condcode == NULL)
4900440a403fSchristos 	as_fatal (_("Virtual memory exhausted"));
4901440a403fSchristos 
4902440a403fSchristos       ccode = ext_condcode.arc_ext_condcode + ext_condcode.size - 1;
4903440a403fSchristos       ccode->name   = ereg.name;
4904440a403fSchristos       ccode->code   = ereg.number;
4905440a403fSchristos       ccode->bits   = 5;
4906440a403fSchristos       ccode->shift  = 0;
4907440a403fSchristos       ccode->favail = 0; /* not used.  */
4908440a403fSchristos       ccode++;
4909440a403fSchristos       memset (ccode, 0, sizeof (struct arc_flag_operand));
4910440a403fSchristos       break;
4911440a403fSchristos     default:
4912440a403fSchristos       as_bad (_("Unknown extension"));
4913440a403fSchristos       break;
4914440a403fSchristos     }
4915440a403fSchristos   create_extcore_section (&ereg, opertype);
4916440a403fSchristos }
4917440a403fSchristos 
491806324dcfSchristos /* Parse a .arc_attribute directive.  */
491906324dcfSchristos 
492006324dcfSchristos static void
arc_attribute(int ignored ATTRIBUTE_UNUSED)492106324dcfSchristos arc_attribute (int ignored ATTRIBUTE_UNUSED)
492206324dcfSchristos {
492306324dcfSchristos   int tag = obj_elf_vendor_attribute (OBJ_ATTR_PROC);
492406324dcfSchristos 
492506324dcfSchristos   if (tag < NUM_KNOWN_OBJ_ATTRIBUTES)
492606324dcfSchristos     attributes_set_explicitly[tag] = TRUE;
492706324dcfSchristos }
492806324dcfSchristos 
492906324dcfSchristos /* Set an attribute if it has not already been set by the user.  */
493006324dcfSchristos 
493106324dcfSchristos static void
arc_set_attribute_int(int tag,int value)493206324dcfSchristos arc_set_attribute_int (int tag, int value)
493306324dcfSchristos {
493406324dcfSchristos   if (tag < 1
493506324dcfSchristos       || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
493606324dcfSchristos       || !attributes_set_explicitly[tag])
493706324dcfSchristos     bfd_elf_add_proc_attr_int (stdoutput, tag, value);
493806324dcfSchristos }
493906324dcfSchristos 
494006324dcfSchristos static void
arc_set_attribute_string(int tag,const char * value)494106324dcfSchristos arc_set_attribute_string (int tag, const char *value)
494206324dcfSchristos {
494306324dcfSchristos   if (tag < 1
494406324dcfSchristos       || tag >= NUM_KNOWN_OBJ_ATTRIBUTES
494506324dcfSchristos       || !attributes_set_explicitly[tag])
494606324dcfSchristos     bfd_elf_add_proc_attr_string (stdoutput, tag, value);
494706324dcfSchristos }
494806324dcfSchristos 
494906324dcfSchristos /* Allocate and concatenate two strings.  s1 can be NULL but not
495006324dcfSchristos    s2.  s1 pointer is freed at end of this procedure.  */
495106324dcfSchristos 
495206324dcfSchristos static char *
arc_stralloc(char * s1,const char * s2)495306324dcfSchristos arc_stralloc (char * s1, const char * s2)
495406324dcfSchristos {
495506324dcfSchristos   char * p;
495606324dcfSchristos   int len = 0;
495706324dcfSchristos 
495806324dcfSchristos   if (s1)
495906324dcfSchristos     len = strlen (s1) + 1;
496006324dcfSchristos 
496106324dcfSchristos   /* Only s1 can be null.  */
496206324dcfSchristos   gas_assert (s2);
496306324dcfSchristos   len += strlen (s2) + 1;
496406324dcfSchristos 
496506324dcfSchristos   p = (char *) xmalloc (len);
496606324dcfSchristos   if (p == NULL)
496706324dcfSchristos     as_fatal (_("Virtual memory exhausted"));
496806324dcfSchristos 
496906324dcfSchristos   if (s1)
497006324dcfSchristos     {
497106324dcfSchristos       strcpy (p, s1);
497206324dcfSchristos       strcat (p, ",");
497306324dcfSchristos       strcat (p, s2);
497406324dcfSchristos       free (s1);
497506324dcfSchristos     }
497606324dcfSchristos   else
497706324dcfSchristos     strcpy (p, s2);
497806324dcfSchristos 
497906324dcfSchristos   return p;
498006324dcfSchristos }
498106324dcfSchristos 
498206324dcfSchristos /* Set the public ARC object attributes.  */
498306324dcfSchristos 
498406324dcfSchristos static void
arc_set_public_attributes(void)498506324dcfSchristos arc_set_public_attributes (void)
498606324dcfSchristos {
498706324dcfSchristos   int base = 0;
498806324dcfSchristos   char *s = NULL;
498906324dcfSchristos   unsigned int i;
499006324dcfSchristos 
499106324dcfSchristos   /* Tag_ARC_CPU_name.  */
499206324dcfSchristos   arc_set_attribute_string (Tag_ARC_CPU_name, selected_cpu.name);
499306324dcfSchristos 
499406324dcfSchristos   /* Tag_ARC_CPU_base.  */
499506324dcfSchristos   switch (selected_cpu.eflags & EF_ARC_MACH_MSK)
499606324dcfSchristos     {
499706324dcfSchristos     case E_ARC_MACH_ARC600:
499806324dcfSchristos     case E_ARC_MACH_ARC601:
499906324dcfSchristos       base = TAG_CPU_ARC6xx;
500006324dcfSchristos       break;
500106324dcfSchristos     case E_ARC_MACH_ARC700:
500206324dcfSchristos       base = TAG_CPU_ARC7xx;
500306324dcfSchristos       break;
500406324dcfSchristos     case EF_ARC_CPU_ARCV2EM:
500506324dcfSchristos       base = TAG_CPU_ARCEM;
500606324dcfSchristos       break;
500706324dcfSchristos     case EF_ARC_CPU_ARCV2HS:
500806324dcfSchristos       base = TAG_CPU_ARCHS;
500906324dcfSchristos       break;
501006324dcfSchristos     default:
501106324dcfSchristos       base = 0;
501206324dcfSchristos       break;
501306324dcfSchristos     }
501406324dcfSchristos   if (attributes_set_explicitly[Tag_ARC_CPU_base]
501506324dcfSchristos       && (base != bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
501606324dcfSchristos 					    Tag_ARC_CPU_base)))
501706324dcfSchristos     as_warn (_("Overwrite explicitly set Tag_ARC_CPU_base"));
501806324dcfSchristos   bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_CPU_base, base);
501906324dcfSchristos 
502006324dcfSchristos   /* Tag_ARC_ABI_osver.  */
502106324dcfSchristos   if (attributes_set_explicitly[Tag_ARC_ABI_osver])
502206324dcfSchristos     {
502306324dcfSchristos       int val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
502406324dcfSchristos 					  Tag_ARC_ABI_osver);
502506324dcfSchristos 
502606324dcfSchristos       selected_cpu.eflags = ((selected_cpu.eflags & ~EF_ARC_OSABI_MSK)
502706324dcfSchristos 			     | (val & 0x0f << 8));
502806324dcfSchristos     }
502906324dcfSchristos   else
503006324dcfSchristos     {
503106324dcfSchristos       arc_set_attribute_int (Tag_ARC_ABI_osver, E_ARC_OSABI_CURRENT >> 8);
503206324dcfSchristos     }
503306324dcfSchristos 
503406324dcfSchristos   /* Tag_ARC_ISA_config.  */
503506324dcfSchristos   arc_check_feature();
503606324dcfSchristos 
503706324dcfSchristos   for (i = 0; i < ARRAY_SIZE (feature_list); i++)
503806324dcfSchristos     if (selected_cpu.features & feature_list[i].feature)
503906324dcfSchristos       s = arc_stralloc (s, feature_list[i].attr);
504006324dcfSchristos 
504106324dcfSchristos   if (s)
504206324dcfSchristos     arc_set_attribute_string (Tag_ARC_ISA_config, s);
504306324dcfSchristos 
504406324dcfSchristos   /* Tag_ARC_ISA_mpy_option.  */
504506324dcfSchristos   arc_set_attribute_int (Tag_ARC_ISA_mpy_option, mpy_option);
504606324dcfSchristos 
504706324dcfSchristos   /* Tag_ARC_ABI_pic.  */
504806324dcfSchristos   arc_set_attribute_int (Tag_ARC_ABI_pic, pic_option);
504906324dcfSchristos 
505006324dcfSchristos   /* Tag_ARC_ABI_sda.  */
505106324dcfSchristos   arc_set_attribute_int (Tag_ARC_ABI_sda, sda_option);
505206324dcfSchristos 
505306324dcfSchristos   /* Tag_ARC_ABI_tls.  */
505406324dcfSchristos   arc_set_attribute_int (Tag_ARC_ABI_tls, tls_option);
5055*b88e3e88Schristos 
5056*b88e3e88Schristos   /* Tag_ARC_ATR_version.  */
5057*b88e3e88Schristos   arc_set_attribute_int (Tag_ARC_ATR_version, 1);
5058*b88e3e88Schristos 
5059*b88e3e88Schristos   /* Tag_ARC_ABI_rf16.  */
5060*b88e3e88Schristos   if (attributes_set_explicitly[Tag_ARC_ABI_rf16]
5061*b88e3e88Schristos       && bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_PROC,
5062*b88e3e88Schristos 				   Tag_ARC_ABI_rf16)
5063*b88e3e88Schristos       && !rf16_only)
5064*b88e3e88Schristos     {
5065*b88e3e88Schristos       as_warn (_("Overwrite explicitly set Tag_ARC_ABI_rf16 to full "
5066*b88e3e88Schristos 		 "register file"));
5067*b88e3e88Schristos       bfd_elf_add_proc_attr_int (stdoutput, Tag_ARC_ABI_rf16, 0);
5068*b88e3e88Schristos     }
506906324dcfSchristos }
507006324dcfSchristos 
507106324dcfSchristos /* Add the default contents for the .ARC.attributes section.  */
507206324dcfSchristos 
507306324dcfSchristos void
arc_md_end(void)507406324dcfSchristos arc_md_end (void)
507506324dcfSchristos {
507606324dcfSchristos   arc_set_public_attributes ();
507706324dcfSchristos 
507806324dcfSchristos   if (!bfd_set_arch_mach (stdoutput, bfd_arch_arc, selected_cpu.mach))
507906324dcfSchristos     as_fatal (_("could not set architecture and machine"));
508006324dcfSchristos 
508106324dcfSchristos   bfd_set_private_flags (stdoutput, selected_cpu.eflags);
508206324dcfSchristos }
508306324dcfSchristos 
arc_copy_symbol_attributes(symbolS * dest,symbolS * src)508406324dcfSchristos void arc_copy_symbol_attributes (symbolS *dest, symbolS *src)
508506324dcfSchristos {
508606324dcfSchristos   ARC_GET_FLAG (dest) = ARC_GET_FLAG (src);
508706324dcfSchristos }
508806324dcfSchristos 
arc_convert_symbolic_attribute(const char * name)508906324dcfSchristos int arc_convert_symbolic_attribute (const char *name)
509006324dcfSchristos {
509106324dcfSchristos   static const struct
509206324dcfSchristos   {
509306324dcfSchristos     const char * name;
509406324dcfSchristos     const int    tag;
509506324dcfSchristos   }
509606324dcfSchristos   attribute_table[] =
509706324dcfSchristos     {
509806324dcfSchristos #define T(tag) {#tag, tag}
509906324dcfSchristos   T (Tag_ARC_PCS_config),
510006324dcfSchristos   T (Tag_ARC_CPU_base),
510106324dcfSchristos   T (Tag_ARC_CPU_variation),
510206324dcfSchristos   T (Tag_ARC_CPU_name),
510306324dcfSchristos   T (Tag_ARC_ABI_rf16),
510406324dcfSchristos   T (Tag_ARC_ABI_osver),
510506324dcfSchristos   T (Tag_ARC_ABI_sda),
510606324dcfSchristos   T (Tag_ARC_ABI_pic),
510706324dcfSchristos   T (Tag_ARC_ABI_tls),
510806324dcfSchristos   T (Tag_ARC_ABI_enumsize),
510906324dcfSchristos   T (Tag_ARC_ABI_exceptions),
511006324dcfSchristos   T (Tag_ARC_ABI_double_size),
511106324dcfSchristos   T (Tag_ARC_ISA_config),
511206324dcfSchristos   T (Tag_ARC_ISA_apex),
5113*b88e3e88Schristos   T (Tag_ARC_ISA_mpy_option),
5114*b88e3e88Schristos   T (Tag_ARC_ATR_version)
511506324dcfSchristos #undef T
511606324dcfSchristos     };
511706324dcfSchristos   unsigned int i;
511806324dcfSchristos 
511906324dcfSchristos   if (name == NULL)
512006324dcfSchristos     return -1;
512106324dcfSchristos 
512206324dcfSchristos   for (i = 0; i < ARRAY_SIZE (attribute_table); i++)
512306324dcfSchristos     if (streq (name, attribute_table[i].name))
512406324dcfSchristos       return attribute_table[i].tag;
512506324dcfSchristos 
512606324dcfSchristos   return -1;
512706324dcfSchristos }
512806324dcfSchristos 
5129440a403fSchristos /* Local variables:
5130440a403fSchristos    eval: (c-set-style "gnu")
5131440a403fSchristos    indent-tabs-mode: t
5132440a403fSchristos    End:  */
5133