1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright 1996, 1997, 1999, 2000 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, 59 Temple Place - Suite 330,
24 Boston, MA 02111-1307, USA. */
30 #include "coff/tic80.h"
31 #include "coff/internal.h"
34 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
35 #define COFF_ALIGN_IN_SECTION_HEADER 1
36 #define COFF_ALIGN_IN_SFLAGS 1
38 #define GET_SCNHDR_FLAGS bfd_h_get_16
39 #define PUT_SCNHDR_FLAGS bfd_h_put_16
41 static void rtype2howto
42 PARAMS ((arelent
*cache_ptr
, struct internal_reloc
*dst
));
43 static bfd_reloc_status_type ppbase_reloc
44 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
45 static bfd_reloc_status_type glob15_reloc
46 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
47 static bfd_reloc_status_type glob16_reloc
48 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
49 static bfd_reloc_status_type local16_reloc
50 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
51 static boolean coff_tic80_relocate_section
52 PARAMS ((bfd
*, struct bfd_link_info
*, bfd
*, asection
*, bfd_byte
*,
53 struct internal_reloc
*, struct internal_syment
*, asection
**));
55 static reloc_howto_type tic80_howto_table
[] =
58 HOWTO (R_RELLONG
, /* type */
60 2, /* size (0 = byte, 1 = short, 2 = long) */
62 false, /* pc_relative */
64 complain_overflow_bitfield
, /* complain_on_overflow */
65 NULL
, /* special_function */
67 true, /* partial_inplace */
68 0xffffffff, /* src_mask */
69 0xffffffff, /* dst_mask */
70 false), /* pcrel_offset */
72 HOWTO (R_MPPCR
, /* type */
74 2, /* size (0 = byte, 1 = short, 2 = long) */
76 true, /* pc_relative */
78 complain_overflow_signed
, /* complain_on_overflow */
79 NULL
, /* special_function */
81 true, /* partial_inplace */
82 0xffffffff, /* src_mask */
83 0xffffffff, /* dst_mask */
84 true), /* pcrel_offset */
86 HOWTO (R_ABS
, /* type */
88 2, /* size (0 = byte, 1 = short, 2 = long) */
90 false, /* pc_relative */
92 complain_overflow_bitfield
, /* complain_on_overflow */
93 NULL
, /* special_function */
95 true, /* partial_inplace */
96 0xffffffff, /* src_mask */
97 0xffffffff, /* dst_mask */
98 false), /* pcrel_offset */
100 HOWTO (R_PPBASE
, /* type */
102 2, /* size (0 = byte, 1 = short, 2 = long) */
104 false, /* pc_relative */
106 complain_overflow_dont
, /* complain_on_overflow */
107 ppbase_reloc
, /* special_function */
109 true, /* partial_inplace */
110 0xffffffff, /* src_mask */
111 0xffffffff, /* dst_mask */
112 false), /* pcrel_offset */
114 HOWTO (R_PPLBASE
, /* type */
116 2, /* size (0 = byte, 1 = short, 2 = long) */
118 false, /* pc_relative */
120 complain_overflow_dont
, /* complain_on_overflow */
121 ppbase_reloc
, /* special_function */
122 "PPLBASE", /* name */
123 true, /* partial_inplace */
124 0xffffffff, /* src_mask */
125 0xffffffff, /* dst_mask */
126 false), /* pcrel_offset */
128 HOWTO (R_PP15
, /* type */
130 2, /* size (0 = byte, 1 = short, 2 = long) */
132 false, /* pc_relative */
134 complain_overflow_dont
, /* complain_on_overflow */
135 glob15_reloc
, /* special_function */
137 true, /* partial_inplace */
138 0x1ffc0, /* src_mask */
139 0x1ffc0, /* dst_mask */
140 false), /* pcrel_offset */
142 HOWTO (R_PP15W
, /* type */
144 2, /* size (0 = byte, 1 = short, 2 = long) */
146 false, /* pc_relative */
148 complain_overflow_dont
, /* complain_on_overflow */
149 glob15_reloc
, /* special_function */
151 true, /* partial_inplace */
152 0x1ffc0, /* src_mask */
153 0x1ffc0, /* dst_mask */
154 false), /* pcrel_offset */
156 HOWTO (R_PP15H
, /* type */
158 2, /* size (0 = byte, 1 = short, 2 = long) */
160 false, /* pc_relative */
162 complain_overflow_dont
, /* complain_on_overflow */
163 glob15_reloc
, /* special_function */
165 true, /* partial_inplace */
166 0x1ffc0, /* src_mask */
167 0x1ffc0, /* dst_mask */
168 false), /* pcrel_offset */
170 HOWTO (R_PP16B
, /* type */
172 2, /* size (0 = byte, 1 = short, 2 = long) */
174 false, /* pc_relative */
176 complain_overflow_dont
, /* complain_on_overflow */
177 glob16_reloc
, /* special_function */
179 true, /* partial_inplace */
180 0x3ffc0, /* src_mask */
181 0x3ffc0, /* dst_mask */
182 false), /* pcrel_offset */
184 HOWTO (R_PPL15
, /* type */
186 2, /* size (0 = byte, 1 = short, 2 = long) */
188 false, /* pc_relative */
190 complain_overflow_dont
, /* complain_on_overflow */
191 NULL
, /* special_function */
193 true, /* partial_inplace */
194 0x7fff, /* src_mask */
195 0x7fff, /* dst_mask */
196 false), /* pcrel_offset */
198 HOWTO (R_PPL15W
, /* type */
200 2, /* size (0 = byte, 1 = short, 2 = long) */
202 false, /* pc_relative */
204 complain_overflow_dont
, /* complain_on_overflow */
205 NULL
, /* special_function */
207 true, /* partial_inplace */
208 0x7fff, /* src_mask */
209 0x7fff, /* dst_mask */
210 false), /* pcrel_offset */
212 HOWTO (R_PPL15H
, /* type */
214 2, /* size (0 = byte, 1 = short, 2 = long) */
216 false, /* pc_relative */
218 complain_overflow_dont
, /* complain_on_overflow */
219 NULL
, /* special_function */
221 true, /* partial_inplace */
222 0x7fff, /* src_mask */
223 0x7fff, /* dst_mask */
224 false), /* pcrel_offset */
226 HOWTO (R_PPL16B
, /* type */
228 2, /* size (0 = byte, 1 = short, 2 = long) */
230 false, /* pc_relative */
232 complain_overflow_dont
, /* complain_on_overflow */
233 local16_reloc
, /* special_function */
235 true, /* partial_inplace */
236 0xffff, /* src_mask */
237 0xffff, /* dst_mask */
238 false), /* pcrel_offset */
240 HOWTO (R_PPN15
, /* type */
242 -2, /* size (0 = byte, 1 = short, 2 = long) */
244 false, /* pc_relative */
246 complain_overflow_dont
, /* complain_on_overflow */
247 glob15_reloc
, /* special_function */
249 true, /* partial_inplace */
250 0x1ffc0, /* src_mask */
251 0x1ffc0, /* dst_mask */
252 false), /* pcrel_offset */
254 HOWTO (R_PPN15W
, /* type */
256 -2, /* size (0 = byte, 1 = short, 2 = long) */
258 false, /* pc_relative */
260 complain_overflow_dont
, /* complain_on_overflow */
261 glob15_reloc
, /* special_function */
263 true, /* partial_inplace */
264 0x1ffc0, /* src_mask */
265 0x1ffc0, /* dst_mask */
266 false), /* pcrel_offset */
268 HOWTO (R_PPN15H
, /* type */
270 -2, /* size (0 = byte, 1 = short, 2 = long) */
272 false, /* pc_relative */
274 complain_overflow_dont
, /* complain_on_overflow */
275 glob15_reloc
, /* special_function */
277 true, /* partial_inplace */
278 0x1ffc0, /* src_mask */
279 0x1ffc0, /* dst_mask */
280 false), /* pcrel_offset */
282 HOWTO (R_PPN16B
, /* type */
284 -2, /* size (0 = byte, 1 = short, 2 = long) */
286 false, /* pc_relative */
288 complain_overflow_dont
, /* complain_on_overflow */
289 glob16_reloc
, /* special_function */
291 true, /* partial_inplace */
292 0x3ffc0, /* src_mask */
293 0x3ffc0, /* dst_mask */
294 false), /* pcrel_offset */
296 HOWTO (R_PPLN15
, /* type */
298 -2, /* size (0 = byte, 1 = short, 2 = long) */
300 false, /* pc_relative */
302 complain_overflow_dont
, /* complain_on_overflow */
303 NULL
, /* special_function */
305 true, /* partial_inplace */
306 0x7fff, /* src_mask */
307 0x7fff, /* dst_mask */
308 false), /* pcrel_offset */
310 HOWTO (R_PPLN15W
, /* type */
312 -2, /* size (0 = byte, 1 = short, 2 = long) */
314 false, /* pc_relative */
316 complain_overflow_dont
, /* complain_on_overflow */
317 NULL
, /* special_function */
318 "PPLN15W", /* name */
319 true, /* partial_inplace */
320 0x7fff, /* src_mask */
321 0x7fff, /* dst_mask */
322 false), /* pcrel_offset */
324 HOWTO (R_PPLN15H
, /* type */
326 -2, /* size (0 = byte, 1 = short, 2 = long) */
328 false, /* pc_relative */
330 complain_overflow_dont
, /* complain_on_overflow */
331 NULL
, /* special_function */
332 "PPLN15H", /* name */
333 true, /* partial_inplace */
334 0x7fff, /* src_mask */
335 0x7fff, /* dst_mask */
336 false), /* pcrel_offset */
338 HOWTO (R_PPLN16B
, /* type */
340 -2, /* size (0 = byte, 1 = short, 2 = long) */
342 false, /* pc_relative */
344 complain_overflow_dont
, /* complain_on_overflow */
345 local16_reloc
, /* special_function */
346 "PPLN16B", /* name */
347 true, /* partial_inplace */
348 0xffff, /* src_mask */
349 0xffff, /* dst_mask */
350 false) /* pcrel_offset */
353 /* Special relocation functions, used when the output file is not
354 itself a COFF TIc80 file. */
356 /* This special function is used for the base address type
359 static bfd_reloc_status_type
360 ppbase_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
362 bfd
*abfd ATTRIBUTE_UNUSED
;
363 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
364 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
365 PTR data ATTRIBUTE_UNUSED
;
366 asection
*input_section ATTRIBUTE_UNUSED
;
367 bfd
*output_bfd ATTRIBUTE_UNUSED
;
368 char **error_message ATTRIBUTE_UNUSED
;
374 /* This special function is used for the global 15 bit relocations. */
376 static bfd_reloc_status_type
377 glob15_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
379 bfd
*abfd ATTRIBUTE_UNUSED
;
380 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
381 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
382 PTR 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 (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
396 bfd
*abfd ATTRIBUTE_UNUSED
;
397 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
398 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
399 PTR 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 (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
413 bfd
*abfd ATTRIBUTE_UNUSED
;
414 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
415 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
416 PTR data ATTRIBUTE_UNUSED
;
417 asection
*input_section ATTRIBUTE_UNUSED
;
418 bfd
*output_bfd ATTRIBUTE_UNUSED
;
419 char **error_message ATTRIBUTE_UNUSED
;
425 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
426 If passed an r_type we don't recognize the abort rather than silently failing
427 to generate an output file. */
430 rtype2howto (cache_ptr
, dst
)
432 struct internal_reloc
*dst
;
436 for (i
= 0; i
< sizeof tic80_howto_table
/ sizeof tic80_howto_table
[0]; i
++)
438 if (tic80_howto_table
[i
].type
== dst
->r_type
)
440 cache_ptr
->howto
= tic80_howto_table
+ i
;
445 (*_bfd_error_handler
) (_("Unrecognized reloc type 0x%x"),
446 (unsigned int) dst
->r_type
);
447 cache_ptr
->howto
= tic80_howto_table
+ 0;
450 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
451 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
453 static reloc_howto_type
*
454 coff_tic80_rtype_to_howto (abfd
, sec
, rel
, h
, sym
, addendp
)
455 bfd
*abfd ATTRIBUTE_UNUSED
;
457 struct internal_reloc
*rel
;
458 struct coff_link_hash_entry
*h ATTRIBUTE_UNUSED
;
459 struct internal_syment
*sym ATTRIBUTE_UNUSED
;
464 if (rel
-> r_symndx
== -1 && addendp
!= NULL
)
466 /* This is a TI "internal relocation", which means that the relocation
467 amount is the amount by which the current section is being relocated
468 in the output section. */
469 *addendp
= (sec
-> output_section
-> vma
+ sec
-> output_offset
) - sec
-> vma
;
471 RTYPE2HOWTO (&genrel
, rel
);
476 #define BADMAG(x) TIC80BADMAG(x)
479 #define coff_relocate_section coff_tic80_relocate_section
481 /* We need a special relocation routine to handle the PP relocs. Most
482 of this is a copy of _bfd_coff_generic_relocate_section. */
485 coff_tic80_relocate_section (output_bfd
, info
, input_bfd
,
486 input_section
, contents
, relocs
, syms
,
489 struct bfd_link_info
*info
;
491 asection
*input_section
;
493 struct internal_reloc
*relocs
;
494 struct internal_syment
*syms
;
497 struct internal_reloc
*rel
;
498 struct internal_reloc
*relend
;
501 relend
= rel
+ input_section
->reloc_count
;
502 for (; rel
< relend
; rel
++)
505 struct coff_link_hash_entry
*h
;
506 struct internal_syment
*sym
;
509 reloc_howto_type
*howto
;
510 bfd_reloc_status_type rstat
;
513 symndx
= rel
->r_symndx
;
522 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
526 /* COFF treats common symbols in one of two ways. Either the
527 size of the symbol is included in the section contents, or it
528 is not. We assume that the size is not included, and force
529 the rtype_to_howto function to adjust the addend as needed. */
531 if (sym
!= NULL
&& sym
->n_scnum
!= 0)
532 addend
= - sym
->n_value
;
536 howto
= bfd_coff_rtype_to_howto (input_bfd
, input_section
, rel
, h
,
549 sec
= bfd_abs_section_ptr
;
554 sec
= sections
[symndx
];
555 val
= (sec
->output_section
->vma
558 if (! obj_pe (output_bfd
))
564 if (h
->root
.type
== bfd_link_hash_defined
565 || h
->root
.type
== bfd_link_hash_defweak
)
569 sec
= h
->root
.u
.def
.section
;
570 val
= (h
->root
.u
.def
.value
571 + sec
->output_section
->vma
572 + sec
->output_offset
);
575 else if (! info
->relocateable
)
577 if (! ((*info
->callbacks
->undefined_symbol
)
578 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
579 rel
->r_vaddr
- input_section
->vma
, true)))
584 addr
= rel
->r_vaddr
- input_section
->vma
;
586 /* FIXME: This code assumes little endian, but the PP can
587 apparently be bi-endian. I don't know if the bi-endianness
588 applies to the instruction set or just to the data. */
600 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
601 contents
, addr
, val
, addend
);
610 /* Offset the address so that we can use 4 byte relocations. */
611 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
612 contents
+ 2, addr
, val
, addend
);
618 /* The most significant bit is stored in bit 6. */
621 hold
= contents
[addr
+ 4];
622 contents
[addr
+ 4] &=~ 0x20;
623 contents
[addr
+ 4] |= (contents
[addr
] >> 1) & 0x20;
624 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
627 contents
[addr
] &=~ 0x40;
628 contents
[addr
] |= (contents
[addr
+ 4] << 1) & 0x40;
629 contents
[addr
+ 4] &=~ 0x20;
630 contents
[addr
+ 4] |= hold
& 0x20;
637 /* The most significant bit is stored in bit 28. */
640 hold
= contents
[addr
+ 1];
641 contents
[addr
+ 1] &=~ 0x80;
642 contents
[addr
+ 1] |= (contents
[addr
+ 3] << 3) & 0x80;
643 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
646 contents
[addr
+ 3] &= ~0x10;
647 contents
[addr
+ 3] |= (contents
[addr
+ 1] >> 3) & 0x10;
648 contents
[addr
+ 1] &=~ 0x80;
649 contents
[addr
+ 1] |= hold
& 0x80;
654 /* Parameter RAM is from 0x1000000 to 0x1000800. */
655 contents
[addr
] &=~ 0x3;
656 if (val
>= 0x1000000 && val
< 0x1000800)
657 contents
[addr
] |= 0x3;
659 contents
[addr
] |= 0x2;
660 rstat
= bfd_reloc_ok
;
664 /* Parameter RAM is from 0x1000000 to 0x1000800. */
665 contents
[addr
+ 2] &= ~0xc0;
666 if (val
>= 0x1000000 && val
< 0x1000800)
667 contents
[addr
+ 2] |= 0xc0;
669 contents
[addr
+ 2] |= 0x80;
670 rstat
= bfd_reloc_ok
;
680 case bfd_reloc_outofrange
:
681 (*_bfd_error_handler
)
682 (_("%s: bad reloc address 0x%lx in section `%s'"),
683 bfd_get_filename (input_bfd
),
684 (unsigned long) rel
->r_vaddr
,
685 bfd_get_section_name (input_bfd
, input_section
));
687 case bfd_reloc_overflow
:
690 char buf
[SYMNMLEN
+ 1];
695 name
= h
->root
.root
.string
;
698 name
= _bfd_coff_internal_syment_name (input_bfd
, sym
, buf
);
703 if (! ((*info
->callbacks
->reloc_overflow
)
704 (info
, name
, howto
->name
, (bfd_vma
) 0, input_bfd
,
705 input_section
, rel
->r_vaddr
- input_section
->vma
)))
713 #define TIC80COFF 1 /* Customize coffcode.h */
714 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
715 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
716 #include "coffcode.h"
718 CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec
, "coff-tic80", D_PAGED
, 0, '_', NULL
)