1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2 Copyright 1996, 1997, 1999, 2000, 2001, 2002, 2003
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, 59 Temple Place - Suite 330,
25 Boston, MA 02111-1307, USA. */
31 #include "coff/tic80.h"
32 #include "coff/internal.h"
35 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
36 #define COFF_ALIGN_IN_SECTION_HEADER 1
37 #define COFF_ALIGN_IN_SFLAGS 1
39 #define GET_SCNHDR_FLAGS H_GET_16
40 #define PUT_SCNHDR_FLAGS H_PUT_16
42 static void rtype2howto
43 PARAMS ((arelent
*cache_ptr
, struct internal_reloc
*dst
));
44 static bfd_reloc_status_type ppbase_reloc
45 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
46 static bfd_reloc_status_type glob15_reloc
47 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
48 static bfd_reloc_status_type glob16_reloc
49 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
50 static bfd_reloc_status_type local16_reloc
51 PARAMS ((bfd
*, arelent
*, asymbol
*, PTR
, asection
*, bfd
*, char **));
52 static bfd_boolean coff_tic80_relocate_section
53 PARAMS ((bfd
*, struct bfd_link_info
*, bfd
*, asection
*, bfd_byte
*,
54 struct internal_reloc
*, struct internal_syment
*, asection
**));
55 static reloc_howto_type
* coff_tic80_rtype_to_howto
56 PARAMS ((bfd
*, asection
*, struct internal_reloc
*,
57 struct coff_link_hash_entry
*, struct internal_syment
*,
60 static reloc_howto_type tic80_howto_table
[] =
63 HOWTO (R_RELLONG
, /* type */
65 2, /* size (0 = byte, 1 = short, 2 = long) */
67 FALSE
, /* pc_relative */
69 complain_overflow_bitfield
, /* complain_on_overflow */
70 NULL
, /* special_function */
72 TRUE
, /* partial_inplace */
73 0xffffffff, /* src_mask */
74 0xffffffff, /* dst_mask */
75 FALSE
), /* pcrel_offset */
77 HOWTO (R_MPPCR
, /* type */
79 2, /* size (0 = byte, 1 = short, 2 = long) */
81 TRUE
, /* pc_relative */
83 complain_overflow_signed
, /* complain_on_overflow */
84 NULL
, /* special_function */
86 TRUE
, /* partial_inplace */
87 0xffffffff, /* src_mask */
88 0xffffffff, /* dst_mask */
89 TRUE
), /* pcrel_offset */
91 HOWTO (R_ABS
, /* type */
93 2, /* size (0 = byte, 1 = short, 2 = long) */
95 FALSE
, /* pc_relative */
97 complain_overflow_bitfield
, /* complain_on_overflow */
98 NULL
, /* special_function */
100 TRUE
, /* partial_inplace */
101 0xffffffff, /* src_mask */
102 0xffffffff, /* dst_mask */
103 FALSE
), /* pcrel_offset */
105 HOWTO (R_PPBASE
, /* type */
107 2, /* size (0 = byte, 1 = short, 2 = long) */
109 FALSE
, /* pc_relative */
111 complain_overflow_dont
, /* complain_on_overflow */
112 ppbase_reloc
, /* special_function */
114 TRUE
, /* partial_inplace */
115 0xffffffff, /* src_mask */
116 0xffffffff, /* dst_mask */
117 FALSE
), /* pcrel_offset */
119 HOWTO (R_PPLBASE
, /* type */
121 2, /* size (0 = byte, 1 = short, 2 = long) */
123 FALSE
, /* pc_relative */
125 complain_overflow_dont
, /* complain_on_overflow */
126 ppbase_reloc
, /* special_function */
127 "PPLBASE", /* name */
128 TRUE
, /* partial_inplace */
129 0xffffffff, /* src_mask */
130 0xffffffff, /* dst_mask */
131 FALSE
), /* pcrel_offset */
133 HOWTO (R_PP15
, /* type */
135 2, /* size (0 = byte, 1 = short, 2 = long) */
137 FALSE
, /* pc_relative */
139 complain_overflow_dont
, /* complain_on_overflow */
140 glob15_reloc
, /* special_function */
142 TRUE
, /* partial_inplace */
143 0x1ffc0, /* src_mask */
144 0x1ffc0, /* dst_mask */
145 FALSE
), /* pcrel_offset */
147 HOWTO (R_PP15W
, /* type */
149 2, /* size (0 = byte, 1 = short, 2 = long) */
151 FALSE
, /* pc_relative */
153 complain_overflow_dont
, /* complain_on_overflow */
154 glob15_reloc
, /* special_function */
156 TRUE
, /* partial_inplace */
157 0x1ffc0, /* src_mask */
158 0x1ffc0, /* dst_mask */
159 FALSE
), /* pcrel_offset */
161 HOWTO (R_PP15H
, /* type */
163 2, /* size (0 = byte, 1 = short, 2 = long) */
165 FALSE
, /* pc_relative */
167 complain_overflow_dont
, /* complain_on_overflow */
168 glob15_reloc
, /* special_function */
170 TRUE
, /* partial_inplace */
171 0x1ffc0, /* src_mask */
172 0x1ffc0, /* dst_mask */
173 FALSE
), /* pcrel_offset */
175 HOWTO (R_PP16B
, /* type */
177 2, /* size (0 = byte, 1 = short, 2 = long) */
179 FALSE
, /* pc_relative */
181 complain_overflow_dont
, /* complain_on_overflow */
182 glob16_reloc
, /* special_function */
184 TRUE
, /* partial_inplace */
185 0x3ffc0, /* src_mask */
186 0x3ffc0, /* dst_mask */
187 FALSE
), /* pcrel_offset */
189 HOWTO (R_PPL15
, /* type */
191 2, /* size (0 = byte, 1 = short, 2 = long) */
193 FALSE
, /* pc_relative */
195 complain_overflow_dont
, /* complain_on_overflow */
196 NULL
, /* special_function */
198 TRUE
, /* partial_inplace */
199 0x7fff, /* src_mask */
200 0x7fff, /* dst_mask */
201 FALSE
), /* pcrel_offset */
203 HOWTO (R_PPL15W
, /* type */
205 2, /* size (0 = byte, 1 = short, 2 = long) */
207 FALSE
, /* pc_relative */
209 complain_overflow_dont
, /* complain_on_overflow */
210 NULL
, /* special_function */
212 TRUE
, /* partial_inplace */
213 0x7fff, /* src_mask */
214 0x7fff, /* dst_mask */
215 FALSE
), /* pcrel_offset */
217 HOWTO (R_PPL15H
, /* type */
219 2, /* size (0 = byte, 1 = short, 2 = long) */
221 FALSE
, /* pc_relative */
223 complain_overflow_dont
, /* complain_on_overflow */
224 NULL
, /* special_function */
226 TRUE
, /* partial_inplace */
227 0x7fff, /* src_mask */
228 0x7fff, /* dst_mask */
229 FALSE
), /* pcrel_offset */
231 HOWTO (R_PPL16B
, /* type */
233 2, /* size (0 = byte, 1 = short, 2 = long) */
235 FALSE
, /* pc_relative */
237 complain_overflow_dont
, /* complain_on_overflow */
238 local16_reloc
, /* special_function */
240 TRUE
, /* partial_inplace */
241 0xffff, /* src_mask */
242 0xffff, /* dst_mask */
243 FALSE
), /* pcrel_offset */
245 HOWTO (R_PPN15
, /* type */
247 -2, /* size (0 = byte, 1 = short, 2 = long) */
249 FALSE
, /* pc_relative */
251 complain_overflow_dont
, /* complain_on_overflow */
252 glob15_reloc
, /* special_function */
254 TRUE
, /* partial_inplace */
255 0x1ffc0, /* src_mask */
256 0x1ffc0, /* dst_mask */
257 FALSE
), /* pcrel_offset */
259 HOWTO (R_PPN15W
, /* type */
261 -2, /* size (0 = byte, 1 = short, 2 = long) */
263 FALSE
, /* pc_relative */
265 complain_overflow_dont
, /* complain_on_overflow */
266 glob15_reloc
, /* special_function */
268 TRUE
, /* partial_inplace */
269 0x1ffc0, /* src_mask */
270 0x1ffc0, /* dst_mask */
271 FALSE
), /* pcrel_offset */
273 HOWTO (R_PPN15H
, /* type */
275 -2, /* size (0 = byte, 1 = short, 2 = long) */
277 FALSE
, /* pc_relative */
279 complain_overflow_dont
, /* complain_on_overflow */
280 glob15_reloc
, /* special_function */
282 TRUE
, /* partial_inplace */
283 0x1ffc0, /* src_mask */
284 0x1ffc0, /* dst_mask */
285 FALSE
), /* pcrel_offset */
287 HOWTO (R_PPN16B
, /* type */
289 -2, /* size (0 = byte, 1 = short, 2 = long) */
291 FALSE
, /* pc_relative */
293 complain_overflow_dont
, /* complain_on_overflow */
294 glob16_reloc
, /* special_function */
296 TRUE
, /* partial_inplace */
297 0x3ffc0, /* src_mask */
298 0x3ffc0, /* dst_mask */
299 FALSE
), /* pcrel_offset */
301 HOWTO (R_PPLN15
, /* type */
303 -2, /* size (0 = byte, 1 = short, 2 = long) */
305 FALSE
, /* pc_relative */
307 complain_overflow_dont
, /* complain_on_overflow */
308 NULL
, /* special_function */
310 TRUE
, /* partial_inplace */
311 0x7fff, /* src_mask */
312 0x7fff, /* dst_mask */
313 FALSE
), /* pcrel_offset */
315 HOWTO (R_PPLN15W
, /* type */
317 -2, /* size (0 = byte, 1 = short, 2 = long) */
319 FALSE
, /* pc_relative */
321 complain_overflow_dont
, /* complain_on_overflow */
322 NULL
, /* special_function */
323 "PPLN15W", /* name */
324 TRUE
, /* partial_inplace */
325 0x7fff, /* src_mask */
326 0x7fff, /* dst_mask */
327 FALSE
), /* pcrel_offset */
329 HOWTO (R_PPLN15H
, /* type */
331 -2, /* size (0 = byte, 1 = short, 2 = long) */
333 FALSE
, /* pc_relative */
335 complain_overflow_dont
, /* complain_on_overflow */
336 NULL
, /* special_function */
337 "PPLN15H", /* name */
338 TRUE
, /* partial_inplace */
339 0x7fff, /* src_mask */
340 0x7fff, /* dst_mask */
341 FALSE
), /* pcrel_offset */
343 HOWTO (R_PPLN16B
, /* type */
345 -2, /* size (0 = byte, 1 = short, 2 = long) */
347 FALSE
, /* pc_relative */
349 complain_overflow_dont
, /* complain_on_overflow */
350 local16_reloc
, /* special_function */
351 "PPLN16B", /* name */
352 TRUE
, /* partial_inplace */
353 0xffff, /* src_mask */
354 0xffff, /* dst_mask */
355 FALSE
) /* pcrel_offset */
358 /* Special relocation functions, used when the output file is not
359 itself a COFF TIc80 file. */
361 /* This special function is used for the base address type
364 static bfd_reloc_status_type
365 ppbase_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
367 bfd
*abfd ATTRIBUTE_UNUSED
;
368 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
369 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
370 PTR data ATTRIBUTE_UNUSED
;
371 asection
*input_section ATTRIBUTE_UNUSED
;
372 bfd
*output_bfd ATTRIBUTE_UNUSED
;
373 char **error_message ATTRIBUTE_UNUSED
;
379 /* This special function is used for the global 15 bit relocations. */
381 static bfd_reloc_status_type
382 glob15_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
384 bfd
*abfd ATTRIBUTE_UNUSED
;
385 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
386 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
387 PTR data ATTRIBUTE_UNUSED
;
388 asection
*input_section ATTRIBUTE_UNUSED
;
389 bfd
*output_bfd ATTRIBUTE_UNUSED
;
390 char **error_message ATTRIBUTE_UNUSED
;
396 /* This special function is used for the global 16 bit relocations. */
398 static bfd_reloc_status_type
399 glob16_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
401 bfd
*abfd ATTRIBUTE_UNUSED
;
402 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
403 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
404 PTR data ATTRIBUTE_UNUSED
;
405 asection
*input_section ATTRIBUTE_UNUSED
;
406 bfd
*output_bfd ATTRIBUTE_UNUSED
;
407 char **error_message ATTRIBUTE_UNUSED
;
413 /* This special function is used for the local 16 bit relocations. */
415 static bfd_reloc_status_type
416 local16_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
418 bfd
*abfd ATTRIBUTE_UNUSED
;
419 arelent
*reloc_entry ATTRIBUTE_UNUSED
;
420 asymbol
*symbol_in ATTRIBUTE_UNUSED
;
421 PTR data ATTRIBUTE_UNUSED
;
422 asection
*input_section ATTRIBUTE_UNUSED
;
423 bfd
*output_bfd ATTRIBUTE_UNUSED
;
424 char **error_message ATTRIBUTE_UNUSED
;
430 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
431 If passed an r_type we don't recognize the abort rather than silently failing
432 to generate an output file. */
435 rtype2howto (cache_ptr
, dst
)
437 struct internal_reloc
*dst
;
441 for (i
= 0; i
< sizeof tic80_howto_table
/ sizeof tic80_howto_table
[0]; i
++)
443 if (tic80_howto_table
[i
].type
== dst
->r_type
)
445 cache_ptr
->howto
= tic80_howto_table
+ i
;
450 (*_bfd_error_handler
) (_("Unrecognized reloc type 0x%x"),
451 (unsigned int) dst
->r_type
);
452 cache_ptr
->howto
= tic80_howto_table
+ 0;
455 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
456 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
458 static reloc_howto_type
*
459 coff_tic80_rtype_to_howto (abfd
, sec
, rel
, h
, sym
, addendp
)
460 bfd
*abfd ATTRIBUTE_UNUSED
;
462 struct internal_reloc
*rel
;
463 struct coff_link_hash_entry
*h ATTRIBUTE_UNUSED
;
464 struct internal_syment
*sym ATTRIBUTE_UNUSED
;
469 if (rel
-> r_symndx
== -1 && addendp
!= NULL
)
471 /* This is a TI "internal relocation", which means that the relocation
472 amount is the amount by which the current section is being relocated
473 in the output section. */
474 *addendp
= (sec
-> output_section
-> vma
+ sec
-> output_offset
) - sec
-> vma
;
476 RTYPE2HOWTO (&genrel
, rel
);
481 #define BADMAG(x) TIC80BADMAG(x)
484 #define coff_relocate_section coff_tic80_relocate_section
486 /* We need a special relocation routine to handle the PP relocs. Most
487 of this is a copy of _bfd_coff_generic_relocate_section. */
490 coff_tic80_relocate_section (output_bfd
, info
, input_bfd
,
491 input_section
, contents
, relocs
, syms
,
494 struct bfd_link_info
*info
;
496 asection
*input_section
;
498 struct internal_reloc
*relocs
;
499 struct internal_syment
*syms
;
502 struct internal_reloc
*rel
;
503 struct internal_reloc
*relend
;
506 relend
= rel
+ input_section
->reloc_count
;
507 for (; rel
< relend
; rel
++)
510 struct coff_link_hash_entry
*h
;
511 struct internal_syment
*sym
;
514 reloc_howto_type
*howto
;
515 bfd_reloc_status_type rstat
;
518 symndx
= rel
->r_symndx
;
527 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
531 /* COFF treats common symbols in one of two ways. Either the
532 size of the symbol is included in the section contents, or it
533 is not. We assume that the size is not included, and force
534 the rtype_to_howto function to adjust the addend as needed. */
536 if (sym
!= NULL
&& sym
->n_scnum
!= 0)
537 addend
= - sym
->n_value
;
541 howto
= bfd_coff_rtype_to_howto (input_bfd
, input_section
, rel
, h
,
554 sec
= bfd_abs_section_ptr
;
559 sec
= sections
[symndx
];
560 val
= (sec
->output_section
->vma
563 if (! obj_pe (output_bfd
))
569 if (h
->root
.type
== bfd_link_hash_defined
570 || h
->root
.type
== bfd_link_hash_defweak
)
574 sec
= h
->root
.u
.def
.section
;
575 val
= (h
->root
.u
.def
.value
576 + sec
->output_section
->vma
577 + sec
->output_offset
);
580 else if (! info
->relocatable
)
582 if (! ((*info
->callbacks
->undefined_symbol
)
583 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
584 rel
->r_vaddr
- input_section
->vma
, TRUE
)))
589 addr
= rel
->r_vaddr
- input_section
->vma
;
591 /* FIXME: This code assumes little endian, but the PP can
592 apparently be bi-endian. I don't know if the bi-endianness
593 applies to the instruction set or just to the data. */
605 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
606 contents
, addr
, val
, addend
);
615 /* Offset the address so that we can use 4 byte relocations. */
616 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
617 contents
+ 2, addr
, val
, addend
);
623 /* The most significant bit is stored in bit 6. */
626 hold
= contents
[addr
+ 4];
627 contents
[addr
+ 4] &=~ 0x20;
628 contents
[addr
+ 4] |= (contents
[addr
] >> 1) & 0x20;
629 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
632 contents
[addr
] &=~ 0x40;
633 contents
[addr
] |= (contents
[addr
+ 4] << 1) & 0x40;
634 contents
[addr
+ 4] &=~ 0x20;
635 contents
[addr
+ 4] |= hold
& 0x20;
642 /* The most significant bit is stored in bit 28. */
645 hold
= contents
[addr
+ 1];
646 contents
[addr
+ 1] &=~ 0x80;
647 contents
[addr
+ 1] |= (contents
[addr
+ 3] << 3) & 0x80;
648 rstat
= _bfd_final_link_relocate (howto
, input_bfd
, input_section
,
651 contents
[addr
+ 3] &= ~0x10;
652 contents
[addr
+ 3] |= (contents
[addr
+ 1] >> 3) & 0x10;
653 contents
[addr
+ 1] &=~ 0x80;
654 contents
[addr
+ 1] |= hold
& 0x80;
659 /* Parameter RAM is from 0x1000000 to 0x1000800. */
660 contents
[addr
] &=~ 0x3;
661 if (val
>= 0x1000000 && val
< 0x1000800)
662 contents
[addr
] |= 0x3;
664 contents
[addr
] |= 0x2;
665 rstat
= bfd_reloc_ok
;
669 /* Parameter RAM is from 0x1000000 to 0x1000800. */
670 contents
[addr
+ 2] &= ~0xc0;
671 if (val
>= 0x1000000 && val
< 0x1000800)
672 contents
[addr
+ 2] |= 0xc0;
674 contents
[addr
+ 2] |= 0x80;
675 rstat
= bfd_reloc_ok
;
685 case bfd_reloc_outofrange
:
686 (*_bfd_error_handler
)
687 (_("%s: bad reloc address 0x%lx in section `%s'"),
688 bfd_archive_filename (input_bfd
),
689 (unsigned long) rel
->r_vaddr
,
690 bfd_get_section_name (input_bfd
, input_section
));
692 case bfd_reloc_overflow
:
695 char buf
[SYMNMLEN
+ 1];
700 name
= h
->root
.root
.string
;
703 name
= _bfd_coff_internal_syment_name (input_bfd
, sym
, buf
);
708 if (! ((*info
->callbacks
->reloc_overflow
)
709 (info
, name
, howto
->name
, (bfd_vma
) 0, input_bfd
,
710 input_section
, rel
->r_vaddr
- input_section
->vma
)))
718 #define TIC80COFF 1 /* Customize coffcode.h */
719 #undef C_AUTOARG /* Clashes with TIc80's C_UEXT */
720 #undef C_LASTENT /* Clashes with TIc80's C_STATLAB */
721 #include "coffcode.h"
723 CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec
, "coff-tic80", D_PAGED
, 0, '_', NULL
, COFF_SWAP_TABLE
)