Fix calculation of address for pc rel operations.
[deliverable/binutils-gdb.git] / gas / config / tc-fr30.c
1 /* tc-fr30.c -- Assembler for the Fujitsu FR30.
2 Copyright (C) 1998 Free Software Foundation.
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 2, 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, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include "as.h"
24 #include "subsegs.h"
25 #include "symcat.h"
26 #include "cgen-opc.h"
27 #include "cgen.h"
28
29 /* Structure to hold all of the different components describing
30 an individual instruction. */
31 typedef struct
32 {
33 const CGEN_INSN * insn;
34 const CGEN_INSN * orig_insn;
35 CGEN_FIELDS fields;
36 #if CGEN_INT_INSN_P
37 CGEN_INSN_INT buffer [1];
38 #define INSN_VALUE(buf) (*(buf))
39 #else
40 unsigned char buffer [CGEN_MAX_INSN_SIZE];
41 #define INSN_VALUE(buf) (buf)
42 #endif
43 char * addr;
44 fragS * frag;
45 int num_fixups;
46 fixS * fixups [GAS_CGEN_MAX_FIXUPS];
47 int indices [MAX_OPERAND_INSTANCES];
48 }
49 fr30_insn;
50
51 const char comment_chars[] = ";";
52 const char line_comment_chars[] = "#";
53 const char line_separator_chars[] = "";
54 const char EXP_CHARS[] = "eE";
55 const char FLT_CHARS[] = "dD";
56 \f
57 #define FR30_SHORTOPTS ""
58 const char * md_shortopts = FR30_SHORTOPTS;
59
60 struct option md_longopts[] =
61 {
62 {NULL, no_argument, NULL, 0}
63 };
64 size_t md_longopts_size = sizeof (md_longopts);
65
66 int
67 md_parse_option (c, arg)
68 int c;
69 char * arg;
70 {
71 switch (c)
72 {
73 default:
74 return 0;
75 }
76 return 1;
77 }
78
79 void
80 md_show_usage (stream)
81 FILE * stream;
82 {
83 fprintf (stream, _(" FR30 specific command line options:\n"));
84 }
85
86 /* The target specific pseudo-ops which we support. */
87 const pseudo_typeS md_pseudo_table[] =
88 {
89 { "word", cons, 4 },
90 { NULL, NULL, 0 }
91 };
92
93 \f
94 void
95 md_begin ()
96 {
97 flagword applicable;
98 segT seg;
99 subsegT subseg;
100
101 /* Initialize the `cgen' interface. */
102
103 /* Set the machine number and endian. */
104 gas_cgen_opcode_desc = fr30_cgen_opcode_open (bfd_mach_fr30, CGEN_ENDIAN_BIG);
105 fr30_cgen_init_asm (gas_cgen_opcode_desc);
106
107 /* This is a callback from cgen to gas to parse operands. */
108 cgen_set_parse_operand_fn (gas_cgen_opcode_desc, gas_cgen_parse_operand);
109 }
110
111 void
112 md_assemble (str)
113 char * str;
114 {
115 fr30_insn insn;
116 char * errmsg;
117 char * str2 = NULL;
118
119 /* Initialize GAS's cgen interface for a new instruction. */
120 gas_cgen_init_parse ();
121
122 insn.insn = fr30_cgen_assemble_insn
123 (gas_cgen_opcode_desc, str, & insn.fields, insn.buffer, & errmsg);
124
125 if (!insn.insn)
126 {
127 as_bad (errmsg);
128 return;
129 }
130
131 /* Doesn't really matter what we pass for RELAX_P here. */
132 gas_cgen_finish_insn (insn.insn, insn.buffer,
133 CGEN_FIELDS_BITSIZE (& insn.fields), 1, NULL);
134 }
135
136 /* The syntax in the manual says constants begin with '#'.
137 We just ignore it. */
138
139 void
140 md_operand (expressionP)
141 expressionS * expressionP;
142 {
143 if (* input_line_pointer == '#')
144 {
145 input_line_pointer ++;
146 expression (expressionP);
147 }
148 }
149
150 valueT
151 md_section_align (segment, size)
152 segT segment;
153 valueT size;
154 {
155 int align = bfd_get_section_alignment (stdoutput, segment);
156 return ((size + (1 << align) - 1) & (-1 << align));
157 }
158
159 symbolS *
160 md_undefined_symbol (name)
161 char * name;
162 {
163 return 0;
164 }
165 \f
166 /* Interface to relax_segment. */
167
168 /* FIXME: Build table by hand, get it working, then machine generate. */
169
170 const relax_typeS md_relax_table[] =
171 {
172 /* The fields are:
173 1) most positive reach of this state,
174 2) most negative reach of this state,
175 3) how many bytes this mode will add to the size of the current frag
176 4) which index into the table to try if we can't fit into this one. */
177
178 /* The first entry must be unused because an `rlx_more' value of zero ends
179 each list. */
180 {1, 1, 0, 0},
181
182 /* The displacement used by GAS is from the end of the 2 byte insn,
183 so we subtract 2 from the following. */
184 /* 16 bit insn, 8 bit disp -> 10 bit range.
185 This doesn't handle a branch in the right slot at the border:
186 the "& -4" isn't taken into account. It's not important enough to
187 complicate things over it, so we subtract an extra 2 (or + 2 in -ve
188 case). */
189 {511 - 2 - 2, -512 - 2 + 2, 0, 2 },
190 /* 32 bit insn, 24 bit disp -> 26 bit range. */
191 {0x2000000 - 1 - 2, -0x2000000 - 2, 2, 0 },
192 /* Same thing, but with leading nop for alignment. */
193 {0x2000000 - 1 - 2, -0x2000000 - 2, 4, 0 }
194 };
195
196 long
197 fr30_relax_frag (fragP, stretch)
198 fragS * fragP;
199 long stretch;
200 {
201 /* Address of branch insn. */
202 long address = fragP->fr_address + fragP->fr_fix - 2;
203 long growth = 0;
204
205 /* Keep 32 bit insns aligned on 32 bit boundaries. */
206 if (fragP->fr_subtype == 2)
207 {
208 if ((address & 3) != 0)
209 {
210 fragP->fr_subtype = 3;
211 growth = 2;
212 }
213 }
214 else if (fragP->fr_subtype == 3)
215 {
216 if ((address & 3) == 0)
217 {
218 fragP->fr_subtype = 2;
219 growth = -2;
220 }
221 }
222 else
223 {
224 growth = relax_frag (fragP, stretch);
225
226 /* Long jump on odd halfword boundary? */
227 if (fragP->fr_subtype == 2 && (address & 3) != 0)
228 {
229 fragP->fr_subtype = 3;
230 growth += 2;
231 }
232 }
233
234 return growth;
235 }
236
237 /* Return an initial guess of the length by which a fragment must grow to
238 hold a branch to reach its destination.
239 Also updates fr_type/fr_subtype as necessary.
240
241 Called just before doing relaxation.
242 Any symbol that is now undefined will not become defined.
243 The guess for fr_var is ACTUALLY the growth beyond fr_fix.
244 Whatever we do to grow fr_fix or fr_var contributes to our returned value.
245 Although it may not be explicit in the frag, pretend fr_var starts with a
246 0 value. */
247
248 int
249 md_estimate_size_before_relax (fragP, segment)
250 fragS * fragP;
251 segT segment;
252 {
253 int old_fr_fix = fragP->fr_fix;
254
255 /* The only thing we have to handle here are symbols outside of the
256 current segment. They may be undefined or in a different segment in
257 which case linker scripts may place them anywhere.
258 However, we can't finish the fragment here and emit the reloc as insn
259 alignment requirements may move the insn about. */
260
261 if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
262 {
263 /* The symbol is undefined in this segment.
264 Change the relaxation subtype to the max allowable and leave
265 all further handling to md_convert_frag. */
266 fragP->fr_subtype = 2;
267
268 #if 0 /* Can't use this, but leave in for illustration. */
269 /* Change 16 bit insn to 32 bit insn. */
270 fragP->fr_opcode[0] |= 0x80;
271
272 /* Increase known (fixed) size of fragment. */
273 fragP->fr_fix += 2;
274
275 /* Create a relocation for it. */
276 fix_new (fragP, old_fr_fix, 4,
277 fragP->fr_symbol,
278 fragP->fr_offset, 1 /* pcrel */,
279 /* FIXME: Can't use a real BFD reloc here.
280 gas_cgen_md_apply_fix3 can't handle it. */
281 BFD_RELOC_FR30_26_PCREL);
282
283 /* Mark this fragment as finished. */
284 frag_wane (fragP);
285 #else
286 {
287 const CGEN_INSN * insn;
288 int i;
289
290 /* Update the recorded insn.
291 Fortunately we don't have to look very far.
292 FIXME: Change this to record in the instruction the next higher
293 relaxable insn to use. */
294 for (i = 0, insn = fragP->fr_cgen.insn; i < 4; i++, insn++)
295 {
296 if ((strcmp (CGEN_INSN_MNEMONIC (insn),
297 CGEN_INSN_MNEMONIC (fragP->fr_cgen.insn))
298 == 0)
299 && CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX))
300 break;
301 }
302 if (i == 4)
303 abort ();
304
305 fragP->fr_cgen.insn = insn;
306 return 2;
307 }
308 #endif
309 }
310
311 return (fragP->fr_var + fragP->fr_fix - old_fr_fix);
312 }
313
314 /* *fragP has been relaxed to its final size, and now needs to have
315 the bytes inside it modified to conform to the new size.
316
317 Called after relaxation is finished.
318 fragP->fr_type == rs_machine_dependent.
319 fragP->fr_subtype is the subtype of what the address relaxed to. */
320
321 void
322 md_convert_frag (abfd, sec, fragP)
323 bfd * abfd;
324 segT sec;
325 fragS * fragP;
326 {
327 #if 0
328 char * opcode;
329 char * displacement;
330 int target_address;
331 int opcode_address;
332 int extension;
333 int addend;
334
335 opcode = fragP->fr_opcode;
336
337 /* Address opcode resides at in file space. */
338 opcode_address = fragP->fr_address + fragP->fr_fix - 2;
339
340 switch (fragP->fr_subtype)
341 {
342 case 1 :
343 extension = 0;
344 displacement = & opcode[1];
345 break;
346 case 2 :
347 opcode[0] |= 0x80;
348 extension = 2;
349 displacement = & opcode[1];
350 break;
351 case 3 :
352 opcode[2] = opcode[0] | 0x80;
353 md_number_to_chars (opcode, PAR_NOP_INSN, 2);
354 opcode_address += 2;
355 extension = 4;
356 displacement = & opcode[3];
357 break;
358 default :
359 abort ();
360 }
361
362 if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
363 {
364 /* symbol must be resolved by linker */
365 if (fragP->fr_offset & 3)
366 as_warn (_("Addend to unresolved symbol not on word boundary."));
367 addend = fragP->fr_offset >> 2;
368 }
369 else
370 {
371 /* Address we want to reach in file space. */
372 target_address = S_GET_VALUE (fragP->fr_symbol) + fragP->fr_offset;
373 target_address += fragP->fr_symbol->sy_frag->fr_address;
374 addend = (target_address - (opcode_address & -4)) >> 2;
375 }
376
377 /* Create a relocation for symbols that must be resolved by the linker.
378 Otherwise output the completed insn. */
379
380 if (S_GET_SEGMENT (fragP->fr_symbol) != sec)
381 {
382 assert (fragP->fr_subtype != 1);
383 assert (fragP->fr_cgen.insn != 0);
384 gas_cgen_record_fixup (fragP,
385 /* Offset of branch insn in frag. */
386 fragP->fr_fix + extension - 4,
387 fragP->fr_cgen.insn,
388 4 /*length*/,
389 /* FIXME: quick hack */
390 #if 0
391 CGEN_OPERAND_ENTRY (fragP->fr_cgen.opindex),
392 #else
393 CGEN_OPERAND_ENTRY (FR30_OPERAND_DISP24),
394 #endif
395 fragP->fr_cgen.opinfo,
396 fragP->fr_symbol, fragP->fr_offset);
397 }
398
399 #define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3)
400
401 md_number_to_chars (displacement, (valueT) addend,
402 SIZE_FROM_RELAX_STATE (fragP->fr_subtype));
403
404 fragP->fr_fix += extension;
405 #endif
406 }
407 \f
408 /* Functions concerning relocs. */
409
410 /* The location from which a PC relative jump should be calculated,
411 given a PC relative reloc. */
412
413 long
414 md_pcrel_from_section (fixP, sec)
415 fixS * fixP;
416 segT sec;
417 {
418 if (fixP->fx_addsy != (symbolS *) NULL
419 && (! S_IS_DEFINED (fixP->fx_addsy)
420 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
421 {
422 /* The symbol is undefined (or is defined but not in this section).
423 Let the linker figure it out. */
424 return 0;
425 }
426
427 return (fixP->fx_frag->fr_address + fixP->fx_where + 2) & ~1;
428 }
429
430 /* Return the bfd reloc type for OPERAND of INSN at fixup FIXP.
431 Returns BFD_RELOC_NONE if no reloc type can be found.
432 *FIXP may be modified if desired. */
433
434 bfd_reloc_code_real_type
435 md_cgen_lookup_reloc (insn, operand, fixP)
436 const CGEN_INSN * insn;
437 const CGEN_OPERAND * operand;
438 fixS * fixP;
439 {
440 switch (CGEN_OPERAND_TYPE (operand))
441 {
442 case FR30_OPERAND_LABEL9: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_9_PCREL;
443 case FR30_OPERAND_LABEL12: fixP->fx_pcrel = 1; return BFD_RELOC_FR30_12_PCREL;
444 case FR30_OPERAND_DISP10: return BFD_RELOC_FR30_10_IN_8;
445 case FR30_OPERAND_DISP9: return BFD_RELOC_FR30_9_IN_8;
446 case FR30_OPERAND_DISP8: return BFD_RELOC_FR30_8_IN_8;
447 case FR30_OPERAND_UDISP6: return BFD_RELOC_FR30_6_IN_4;
448 case FR30_OPERAND_I8: return BFD_RELOC_8;
449 case FR30_OPERAND_I32: return BFD_RELOC_32;
450 /* waiting for this to be defined by Dave....
451 case FR30_OPERAND_I20: return BFD_RELOC_FR30_20;
452 */
453 default : /* avoid -Wall warning */
454 break;
455 }
456
457 return BFD_RELOC_NONE;
458 }
459
460
461 /* Return BFD reloc type from opinfo field in a fixS.
462 It's tricky using fx_r_type in fr30_frob_file because the values
463 are BFD_RELOC_UNUSED + operand number. */
464 #define FX_OPINFO_R_TYPE(f) ((f)->tc_fix_data.opinfo)
465
466 /* See whether we need to force a relocation into the output file.
467 This is used to force out switch and PC relative relocations when
468 relaxing. */
469
470 int
471 fr30_force_relocation (fix)
472 fixS * fix;
473 {
474 if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT
475 || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
476 return 1;
477
478 return fix->fx_pcrel;
479 }
480 \f
481 /* Write a value out to the object file, using the appropriate endianness. */
482
483 void
484 md_number_to_chars (buf, val, n)
485 char * buf;
486 valueT val;
487 int n;
488 {
489 number_to_chars_bigendian (buf, val, n);
490 }
491
492 /* Turn a string in input_line_pointer into a floating point constant of type
493 type, and store the appropriate bytes in *litP. The number of LITTLENUMS
494 emitted is stored in *sizeP . An error message is returned, or NULL on OK.
495 */
496
497 /* Equal to MAX_PRECISION in atof-ieee.c */
498 #define MAX_LITTLENUMS 6
499
500 char *
501 md_atof (type, litP, sizeP)
502 char type;
503 char * litP;
504 int * sizeP;
505 {
506 int i;
507 int prec;
508 LITTLENUM_TYPE words [MAX_LITTLENUMS];
509 char * t;
510 char * atof_ieee ();
511
512 switch (type)
513 {
514 case 'f':
515 case 'F':
516 case 's':
517 case 'S':
518 prec = 2;
519 break;
520
521 case 'd':
522 case 'D':
523 case 'r':
524 case 'R':
525 prec = 4;
526 break;
527
528 /* FIXME: Some targets allow other format chars for bigger sizes here. */
529
530 default:
531 * sizeP = 0;
532 return _("Bad call to md_atof()");
533 }
534
535 t = atof_ieee (input_line_pointer, type, words);
536 if (t)
537 input_line_pointer = t;
538 * sizeP = prec * sizeof (LITTLENUM_TYPE);
539
540 for (i = 0; i < prec; i++)
541 {
542 md_number_to_chars (litP, (valueT) words[i],
543 sizeof (LITTLENUM_TYPE));
544 litP += sizeof (LITTLENUM_TYPE);
545 }
546
547 return 0;
548 }
549
550 /* Worker function for fr30_is_colon_insn(). */
551 static char
552 restore_colon (advance_i_l_p_by)
553 int advance_i_l_p_by;
554 {
555 char c;
556
557 /* Restore the colon, and advance input_line_pointer to
558 the end of the new symbol. */
559 * input_line_pointer = ':';
560 input_line_pointer += advance_i_l_p_by;
561 c = * input_line_pointer;
562 * input_line_pointer = 0;
563
564 return c;
565 }
566
567 /* Determines if the symbol starting at START and ending in
568 a colon that was at the location pointed to by INPUT_LINE_POINTER
569 (but which has now been replaced bu a NUL) is in fact an
570 LDI:8, LDI:20, LDI:32, CALL:D. JMP:D, RET:D or Bcc:D instruction.
571 If it is, then it restores the colon, advances INPUT_LINE_POINTER
572 to the real end of the instruction/symbol, and returns the character
573 that really terminated the symbol. Otherwise it returns 0. */
574 char
575 fr30_is_colon_insn (start)
576 char * start;
577 {
578 char * i_l_p = input_line_pointer;
579
580 /* Check to see if the symbol parsed so far is 'ldi' */
581 if ( (start[0] != 'l' && start[0] != 'L')
582 || (start[1] != 'd' && start[1] != 'D')
583 || (start[2] != 'i' && start[2] != 'I')
584 || start[3] != 0)
585 {
586 /* Nope - check to see a 'd' follows the colon. */
587 if ( (i_l_p[1] == 'd' || i_l_p[1] == 'D')
588 && (i_l_p[2] == ' ' || i_l_p[2] == '\t' || i_l_p[2] == '\n'))
589 {
590 /* Yup - it might be delay slot instruction. */
591 int i;
592 static char * delay_insns [] =
593 {
594 "call", "jmp", "ret", "bra", "bno",
595 "beq", "bne", "bc", "bnc", "bn",
596 "bp", "bv", "bnv", "blt", "bge",
597 "ble", "bgt", "bls", "bhi"
598 };
599
600 for (i = sizeof (delay_insns) / sizeof (delay_insns[0]); i--;)
601 {
602 char * insn = delay_insns[i];
603 int len = strlen (insn);
604
605 if (start [len] != 0)
606 continue;
607
608 while (len --)
609 if (tolower (start [len]) != insn [len])
610 break;
611
612 if (len == -1)
613 return restore_colon (1);
614 }
615 }
616
617 /* Nope - it is a normal label. */
618 return 0;
619 }
620
621 /* Check to see if the text following the colon is '8' */
622 if (i_l_p[1] == '8' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
623 return restore_colon (2);
624
625 /* Check to see if the text following the colon is '20' */
626 else if (i_l_p[1] == '2' && i_l_p[2] =='0' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
627 return restore_colon (3);
628
629 /* Check to see if the text following the colon is '32' */
630 else if (i_l_p[1] == '3' && i_l_p[2] =='2' && (i_l_p[3] == ' ' || i_l_p[3] == '\t'))
631 return restore_colon (3);
632
633 return 0;
634 }
This page took 0.062719 seconds and 5 git commands to generate.