[.]
[deliverable/binutils-gdb.git] / gas / config / tc-rl78.c
1 /* tc-rl78.c -- Assembler for the Renesas RL78
2 Copyright 2011
3 Free Software Foundation, Inc.
4
5 This file is part of GAS, the GNU Assembler.
6
7 GAS is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GAS is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GAS; see the file COPYING. If not, write to the Free
19 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
20 02110-1301, USA. */
21
22 #include "as.h"
23 #include "struc-symbol.h"
24 #include "obstack.h"
25 #include "safe-ctype.h"
26 #include "dwarf2dbg.h"
27 #include "libbfd.h"
28 #include "elf/common.h"
29 #include "elf/rl78.h"
30 #include "rl78-defs.h"
31 #include "filenames.h"
32 #include "listing.h"
33 #include "sb.h"
34 #include "macro.h"
35
36 const char comment_chars[] = ";";
37 /* Note that input_file.c hand checks for '#' at the beginning of the
38 first line of the input file. This is because the compiler outputs
39 #NO_APP at the beginning of its output. */
40 const char line_comment_chars[] = "#";
41 const char line_separator_chars[] = "|";
42
43 const char EXP_CHARS[] = "eE";
44 const char FLT_CHARS[] = "dD";
45
46 /*------------------------------------------------------------------*/
47
48 char * rl78_lex_start;
49 char * rl78_lex_end;
50
51 typedef struct rl78_bytesT
52 {
53 char prefix[1];
54 int n_prefix;
55 char base[4];
56 int n_base;
57 char ops[8];
58 int n_ops;
59 struct
60 {
61 expressionS exp;
62 char offset;
63 char nbits;
64 char type; /* RL78REL_*. */
65 int reloc;
66 fixS * fixP;
67 } fixups[2];
68 int n_fixups;
69 struct
70 {
71 char type;
72 char field_pos;
73 char val_ofs;
74 } relax[2];
75 int n_relax;
76 int link_relax;
77 fixS *link_relax_fixP;
78 char times_grown;
79 char times_shrank;
80 } rl78_bytesT;
81
82 static rl78_bytesT rl78_bytes;
83
84 static void
85 rl78_fixup (expressionS exp, int offsetbits, int nbits, int type)
86 {
87 rl78_bytes.fixups[rl78_bytes.n_fixups].exp = exp;
88 rl78_bytes.fixups[rl78_bytes.n_fixups].offset = offsetbits;
89 rl78_bytes.fixups[rl78_bytes.n_fixups].nbits = nbits;
90 rl78_bytes.fixups[rl78_bytes.n_fixups].type = type;
91 rl78_bytes.fixups[rl78_bytes.n_fixups].reloc = exp.X_md;
92 rl78_bytes.n_fixups ++;
93 }
94
95 #define rl78_field_fixup(exp, offset, nbits, type) \
96 rl78_fixup (exp, offset + 8 * rl78_bytes.n_prefix), nbits, type)
97
98 #define rl78_op_fixup(exp, offset, nbits, type) \
99 rl78_fixup (exp, offset + 8 * (rl78_bytes.n_prefix + rl78_bytes.n_base), nbits, type)
100
101 void
102 rl78_prefix (int p)
103 {
104 rl78_bytes.prefix[0] = p;
105 rl78_bytes.n_prefix = 1;
106 }
107
108 int
109 rl78_has_prefix ()
110 {
111 return rl78_bytes.n_prefix;
112 }
113
114 void
115 rl78_base1 (int b1)
116 {
117 rl78_bytes.base[0] = b1;
118 rl78_bytes.n_base = 1;
119 }
120
121 void
122 rl78_base2 (int b1, int b2)
123 {
124 rl78_bytes.base[0] = b1;
125 rl78_bytes.base[1] = b2;
126 rl78_bytes.n_base = 2;
127 }
128
129 void
130 rl78_base3 (int b1, int b2, int b3)
131 {
132 rl78_bytes.base[0] = b1;
133 rl78_bytes.base[1] = b2;
134 rl78_bytes.base[2] = b3;
135 rl78_bytes.n_base = 3;
136 }
137
138 void
139 rl78_base4 (int b1, int b2, int b3, int b4)
140 {
141 rl78_bytes.base[0] = b1;
142 rl78_bytes.base[1] = b2;
143 rl78_bytes.base[2] = b3;
144 rl78_bytes.base[3] = b4;
145 rl78_bytes.n_base = 4;
146 }
147
148 #define F_PRECISION 2
149
150 void
151 rl78_op (expressionS exp, int nbytes, int type)
152 {
153 int v = 0;
154
155 if ((exp.X_op == O_constant || exp.X_op == O_big)
156 && type != RL78REL_PCREL)
157 {
158 if (exp.X_op == O_big && exp.X_add_number <= 0)
159 {
160 LITTLENUM_TYPE w[2];
161 char * ip = rl78_bytes.ops + rl78_bytes.n_ops;
162
163 gen_to_words (w, F_PRECISION, 8);
164 ip[3] = w[0] >> 8;
165 ip[2] = w[0];
166 ip[1] = w[1] >> 8;
167 ip[0] = w[1];
168 rl78_bytes.n_ops += 4;
169 }
170 else
171 {
172 v = exp.X_add_number;
173 while (nbytes)
174 {
175 rl78_bytes.ops[rl78_bytes.n_ops++] =v & 0xff;
176 v >>= 8;
177 nbytes --;
178 }
179 }
180 }
181 else
182 {
183 rl78_op_fixup (exp, rl78_bytes.n_ops * 8, nbytes * 8, type);
184 memset (rl78_bytes.ops + rl78_bytes.n_ops, 0, nbytes);
185 rl78_bytes.n_ops += nbytes;
186 }
187 }
188
189 /* This gets complicated when the field spans bytes, because fields
190 are numbered from the MSB of the first byte as zero, and bits are
191 stored LSB towards the LSB of the byte. Thus, a simple four-bit
192 insertion of 12 at position 4 of 0x00 yields: 0x0b. A three-bit
193 insertion of b'MXL at position 7 is like this:
194
195 - - - - - - - - - - - - - - - -
196 M X L */
197
198 void
199 rl78_field (int val, int pos, int sz)
200 {
201 int valm;
202 int bytep, bitp;
203
204 if (sz > 0)
205 {
206 if (val < 0 || val >= (1 << sz))
207 as_bad (_("Value %d doesn't fit in unsigned %d-bit field"), val, sz);
208 }
209 else
210 {
211 sz = - sz;
212 if (val < -(1 << (sz - 1)) || val >= (1 << (sz - 1)))
213 as_bad (_("Value %d doesn't fit in signed %d-bit field"), val, sz);
214 }
215
216 /* This code points at 'M' in the above example. */
217 bytep = pos / 8;
218 bitp = pos % 8;
219
220 while (bitp + sz > 8)
221 {
222 int ssz = 8 - bitp;
223 int svalm;
224
225 svalm = val >> (sz - ssz);
226 svalm = svalm & ((1 << ssz) - 1);
227 svalm = svalm << (8 - bitp - ssz);
228 gas_assert (bytep < rl78_bytes.n_base);
229 rl78_bytes.base[bytep] |= svalm;
230
231 bitp = 0;
232 sz -= ssz;
233 bytep ++;
234 }
235 valm = val & ((1 << sz) - 1);
236 valm = valm << (8 - bitp - sz);
237 gas_assert (bytep < rl78_bytes.n_base);
238 rl78_bytes.base[bytep] |= valm;
239 }
240
241 /*------------------------------------------------------------------*/
242
243 #define RL78_SHORTOPTS ""
244 const char * md_shortopts = RL78_SHORTOPTS;
245
246 /* Assembler options. */
247 struct option md_longopts[] =
248 {
249 {NULL, no_argument, NULL, 0}
250 };
251 size_t md_longopts_size = sizeof (md_longopts);
252
253 int
254 md_parse_option (int c ATTRIBUTE_UNUSED, char * arg ATTRIBUTE_UNUSED)
255 {
256 return 0;
257 }
258
259 void
260 md_show_usage (FILE * stream ATTRIBUTE_UNUSED)
261 {
262 }
263
264
265 static void
266 s_bss (int ignore ATTRIBUTE_UNUSED)
267 {
268 int temp;
269
270 temp = get_absolute_expression ();
271 subseg_set (bss_section, (subsegT) temp);
272 demand_empty_rest_of_line ();
273 }
274
275 /* The target specific pseudo-ops which we support. */
276 const pseudo_typeS md_pseudo_table[] =
277 {
278 /* Our "standard" pseudos. */
279 { "double", float_cons, 'd' },
280 { "bss", s_bss, 0 },
281 { "3byte", cons, 3 },
282 { "int", cons, 4 },
283 { "word", cons, 4 },
284
285 /* End of list marker. */
286 { NULL, NULL, 0 }
287 };
288
289 void
290 md_begin (void)
291 {
292 }
293
294 void
295 rl78_md_end (void)
296 {
297 }
298
299 /* Write a value out to the object file, using the appropriate endianness. */
300 void
301 md_number_to_chars (char * buf, valueT val, int n)
302 {
303 number_to_chars_littleendian (buf, val, n);
304 }
305
306 static struct
307 {
308 char * fname;
309 int reloc;
310 }
311 reloc_functions[] =
312 {
313 { "lo16", BFD_RELOC_RL78_LO16 },
314 { "hi16", BFD_RELOC_RL78_HI16 },
315 { "hi8", BFD_RELOC_RL78_HI8 },
316 { 0, 0 }
317 };
318
319 void
320 md_operand (expressionS * exp ATTRIBUTE_UNUSED)
321 {
322 int reloc = 0;
323 int i;
324
325 for (i = 0; reloc_functions[i].fname; i++)
326 {
327 int flen = strlen (reloc_functions[i].fname);
328
329 if (input_line_pointer[0] == '%'
330 && strncasecmp (input_line_pointer + 1, reloc_functions[i].fname, flen) == 0
331 && input_line_pointer[flen + 1] == '(')
332 {
333 reloc = reloc_functions[i].reloc;
334 input_line_pointer += flen + 2;
335 break;
336 }
337 }
338 if (reloc == 0)
339 return;
340
341 expression (exp);
342 if (* input_line_pointer == ')')
343 input_line_pointer ++;
344
345 exp->X_md = reloc;
346 }
347
348 void
349 rl78_frag_init (fragS * fragP)
350 {
351 fragP->tc_frag_data = 0;
352 }
353
354 char *
355 md_atof (int type, char * litP, int * sizeP)
356 {
357 return ieee_md_atof (type, litP, sizeP, target_big_endian);
358 }
359
360 symbolS *
361 md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
362 {
363 return NULL;
364 }
365
366 #define APPEND(B, N_B) \
367 if (rl78_bytes.N_B) \
368 { \
369 memcpy (bytes + idx, rl78_bytes.B, rl78_bytes.N_B); \
370 idx += rl78_bytes.N_B; \
371 }
372
373
374 void
375 md_assemble (char * str)
376 {
377 char * bytes;
378 fragS * frag_then = frag_now;
379 int idx = 0;
380 int i;
381 int rel;
382 expressionS *exp;
383
384 /*printf("\033[32mASM: %s\033[0m\n", str);*/
385
386 dwarf2_emit_insn (0);
387
388 memset (& rl78_bytes, 0, sizeof (rl78_bytes));
389
390 rl78_lex_init (str, str + strlen (str));
391
392 rl78_parse ();
393
394 bytes = frag_more (rl78_bytes.n_prefix + rl78_bytes.n_base + rl78_bytes.n_ops);
395 frag_then = frag_now;
396
397 APPEND (prefix, n_prefix);
398 APPEND (base, n_base);
399 APPEND (ops, n_ops);
400
401 for (i = 0; i < rl78_bytes.n_fixups; i ++)
402 {
403 /* index: [nbytes][type] */
404 static int reloc_map[5][4] =
405 {
406 { 0, 0 },
407 { BFD_RELOC_8, BFD_RELOC_8_PCREL },
408 { BFD_RELOC_16, BFD_RELOC_16_PCREL },
409 { BFD_RELOC_24, BFD_RELOC_24_PCREL },
410 { BFD_RELOC_32, BFD_RELOC_32_PCREL },
411 };
412 fixS * f;
413
414 idx = rl78_bytes.fixups[i].offset / 8;
415 rel = reloc_map [rl78_bytes.fixups[i].nbits / 8][(int) rl78_bytes.fixups[i].type];
416
417 if (rl78_bytes.fixups[i].reloc)
418 rel = rl78_bytes.fixups[i].reloc;
419
420 if (frag_then->tc_frag_data)
421 exp = & frag_then->tc_frag_data->fixups[i].exp;
422 else
423 exp = & rl78_bytes.fixups[i].exp;
424
425 f = fix_new_exp (frag_then,
426 (char *) bytes + idx - frag_then->fr_literal,
427 rl78_bytes.fixups[i].nbits / 8,
428 exp,
429 rl78_bytes.fixups[i].type == RL78REL_PCREL ? 1 : 0,
430 rel);
431 if (frag_then->tc_frag_data)
432 frag_then->tc_frag_data->fixups[i].fixP = f;
433 }
434 }
435
436 void
437 rl78_cons_fix_new (fragS * frag,
438 int where,
439 int size,
440 expressionS * exp)
441 {
442 bfd_reloc_code_real_type type;
443
444 switch (size)
445 {
446 case 1:
447 type = BFD_RELOC_8;
448 break;
449 case 2:
450 type = BFD_RELOC_16;
451 break;
452 case 3:
453 type = BFD_RELOC_24;
454 break;
455 case 4:
456 type = BFD_RELOC_32;
457 break;
458 default:
459 as_bad (_("unsupported constant size %d\n"), size);
460 return;
461 }
462
463 if (exp->X_op == O_subtract && exp->X_op_symbol)
464 {
465 if (size != 4 && size != 2 && size != 1)
466 as_bad (_("difference of two symbols only supported with .long, .short, or .byte"));
467 else
468 type = BFD_RELOC_RL78_DIFF;
469 }
470
471 fix_new_exp (frag, where, (int) size, exp, 0, type);
472 }
473
474 /* No relaxation just yet */
475 int
476 md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, segT segment ATTRIBUTE_UNUSED)
477 {
478 return 0;
479 }
480 arelent **
481 tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp)
482 {
483 static arelent * reloc[8];
484 int rp;
485 int is_opcode = 0;
486
487 if (fixp->fx_r_type == BFD_RELOC_NONE)
488 {
489 reloc[0] = NULL;
490 return reloc;
491 }
492
493 if (fixp->fx_subsy
494 && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
495 {
496 fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy);
497 fixp->fx_subsy = NULL;
498 }
499
500 reloc[0] = (arelent *) xmalloc (sizeof (arelent));
501 reloc[0]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
502 * reloc[0]->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
503 reloc[0]->address = fixp->fx_frag->fr_address + fixp->fx_where;
504 reloc[0]->addend = fixp->fx_offset;
505
506 if (fixp->fx_r_type == BFD_RELOC_RL78_32_OP
507 && fixp->fx_subsy)
508 {
509 fixp->fx_r_type = BFD_RELOC_RL78_DIFF;
510 is_opcode = 1;
511 }
512
513 #define OPX(REL,SYM,ADD) \
514 reloc[rp] = (arelent *) xmalloc (sizeof (arelent)); \
515 reloc[rp]->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); \
516 reloc[rp]->howto = bfd_reloc_type_lookup (stdoutput, REL); \
517 reloc[rp]->addend = ADD; \
518 * reloc[rp]->sym_ptr_ptr = SYM; \
519 reloc[rp]->address = fixp->fx_frag->fr_address + fixp->fx_where; \
520 reloc[++rp] = NULL
521 #define OPSYM(SYM) OPX(BFD_RELOC_RL78_SYM, SYM, 0)
522 #define OPIMM(IMM) OPX(BFD_RELOC_RL78_SYM, abs_symbol.bsym, IMM)
523 #define OP(OP) OPX(BFD_RELOC_RL78_##OP, *reloc[0]->sym_ptr_ptr, 0)
524 #define SYM0() reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_RL78_SYM)
525
526 rp = 1;
527
528 /* Certain BFD relocations cannot be translated directly into
529 a single (non-Red Hat) RL78 relocation, but instead need
530 multiple RL78 relocations - handle them here. */
531 switch (fixp->fx_r_type)
532 {
533 case BFD_RELOC_RL78_DIFF:
534 SYM0 ();
535 OPSYM (symbol_get_bfdsym (fixp->fx_subsy));
536 OP(OP_SUBTRACT);
537
538 switch (fixp->fx_size)
539 {
540 case 1:
541 OP(ABS8);
542 break;
543 case 2:
544 OP (ABS16);
545 break;
546 case 4:
547 OP (ABS32);
548 break;
549 }
550 break;
551
552 case BFD_RELOC_RL78_NEG32:
553 SYM0 ();
554 OP (OP_NEG);
555 OP (ABS32);
556 break;
557
558 case BFD_RELOC_RL78_LO16:
559 SYM0 ();
560 OPIMM (0xffff);
561 OP (OP_AND);
562 OP (ABS16);
563 break;
564
565 case BFD_RELOC_RL78_HI16:
566 SYM0 ();
567 OPIMM (16);
568 OP (OP_SHRA);
569 OP (ABS16);
570 break;
571
572 case BFD_RELOC_RL78_HI8:
573 SYM0 ();
574 OPIMM (16);
575 OP (OP_SHRA);
576 OPIMM (0xff);
577 OP (OP_AND);
578 OP (ABS8);
579 break;
580
581 default:
582 reloc[0]->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
583 reloc[1] = NULL;
584 break;
585 }
586
587 return reloc;
588 }
589
590 int
591 rl78_validate_fix_sub (struct fix * f)
592 {
593 /* We permit the subtraction of two symbols in a few cases. */
594 /* mov #sym1-sym2, R3 */
595 if (f->fx_r_type == BFD_RELOC_RL78_32_OP)
596 return 1;
597 /* .long sym1-sym2 */
598 if (f->fx_r_type == BFD_RELOC_RL78_DIFF
599 && ! f->fx_pcrel
600 && (f->fx_size == 4 || f->fx_size == 2 || f->fx_size == 1))
601 return 1;
602 return 0;
603 }
604
605 long
606 md_pcrel_from_section (fixS * fixP, segT sec)
607 {
608 long rv;
609
610 if (fixP->fx_addsy != NULL
611 && (! S_IS_DEFINED (fixP->fx_addsy)
612 || S_GET_SEGMENT (fixP->fx_addsy) != sec))
613 /* The symbol is undefined (or is defined but not in this section).
614 Let the linker figure it out. */
615 return 0;
616
617 rv = fixP->fx_frag->fr_address + fixP->fx_where;
618 switch (fixP->fx_r_type)
619 {
620 case BFD_RELOC_8_PCREL:
621 rv += 1;
622 break;
623 case BFD_RELOC_16_PCREL:
624 rv += 2;
625 break;
626 default:
627 break;
628 }
629 return rv;
630 }
631
632 void
633 md_apply_fix (struct fix * f ATTRIBUTE_UNUSED,
634 valueT * t ATTRIBUTE_UNUSED,
635 segT s ATTRIBUTE_UNUSED)
636 {
637 char * op;
638 unsigned long val;
639
640 if (f->fx_addsy && S_FORCE_RELOC (f->fx_addsy, 1))
641 return;
642 if (f->fx_subsy && S_FORCE_RELOC (f->fx_subsy, 1))
643 return;
644
645 op = f->fx_frag->fr_literal + f->fx_where;
646 val = (unsigned long) * t;
647
648 switch (f->fx_r_type)
649 {
650 case BFD_RELOC_NONE:
651 break;
652
653 case BFD_RELOC_8:
654 case BFD_RELOC_8_PCREL:
655 op[0] = val;
656 break;
657
658 case BFD_RELOC_16:
659 case BFD_RELOC_16_PCREL:
660 op[0] = val;
661 op[1] = val >> 8;
662 break;
663
664 case BFD_RELOC_24:
665 op[0] = val;
666 op[1] = val >> 8;
667 op[2] = val >> 16;
668 break;
669
670 case BFD_RELOC_32:
671 case BFD_RELOC_RL78_DIFF:
672 op[0] = val;
673 op[1] = val >> 8;
674 op[2] = val >> 16;
675 op[3] = val >> 24;
676 break;
677
678 default:
679 as_bad (_("Unknown reloc in md_apply_fix: %s"),
680 bfd_get_reloc_code_name (f->fx_r_type));
681 break;
682 }
683
684 if (f->fx_addsy == NULL)
685 f->fx_done = 1;
686 }
687
688 valueT
689 md_section_align (segT segment, valueT size)
690 {
691 int align = bfd_get_section_alignment (stdoutput, segment);
692 return ((size + (1 << align) - 1) & (-1 << align));
693 }
694
695 void
696 md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED,
697 segT segment ATTRIBUTE_UNUSED,
698 fragS * fragP ATTRIBUTE_UNUSED)
699 {
700 /* No relaxation yet */
701 }
This page took 0.047278 seconds and 5 git commands to generate.