1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright 1996, 1997 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 2 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, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
29 #include "coff/tic80.h"
30 #include "coff/internal.h"
33 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
34 #define COFF_ALIGN_IN_SECTION_HEADER 1
36 #define GET_SCNHDR_FLAGS bfd_h_get_16
37 #define PUT_SCNHDR_FLAGS bfd_h_put_16
39 static void rtype2howto
40 PARAMS ((arelent *cache_ptr, struct internal_reloc *dst));
41 static bfd_reloc_status_type ppbase_reloc
42 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
43 static bfd_reloc_status_type glob15_reloc
44 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
45 static bfd_reloc_status_type glob16_reloc
46 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
47 static bfd_reloc_status_type local16_reloc
48 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
49 static boolean coff_tic80_relocate_section
50 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
51 struct internal_reloc *, struct internal_syment *, asection **));
53 static reloc_howto_type tic80_howto_table[] =
56 HOWTO (R_RELLONG, /* type */
58 2, /* size (0 = byte, 1 = short, 2 = long) */
60 false, /* pc_relative */
62 complain_overflow_bitfield, /* complain_on_overflow */
63 NULL, /* special_function */
65 true, /* partial_inplace */
66 0xffffffff, /* src_mask */
67 0xffffffff, /* dst_mask */
68 false), /* pcrel_offset */
70 HOWTO (R_MPPCR, /* type */
72 2, /* size (0 = byte, 1 = short, 2 = long) */
74 true, /* pc_relative */
76 complain_overflow_signed, /* complain_on_overflow */
77 NULL, /* special_function */
79 true, /* partial_inplace */
80 0xffffffff, /* src_mask */
81 0xffffffff, /* dst_mask */
82 true), /* pcrel_offset */
84 HOWTO (R_ABS, /* type */
86 2, /* size (0 = byte, 1 = short, 2 = long) */
88 false, /* pc_relative */
90 complain_overflow_bitfield, /* complain_on_overflow */
91 NULL, /* special_function */
93 true, /* partial_inplace */
94 0xffffffff, /* src_mask */
95 0xffffffff, /* dst_mask */
96 false), /* pcrel_offset */
98 HOWTO (R_PPBASE, /* type */
100 2, /* size (0 = byte, 1 = short, 2 = long) */
102 false, /* pc_relative */
104 complain_overflow_dont, /* complain_on_overflow */
105 ppbase_reloc, /* special_function */
107 true, /* partial_inplace */
108 0xffffffff, /* src_mask */
109 0xffffffff, /* dst_mask */
110 false), /* pcrel_offset */
112 HOWTO (R_PPLBASE, /* type */
114 2, /* size (0 = byte, 1 = short, 2 = long) */
116 false, /* pc_relative */
118 complain_overflow_dont, /* complain_on_overflow */
119 ppbase_reloc, /* special_function */
120 "PPLBASE", /* name */
121 true, /* partial_inplace */
122 0xffffffff, /* src_mask */
123 0xffffffff, /* dst_mask */
124 false), /* pcrel_offset */
126 HOWTO (R_PP15, /* type */
128 2, /* size (0 = byte, 1 = short, 2 = long) */
130 false, /* pc_relative */
132 complain_overflow_dont, /* complain_on_overflow */
133 glob15_reloc, /* special_function */
135 true, /* partial_inplace */
136 0x1ffc0, /* src_mask */
137 0x1ffc0, /* dst_mask */
138 false), /* pcrel_offset */
140 HOWTO (R_PP15W, /* type */
142 2, /* size (0 = byte, 1 = short, 2 = long) */
144 false, /* pc_relative */
146 complain_overflow_dont, /* complain_on_overflow */
147 glob15_reloc, /* special_function */
149 true, /* partial_inplace */
150 0x1ffc0, /* src_mask */
151 0x1ffc0, /* dst_mask */
152 false), /* pcrel_offset */
154 HOWTO (R_PP15H, /* type */
156 2, /* size (0 = byte, 1 = short, 2 = long) */
158 false, /* pc_relative */
160 complain_overflow_dont, /* complain_on_overflow */
161 glob15_reloc, /* special_function */
163 true, /* partial_inplace */
164 0x1ffc0, /* src_mask */
165 0x1ffc0, /* dst_mask */
166 false), /* pcrel_offset */
168 HOWTO (R_PP16B, /* type */
170 2, /* size (0 = byte, 1 = short, 2 = long) */
172 false, /* pc_relative */
174 complain_overflow_dont, /* complain_on_overflow */
175 glob16_reloc, /* special_function */
177 true, /* partial_inplace */
178 0x3ffc0, /* src_mask */
179 0x3ffc0, /* dst_mask */
180 false), /* pcrel_offset */
182 HOWTO (R_PPL15, /* type */
184 2, /* size (0 = byte, 1 = short, 2 = long) */
186 false, /* pc_relative */
188 complain_overflow_dont, /* complain_on_overflow */
189 NULL, /* special_function */
191 true, /* partial_inplace */
192 0x7fff, /* src_mask */
193 0x7fff, /* dst_mask */
194 false), /* pcrel_offset */
196 HOWTO (R_PPL15W, /* type */
198 2, /* size (0 = byte, 1 = short, 2 = long) */
200 false, /* pc_relative */
202 complain_overflow_dont, /* complain_on_overflow */
203 NULL, /* special_function */
205 true, /* partial_inplace */
206 0x7fff, /* src_mask */
207 0x7fff, /* dst_mask */
208 false), /* pcrel_offset */
210 HOWTO (R_PPL15H, /* type */
212 2, /* size (0 = byte, 1 = short, 2 = long) */
214 false, /* pc_relative */
216 complain_overflow_dont, /* complain_on_overflow */
217 NULL, /* special_function */
219 true, /* partial_inplace */
220 0x7fff, /* src_mask */
221 0x7fff, /* dst_mask */
222 false), /* pcrel_offset */
224 HOWTO (R_PPL16B, /* type */
226 2, /* size (0 = byte, 1 = short, 2 = long) */
228 false, /* pc_relative */
230 complain_overflow_dont, /* complain_on_overflow */
231 local16_reloc, /* special_function */
233 true, /* partial_inplace */
234 0xffff, /* src_mask */
235 0xffff, /* dst_mask */
236 false), /* pcrel_offset */
238 HOWTO (R_PPN15, /* type */
240 -2, /* size (0 = byte, 1 = short, 2 = long) */
242 false, /* pc_relative */
244 complain_overflow_dont, /* complain_on_overflow */
245 glob15_reloc, /* special_function */
247 true, /* partial_inplace */
248 0x1ffc0, /* src_mask */
249 0x1ffc0, /* dst_mask */
250 false), /* pcrel_offset */
252 HOWTO (R_PPN15W, /* type */
254 -2, /* size (0 = byte, 1 = short, 2 = long) */
256 false, /* pc_relative */
258 complain_overflow_dont, /* complain_on_overflow */
259 glob15_reloc, /* special_function */
261 true, /* partial_inplace */
262 0x1ffc0, /* src_mask */
263 0x1ffc0, /* dst_mask */
264 false), /* pcrel_offset */
266 HOWTO (R_PPN15H, /* type */
268 -2, /* size (0 = byte, 1 = short, 2 = long) */
270 false, /* pc_relative */
272 complain_overflow_dont, /* complain_on_overflow */
273 glob15_reloc, /* special_function */
275 true, /* partial_inplace */
276 0x1ffc0, /* src_mask */
277 0x1ffc0, /* dst_mask */
278 false), /* pcrel_offset */
280 HOWTO (R_PPN16B, /* type */
282 -2, /* size (0 = byte, 1 = short, 2 = long) */
284 false, /* pc_relative */
286 complain_overflow_dont, /* complain_on_overflow */
287 glob16_reloc, /* special_function */
289 true, /* partial_inplace */
290 0x3ffc0, /* src_mask */
291 0x3ffc0, /* dst_mask */
292 false), /* pcrel_offset */
294 HOWTO (R_PPLN15, /* type */
296 -2, /* size (0 = byte, 1 = short, 2 = long) */
298 false, /* pc_relative */
300 complain_overflow_dont, /* complain_on_overflow */
301 NULL, /* special_function */
303 true, /* partial_inplace */
304 0x7fff, /* src_mask */
305 0x7fff, /* dst_mask */
306 false), /* pcrel_offset */
308 HOWTO (R_PPLN15W, /* type */
310 -2, /* size (0 = byte, 1 = short, 2 = long) */
312 false, /* pc_relative */
314 complain_overflow_dont, /* complain_on_overflow */
315 NULL, /* special_function */
316 "PPLN15W", /* name */
317 true, /* partial_inplace */
318 0x7fff, /* src_mask */
319 0x7fff, /* dst_mask */
320 false), /* pcrel_offset */
322 HOWTO (R_PPLN15H, /* type */
324 -2, /* size (0 = byte, 1 = short, 2 = long) */
326 false, /* pc_relative */
328 complain_overflow_dont, /* complain_on_overflow */
329 NULL, /* special_function */
330 "PPLN15H", /* name */
331 true, /* partial_inplace */
332 0x7fff, /* src_mask */
333 0x7fff, /* dst_mask */
334 false), /* pcrel_offset */
336 HOWTO (R_PPLN16B, /* type */
338 -2, /* size (0 = byte, 1 = short, 2 = long) */
340 false, /* pc_relative */
342 complain_overflow_dont, /* complain_on_overflow */
343 local16_reloc, /* special_function */
344 "PPLN16B", /* name */
345 true, /* partial_inplace */
346 0xffff, /* src_mask */
347 0xffff, /* dst_mask */
348 false) /* pcrel_offset */
351 /* Special relocation functions, used when the output file is not
352 itself a COFF TIc80 file. */
354 /* This special function is used for the base address type
357 static bfd_reloc_status_type
358 ppbase_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
361 arelent *reloc_entry;
364 asection *input_section;
366 char **error_message;
372 /* This special function is used for the global 15 bit relocations. */
374 static bfd_reloc_status_type
375 glob15_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
378 arelent *reloc_entry;
381 asection *input_section;
383 char **error_message;
389 /* This special function is used for the global 16 bit relocations. */
391 static bfd_reloc_status_type
392 glob16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
395 arelent *reloc_entry;
398 asection *input_section;
400 char **error_message;
406 /* This special function is used for the local 16 bit relocations. */
408 static bfd_reloc_status_type
409 local16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
412 arelent *reloc_entry;
415 asection *input_section;
417 char **error_message;
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 (cache_ptr, dst)
430 struct internal_reloc *dst;
434 for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
436 if (tic80_howto_table[i].type == dst->r_type)
438 cache_ptr->howto = tic80_howto_table + i;
443 (*_bfd_error_handler) ("Unrecognized reloc type 0x%x",
444 (unsigned int) dst->r_type);
445 cache_ptr->howto = tic80_howto_table + 0;
448 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
449 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
451 static reloc_howto_type *
452 coff_tic80_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
455 struct internal_reloc *rel;
456 struct coff_link_hash_entry *h;
457 struct internal_syment *sym;
462 if (rel -> r_symndx == -1 && addendp != NULL)
464 /* This is a TI "internal relocation", which means that the relocation
465 amount is the amount by which the current section is being relocated
466 in the output section. */
467 *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
469 RTYPE2HOWTO (&genrel, rel);
474 #define BADMAG(x) TIC80BADMAG(x)
477 #define coff_relocate_section coff_tic80_relocate_section
479 /* We need a special relocation routine to handle the PP relocs. Most
480 of this is a copy of _bfd_coff_generic_relocate_section. */
483 coff_tic80_relocate_section (output_bfd, info, input_bfd,
484 input_section, contents, relocs, syms,
487 struct bfd_link_info *info;
489 asection *input_section;
491 struct internal_reloc *relocs;
492 struct internal_syment *syms;
495 struct internal_reloc *rel;
496 struct internal_reloc *relend;
499 relend = rel + input_section->reloc_count;
500 for (; rel < relend; rel++)
503 struct coff_link_hash_entry *h;
504 struct internal_syment *sym;
507 reloc_howto_type *howto;
508 bfd_reloc_status_type rstat;
511 symndx = rel->r_symndx;
520 h = obj_coff_sym_hashes (input_bfd)[symndx];
524 /* COFF treats common symbols in one of two ways. Either the
525 size of the symbol is included in the section contents, or it
526 is not. We assume that the size is not included, and force
527 the rtype_to_howto function to adjust the addend as needed. */
529 if (sym != NULL && sym->n_scnum != 0)
530 addend = - sym->n_value;
534 howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
547 sec = bfd_abs_section_ptr;
552 sec = sections[symndx];
553 val = (sec->output_section->vma
556 if (! obj_pe (output_bfd))
562 if (h->root.type == bfd_link_hash_defined
563 || h->root.type == bfd_link_hash_defweak)
567 sec = h->root.u.def.section;
568 val = (h->root.u.def.value
569 + sec->output_section->vma
570 + sec->output_offset);
573 else if (! info->relocateable)
575 if (! ((*info->callbacks->undefined_symbol)
576 (info, h->root.root.string, input_bfd, input_section,
577 rel->r_vaddr - input_section->vma)))
582 addr = rel->r_vaddr - input_section->vma;
584 /* FIXME: This code assumes little endian, but the PP can
585 apparently be bi-endian. I don't know if the bi-endianness
586 applies to the instruction set or just to the data. */
598 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
599 contents, addr, val, addend);
608 /* Offset the address so that we can use 4 byte relocations. */
609 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
610 contents + 2, addr, val, addend);
616 /* The most significant bit is stored in bit 6. */
619 hold = contents[addr + 4];
620 contents[addr + 4] &=~ 0x20;
621 contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
622 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
625 contents[addr] &=~ 0x40;
626 contents[addr] |= (contents[addr + 4] << 1) & 0x40;
627 contents[addr + 4] &=~ 0x20;
628 contents[addr + 4] |= hold & 0x20;
635 /* The most significant bit is stored in bit 28. */
638 hold = contents[addr + 1];
639 contents[addr + 1] &=~ 0x80;
640 contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
641 rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
644 contents[addr + 3] &= ~0x10;
645 contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
646 contents[addr + 1] &=~ 0x80;
647 contents[addr + 1] |= hold & 0x80;
652 /* Parameter RAM is from 0x1000000 to 0x1000800. */
653 contents[addr] &=~ 0x3;
654 if (val >= 0x1000000 && val < 0x1000800)
655 contents[addr] |= 0x3;
657 contents[addr] |= 0x2;
658 rstat = bfd_reloc_ok;
662 /* Parameter RAM is from 0x1000000 to 0x1000800. */
663 contents[addr + 2] &= ~0xc0;
664 if (val >= 0x1000000 && val < 0x1000800)
665 contents[addr + 2] |= 0xc0;
667 contents[addr + 2] |= 0x80;
668 rstat = bfd_reloc_ok;
678 case bfd_reloc_outofrange:
679 (*_bfd_error_handler)
680 ("%s: bad reloc address 0x%lx in section `%s'",
681 bfd_get_filename (input_bfd),
682 (unsigned long) rel->r_vaddr,
683 bfd_get_section_name (input_bfd, input_section));
685 case bfd_reloc_overflow:
688 char buf[SYMNMLEN + 1];
693 name = h->root.root.string;
696 name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
701 if (! ((*info->callbacks->reloc_overflow)
702 (info, name, howto->name, (bfd_vma) 0, input_bfd,
703 input_section, rel->r_vaddr - input_section->vma)))
711 #define TIC80COFF 1 /* Customize coffcode.h */
712 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
713 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
714 #include "coffcode.h"
719 "coff-tic80", /* name */
720 bfd_target_coff_flavour,
721 BFD_ENDIAN_LITTLE, /* data byte order is little (arch supports both) */
722 BFD_ENDIAN_LITTLE, /* header byte order is little */
724 (HAS_RELOC | EXEC_P | /* object flags */
725 HAS_LINENO | HAS_DEBUG |
726 HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED),
728 (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
729 '_', /* leading underscore */
730 '/', /* ar_pad_char */
731 15, /* ar_max_namelen */
732 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
733 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
734 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
735 bfd_getl64, bfd_getl_signed_64, bfd_putl64,
736 bfd_getl32, bfd_getl_signed_32, bfd_putl32,
737 bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
739 {_bfd_dummy_target, coff_object_p, /* bfd_check_format */
740 bfd_generic_archive_p, _bfd_dummy_target},
741 {bfd_false, coff_mkobject, _bfd_generic_mkarchive, /* bfd_set_format */
743 {bfd_false, coff_write_object_contents, /* bfd_write_contents */
744 _bfd_write_archive_contents, bfd_false},
746 BFD_JUMP_TABLE_GENERIC (coff),
747 BFD_JUMP_TABLE_COPY (coff),
748 BFD_JUMP_TABLE_CORE (_bfd_nocore),
749 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
750 BFD_JUMP_TABLE_SYMBOLS (coff),
751 BFD_JUMP_TABLE_RELOCS (coff),
752 BFD_JUMP_TABLE_WRITE (coff),
753 BFD_JUMP_TABLE_LINK (coff),
754 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),