1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004, 2005
3 Free Software Foundation, Inc.
5 Written by Fred Fish (fnf@cygnus.com)
7 There is nothing new under the sun. This file draws a lot on other
10 This file is part of BFD, the Binary File Descriptor library.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, 51 Franklin Street - Fifth Floor,
25 Boston, MA 02110-1301, USA. */
32 /* Newlib-based hosts define _CONST as a STDC-safe alias for const,
33 but to the tic80 toolchain it means something altogether different.
34 Since sysdep.h will have pulled in stdio.h and hence _ansi.h which
35 contains this definition, we must undef it before including the
36 tic80-specific definition. */
39 #include "coff/tic80.h"
40 #include "coff/internal.h"
43 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44 #define COFF_ALIGN_IN_SECTION_HEADER 1
45 #define COFF_ALIGN_IN_SFLAGS 1
47 #define GET_SCNHDR_FLAGS H_GET_16
48 #define PUT_SCNHDR_FLAGS H_PUT_16
50 static void rtype2howto
51 PARAMS ((arelent *cache_ptr, struct internal_reloc *dst));
52 static bfd_reloc_status_type ppbase_reloc
53 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
54 static bfd_reloc_status_type glob15_reloc
55 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
56 static bfd_reloc_status_type glob16_reloc
57 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
58 static bfd_reloc_status_type local16_reloc
59 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
60 static bfd_boolean coff_tic80_relocate_section
61 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
62 struct internal_reloc *, struct internal_syment *, asection **));
63 static reloc_howto_type * coff_tic80_rtype_to_howto
64 PARAMS ((bfd *, asection *, struct internal_reloc *,
65 struct coff_link_hash_entry *, struct internal_syment *,
68 static reloc_howto_type tic80_howto_table[] =
71 HOWTO (R_RELLONG, /* type */
73 2, /* size (0 = byte, 1 = short, 2 = long) */
75 FALSE, /* pc_relative */
77 complain_overflow_bitfield, /* complain_on_overflow */
78 NULL, /* special_function */
80 TRUE, /* partial_inplace */
81 0xffffffff, /* src_mask */
82 0xffffffff, /* dst_mask */
83 FALSE), /* pcrel_offset */
85 HOWTO (R_MPPCR, /* type */
87 2, /* size (0 = byte, 1 = short, 2 = long) */
89 TRUE, /* pc_relative */
91 complain_overflow_signed, /* complain_on_overflow */
92 NULL, /* special_function */
94 TRUE, /* partial_inplace */
95 0xffffffff, /* src_mask */
96 0xffffffff, /* dst_mask */
97 TRUE), /* pcrel_offset */
99 HOWTO (R_ABS, /* type */
101 2, /* size (0 = byte, 1 = short, 2 = long) */
103 FALSE, /* pc_relative */
105 complain_overflow_bitfield, /* complain_on_overflow */
106 NULL, /* special_function */
108 TRUE, /* partial_inplace */
109 0xffffffff, /* src_mask */
110 0xffffffff, /* dst_mask */
111 FALSE), /* pcrel_offset */
113 HOWTO (R_PPBASE, /* type */
115 2, /* size (0 = byte, 1 = short, 2 = long) */
117 FALSE, /* pc_relative */
119 complain_overflow_dont, /* complain_on_overflow */
120 ppbase_reloc, /* special_function */
122 TRUE, /* partial_inplace */
123 0xffffffff, /* src_mask */
124 0xffffffff, /* dst_mask */
125 FALSE), /* pcrel_offset */
127 HOWTO (R_PPLBASE, /* type */
129 2, /* size (0 = byte, 1 = short, 2 = long) */
131 FALSE, /* pc_relative */
133 complain_overflow_dont, /* complain_on_overflow */
134 ppbase_reloc, /* special_function */
135 "PPLBASE", /* name */
136 TRUE, /* partial_inplace */
137 0xffffffff, /* src_mask */
138 0xffffffff, /* dst_mask */
139 FALSE), /* pcrel_offset */
141 HOWTO (R_PP15, /* type */
143 2, /* size (0 = byte, 1 = short, 2 = long) */
145 FALSE, /* pc_relative */
147 complain_overflow_dont, /* complain_on_overflow */
148 glob15_reloc, /* special_function */
150 TRUE, /* partial_inplace */
151 0x1ffc0, /* src_mask */
152 0x1ffc0, /* dst_mask */
153 FALSE), /* pcrel_offset */
155 HOWTO (R_PP15W, /* type */
157 2, /* size (0 = byte, 1 = short, 2 = long) */
159 FALSE, /* pc_relative */
161 complain_overflow_dont, /* complain_on_overflow */
162 glob15_reloc, /* special_function */
164 TRUE, /* partial_inplace */
165 0x1ffc0, /* src_mask */
166 0x1ffc0, /* dst_mask */
167 FALSE), /* pcrel_offset */
169 HOWTO (R_PP15H, /* type */
171 2, /* size (0 = byte, 1 = short, 2 = long) */
173 FALSE, /* pc_relative */
175 complain_overflow_dont, /* complain_on_overflow */
176 glob15_reloc, /* special_function */
178 TRUE, /* partial_inplace */
179 0x1ffc0, /* src_mask */
180 0x1ffc0, /* dst_mask */
181 FALSE), /* pcrel_offset */
183 HOWTO (R_PP16B, /* type */
185 2, /* size (0 = byte, 1 = short, 2 = long) */
187 FALSE, /* pc_relative */
189 complain_overflow_dont, /* complain_on_overflow */
190 glob16_reloc, /* special_function */
192 TRUE, /* partial_inplace */
193 0x3ffc0, /* src_mask */
194 0x3ffc0, /* dst_mask */
195 FALSE), /* pcrel_offset */
197 HOWTO (R_PPL15, /* type */
199 2, /* size (0 = byte, 1 = short, 2 = long) */
201 FALSE, /* pc_relative */
203 complain_overflow_dont, /* complain_on_overflow */
204 NULL, /* special_function */
206 TRUE, /* partial_inplace */
207 0x7fff, /* src_mask */
208 0x7fff, /* dst_mask */
209 FALSE), /* pcrel_offset */
211 HOWTO (R_PPL15W, /* type */
213 2, /* size (0 = byte, 1 = short, 2 = long) */
215 FALSE, /* pc_relative */
217 complain_overflow_dont, /* complain_on_overflow */
218 NULL, /* special_function */
220 TRUE, /* partial_inplace */
221 0x7fff, /* src_mask */
222 0x7fff, /* dst_mask */
223 FALSE), /* pcrel_offset */
225 HOWTO (R_PPL15H, /* type */
227 2, /* size (0 = byte, 1 = short, 2 = long) */
229 FALSE, /* pc_relative */
231 complain_overflow_dont, /* complain_on_overflow */
232 NULL, /* special_function */
234 TRUE, /* partial_inplace */
235 0x7fff, /* src_mask */
236 0x7fff, /* dst_mask */
237 FALSE), /* pcrel_offset */
239 HOWTO (R_PPL16B, /* type */
241 2, /* size (0 = byte, 1 = short, 2 = long) */
243 FALSE, /* pc_relative */
245 complain_overflow_dont, /* complain_on_overflow */
246 local16_reloc, /* special_function */
248 TRUE, /* partial_inplace */
249 0xffff, /* src_mask */
250 0xffff, /* dst_mask */
251 FALSE), /* pcrel_offset */
253 HOWTO (R_PPN15, /* type */
255 -2, /* size (0 = byte, 1 = short, 2 = long) */
257 FALSE, /* pc_relative */
259 complain_overflow_dont, /* complain_on_overflow */
260 glob15_reloc, /* special_function */
262 TRUE, /* partial_inplace */
263 0x1ffc0, /* src_mask */
264 0x1ffc0, /* dst_mask */
265 FALSE), /* pcrel_offset */
267 HOWTO (R_PPN15W, /* type */
269 -2, /* size (0 = byte, 1 = short, 2 = long) */
271 FALSE, /* pc_relative */
273 complain_overflow_dont, /* complain_on_overflow */
274 glob15_reloc, /* special_function */
276 TRUE, /* partial_inplace */
277 0x1ffc0, /* src_mask */
278 0x1ffc0, /* dst_mask */
279 FALSE), /* pcrel_offset */
281 HOWTO (R_PPN15H, /* type */
283 -2, /* size (0 = byte, 1 = short, 2 = long) */
285 FALSE, /* pc_relative */
287 complain_overflow_dont, /* complain_on_overflow */
288 glob15_reloc, /* special_function */
290 TRUE, /* partial_inplace */
291 0x1ffc0, /* src_mask */
292 0x1ffc0, /* dst_mask */
293 FALSE), /* pcrel_offset */
295 HOWTO (R_PPN16B, /* type */
297 -2, /* size (0 = byte, 1 = short, 2 = long) */
299 FALSE, /* pc_relative */
301 complain_overflow_dont, /* complain_on_overflow */
302 glob16_reloc, /* special_function */
304 TRUE, /* partial_inplace */
305 0x3ffc0, /* src_mask */
306 0x3ffc0, /* dst_mask */
307 FALSE), /* pcrel_offset */
309 HOWTO (R_PPLN15, /* type */
311 -2, /* size (0 = byte, 1 = short, 2 = long) */
313 FALSE, /* pc_relative */
315 complain_overflow_dont, /* complain_on_overflow */
316 NULL, /* special_function */
318 TRUE, /* partial_inplace */
319 0x7fff, /* src_mask */
320 0x7fff, /* dst_mask */
321 FALSE), /* pcrel_offset */
323 HOWTO (R_PPLN15W, /* type */
325 -2, /* size (0 = byte, 1 = short, 2 = long) */
327 FALSE, /* pc_relative */
329 complain_overflow_dont, /* complain_on_overflow */
330 NULL, /* special_function */
331 "PPLN15W", /* name */
332 TRUE, /* partial_inplace */
333 0x7fff, /* src_mask */
334 0x7fff, /* dst_mask */
335 FALSE), /* pcrel_offset */
337 HOWTO (R_PPLN15H, /* type */
339 -2, /* size (0 = byte, 1 = short, 2 = long) */
341 FALSE, /* pc_relative */
343 complain_overflow_dont, /* complain_on_overflow */
344 NULL, /* special_function */
345 "PPLN15H", /* name */
346 TRUE, /* partial_inplace */
347 0x7fff, /* src_mask */
348 0x7fff, /* dst_mask */
349 FALSE), /* pcrel_offset */
351 HOWTO (R_PPLN16B, /* type */
353 -2, /* size (0 = byte, 1 = short, 2 = long) */
355 FALSE, /* pc_relative */
357 complain_overflow_dont, /* complain_on_overflow */
358 local16_reloc, /* special_function */
359 "PPLN16B", /* name */
360 TRUE, /* partial_inplace */
361 0xffff, /* src_mask */
362 0xffff, /* dst_mask */
363 FALSE) /* pcrel_offset */
366 /* Special relocation functions, used when the output file is not
367 itself a COFF TIc80 file. */
369 /* This special function is used for the base address type
372 static bfd_reloc_status_type
373 ppbase_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
375 bfd *abfd ATTRIBUTE_UNUSED;
376 arelent *reloc_entry ATTRIBUTE_UNUSED;
377 asymbol *symbol_in ATTRIBUTE_UNUSED;
378 PTR data ATTRIBUTE_UNUSED;
379 asection *input_section ATTRIBUTE_UNUSED;
380 bfd *output_bfd ATTRIBUTE_UNUSED;
381 char **error_message ATTRIBUTE_UNUSED;
387 /* This special function is used for the global 15 bit relocations. */
389 static bfd_reloc_status_type
390 glob15_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
392 bfd *abfd ATTRIBUTE_UNUSED;
393 arelent *reloc_entry ATTRIBUTE_UNUSED;
394 asymbol *symbol_in ATTRIBUTE_UNUSED;
395 PTR data ATTRIBUTE_UNUSED;
396 asection *input_section ATTRIBUTE_UNUSED;
397 bfd *output_bfd ATTRIBUTE_UNUSED;
398 char **error_message ATTRIBUTE_UNUSED;
404 /* This special function is used for the global 16 bit relocations. */
406 static bfd_reloc_status_type
407 glob16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
409 bfd *abfd ATTRIBUTE_UNUSED;
410 arelent *reloc_entry ATTRIBUTE_UNUSED;
411 asymbol *symbol_in ATTRIBUTE_UNUSED;
412 PTR data ATTRIBUTE_UNUSED;
413 asection *input_section ATTRIBUTE_UNUSED;
414 bfd *output_bfd ATTRIBUTE_UNUSED;
415 char **error_message ATTRIBUTE_UNUSED;
421 /* This special function is used for the local 16 bit relocations. */
423 static bfd_reloc_status_type
424 local16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
426 bfd *abfd ATTRIBUTE_UNUSED;
427 arelent *reloc_entry ATTRIBUTE_UNUSED;
428 asymbol *symbol_in ATTRIBUTE_UNUSED;
429 PTR data ATTRIBUTE_UNUSED;
430 asection *input_section ATTRIBUTE_UNUSED;
431 bfd *output_bfd ATTRIBUTE_UNUSED;
432 char **error_message ATTRIBUTE_UNUSED;
438 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
439 If passed an r_type we don't recognize the abort rather than silently failing
440 to generate an output file. */
443 rtype2howto (cache_ptr, dst)
445 struct internal_reloc *dst;
449 for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
451 if (tic80_howto_table[i].type == dst->r_type)
453 cache_ptr->howto = tic80_howto_table + i;
458 (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
459 (unsigned int) dst->r_type);
460 cache_ptr->howto = tic80_howto_table + 0;
463 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
464 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
466 static reloc_howto_type *
467 coff_tic80_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
468 bfd *abfd ATTRIBUTE_UNUSED;
470 struct internal_reloc *rel;
471 struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
472 struct internal_syment *sym ATTRIBUTE_UNUSED;
477 if (rel -> r_symndx == -1 && addendp != NULL)
479 /* This is a TI "internal relocation", which means that the relocation
480 amount is the amount by which the current section is being relocated
481 in the output section. */
482 *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
484 RTYPE2HOWTO (&genrel, rel);
489 #define BADMAG(x) TIC80BADMAG(x)
492 #define coff_relocate_section coff_tic80_relocate_section
494 /* We need a special relocation routine to handle the PP relocs. Most
495 of this is a copy of _bfd_coff_generic_relocate_section. */
498 coff_tic80_relocate_section (output_bfd, info, input_bfd,
499 input_section, contents, relocs, syms,
502 struct bfd_link_info *info;
504 asection *input_section;
506 struct internal_reloc *relocs;
507 struct internal_syment *syms;
510 struct internal_reloc *rel;
511 struct internal_reloc *relend;
514 relend = rel + input_section->reloc_count;
515 for (; rel < relend; rel++)
518 struct coff_link_hash_entry *h;
519 struct internal_syment *sym;
522 reloc_howto_type *howto;
523 bfd_reloc_status_type rstat;
526 symndx = rel->r_symndx;
535 h = obj_coff_sym_hashes (input_bfd)[symndx];
539 /* COFF treats common symbols in one of two ways. Either the
540 size of the symbol is included in the section contents, or it
541 is not. We assume that the size is not included, and force
542 the rtype_to_howto function to adjust the addend as needed. */
544 if (sym != NULL && sym->n_scnum != 0)
545 addend = - sym->n_value;
549 howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
562 sec = bfd_abs_section_ptr;
567 sec = sections[symndx];
568 val = (sec->output_section->vma
571 if (! obj_pe (output_bfd))
577 if (h->root.type == bfd_link_hash_defined
578 || h->root.type == bfd_link_hash_defweak)
582 sec = h->root.u.def.section;
583 val = (h->root.u.def.value
584 + sec->output_section->vma
585 + sec->output_offset);
588 else if (! info->relocatable)
590 if (! ((*info->callbacks->undefined_symbol)
591 (info, h->root.root.string, input_bfd, input_section,
592 rel->r_vaddr - input_section->vma, TRUE)))
597 addr = rel->r_vaddr - input_section->vma;
599 /* FIXME: This code assumes little endian, but the PP can
600 apparently be bi-endian. I don't know if the bi-endianness
601 applies to the instruction set or just to the data. */
613 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
614 contents, addr, val, addend);
623 /* Offset the address so that we can use 4 byte relocations. */
624 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
625 contents + 2, addr, val, addend);
631 /* The most significant bit is stored in bit 6. */
634 hold = contents[addr + 4];
635 contents[addr + 4] &=~ 0x20;
636 contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
637 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
640 contents[addr] &=~ 0x40;
641 contents[addr] |= (contents[addr + 4] << 1) & 0x40;
642 contents[addr + 4] &=~ 0x20;
643 contents[addr + 4] |= hold & 0x20;
650 /* The most significant bit is stored in bit 28. */
653 hold = contents[addr + 1];
654 contents[addr + 1] &=~ 0x80;
655 contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
656 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
659 contents[addr + 3] &= ~0x10;
660 contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
661 contents[addr + 1] &=~ 0x80;
662 contents[addr + 1] |= hold & 0x80;
667 /* Parameter RAM is from 0x1000000 to 0x1000800. */
668 contents[addr] &=~ 0x3;
669 if (val >= 0x1000000 && val < 0x1000800)
670 contents[addr] |= 0x3;
672 contents[addr] |= 0x2;
673 rstat = bfd_reloc_ok;
677 /* Parameter RAM is from 0x1000000 to 0x1000800. */
678 contents[addr + 2] &= ~0xc0;
679 if (val >= 0x1000000 && val < 0x1000800)
680 contents[addr + 2] |= 0xc0;
682 contents[addr + 2] |= 0x80;
683 rstat = bfd_reloc_ok;
693 case bfd_reloc_outofrange:
694 (*_bfd_error_handler)
695 (_("%B: bad reloc address 0x%lx in section `%A'"),
696 input_bfd, input_section, (unsigned long) rel->r_vaddr);
698 case bfd_reloc_overflow:
701 char buf[SYMNMLEN + 1];
709 name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
714 if (! ((*info->callbacks->reloc_overflow)
715 (info, (h ? &h->root : NULL), name, howto->name,
716 (bfd_vma) 0, input_bfd, input_section,
717 rel->r_vaddr - input_section->vma)))
725 /* Clear the r_reserved field in relocs. */
726 #define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \
729 dst->r_reserved[0] = 0; \
730 dst->r_reserved[1] = 0; \
734 #define TIC80COFF 1 /* Customize coffcode.h */
735 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
736 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
737 #include "coffcode.h"
739 CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)