1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright (C) 1996-2014 Free Software Foundation, Inc.
4 Written by Fred Fish (fnf@cygnus.com)
6 There is nothing new under the sun. This file draws a lot on other
9 This file is part of BFD, the Binary File Descriptor library.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 3 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, 51 Franklin Street - Fifth Floor,
24 Boston, MA 02110-1301, USA. */
31 /* Newlib-based hosts define _CONST as a STDC-safe alias for const,
32 but to the tic80 toolchain it means something altogether different.
33 Since sysdep.h will have pulled in stdio.h and hence _ansi.h which
34 contains this definition, we must undef it before including the
35 tic80-specific definition. */
38 #include "coff/tic80.h"
39 #include "coff/internal.h"
42 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
43 #define COFF_ALIGN_IN_SECTION_HEADER 1
44 #define COFF_ALIGN_IN_SFLAGS 1
46 #define GET_SCNHDR_FLAGS H_GET_16
47 #define PUT_SCNHDR_FLAGS H_PUT_16
49 static bfd_reloc_status_type ppbase_reloc
50 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
51 static bfd_reloc_status_type glob15_reloc
52 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
53 static bfd_reloc_status_type glob16_reloc
54 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55 static bfd_reloc_status_type local16_reloc
56 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
59 static reloc_howto_type tic80_howto_table[] =
62 HOWTO (R_RELLONG, /* type */
64 2, /* size (0 = byte, 1 = short, 2 = long) */
66 FALSE, /* pc_relative */
68 complain_overflow_bitfield, /* complain_on_overflow */
69 NULL, /* special_function */
71 TRUE, /* partial_inplace */
72 0xffffffff, /* src_mask */
73 0xffffffff, /* dst_mask */
74 FALSE), /* pcrel_offset */
76 HOWTO (R_MPPCR, /* type */
78 2, /* size (0 = byte, 1 = short, 2 = long) */
80 TRUE, /* pc_relative */
82 complain_overflow_signed, /* complain_on_overflow */
83 NULL, /* special_function */
85 TRUE, /* partial_inplace */
86 0xffffffff, /* src_mask */
87 0xffffffff, /* dst_mask */
88 TRUE), /* pcrel_offset */
90 HOWTO (R_ABS, /* type */
92 2, /* size (0 = byte, 1 = short, 2 = long) */
94 FALSE, /* pc_relative */
96 complain_overflow_bitfield, /* complain_on_overflow */
97 NULL, /* special_function */
99 TRUE, /* partial_inplace */
100 0xffffffff, /* src_mask */
101 0xffffffff, /* dst_mask */
102 FALSE), /* pcrel_offset */
104 HOWTO (R_PPBASE, /* type */
106 2, /* size (0 = byte, 1 = short, 2 = long) */
108 FALSE, /* pc_relative */
110 complain_overflow_dont, /* complain_on_overflow */
111 ppbase_reloc, /* special_function */
113 TRUE, /* partial_inplace */
114 0xffffffff, /* src_mask */
115 0xffffffff, /* dst_mask */
116 FALSE), /* pcrel_offset */
118 HOWTO (R_PPLBASE, /* type */
120 2, /* size (0 = byte, 1 = short, 2 = long) */
122 FALSE, /* pc_relative */
124 complain_overflow_dont, /* complain_on_overflow */
125 ppbase_reloc, /* special_function */
126 "PPLBASE", /* name */
127 TRUE, /* partial_inplace */
128 0xffffffff, /* src_mask */
129 0xffffffff, /* dst_mask */
130 FALSE), /* pcrel_offset */
132 HOWTO (R_PP15, /* type */
134 2, /* size (0 = byte, 1 = short, 2 = long) */
136 FALSE, /* pc_relative */
138 complain_overflow_dont, /* complain_on_overflow */
139 glob15_reloc, /* special_function */
141 TRUE, /* partial_inplace */
142 0x1ffc0, /* src_mask */
143 0x1ffc0, /* dst_mask */
144 FALSE), /* pcrel_offset */
146 HOWTO (R_PP15W, /* type */
148 2, /* size (0 = byte, 1 = short, 2 = long) */
150 FALSE, /* pc_relative */
152 complain_overflow_dont, /* complain_on_overflow */
153 glob15_reloc, /* special_function */
155 TRUE, /* partial_inplace */
156 0x1ffc0, /* src_mask */
157 0x1ffc0, /* dst_mask */
158 FALSE), /* pcrel_offset */
160 HOWTO (R_PP15H, /* type */
162 2, /* size (0 = byte, 1 = short, 2 = long) */
164 FALSE, /* pc_relative */
166 complain_overflow_dont, /* complain_on_overflow */
167 glob15_reloc, /* special_function */
169 TRUE, /* partial_inplace */
170 0x1ffc0, /* src_mask */
171 0x1ffc0, /* dst_mask */
172 FALSE), /* pcrel_offset */
174 HOWTO (R_PP16B, /* type */
176 2, /* size (0 = byte, 1 = short, 2 = long) */
178 FALSE, /* pc_relative */
180 complain_overflow_dont, /* complain_on_overflow */
181 glob16_reloc, /* special_function */
183 TRUE, /* partial_inplace */
184 0x3ffc0, /* src_mask */
185 0x3ffc0, /* dst_mask */
186 FALSE), /* pcrel_offset */
188 HOWTO (R_PPL15, /* type */
190 2, /* size (0 = byte, 1 = short, 2 = long) */
192 FALSE, /* pc_relative */
194 complain_overflow_dont, /* complain_on_overflow */
195 NULL, /* special_function */
197 TRUE, /* partial_inplace */
198 0x7fff, /* src_mask */
199 0x7fff, /* dst_mask */
200 FALSE), /* pcrel_offset */
202 HOWTO (R_PPL15W, /* type */
204 2, /* size (0 = byte, 1 = short, 2 = long) */
206 FALSE, /* pc_relative */
208 complain_overflow_dont, /* complain_on_overflow */
209 NULL, /* special_function */
211 TRUE, /* partial_inplace */
212 0x7fff, /* src_mask */
213 0x7fff, /* dst_mask */
214 FALSE), /* pcrel_offset */
216 HOWTO (R_PPL15H, /* type */
218 2, /* size (0 = byte, 1 = short, 2 = long) */
220 FALSE, /* pc_relative */
222 complain_overflow_dont, /* complain_on_overflow */
223 NULL, /* special_function */
225 TRUE, /* partial_inplace */
226 0x7fff, /* src_mask */
227 0x7fff, /* dst_mask */
228 FALSE), /* pcrel_offset */
230 HOWTO (R_PPL16B, /* type */
232 2, /* size (0 = byte, 1 = short, 2 = long) */
234 FALSE, /* pc_relative */
236 complain_overflow_dont, /* complain_on_overflow */
237 local16_reloc, /* special_function */
239 TRUE, /* partial_inplace */
240 0xffff, /* src_mask */
241 0xffff, /* dst_mask */
242 FALSE), /* pcrel_offset */
244 HOWTO (R_PPN15, /* type */
246 -2, /* size (0 = byte, 1 = short, 2 = long) */
248 FALSE, /* pc_relative */
250 complain_overflow_dont, /* complain_on_overflow */
251 glob15_reloc, /* special_function */
253 TRUE, /* partial_inplace */
254 0x1ffc0, /* src_mask */
255 0x1ffc0, /* dst_mask */
256 FALSE), /* pcrel_offset */
258 HOWTO (R_PPN15W, /* type */
260 -2, /* size (0 = byte, 1 = short, 2 = long) */
262 FALSE, /* pc_relative */
264 complain_overflow_dont, /* complain_on_overflow */
265 glob15_reloc, /* special_function */
267 TRUE, /* partial_inplace */
268 0x1ffc0, /* src_mask */
269 0x1ffc0, /* dst_mask */
270 FALSE), /* pcrel_offset */
272 HOWTO (R_PPN15H, /* type */
274 -2, /* size (0 = byte, 1 = short, 2 = long) */
276 FALSE, /* pc_relative */
278 complain_overflow_dont, /* complain_on_overflow */
279 glob15_reloc, /* special_function */
281 TRUE, /* partial_inplace */
282 0x1ffc0, /* src_mask */
283 0x1ffc0, /* dst_mask */
284 FALSE), /* pcrel_offset */
286 HOWTO (R_PPN16B, /* type */
288 -2, /* size (0 = byte, 1 = short, 2 = long) */
290 FALSE, /* pc_relative */
292 complain_overflow_dont, /* complain_on_overflow */
293 glob16_reloc, /* special_function */
295 TRUE, /* partial_inplace */
296 0x3ffc0, /* src_mask */
297 0x3ffc0, /* dst_mask */
298 FALSE), /* pcrel_offset */
300 HOWTO (R_PPLN15, /* type */
302 -2, /* size (0 = byte, 1 = short, 2 = long) */
304 FALSE, /* pc_relative */
306 complain_overflow_dont, /* complain_on_overflow */
307 NULL, /* special_function */
309 TRUE, /* partial_inplace */
310 0x7fff, /* src_mask */
311 0x7fff, /* dst_mask */
312 FALSE), /* pcrel_offset */
314 HOWTO (R_PPLN15W, /* type */
316 -2, /* size (0 = byte, 1 = short, 2 = long) */
318 FALSE, /* pc_relative */
320 complain_overflow_dont, /* complain_on_overflow */
321 NULL, /* special_function */
322 "PPLN15W", /* name */
323 TRUE, /* partial_inplace */
324 0x7fff, /* src_mask */
325 0x7fff, /* dst_mask */
326 FALSE), /* pcrel_offset */
328 HOWTO (R_PPLN15H, /* type */
330 -2, /* size (0 = byte, 1 = short, 2 = long) */
332 FALSE, /* pc_relative */
334 complain_overflow_dont, /* complain_on_overflow */
335 NULL, /* special_function */
336 "PPLN15H", /* name */
337 TRUE, /* partial_inplace */
338 0x7fff, /* src_mask */
339 0x7fff, /* dst_mask */
340 FALSE), /* pcrel_offset */
342 HOWTO (R_PPLN16B, /* type */
344 -2, /* size (0 = byte, 1 = short, 2 = long) */
346 FALSE, /* pc_relative */
348 complain_overflow_dont, /* complain_on_overflow */
349 local16_reloc, /* special_function */
350 "PPLN16B", /* name */
351 TRUE, /* partial_inplace */
352 0xffff, /* src_mask */
353 0xffff, /* dst_mask */
354 FALSE) /* pcrel_offset */
357 /* Special relocation functions, used when the output file is not
358 itself a COFF TIc80 file. */
360 /* This special function is used for the base address type
363 static bfd_reloc_status_type
364 ppbase_reloc (bfd *abfd ATTRIBUTE_UNUSED,
365 arelent *reloc_entry ATTRIBUTE_UNUSED,
366 asymbol *symbol_in ATTRIBUTE_UNUSED,
367 void * data ATTRIBUTE_UNUSED,
368 asection *input_section ATTRIBUTE_UNUSED,
369 bfd *output_bfd ATTRIBUTE_UNUSED,
370 char **error_message ATTRIBUTE_UNUSED)
376 /* This special function is used for the global 15 bit relocations. */
378 static bfd_reloc_status_type
379 glob15_reloc (bfd *abfd ATTRIBUTE_UNUSED,
380 arelent *reloc_entry ATTRIBUTE_UNUSED,
381 asymbol *symbol_in ATTRIBUTE_UNUSED,
382 void * data ATTRIBUTE_UNUSED,
383 asection *input_section ATTRIBUTE_UNUSED,
384 bfd *output_bfd ATTRIBUTE_UNUSED,
385 char **error_message ATTRIBUTE_UNUSED)
391 /* This special function is used for the global 16 bit relocations. */
393 static bfd_reloc_status_type
394 glob16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
395 arelent *reloc_entry ATTRIBUTE_UNUSED,
396 asymbol *symbol_in ATTRIBUTE_UNUSED,
397 void * data ATTRIBUTE_UNUSED,
398 asection *input_section ATTRIBUTE_UNUSED,
399 bfd *output_bfd ATTRIBUTE_UNUSED,
400 char **error_message ATTRIBUTE_UNUSED)
406 /* This special function is used for the local 16 bit relocations. */
408 static bfd_reloc_status_type
409 local16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
410 arelent *reloc_entry ATTRIBUTE_UNUSED,
411 asymbol *symbol_in ATTRIBUTE_UNUSED,
412 void * data ATTRIBUTE_UNUSED,
413 asection *input_section ATTRIBUTE_UNUSED,
414 bfd *output_bfd ATTRIBUTE_UNUSED,
415 char **error_message ATTRIBUTE_UNUSED)
421 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
422 If passed an r_type we don't recognize the abort rather than silently failing
423 to generate an output file. */
426 rtype2howto (arelent *cache_ptr, struct internal_reloc *dst)
430 for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
432 if (tic80_howto_table[i].type == dst->r_type)
434 cache_ptr->howto = tic80_howto_table + i;
439 (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
440 (unsigned int) dst->r_type);
441 cache_ptr->howto = tic80_howto_table + 0;
444 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
445 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
447 static reloc_howto_type *
448 coff_tic80_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
450 struct internal_reloc *rel,
451 struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
452 struct internal_syment *sym ATTRIBUTE_UNUSED,
457 if (rel -> r_symndx == -1 && addendp != NULL)
459 /* This is a TI "internal relocation", which means that the relocation
460 amount is the amount by which the current section is being relocated
461 in the output section. */
462 *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
464 RTYPE2HOWTO (&genrel, rel);
469 #define BADMAG(x) TIC80BADMAG(x)
472 #define coff_relocate_section coff_tic80_relocate_section
474 /* We need a special relocation routine to handle the PP relocs. Most
475 of this is a copy of _bfd_coff_generic_relocate_section. */
478 coff_tic80_relocate_section (bfd *output_bfd,
479 struct bfd_link_info *info,
481 asection *input_section,
483 struct internal_reloc *relocs,
484 struct internal_syment *syms,
487 struct internal_reloc *rel;
488 struct internal_reloc *relend;
491 relend = rel + input_section->reloc_count;
492 for (; rel < relend; rel++)
495 struct coff_link_hash_entry *h;
496 struct internal_syment *sym;
499 reloc_howto_type *howto;
500 bfd_reloc_status_type rstat;
503 symndx = rel->r_symndx;
512 h = obj_coff_sym_hashes (input_bfd)[symndx];
516 /* COFF treats common symbols in one of two ways. Either the
517 size of the symbol is included in the section contents, or it
518 is not. We assume that the size is not included, and force
519 the rtype_to_howto function to adjust the addend as needed. */
521 if (sym != NULL && sym->n_scnum != 0)
522 addend = - sym->n_value;
526 howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
539 sec = bfd_abs_section_ptr;
544 sec = sections[symndx];
545 val = (sec->output_section->vma
548 if (! obj_pe (output_bfd))
554 if (h->root.type == bfd_link_hash_defined
555 || h->root.type == bfd_link_hash_defweak)
559 sec = h->root.u.def.section;
560 val = (h->root.u.def.value
561 + sec->output_section->vma
562 + sec->output_offset);
565 else if (! info->relocatable)
567 if (! ((*info->callbacks->undefined_symbol)
568 (info, h->root.root.string, input_bfd, input_section,
569 rel->r_vaddr - input_section->vma, TRUE)))
574 addr = rel->r_vaddr - input_section->vma;
576 /* FIXME: This code assumes little endian, but the PP can
577 apparently be bi-endian. I don't know if the bi-endianness
578 applies to the instruction set or just to the data. */
590 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
591 contents, addr, val, addend);
600 /* Offset the address so that we can use 4 byte relocations. */
601 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
602 contents + 2, addr, val, addend);
608 /* The most significant bit is stored in bit 6. */
611 hold = contents[addr + 4];
612 contents[addr + 4] &=~ 0x20;
613 contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
614 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
617 contents[addr] &=~ 0x40;
618 contents[addr] |= (contents[addr + 4] << 1) & 0x40;
619 contents[addr + 4] &=~ 0x20;
620 contents[addr + 4] |= hold & 0x20;
627 /* The most significant bit is stored in bit 28. */
630 hold = contents[addr + 1];
631 contents[addr + 1] &=~ 0x80;
632 contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
633 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
636 contents[addr + 3] &= ~0x10;
637 contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
638 contents[addr + 1] &=~ 0x80;
639 contents[addr + 1] |= hold & 0x80;
644 /* Parameter RAM is from 0x1000000 to 0x1000800. */
645 contents[addr] &=~ 0x3;
646 if (val >= 0x1000000 && val < 0x1000800)
647 contents[addr] |= 0x3;
649 contents[addr] |= 0x2;
650 rstat = bfd_reloc_ok;
654 /* Parameter RAM is from 0x1000000 to 0x1000800. */
655 contents[addr + 2] &= ~0xc0;
656 if (val >= 0x1000000 && val < 0x1000800)
657 contents[addr + 2] |= 0xc0;
659 contents[addr + 2] |= 0x80;
660 rstat = bfd_reloc_ok;
670 case bfd_reloc_outofrange:
671 (*_bfd_error_handler)
672 (_("%B: bad reloc address 0x%lx in section `%A'"),
673 input_bfd, input_section, (unsigned long) rel->r_vaddr);
675 case bfd_reloc_overflow:
678 char buf[SYMNMLEN + 1];
686 name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
691 if (! ((*info->callbacks->reloc_overflow)
692 (info, (h ? &h->root : NULL), name, howto->name,
693 (bfd_vma) 0, input_bfd, input_section,
694 rel->r_vaddr - input_section->vma)))
702 #define TIC80COFF 1 /* Customize coffcode.h */
703 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
704 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
706 #ifndef bfd_pe_print_pdata
707 #define bfd_pe_print_pdata NULL
710 #include "coffcode.h"
712 CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)