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)
35 static void rtype2howto
36 PARAMS ((arelent
*cache_ptr
, struct internal_reloc
*dst
));
37 static bfd_reloc_status_type ppbase_reloc
38 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
39 static bfd_reloc_status_type glob15_reloc
40 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
41 static bfd_reloc_status_type glob16_reloc
42 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
43 static bfd_reloc_status_type local16_reloc
44 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
45 static boolean coff_tic80_relocate_section
46 PARAMS ((bfd
*, struct bfd_link_info
*, bfd
*, asection
*, bfd_byte
*,
47 struct internal_reloc
*, struct internal_syment
*, asection
**));
49 static reloc_howto_type tic80_howto_table
[] =
52 HOWTO (R_RELLONG
, /* type */
54 2, /* size (0 = byte, 1 = short, 2 = long) */
56 false, /* pc_relative */
58 complain_overflow_bitfield
, /* complain_on_overflow */
59 NULL
, /* special_function */
61 true, /* partial_inplace */
62 0xffffffff, /* src_mask */
63 0xffffffff, /* dst_mask */
64 false), /* pcrel_offset */
66 HOWTO (R_MPPCR
, /* type */
68 2, /* size (0 = byte, 1 = short, 2 = long) */
70 true, /* pc_relative */
72 complain_overflow_signed
, /* complain_on_overflow */
73 NULL
, /* special_function */
75 true, /* partial_inplace */
76 0xffffffff, /* src_mask */
77 0xffffffff, /* dst_mask */
78 true), /* pcrel_offset */
80 HOWTO (R_ABS
, /* type */
82 2, /* size (0 = byte, 1 = short, 2 = long) */
84 false, /* pc_relative */
86 complain_overflow_bitfield
, /* complain_on_overflow */
87 NULL
, /* special_function */
89 true, /* partial_inplace */
90 0xffffffff, /* src_mask */
91 0xffffffff, /* dst_mask */
92 false), /* pcrel_offset */
94 HOWTO (R_PPBASE
, /* type */
96 2, /* size (0 = byte, 1 = short, 2 = long) */
98 false, /* pc_relative */
100 complain_overflow_dont
, /* complain_on_overflow */
101 ppbase_reloc
, /* special_function */
103 true, /* partial_inplace */
104 0xffffffff, /* src_mask */
105 0xffffffff, /* dst_mask */
106 false), /* pcrel_offset */
108 HOWTO (R_PPLBASE
, /* type */
110 2, /* size (0 = byte, 1 = short, 2 = long) */
112 false, /* pc_relative */
114 complain_overflow_dont
, /* complain_on_overflow */
115 ppbase_reloc
, /* special_function */
116 "PPLBASE", /* name */
117 true, /* partial_inplace */
118 0xffffffff, /* src_mask */
119 0xffffffff, /* dst_mask */
120 false), /* pcrel_offset */
122 HOWTO (R_PP15
, /* type */
124 2, /* size (0 = byte, 1 = short, 2 = long) */
126 false, /* pc_relative */
128 complain_overflow_dont
, /* complain_on_overflow */
129 glob15_reloc
, /* special_function */
131 true, /* partial_inplace */
132 0x1ffc0, /* src_mask */
133 0x1ffc0, /* dst_mask */
134 false), /* pcrel_offset */
136 HOWTO (R_PP15W
, /* type */
138 2, /* size (0 = byte, 1 = short, 2 = long) */
140 false, /* pc_relative */
142 complain_overflow_dont
, /* complain_on_overflow */
143 glob15_reloc
, /* special_function */
145 true, /* partial_inplace */
146 0x1ffc0, /* src_mask */
147 0x1ffc0, /* dst_mask */
148 false), /* pcrel_offset */
150 HOWTO (R_PP15H
, /* type */
152 2, /* size (0 = byte, 1 = short, 2 = long) */
154 false, /* pc_relative */
156 complain_overflow_dont
, /* complain_on_overflow */
157 glob15_reloc
, /* special_function */
159 true, /* partial_inplace */
160 0x1ffc0, /* src_mask */
161 0x1ffc0, /* dst_mask */
162 false), /* pcrel_offset */
164 HOWTO (R_PP16B
, /* type */
166 2, /* size (0 = byte, 1 = short, 2 = long) */
168 false, /* pc_relative */
170 complain_overflow_dont
, /* complain_on_overflow */
171 glob16_reloc
, /* special_function */
173 true, /* partial_inplace */
174 0x3ffc0, /* src_mask */
175 0x3ffc0, /* dst_mask */
176 false), /* pcrel_offset */
178 HOWTO (R_PPL15
, /* type */
180 2, /* size (0 = byte, 1 = short, 2 = long) */
182 false, /* pc_relative */
184 complain_overflow_dont
, /* complain_on_overflow */
185 NULL
, /* special_function */
187 true, /* partial_inplace */
188 0x7fff, /* src_mask */
189 0x7fff, /* dst_mask */
190 false), /* pcrel_offset */
192 HOWTO (R_PPL15W
, /* type */
194 2, /* size (0 = byte, 1 = short, 2 = long) */
196 false, /* pc_relative */
198 complain_overflow_dont
, /* complain_on_overflow */
199 NULL
, /* special_function */
201 true, /* partial_inplace */
202 0x7fff, /* src_mask */
203 0x7fff, /* dst_mask */
204 false), /* pcrel_offset */
206 HOWTO (R_PPL15H
, /* type */
208 2, /* size (0 = byte, 1 = short, 2 = long) */
210 false, /* pc_relative */
212 complain_overflow_dont
, /* complain_on_overflow */
213 NULL
, /* special_function */
215 true, /* partial_inplace */
216 0x7fff, /* src_mask */
217 0x7fff, /* dst_mask */
218 false), /* pcrel_offset */
220 HOWTO (R_PPL16B
, /* type */
222 2, /* size (0 = byte, 1 = short, 2 = long) */
224 false, /* pc_relative */
226 complain_overflow_dont
, /* complain_on_overflow */
227 local16_reloc
, /* special_function */
229 true, /* partial_inplace */
230 0xffff, /* src_mask */
231 0xffff, /* dst_mask */
232 false), /* pcrel_offset */
234 HOWTO (R_PPN15
, /* type */
236 -2, /* size (0 = byte, 1 = short, 2 = long) */
238 false, /* pc_relative */
240 complain_overflow_dont
, /* complain_on_overflow */
241 glob15_reloc
, /* special_function */
243 true, /* partial_inplace */
244 0x1ffc0, /* src_mask */
245 0x1ffc0, /* dst_mask */
246 false), /* pcrel_offset */
248 HOWTO (R_PPN15W
, /* type */
250 -2, /* size (0 = byte, 1 = short, 2 = long) */
252 false, /* pc_relative */
254 complain_overflow_dont
, /* complain_on_overflow */
255 glob15_reloc
, /* special_function */
257 true, /* partial_inplace */
258 0x1ffc0, /* src_mask */
259 0x1ffc0, /* dst_mask */
260 false), /* pcrel_offset */
262 HOWTO (R_PPN15H
, /* type */
264 -2, /* size (0 = byte, 1 = short, 2 = long) */
266 false, /* pc_relative */
268 complain_overflow_dont
, /* complain_on_overflow */
269 glob15_reloc
, /* special_function */
271 true, /* partial_inplace */
272 0x1ffc0, /* src_mask */
273 0x1ffc0, /* dst_mask */
274 false), /* pcrel_offset */
276 HOWTO (R_PPN16B
, /* type */
278 -2, /* size (0 = byte, 1 = short, 2 = long) */
280 false, /* pc_relative */
282 complain_overflow_dont
, /* complain_on_overflow */
283 glob16_reloc
, /* special_function */
285 true, /* partial_inplace */
286 0x3ffc0, /* src_mask */
287 0x3ffc0, /* dst_mask */
288 false), /* pcrel_offset */
290 HOWTO (R_PPLN15
, /* type */
292 -2, /* size (0 = byte, 1 = short, 2 = long) */
294 false, /* pc_relative */
296 complain_overflow_dont
, /* complain_on_overflow */
297 NULL
, /* special_function */
299 true, /* partial_inplace */
300 0x7fff, /* src_mask */
301 0x7fff, /* dst_mask */
302 false), /* pcrel_offset */
304 HOWTO (R_PPLN15W
, /* type */
306 -2, /* size (0 = byte, 1 = short, 2 = long) */
308 false, /* pc_relative */
310 complain_overflow_dont
, /* complain_on_overflow */
311 NULL
, /* special_function */
312 "PPLN15W", /* name */
313 true, /* partial_inplace */
314 0x7fff, /* src_mask */
315 0x7fff, /* dst_mask */
316 false), /* pcrel_offset */
318 HOWTO (R_PPLN15H
, /* type */
320 -2, /* size (0 = byte, 1 = short, 2 = long) */
322 false, /* pc_relative */
324 complain_overflow_dont
, /* complain_on_overflow */
325 NULL
, /* special_function */
326 "PPLN15H", /* name */
327 true, /* partial_inplace */
328 0x7fff, /* src_mask */
329 0x7fff, /* dst_mask */
330 false), /* pcrel_offset */
332 HOWTO (R_PPLN16B
, /* type */
334 -2, /* size (0 = byte, 1 = short, 2 = long) */
336 false, /* pc_relative */
338 complain_overflow_dont
, /* complain_on_overflow */
339 local16_reloc
, /* special_function */
340 "PPLN16B", /* name */
341 true, /* partial_inplace */
342 0xffff, /* src_mask */
343 0xffff, /* dst_mask */
344 false) /* pcrel_offset */
347 /* Special relocation functions, used when the output file is not
348 itself a COFF TIc80 file. */
350 /* This special function is used for the base address type
353 static bfd_reloc_status_type
354 ppbase_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
357 arelent
*reloc_entry
;
360 asection
*input_section
;
362 char **error_message
;
368 /* This special function is used for the global 15 bit relocations. */
370 static bfd_reloc_status_type
371 glob15_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
374 arelent
*reloc_entry
;
377 asection
*input_section
;
379 char **error_message
;
385 /* This special function is used for the global 16 bit relocations. */
387 static bfd_reloc_status_type
388 glob16_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
391 arelent
*reloc_entry
;
394 asection
*input_section
;
396 char **error_message
;
402 /* This special function is used for the local 16 bit relocations. */
404 static bfd_reloc_status_type
405 local16_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
408 arelent
*reloc_entry
;
411 asection
*input_section
;
413 char **error_message
;
419 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
420 If passed an r_type we don't recognize the abort rather than silently failing
421 to generate an output file. */
424 rtype2howto (cache_ptr
, dst
)
426 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 (abfd
, sec
, rel
, h
, sym
, addendp
)
451 struct internal_reloc
*rel
;
452 struct coff_link_hash_entry
*h
;
453 struct internal_syment
*sym
;
458 if (rel
-> r_symndx
== -1 && addendp
!= NULL
)
460 /* This is a TI "internal relocation", which means that the relocation
461 amount is the amount by which the current section is being relocated
462 in the output section. */
463 *addendp
= (sec
-> output_section
-> vma
+ sec
-> output_offset
) - sec
-> vma
;
465 RTYPE2HOWTO (&genrel
, rel
);
470 #define BADMAG(x) TIC80BADMAG(x)
473 #define coff_relocate_section coff_tic80_relocate_section
475 /* We need a special relocation routine to handle the PP relocs. Most
476 of this is a copy of _bfd_coff_generic_relocate_section. */
479 coff_tic80_relocate_section (output_bfd
, info
, input_bfd
,
480 input_section
, contents
, relocs
, syms
,
483 struct bfd_link_info
*info
;
485 asection
*input_section
;
487 struct internal_reloc
*relocs
;
488 struct internal_syment
*syms
;
491 struct internal_reloc
*rel
;
492 struct internal_reloc
*relend
;
495 relend
= rel
+ input_section
->reloc_count
;
496 for (; rel
< relend
; rel
++)
499 struct coff_link_hash_entry
*h
;
500 struct internal_syment
*sym
;
503 reloc_howto_type
*howto
;
504 bfd_reloc_status_type rstat
;
507 symndx
= rel
->r_symndx
;
516 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
520 /* COFF treats common symbols in one of two ways. Either the
521 size of the symbol is included in the section contents, or it
522 is not. We assume that the size is not included, and force
523 the rtype_to_howto function to adjust the addend as needed. */
525 if (sym
!= NULL
&& sym
->n_scnum
!= 0)
526 addend
= - sym
->n_value
;
530 howto
= bfd_coff_rtype_to_howto (input_bfd
, input_section
, rel
, h
,
543 sec
= bfd_abs_section_ptr
;
548 sec
= sections
[symndx
];
549 val
= (sec
->output_section
->vma
552 if (! obj_pe (output_bfd
))
558 if (h
->root
.type
== bfd_link_hash_defined
559 || h
->root
.type
== bfd_link_hash_defweak
)
563 sec
= h
->root
.u
.def
.section
;
564 val
= (h
->root
.u
.def
.value
565 + sec
->output_section
->vma
566 + sec
->output_offset
);
569 else if (! info
->relocateable
)
571 if (! ((*info
->callbacks
->undefined_symbol
)
572 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
573 rel
->r_vaddr
- input_section
->vma
)))
578 addr
= rel
->r_vaddr
- input_section
->vma
;
580 /* FIXME: This code assumes little endian, but the PP can
581 apparently be bi-endian. I don't know if the bi-endianness
582 applies to the instruction set or just to the data. */
594 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
595 contents
, addr
, val
, addend
);
604 /* Offset the address so that we can use 4 byte relocations. */
605 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
606 contents
+ 2, addr
, val
, addend
);
612 /* The most significant bit is stored in bit 6. */
615 hold
= contents
[addr
+ 4];
616 contents
[addr
+ 4] &=~ 0x20;
617 contents
[addr
+ 4] |= (contents
[addr
] >> 1) & 0x20;
618 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
621 contents
[addr
] &=~ 0x40;
622 contents
[addr
] |= (contents
[addr
+ 4] << 1) & 0x40;
623 contents
[addr
+ 4] &=~ 0x20;
624 contents
[addr
+ 4] |= hold
& 0x20;
631 /* The most significant bit is stored in bit 28. */
634 hold
= contents
[addr
+ 1];
635 contents
[addr
+ 1] &=~ 0x80;
636 contents
[addr
+ 1] |= (contents
[addr
+ 3] << 3) & 0x80;
637 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
640 contents
[addr
+ 3] &= ~0x10;
641 contents
[addr
+ 3] |= (contents
[addr
+ 1] >> 3) & 0x10;
642 contents
[addr
+ 1] &=~ 0x80;
643 contents
[addr
+ 1] |= hold
& 0x80;
648 /* Parameter RAM is from 0x1000000 to 0x1000800. */
649 contents
[addr
] &=~ 0x3;
650 if (val
>= 0x1000000 && val
< 0x1000800)
651 contents
[addr
] |= 0x3;
653 contents
[addr
] |= 0x2;
654 rstat
= bfd_reloc_ok
;
658 /* Parameter RAM is from 0x1000000 to 0x1000800. */
659 contents
[addr
+ 2] &= ~0xc0;
660 if (val
>= 0x1000000 && val
< 0x1000800)
661 contents
[addr
+ 2] |= 0xc0;
663 contents
[addr
+ 2] |= 0x80;
664 rstat
= bfd_reloc_ok
;
674 case bfd_reloc_outofrange
:
675 (*_bfd_error_handler
)
676 ("%s: bad reloc address 0x%lx in section `%s'",
677 bfd_get_filename (input_bfd
),
678 (unsigned long) rel
->r_vaddr
,
679 bfd_get_section_name (input_bfd
, input_section
));
681 case bfd_reloc_overflow
:
684 char buf
[SYMNMLEN
+ 1];
689 name
= h
->root
.root
.string
;
692 name
= _bfd_coff_internal_syment_name (input_bfd
, sym
, buf
);
697 if (! ((*info
->callbacks
->reloc_overflow
)
698 (info
, name
, howto
->name
, (bfd_vma
) 0, input_bfd
,
699 input_section
, rel
->r_vaddr
- input_section
->vma
)))
707 #define TIC80 1 /* Customize coffcode.h */
708 #include "coffcode.h"
713 "coff-tic80", /* name */
714 bfd_target_coff_flavour
,
715 BFD_ENDIAN_LITTLE
, /* data byte order is little (arch supports both) */
716 BFD_ENDIAN_LITTLE
, /* header byte order is little */
718 (HAS_RELOC
| EXEC_P
| /* object flags */
719 HAS_LINENO
| HAS_DEBUG
|
720 HAS_SYMS
| HAS_LOCALS
| WP_TEXT
| D_PAGED
),
722 (SEC_HAS_CONTENTS
| SEC_ALLOC
| SEC_LOAD
| SEC_RELOC
), /* section flags */
723 '_', /* leading underscore */
724 '/', /* ar_pad_char */
725 15, /* ar_max_namelen */
726 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
727 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
728 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
, /* data */
729 bfd_getl64
, bfd_getl_signed_64
, bfd_putl64
,
730 bfd_getl32
, bfd_getl_signed_32
, bfd_putl32
,
731 bfd_getl16
, bfd_getl_signed_16
, bfd_putl16
, /* hdrs */
733 {_bfd_dummy_target
, coff_object_p
, /* bfd_check_format */
734 bfd_generic_archive_p
, _bfd_dummy_target
},
735 {bfd_false
, coff_mkobject
, _bfd_generic_mkarchive
, /* bfd_set_format */
737 {bfd_false
, coff_write_object_contents
, /* bfd_write_contents */
738 _bfd_write_archive_contents
, bfd_false
},
740 BFD_JUMP_TABLE_GENERIC (coff
),
741 BFD_JUMP_TABLE_COPY (coff
),
742 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
743 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff
),
744 BFD_JUMP_TABLE_SYMBOLS (coff
),
745 BFD_JUMP_TABLE_RELOCS (coff
),
746 BFD_JUMP_TABLE_WRITE (coff
),
747 BFD_JUMP_TABLE_LINK (coff
),
748 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),