1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright (C) 1996-2019 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
45 #define COFF_ENCODE_ALIGNMENT(S,X) ((S).s_flags |= (((unsigned)(X) & 0xf) << 8))
46 #define COFF_DECODE_ALIGNMENT(X) (((X) >> 8) & 0xf)
48 #define GET_SCNHDR_FLAGS H_GET_16
49 #define PUT_SCNHDR_FLAGS H_PUT_16
51 static bfd_reloc_status_type ppbase_reloc
52 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
53 static bfd_reloc_status_type glob15_reloc
54 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55 static bfd_reloc_status_type glob16_reloc
56 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
57 static bfd_reloc_status_type local16_reloc
58 (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
61 static reloc_howto_type tic80_howto_table[] =
64 HOWTO (R_RELLONG, /* type */
66 2, /* size (0 = byte, 1 = short, 2 = long) */
68 FALSE, /* pc_relative */
70 complain_overflow_bitfield, /* complain_on_overflow */
71 NULL, /* special_function */
73 TRUE, /* partial_inplace */
74 0xffffffff, /* src_mask */
75 0xffffffff, /* dst_mask */
76 FALSE), /* pcrel_offset */
78 HOWTO (R_MPPCR, /* type */
80 2, /* size (0 = byte, 1 = short, 2 = long) */
82 TRUE, /* pc_relative */
84 complain_overflow_signed, /* complain_on_overflow */
85 NULL, /* special_function */
87 TRUE, /* partial_inplace */
88 0xffffffff, /* src_mask */
89 0xffffffff, /* dst_mask */
90 TRUE), /* pcrel_offset */
92 HOWTO (R_ABS, /* type */
94 2, /* size (0 = byte, 1 = short, 2 = long) */
96 FALSE, /* pc_relative */
98 complain_overflow_bitfield, /* complain_on_overflow */
99 NULL, /* special_function */
101 TRUE, /* partial_inplace */
102 0xffffffff, /* src_mask */
103 0xffffffff, /* dst_mask */
104 FALSE), /* pcrel_offset */
106 HOWTO (R_PPBASE, /* type */
108 2, /* size (0 = byte, 1 = short, 2 = long) */
110 FALSE, /* pc_relative */
112 complain_overflow_dont, /* complain_on_overflow */
113 ppbase_reloc, /* special_function */
115 TRUE, /* partial_inplace */
116 0xffffffff, /* src_mask */
117 0xffffffff, /* dst_mask */
118 FALSE), /* pcrel_offset */
120 HOWTO (R_PPLBASE, /* type */
122 2, /* size (0 = byte, 1 = short, 2 = long) */
124 FALSE, /* pc_relative */
126 complain_overflow_dont, /* complain_on_overflow */
127 ppbase_reloc, /* special_function */
128 "PPLBASE", /* name */
129 TRUE, /* partial_inplace */
130 0xffffffff, /* src_mask */
131 0xffffffff, /* dst_mask */
132 FALSE), /* pcrel_offset */
134 HOWTO (R_PP15, /* type */
136 2, /* size (0 = byte, 1 = short, 2 = long) */
138 FALSE, /* pc_relative */
140 complain_overflow_dont, /* complain_on_overflow */
141 glob15_reloc, /* special_function */
143 TRUE, /* partial_inplace */
144 0x1ffc0, /* src_mask */
145 0x1ffc0, /* dst_mask */
146 FALSE), /* pcrel_offset */
148 HOWTO (R_PP15W, /* type */
150 2, /* size (0 = byte, 1 = short, 2 = long) */
152 FALSE, /* pc_relative */
154 complain_overflow_dont, /* complain_on_overflow */
155 glob15_reloc, /* special_function */
157 TRUE, /* partial_inplace */
158 0x1ffc0, /* src_mask */
159 0x1ffc0, /* dst_mask */
160 FALSE), /* pcrel_offset */
162 HOWTO (R_PP15H, /* type */
164 2, /* size (0 = byte, 1 = short, 2 = long) */
166 FALSE, /* pc_relative */
168 complain_overflow_dont, /* complain_on_overflow */
169 glob15_reloc, /* special_function */
171 TRUE, /* partial_inplace */
172 0x1ffc0, /* src_mask */
173 0x1ffc0, /* dst_mask */
174 FALSE), /* pcrel_offset */
176 HOWTO (R_PP16B, /* type */
178 2, /* size (0 = byte, 1 = short, 2 = long) */
180 FALSE, /* pc_relative */
182 complain_overflow_dont, /* complain_on_overflow */
183 glob16_reloc, /* special_function */
185 TRUE, /* partial_inplace */
186 0x3ffc0, /* src_mask */
187 0x3ffc0, /* dst_mask */
188 FALSE), /* pcrel_offset */
190 HOWTO (R_PPL15, /* type */
192 2, /* size (0 = byte, 1 = short, 2 = long) */
194 FALSE, /* pc_relative */
196 complain_overflow_dont, /* complain_on_overflow */
197 NULL, /* special_function */
199 TRUE, /* partial_inplace */
200 0x7fff, /* src_mask */
201 0x7fff, /* dst_mask */
202 FALSE), /* pcrel_offset */
204 HOWTO (R_PPL15W, /* type */
206 2, /* size (0 = byte, 1 = short, 2 = long) */
208 FALSE, /* pc_relative */
210 complain_overflow_dont, /* complain_on_overflow */
211 NULL, /* special_function */
213 TRUE, /* partial_inplace */
214 0x7fff, /* src_mask */
215 0x7fff, /* dst_mask */
216 FALSE), /* pcrel_offset */
218 HOWTO (R_PPL15H, /* type */
220 2, /* size (0 = byte, 1 = short, 2 = long) */
222 FALSE, /* pc_relative */
224 complain_overflow_dont, /* complain_on_overflow */
225 NULL, /* special_function */
227 TRUE, /* partial_inplace */
228 0x7fff, /* src_mask */
229 0x7fff, /* dst_mask */
230 FALSE), /* pcrel_offset */
232 HOWTO (R_PPL16B, /* type */
234 2, /* size (0 = byte, 1 = short, 2 = long) */
236 FALSE, /* pc_relative */
238 complain_overflow_dont, /* complain_on_overflow */
239 local16_reloc, /* special_function */
241 TRUE, /* partial_inplace */
242 0xffff, /* src_mask */
243 0xffff, /* dst_mask */
244 FALSE), /* pcrel_offset */
246 HOWTO (R_PPN15, /* type */
248 -2, /* size (0 = byte, 1 = short, 2 = long) */
250 FALSE, /* pc_relative */
252 complain_overflow_dont, /* complain_on_overflow */
253 glob15_reloc, /* special_function */
255 TRUE, /* partial_inplace */
256 0x1ffc0, /* src_mask */
257 0x1ffc0, /* dst_mask */
258 FALSE), /* pcrel_offset */
260 HOWTO (R_PPN15W, /* type */
262 -2, /* size (0 = byte, 1 = short, 2 = long) */
264 FALSE, /* pc_relative */
266 complain_overflow_dont, /* complain_on_overflow */
267 glob15_reloc, /* special_function */
269 TRUE, /* partial_inplace */
270 0x1ffc0, /* src_mask */
271 0x1ffc0, /* dst_mask */
272 FALSE), /* pcrel_offset */
274 HOWTO (R_PPN15H, /* type */
276 -2, /* size (0 = byte, 1 = short, 2 = long) */
278 FALSE, /* pc_relative */
280 complain_overflow_dont, /* complain_on_overflow */
281 glob15_reloc, /* special_function */
283 TRUE, /* partial_inplace */
284 0x1ffc0, /* src_mask */
285 0x1ffc0, /* dst_mask */
286 FALSE), /* pcrel_offset */
288 HOWTO (R_PPN16B, /* type */
290 -2, /* size (0 = byte, 1 = short, 2 = long) */
292 FALSE, /* pc_relative */
294 complain_overflow_dont, /* complain_on_overflow */
295 glob16_reloc, /* special_function */
297 TRUE, /* partial_inplace */
298 0x3ffc0, /* src_mask */
299 0x3ffc0, /* dst_mask */
300 FALSE), /* pcrel_offset */
302 HOWTO (R_PPLN15, /* type */
304 -2, /* size (0 = byte, 1 = short, 2 = long) */
306 FALSE, /* pc_relative */
308 complain_overflow_dont, /* complain_on_overflow */
309 NULL, /* special_function */
311 TRUE, /* partial_inplace */
312 0x7fff, /* src_mask */
313 0x7fff, /* dst_mask */
314 FALSE), /* pcrel_offset */
316 HOWTO (R_PPLN15W, /* type */
318 -2, /* size (0 = byte, 1 = short, 2 = long) */
320 FALSE, /* pc_relative */
322 complain_overflow_dont, /* complain_on_overflow */
323 NULL, /* special_function */
324 "PPLN15W", /* name */
325 TRUE, /* partial_inplace */
326 0x7fff, /* src_mask */
327 0x7fff, /* dst_mask */
328 FALSE), /* pcrel_offset */
330 HOWTO (R_PPLN15H, /* type */
332 -2, /* size (0 = byte, 1 = short, 2 = long) */
334 FALSE, /* pc_relative */
336 complain_overflow_dont, /* complain_on_overflow */
337 NULL, /* special_function */
338 "PPLN15H", /* name */
339 TRUE, /* partial_inplace */
340 0x7fff, /* src_mask */
341 0x7fff, /* dst_mask */
342 FALSE), /* pcrel_offset */
344 HOWTO (R_PPLN16B, /* type */
346 -2, /* size (0 = byte, 1 = short, 2 = long) */
348 FALSE, /* pc_relative */
350 complain_overflow_dont, /* complain_on_overflow */
351 local16_reloc, /* special_function */
352 "PPLN16B", /* name */
353 TRUE, /* partial_inplace */
354 0xffff, /* src_mask */
355 0xffff, /* dst_mask */
356 FALSE) /* pcrel_offset */
359 /* Special relocation functions, used when the output file is not
360 itself a COFF TIc80 file. */
362 /* This special function is used for the base address type
365 static bfd_reloc_status_type
366 ppbase_reloc (bfd *abfd ATTRIBUTE_UNUSED,
367 arelent *reloc_entry ATTRIBUTE_UNUSED,
368 asymbol *symbol_in ATTRIBUTE_UNUSED,
369 void * data ATTRIBUTE_UNUSED,
370 asection *input_section ATTRIBUTE_UNUSED,
371 bfd *output_bfd ATTRIBUTE_UNUSED,
372 char **error_message ATTRIBUTE_UNUSED)
378 /* This special function is used for the global 15 bit relocations. */
380 static bfd_reloc_status_type
381 glob15_reloc (bfd *abfd ATTRIBUTE_UNUSED,
382 arelent *reloc_entry ATTRIBUTE_UNUSED,
383 asymbol *symbol_in ATTRIBUTE_UNUSED,
384 void * data ATTRIBUTE_UNUSED,
385 asection *input_section ATTRIBUTE_UNUSED,
386 bfd *output_bfd ATTRIBUTE_UNUSED,
387 char **error_message ATTRIBUTE_UNUSED)
393 /* This special function is used for the global 16 bit relocations. */
395 static bfd_reloc_status_type
396 glob16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
397 arelent *reloc_entry ATTRIBUTE_UNUSED,
398 asymbol *symbol_in ATTRIBUTE_UNUSED,
399 void * data ATTRIBUTE_UNUSED,
400 asection *input_section ATTRIBUTE_UNUSED,
401 bfd *output_bfd ATTRIBUTE_UNUSED,
402 char **error_message ATTRIBUTE_UNUSED)
408 /* This special function is used for the local 16 bit relocations. */
410 static bfd_reloc_status_type
411 local16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
412 arelent *reloc_entry ATTRIBUTE_UNUSED,
413 asymbol *symbol_in ATTRIBUTE_UNUSED,
414 void * data ATTRIBUTE_UNUSED,
415 asection *input_section ATTRIBUTE_UNUSED,
416 bfd *output_bfd ATTRIBUTE_UNUSED,
417 char **error_message ATTRIBUTE_UNUSED)
423 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
424 If passed an r_type we don't recognize the abort rather than silently failing
425 to generate an output file. */
428 rtype2howto (arelent *cache_ptr, struct internal_reloc *dst)
432 for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
434 if (tic80_howto_table[i].type == dst->r_type)
436 cache_ptr->howto = tic80_howto_table + i;
441 _bfd_error_handler (_("unsupported relocation type %#x"),
442 (unsigned int) dst->r_type);
443 cache_ptr->howto = tic80_howto_table + 0;
446 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
447 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
449 static reloc_howto_type *
450 coff_tic80_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
452 struct internal_reloc *rel,
453 struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
454 struct internal_syment *sym ATTRIBUTE_UNUSED,
459 if (rel -> r_symndx == -1 && addendp != NULL)
461 /* This is a TI "internal relocation", which means that the relocation
462 amount is the amount by which the current section is being relocated
463 in the output section. */
464 *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
466 RTYPE2HOWTO (&genrel, rel);
471 #define BADMAG(x) TIC80BADMAG(x)
474 #define coff_relocate_section coff_tic80_relocate_section
476 /* We need a special relocation routine to handle the PP relocs. Most
477 of this is a copy of _bfd_coff_generic_relocate_section. */
480 coff_tic80_relocate_section (bfd *output_bfd,
481 struct bfd_link_info *info,
483 asection *input_section,
485 struct internal_reloc *relocs,
486 struct internal_syment *syms,
489 struct internal_reloc *rel;
490 struct internal_reloc *relend;
493 relend = rel + input_section->reloc_count;
494 for (; rel < relend; rel++)
497 struct coff_link_hash_entry *h;
498 struct internal_syment *sym;
501 reloc_howto_type *howto;
502 bfd_reloc_status_type rstat;
505 symndx = rel->r_symndx;
514 h = obj_coff_sym_hashes (input_bfd)[symndx];
518 /* COFF treats common symbols in one of two ways. Either the
519 size of the symbol is included in the section contents, or it
520 is not. We assume that the size is not included, and force
521 the rtype_to_howto function to adjust the addend as needed. */
523 if (sym != NULL && sym->n_scnum != 0)
524 addend = - sym->n_value;
528 howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
541 sec = bfd_abs_section_ptr;
546 sec = sections[symndx];
547 val = (sec->output_section->vma
550 if (! obj_pe (output_bfd))
556 if (h->root.type == bfd_link_hash_defined
557 || h->root.type == bfd_link_hash_defweak)
561 sec = h->root.u.def.section;
562 val = (h->root.u.def.value
563 + sec->output_section->vma
564 + sec->output_offset);
567 else if (! bfd_link_relocatable (info))
568 (*info->callbacks->undefined_symbol)
569 (info, h->root.root.string, input_bfd, input_section,
570 rel->r_vaddr - input_section->vma, TRUE);
573 addr = rel->r_vaddr - input_section->vma;
575 /* FIXME: This code assumes little endian, but the PP can
576 apparently be bi-endian. I don't know if the bi-endianness
577 applies to the instruction set or just to the data. */
589 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
590 contents, addr, val, addend);
599 /* Offset the address so that we can use 4 byte relocations. */
600 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
601 contents + 2, addr, val, addend);
607 /* The most significant bit is stored in bit 6. */
610 hold = contents[addr + 4];
611 contents[addr + 4] &=~ 0x20;
612 contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
613 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
616 contents[addr] &=~ 0x40;
617 contents[addr] |= (contents[addr + 4] << 1) & 0x40;
618 contents[addr + 4] &=~ 0x20;
619 contents[addr + 4] |= hold & 0x20;
626 /* The most significant bit is stored in bit 28. */
629 hold = contents[addr + 1];
630 contents[addr + 1] &=~ 0x80;
631 contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
632 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
635 contents[addr + 3] &= ~0x10;
636 contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
637 contents[addr + 1] &=~ 0x80;
638 contents[addr + 1] |= hold & 0x80;
643 /* Parameter RAM is from 0x1000000 to 0x1000800. */
644 contents[addr] &=~ 0x3;
645 if (val >= 0x1000000 && val < 0x1000800)
646 contents[addr] |= 0x3;
648 contents[addr] |= 0x2;
649 rstat = bfd_reloc_ok;
653 /* Parameter RAM is from 0x1000000 to 0x1000800. */
654 contents[addr + 2] &= ~0xc0;
655 if (val >= 0x1000000 && val < 0x1000800)
656 contents[addr + 2] |= 0xc0;
658 contents[addr + 2] |= 0x80;
659 rstat = bfd_reloc_ok;
669 case bfd_reloc_outofrange:
671 /* xgettext: c-format */
672 (_("%pB: bad reloc address %#" PRIx64 " in section `%pA'"),
673 input_bfd, (uint64_t) rel->r_vaddr, input_section);
675 case bfd_reloc_overflow:
678 char buf[SYMNMLEN + 1];
686 name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
691 (*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);
701 #define TIC80COFF 1 /* Customize coffcode.h */
702 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
703 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
705 #ifndef bfd_pe_print_pdata
706 #define bfd_pe_print_pdata NULL
709 #include "coffcode.h"
711 CREATE_LITTLE_COFF_TARGET_VEC (tic80_coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)