xref: /netbsd-src/external/gpl3/binutils.old/dist/gas/config/tc-ft32.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1 /* tc-ft32.c -- Assemble code for ft32
2    Copyright (C) 2008-2022 Free Software Foundation, Inc.
3 
4    This file is part of GAS, the GNU Assembler.
5 
6    GAS is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3, or (at your option)
9    any later version.
10 
11    GAS is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with GAS; see the file COPYING.  If not, write to
18    the Free Software Foundation, 51 Franklin Street - Fifth Floor,
19    Boston, MA 02110-1301, USA.  */
20 
21 /* Contributed by Anthony Green <green@spindazzle.org>.  */
22 
23 #include "as.h"
24 #include "safe-ctype.h"
25 #include "opcode/ft32.h"
26 
27 extern const ft32_opc_info_t ft32_opc_info[128];
28 
29 /* See md_parse_option() for meanings of these options.  */
30 static char norelax;			/* True if -norelax switch seen.  */
31 
32 const char comment_chars[]        = "#";
33 const char line_separator_chars[] = ";";
34 const char line_comment_chars[]   = "#";
35 
36 static int pending_reloc;
37 static htab_t opcode_hash_control;
38 
39 static valueT md_chars_to_number (char * buf, int n);
40 
41 const pseudo_typeS md_pseudo_table[] =
42 {
43   {0, 0, 0}
44 };
45 
46 const char FLT_CHARS[] = "rRsSfFdDxXpP";
47 const char EXP_CHARS[] = "eE";
48 
49 /* This function is called once, at assembler startup time.  It sets
50    up the hash table with all the opcodes in it, and also initializes
51    some aliases for compatibility with other assemblers.  */
52 
53 void
md_begin(void)54 md_begin (void)
55 {
56   const ft32_opc_info_t *opcode;
57   opcode_hash_control = str_htab_create ();
58 
59   /* Insert names into hash table.  */
60   for (opcode = ft32_opc_info; opcode->name; opcode++)
61     str_hash_insert (opcode_hash_control, opcode->name, opcode, 0);
62 
63   bfd_set_arch_mach (stdoutput, TARGET_ARCH, 0);
64   if (!norelax)
65     linkrelax = 1;
66 }
67 
68 /* Parse an expression and then restore the input line pointer.  */
69 
70 static char *
parse_exp_save_ilp(char * s,expressionS * op)71 parse_exp_save_ilp (char *s, expressionS *op)
72 {
73   char *save = input_line_pointer;
74 
75   input_line_pointer = s;
76   expression (op);
77   s = input_line_pointer;
78   input_line_pointer = save;
79   return s;
80 }
81 
82 static int
parse_condition(char ** ptr)83 parse_condition (char **ptr)
84 {
85   char *s = *ptr;
86   static const struct
87   {
88     const char *name;
89     int bits;
90   }
91   ccs[] =
92   {
93     { "gt,"   , (2 << FT32_FLD_CR_BIT) | (5 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
94     { "gte,"  , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
95     { "lt,"   , (2 << FT32_FLD_CR_BIT) | (4 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
96     { "lte,"  , (2 << FT32_FLD_CR_BIT) | (5 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
97     { "a,"    , (2 << FT32_FLD_CR_BIT) | (6 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
98     { "ae,"   , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
99     { "be,"   , (2 << FT32_FLD_CR_BIT) | (6 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
100     { "b,"    , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
101     { "nz,"   , (2 << FT32_FLD_CR_BIT) | (0 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
102     { "z,"    , (2 << FT32_FLD_CR_BIT) | (0 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
103     { "nc,"   , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
104     { "c,"    , (2 << FT32_FLD_CR_BIT) | (1 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
105     { "no,"   , (2 << FT32_FLD_CR_BIT) | (2 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
106     { "o,"    , (2 << FT32_FLD_CR_BIT) | (2 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
107     { "ns,"   , (2 << FT32_FLD_CR_BIT) | (3 << FT32_FLD_CB_BIT) | (0 << FT32_FLD_CV_BIT)},
108     { "s,"    , (2 << FT32_FLD_CR_BIT) | (3 << FT32_FLD_CB_BIT) | (1 << FT32_FLD_CV_BIT)},
109     { NULL, 0}
110   }, *pc;
111 
112   for (pc = ccs; pc->name; pc++)
113     {
114       if (memcmp(pc->name, s, strlen(pc->name)) == 0)
115         {
116           *ptr += strlen(pc->name) - 1;
117           return pc->bits;
118         }
119     }
120   return -1;
121 }
122 
123 static int
parse_decimal(char ** ptr)124 parse_decimal (char **ptr)
125 {
126   int r = 0;
127   char *s = *ptr;
128 
129   while (('0' <= *s) && (*s <= '9'))
130     {
131       r *= 10;
132       r += (*s++ - '0');
133     }
134   *ptr = s;
135   return r;
136 }
137 
138 static int
parse_register_operand(char ** ptr)139 parse_register_operand (char **ptr)
140 {
141   int reg;
142   char *s = *ptr;
143 
144   if (*s != '$')
145     {
146       as_bad (_("expecting register"));
147       ignore_rest_of_line ();
148       return -1;
149     }
150   if ((s[1] == 's') && (s[2] == 'p'))
151     {
152       reg = 31;
153     }
154   else if ((s[1] == 'c') && (s[2] == 'c'))
155     {
156       reg = 30;
157     }
158   else if ((s[1] == 'f') && (s[2] == 'p'))
159     {
160       reg = 29;
161     }
162   else if (s[1] == 'r')
163     {
164       reg = s[2] - '0';
165       if ((reg < 0) || (reg > 9))
166 	{
167 	  as_bad (_("illegal register number"));
168 	  ignore_rest_of_line ();
169 	  return -1;
170 	}
171       if ((reg == 1) || (reg == 2) || (reg == 3))
172 	{
173 	  int r2 = s[3] - '0';
174 	  if ((r2 >= 0) && (r2 <= 9))
175 	    {
176 	      reg = (reg * 10) + r2;
177 	      *ptr += 1;
178 	    }
179 	}
180     }
181   else
182     {
183       as_bad (_("illegal register number"));
184       ignore_rest_of_line ();
185       return -1;
186     }
187 
188   *ptr += 3;
189 
190   return reg;
191 }
192 
193 /* This is the guts of the machine-dependent assembler.  STR points to
194    a machine dependent instruction.  This function is supposed to emit
195    the frags/bytes it assembles to.  */
196 
197 void
md_assemble(char * str)198 md_assemble (char *str)
199 {
200   char *op_start;
201   char *op_end;
202   ft32_opc_info_t *opcode;
203   char *output;
204   int idx = 0;
205   char pend;
206   int nlen = 0;
207   unsigned int b;
208   int f;
209   expressionS arg;
210   bool fixed = false;
211   unsigned int sc;
212   bool can_sc;
213 
214   /* Drop leading whitespace.  */
215   while (*str == ' ')
216     str++;
217 
218   /* Find the op code end.  */
219   op_start = str;
220   for (op_end = str;
221        *op_end
222        && !is_end_of_line[*op_end & 0xff]
223        && *op_end != ' '
224        && *op_end != '.';
225        op_end++)
226     nlen++;
227 
228   pend = *op_end;
229   *op_end = 0;
230 
231   if (nlen == 0)
232     as_bad (_("can't find opcode "));
233 
234   opcode = (ft32_opc_info_t *) str_hash_find (opcode_hash_control, op_start);
235   *op_end = pend;
236 
237   if (opcode == NULL)
238     {
239       as_bad (_("unknown opcode %s"), op_start);
240       return;
241     }
242 
243   b = opcode->bits;
244   f = opcode->fields;
245 
246   if (opcode->dw)
247     {
248       int dw;
249 
250       if (*op_end == '.')
251         {
252           switch (op_end[1])
253             {
254               case 'b':
255                 dw = 0;
256                 break;
257               case 's':
258                 dw = 1;
259                 break;
260               case 'l':
261                 dw = 2;
262                 break;
263               default:
264                 as_bad (_("unknown width specifier '.%c'"), op_end[1]);
265                 return;
266             }
267           op_end += 2;
268         }
269       else
270         {
271           dw = 2; /* default is ".l" */
272         }
273       b |= dw << FT32_FLD_DW_BIT;
274     }
275 
276   while (ISSPACE (*op_end))
277     op_end++;
278 
279   output = frag_more (4);
280 
281   while (f)
282     {
283       int lobit = f & -f;
284 
285       if (f & lobit)
286         {
287           switch (lobit)
288 	    {
289 	    case  FT32_FLD_CBCRCV:
290 	      b |= parse_condition( &op_end);
291 	      break;
292 	    case  FT32_FLD_CB:
293 	      b |= parse_decimal (&op_end) << FT32_FLD_CB_BIT;
294 	      break;
295 	    case  FT32_FLD_R_D:
296 	      b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
297 	      break;
298 	    case  FT32_FLD_CR:
299 	      b |= (parse_register_operand (&op_end) - 28) << FT32_FLD_CR_BIT;
300 	      break;
301 	    case  FT32_FLD_CV:
302 	      b |= parse_decimal (&op_end) << FT32_FLD_CV_BIT;
303 	      break;
304 	    case  FT32_FLD_R_1:
305 	      b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
306 	      break;
307 	    case  FT32_FLD_RIMM:
308 	      if (*op_end == '$')
309 		{
310 		  b |= parse_register_operand (&op_end) << FT32_FLD_RIMM_BIT;
311 		}
312 	      else
313 		{
314 		  b |= 0x400 << FT32_FLD_RIMM_BIT;
315 		  op_end = parse_exp_save_ilp (op_end, &arg);
316 		  fixed = true;
317 		  fix_new_exp (frag_now,
318 			       (output - frag_now->fr_literal),
319 			       2,
320 			       &arg,
321 			       0,
322 			       BFD_RELOC_FT32_10);
323 		}
324 	      break;
325 	    case  FT32_FLD_R_2:
326 	      b |= parse_register_operand (&op_end) << FT32_FLD_R_2_BIT;
327 	      break;
328 	    case  FT32_FLD_K20:
329 	      op_end = parse_exp_save_ilp (op_end, &arg);
330 	      fixed = true;
331 	      fix_new_exp (frag_now,
332 			   (output - frag_now->fr_literal),
333 			   3,
334 			   &arg,
335 			   0,
336 			   BFD_RELOC_FT32_20);
337 	      break;
338 	    case  FT32_FLD_PA:
339 	      op_end = parse_exp_save_ilp (op_end, &arg);
340 	      fixed = true;
341 	      fix_new_exp (frag_now,
342 			   (output - frag_now->fr_literal),
343 			   3,
344 			   &arg,
345 			   0,
346 			   BFD_RELOC_FT32_18);
347 	      break;
348 	    case  FT32_FLD_AA:
349 	      op_end = parse_exp_save_ilp (op_end, &arg);
350 	      fixed = true;
351 	      fix_new_exp (frag_now,
352 			   (output - frag_now->fr_literal),
353 			   3,
354 			   &arg,
355 			   0,
356 			   BFD_RELOC_FT32_17);
357 	      break;
358 	    case  FT32_FLD_K16:
359 	      op_end = parse_exp_save_ilp (op_end, &arg);
360 	      fixed = true;
361 	      fix_new_exp (frag_now,
362 			   (output - frag_now->fr_literal),
363 			   2,
364 			   &arg,
365 			   0,
366 			   BFD_RELOC_16);
367 	      break;
368 	    case  FT32_FLD_K15:
369 	      op_end = parse_exp_save_ilp (op_end, &arg);
370 	      if (arg.X_add_number & 0x80)
371 		arg.X_add_number ^= 0x7f00;
372 	      fixed = true;
373 	      fix_new_exp (frag_now,
374 			   (output - frag_now->fr_literal),
375 			   2,
376 			   &arg,
377 			   0,
378 			   BFD_RELOC_FT32_15);
379 	      break;
380 	    case  FT32_FLD_R_D_POST:
381 	      b |= parse_register_operand (&op_end) << FT32_FLD_R_D_BIT;
382 	      break;
383 	    case  FT32_FLD_R_1_POST:
384 	      b |= parse_register_operand (&op_end) << FT32_FLD_R_1_BIT;
385 	      break;
386 	    default:
387 	      as_bad (_("internal error in argument parsing"));
388 	      break;
389 	    }
390 
391           f &= ~lobit;
392 
393           if (f)
394             {
395               while (ISSPACE (*op_end))
396                 op_end++;
397 
398               if (*op_end != ',')
399                 {
400                   as_bad (_("expected comma separator"));
401                   ignore_rest_of_line ();
402                 }
403 
404               op_end++;
405               while (ISSPACE (*op_end))
406                 op_end++;
407             }
408         }
409     }
410 
411   if (*op_end != 0)
412     as_warn (_("extra stuff on line ignored"));
413 
414   can_sc = ft32_shortcode (b, &sc);
415 
416   if (!fixed && can_sc)
417     {
418       arg.X_op = O_constant;
419       arg.X_add_number = 0;
420       arg.X_add_symbol = NULL;
421       arg.X_op_symbol = NULL;
422       fix_new_exp (frag_now,
423                    (output - frag_now->fr_literal),
424                    2,
425                    &arg,
426                    0,
427                    BFD_RELOC_FT32_RELAX);
428     }
429 
430   output[idx++] = 0xff & (b >> 0);
431   output[idx++] = 0xff & (b >> 8);
432   output[idx++] = 0xff & (b >> 16);
433   output[idx++] = 0xff & (b >> 24);
434 
435   dwarf2_emit_insn (4);
436 
437   while (ISSPACE (*op_end))
438     op_end++;
439 
440   if (*op_end != 0)
441     as_warn ("extra stuff on line ignored");
442 
443   if (pending_reloc)
444     as_bad ("Something forgot to clean up\n");
445 }
446 
447 /* Turn a string in input_line_pointer into a floating point constant
448    of type type, and store the appropriate bytes in *LITP.  The number
449    of LITTLENUMS emitted is stored in *SIZEP .  An error message is
450    returned, or NULL on OK.  */
451 
452 const char *
md_atof(int type,char * litP,int * sizeP)453 md_atof (int type, char *litP, int *sizeP)
454 {
455   int prec;
456   LITTLENUM_TYPE words[4];
457   char *t;
458   int i;
459 
460   switch (type)
461     {
462     case 'f':
463       prec = 2;
464       break;
465 
466     case 'd':
467       prec = 4;
468       break;
469 
470     default:
471       *sizeP = 0;
472       return _("bad call to md_atof");
473     }
474 
475   t = atof_ieee (input_line_pointer, type, words);
476   if (t)
477     input_line_pointer = t;
478 
479   *sizeP = prec * 2;
480 
481   for (i = prec - 1; i >= 0; i--)
482     {
483       md_number_to_chars (litP, (valueT) words[i], 2);
484       litP += 2;
485     }
486 
487   return NULL;
488 }
489 
490 const char *md_shortopts = "";
491 
492 struct option md_longopts[] =
493 {
494 #define OPTION_NORELAX (OPTION_MD_BASE)
495   {"norelax", no_argument, NULL, OPTION_NORELAX},
496   {"no-relax", no_argument, NULL, OPTION_NORELAX},
497   {NULL, no_argument, NULL, 0}
498 };
499 size_t md_longopts_size = sizeof (md_longopts);
500 
501 /* We have no target specific options yet, so these next
502    two functions are empty.  */
503 int
md_parse_option(int c ATTRIBUTE_UNUSED,const char * arg ATTRIBUTE_UNUSED)504 md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
505 {
506   switch (c)
507     {
508     case OPTION_NORELAX:
509       norelax = 1;
510       break;
511 
512     default:
513       return 0;
514     }
515 
516   return 1;
517 }
518 
519 void
md_show_usage(FILE * stream ATTRIBUTE_UNUSED)520 md_show_usage (FILE *stream ATTRIBUTE_UNUSED)
521 {
522   fprintf (stream, _("FT32 options:\n"));
523   fprintf (stream, _("\n\
524 -no-relax		don't relax relocations\n\
525 			\n"));
526 }
527 
528 /* Convert from target byte order to host byte order.  */
529 
530 static valueT
md_chars_to_number(char * buf,int n)531 md_chars_to_number (char * buf, int n)
532 {
533   valueT result = 0;
534   unsigned char * where = (unsigned char *) buf;
535 
536   while (n--)
537     {
538       result <<= 8;
539       result |= (where[n] & 255);
540     }
541 
542   return result;
543 }
544 
545 /* Apply a fixup to the object file.  */
546 
547 void
md_apply_fix(fixS * fixP ATTRIBUTE_UNUSED,valueT * valP ATTRIBUTE_UNUSED,segT seg ATTRIBUTE_UNUSED)548 md_apply_fix (fixS *fixP ATTRIBUTE_UNUSED,
549 	      valueT * valP ATTRIBUTE_UNUSED, segT seg ATTRIBUTE_UNUSED)
550 {
551   char *buf = fixP->fx_where + fixP->fx_frag->fr_literal;
552   long val = *valP;
553   long newval;
554 
555   if (linkrelax && fixP->fx_subsy)
556     {
557       /* For a subtraction relocation expression, generate one
558          of the DIFF relocs, with the value being the difference.
559          Note that a sym1 - sym2 expression is adjusted into a
560          section_start_sym + sym4_offset_from_section_start - sym1
561          expression. fixP->fx_addsy holds the section start symbol,
562          fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
563          holds sym1. Calculate the current difference and write value,
564          but leave fx_offset as is - during relaxation,
565          fx_offset - value gives sym1's value.  */
566 
567        switch (fixP->fx_r_type)
568          {
569            case BFD_RELOC_32:
570              fixP->fx_r_type = BFD_RELOC_FT32_DIFF32;
571              break;
572            default:
573              as_bad_subtract (fixP);
574              break;
575          }
576 
577       val = S_GET_VALUE (fixP->fx_addsy) +
578           fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy);
579       *valP = val;
580 
581       fixP->fx_subsy = NULL;
582   }
583 
584   /* We don't actually support subtracting a symbol.  */
585   if (fixP->fx_subsy != (symbolS *) NULL)
586     as_bad_subtract (fixP);
587 
588   switch (fixP->fx_r_type)
589     {
590     case BFD_RELOC_FT32_DIFF32:
591     case BFD_RELOC_32:
592       buf[3] = val >> 24;
593       buf[2] = val >> 16;
594       buf[1] = val >> 8;
595       buf[0] = val >> 0;
596       break;
597 
598     case BFD_RELOC_16:
599       buf[1] = val >> 8;
600       buf[0] = val >> 0;
601       break;
602 
603     case BFD_RELOC_8:
604       *buf = val;
605       break;
606 
607     case BFD_RELOC_FT32_10:
608       if (!val)
609 	break;
610       newval = md_chars_to_number (buf, 2);
611       newval |= (val & ((1 << 10) - 1)) << FT32_FLD_RIMM_BIT;
612       md_number_to_chars (buf, newval, 2);
613       break;
614 
615     case BFD_RELOC_FT32_20:
616       if (!val)
617 	break;
618       newval = md_chars_to_number (buf, 3);
619       newval |= val & ((1 << 20) - 1);
620       md_number_to_chars (buf, newval, 3);
621       break;
622 
623     case BFD_RELOC_FT32_15:
624       if (!val)
625 	break;
626       newval = md_chars_to_number (buf, 2);
627       newval |= val & ((1 << 15) - 1);
628       md_number_to_chars (buf, newval, 2);
629       break;
630 
631     case BFD_RELOC_FT32_17:
632       if (!val)
633 	break;
634       newval = md_chars_to_number (buf, 3);
635       newval |= val & ((1 << 17) - 1);
636       md_number_to_chars (buf, newval, 3);
637       break;
638 
639     case BFD_RELOC_FT32_18:
640       if (!val)
641 	break;
642       newval = md_chars_to_number (buf, 4);
643       newval |= (val >> 2) & ((1 << 18) - 1);
644       md_number_to_chars (buf, newval, 4);
645       break;
646 
647     case BFD_RELOC_FT32_RELAX:
648       break;
649 
650     default:
651       abort ();
652     }
653 
654   if (fixP->fx_addsy == NULL && fixP->fx_pcrel == 0)
655     fixP->fx_done = 1;
656 }
657 
658 void
md_number_to_chars(char * ptr,valueT use,int nbytes)659 md_number_to_chars (char *ptr, valueT use, int nbytes)
660 {
661   number_to_chars_littleendian (ptr, use, nbytes);
662 }
663 
664 /* Generate a machine-dependent relocation.  */
665 
666 arelent *
tc_gen_reloc(asection * section ATTRIBUTE_UNUSED,fixS * fixP)667 tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP)
668 {
669   arelent *relP;
670   bfd_reloc_code_real_type code;
671 
672   switch (fixP->fx_r_type)
673     {
674     case BFD_RELOC_32:
675     case BFD_RELOC_16:
676     case BFD_RELOC_8:
677     case BFD_RELOC_FT32_10:
678     case BFD_RELOC_FT32_20:
679     case BFD_RELOC_FT32_15:
680     case BFD_RELOC_FT32_17:
681     case BFD_RELOC_FT32_18:
682     case BFD_RELOC_FT32_RELAX:
683     case BFD_RELOC_FT32_DIFF32:
684       code = fixP->fx_r_type;
685       break;
686     default:
687       as_bad_where (fixP->fx_file, fixP->fx_line,
688 		    _("Semantics error.  This type of operand can not be "
689                       "relocated, it must be an assembly-time constant"));
690       return NULL;
691     }
692 
693   relP = XNEW (arelent);
694   gas_assert (relP != 0);
695   relP->sym_ptr_ptr = XNEW (asymbol *);
696   *relP->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
697   relP->address = fixP->fx_frag->fr_address + fixP->fx_where;
698 
699   relP->addend = fixP->fx_offset;
700 
701   relP->howto = bfd_reloc_type_lookup (stdoutput, code);
702   if (! relP->howto)
703     {
704       const char *name;
705 
706       name = S_GET_NAME (fixP->fx_addsy);
707       if (name == NULL)
708 	name = _("<unknown>");
709       as_fatal (_("Cannot generate relocation type for symbol %s, code %s"),
710 		name, bfd_get_reloc_code_name (code));
711     }
712 
713   return relP;
714 }
715 
716 /* TC_FORCE_RELOCATION hook */
717 
718 static bool
relaxable_section(asection * sec)719 relaxable_section (asection *sec)
720 {
721   return ((sec->flags & SEC_DEBUGGING) == 0
722           && (sec->flags & SEC_CODE) != 0
723           && (sec->flags & SEC_ALLOC) != 0);
724 }
725 
726 /* Does whatever the xtensa port does.  */
727 
728 int
ft32_validate_fix_sub(fixS * fix)729 ft32_validate_fix_sub (fixS *fix)
730 {
731   segT add_symbol_segment, sub_symbol_segment;
732 
733   /* The difference of two symbols should be resolved by the assembler when
734      linkrelax is not set.  If the linker may relax the section containing
735      the symbols, then an Xtensa DIFF relocation must be generated so that
736      the linker knows to adjust the difference value.  */
737   if (!linkrelax || fix->fx_addsy == NULL)
738     return 0;
739 
740   /* Make sure both symbols are in the same segment, and that segment is
741      "normal" and relaxable.  If the segment is not "normal", then the
742      fix is not valid.  If the segment is not "relaxable", then the fix
743      should have been handled earlier.  */
744   add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy);
745   if (! SEG_NORMAL (add_symbol_segment) ||
746       ! relaxable_section (add_symbol_segment))
747     return 0;
748 
749   sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy);
750   return (sub_symbol_segment == add_symbol_segment);
751 }
752 
753 /* TC_FORCE_RELOCATION hook */
754 
755 /* If linkrelax is turned on, and the symbol to relocate
756    against is in a relaxable segment, don't compute the value -
757    generate a relocation instead.  */
758 
759 int
ft32_force_relocation(fixS * fix)760 ft32_force_relocation (fixS *fix)
761 {
762   if (linkrelax && fix->fx_addsy
763       && relaxable_section (S_GET_SEGMENT (fix->fx_addsy)))
764     {
765       return 1;
766     }
767 
768   return generic_force_reloc (fix);
769 }
770 
771 bool
ft32_allow_local_subtract(expressionS * left,expressionS * right,segT section)772 ft32_allow_local_subtract (expressionS * left,
773 			   expressionS * right,
774 			   segT section)
775 {
776   /* If we are not in relaxation mode, subtraction is OK.  */
777   if (!linkrelax)
778     return true;
779 
780   /* If the symbols are not in a code section then they are OK.  */
781   if ((section->flags & SEC_CODE) == 0)
782     return true;
783 
784   if (left->X_add_symbol == right->X_add_symbol)
785     return true;
786 
787   /* We have to assume that there may be instructions between the
788      two symbols and that relaxation may increase the distance between
789      them.  */
790   return false;
791 }
792