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.
4 
5    Written by Fred Fish (fnf@cygnus.com)
6 
7    There is nothing new under the sun. This file draws a lot on other
8    coff files.
9 
10 This file is part of BFD, the Binary File Descriptor library.
11 
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.
16 
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.
21 
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.  */
26 
27 #include "bfd.h"
28 #include "bfdlink.h"
29 #include "sysdep.h"
30 #include "libbfd.h"
31 #ifdef _CONST
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. */
37 #undef _CONST
38 #endif /* _CONST */
39 #include "coff/tic80.h"
40 #include "coff/internal.h"
41 #include "libcoff.h"
42 
43 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44 #define COFF_ALIGN_IN_SECTION_HEADER 1
45 #define COFF_ALIGN_IN_SFLAGS 1
46 
47 #define GET_SCNHDR_FLAGS H_GET_16
48 #define PUT_SCNHDR_FLAGS H_PUT_16
49 
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 *,
66 	   bfd_vma *));
67 
68 static reloc_howto_type tic80_howto_table[] =
69 {
70 
71   HOWTO (R_RELLONG,			/* type */
72 	 0,				/* rightshift */
73 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
74 	 32,				/* bitsize */
75 	 FALSE,				/* pc_relative */
76 	 0,				/* bitpos */
77 	 complain_overflow_bitfield,	/* complain_on_overflow */
78 	 NULL,				/* special_function */
79 	 "RELLONG",			/* name */
80 	 TRUE,				/* partial_inplace */
81 	 0xffffffff,			/* src_mask */
82 	 0xffffffff,			/* dst_mask */
83 	 FALSE),			/* pcrel_offset */
84 
85   HOWTO (R_MPPCR,			/* type */
86 	 2,				/* rightshift */
87 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
88 	 32,				/* bitsize */
89 	 TRUE,				/* pc_relative */
90 	 0,				/* bitpos */
91 	 complain_overflow_signed,	/* complain_on_overflow */
92 	 NULL,				/* special_function */
93 	 "MPPCR",			/* name */
94 	 TRUE,				/* partial_inplace */
95 	 0xffffffff,			/* src_mask */
96 	 0xffffffff,			/* dst_mask */
97 	 TRUE),				/* pcrel_offset */
98 
99   HOWTO (R_ABS,				/* type */
100 	 0,				/* rightshift */
101 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
102 	 32,				/* bitsize */
103 	 FALSE,				/* pc_relative */
104 	 0,				/* bitpos */
105 	 complain_overflow_bitfield,	/* complain_on_overflow */
106 	 NULL,				/* special_function */
107 	 "ABS",				/* name */
108 	 TRUE,				/* partial_inplace */
109 	 0xffffffff,			/* src_mask */
110 	 0xffffffff,			/* dst_mask */
111 	 FALSE),				/* pcrel_offset */
112 
113   HOWTO (R_PPBASE,			/* type */
114 	 0,				/* rightshift */
115 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
116 	 32,				/* bitsize */
117 	 FALSE,				/* pc_relative */
118 	 0,				/* bitpos */
119 	 complain_overflow_dont,	/* complain_on_overflow */
120 	 ppbase_reloc,			/* special_function */
121 	 "PPBASE",			/* name */
122 	 TRUE,				/* partial_inplace */
123 	 0xffffffff,			/* src_mask */
124 	 0xffffffff,			/* dst_mask */
125 	 FALSE),			/* pcrel_offset */
126 
127   HOWTO (R_PPLBASE,			/* type */
128 	 0,				/* rightshift */
129 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
130 	 32,				/* bitsize */
131 	 FALSE,				/* pc_relative */
132 	 0,				/* bitpos */
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 */
140 
141   HOWTO (R_PP15,			/* type */
142 	 0,				/* rightshift */
143 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
144 	 15,				/* bitsize */
145 	 FALSE,				/* pc_relative */
146 	 6,				/* bitpos */
147 	 complain_overflow_dont,	/* complain_on_overflow */
148 	 glob15_reloc,			/* special_function */
149 	 "PP15",			/* name */
150 	 TRUE,				/* partial_inplace */
151 	 0x1ffc0,			/* src_mask */
152 	 0x1ffc0,			/* dst_mask */
153 	 FALSE),			/* pcrel_offset */
154 
155   HOWTO (R_PP15W,			/* type */
156 	 2,				/* rightshift */
157 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
158 	 15,				/* bitsize */
159 	 FALSE,				/* pc_relative */
160 	 6,				/* bitpos */
161 	 complain_overflow_dont,	/* complain_on_overflow */
162 	 glob15_reloc,			/* special_function */
163 	 "PP15W",			/* name */
164 	 TRUE,				/* partial_inplace */
165 	 0x1ffc0,			/* src_mask */
166 	 0x1ffc0,			/* dst_mask */
167 	 FALSE),			/* pcrel_offset */
168 
169   HOWTO (R_PP15H,			/* type */
170 	 1,				/* rightshift */
171 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
172 	 15,				/* bitsize */
173 	 FALSE,				/* pc_relative */
174 	 6,				/* bitpos */
175 	 complain_overflow_dont,	/* complain_on_overflow */
176 	 glob15_reloc,			/* special_function */
177 	 "PP15H",			/* name */
178 	 TRUE,				/* partial_inplace */
179 	 0x1ffc0,			/* src_mask */
180 	 0x1ffc0,			/* dst_mask */
181 	 FALSE),			/* pcrel_offset */
182 
183   HOWTO (R_PP16B,			/* type */
184 	 0,				/* rightshift */
185 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
186 	 16,				/* bitsize */
187 	 FALSE,				/* pc_relative */
188 	 6,				/* bitpos */
189 	 complain_overflow_dont,	/* complain_on_overflow */
190 	 glob16_reloc,			/* special_function */
191 	 "PP16B",			/* name */
192 	 TRUE,				/* partial_inplace */
193 	 0x3ffc0,			/* src_mask */
194 	 0x3ffc0,			/* dst_mask */
195 	 FALSE),			/* pcrel_offset */
196 
197   HOWTO (R_PPL15,			/* type */
198 	 0,				/* rightshift */
199 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
200 	 15,				/* bitsize */
201 	 FALSE,				/* pc_relative */
202 	 0,				/* bitpos */
203 	 complain_overflow_dont,	/* complain_on_overflow */
204 	 NULL,				/* special_function */
205 	 "PPL15",			/* name */
206 	 TRUE,				/* partial_inplace */
207 	 0x7fff,			/* src_mask */
208 	 0x7fff,			/* dst_mask */
209 	 FALSE),			/* pcrel_offset */
210 
211   HOWTO (R_PPL15W,			/* type */
212 	 2,				/* rightshift */
213 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
214 	 15,				/* bitsize */
215 	 FALSE,				/* pc_relative */
216 	 0,				/* bitpos */
217 	 complain_overflow_dont,	/* complain_on_overflow */
218 	 NULL,				/* special_function */
219 	 "PPL15W",			/* name */
220 	 TRUE,				/* partial_inplace */
221 	 0x7fff,			/* src_mask */
222 	 0x7fff,			/* dst_mask */
223 	 FALSE),			/* pcrel_offset */
224 
225   HOWTO (R_PPL15H,			/* type */
226 	 1,				/* rightshift */
227 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
228 	 15,				/* bitsize */
229 	 FALSE,				/* pc_relative */
230 	 0,				/* bitpos */
231 	 complain_overflow_dont,	/* complain_on_overflow */
232 	 NULL,				/* special_function */
233 	 "PPL15H",			/* name */
234 	 TRUE,				/* partial_inplace */
235 	 0x7fff,			/* src_mask */
236 	 0x7fff,			/* dst_mask */
237 	 FALSE),			/* pcrel_offset */
238 
239   HOWTO (R_PPL16B,			/* type */
240 	 0,				/* rightshift */
241 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
242 	 16,				/* bitsize */
243 	 FALSE,				/* pc_relative */
244 	 0,				/* bitpos */
245 	 complain_overflow_dont,	/* complain_on_overflow */
246 	 local16_reloc,			/* special_function */
247 	 "PPL16B",			/* name */
248 	 TRUE,				/* partial_inplace */
249 	 0xffff,			/* src_mask */
250 	 0xffff,			/* dst_mask */
251 	 FALSE),			/* pcrel_offset */
252 
253   HOWTO (R_PPN15,			/* type */
254 	 0,				/* rightshift */
255 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
256 	 15,				/* bitsize */
257 	 FALSE,				/* pc_relative */
258 	 6,				/* bitpos */
259 	 complain_overflow_dont,	/* complain_on_overflow */
260 	 glob15_reloc,			/* special_function */
261 	 "PPN15",			/* name */
262 	 TRUE,				/* partial_inplace */
263 	 0x1ffc0,			/* src_mask */
264 	 0x1ffc0,			/* dst_mask */
265 	 FALSE),			/* pcrel_offset */
266 
267   HOWTO (R_PPN15W,			/* type */
268 	 2,				/* rightshift */
269 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
270 	 15,				/* bitsize */
271 	 FALSE,				/* pc_relative */
272 	 6,				/* bitpos */
273 	 complain_overflow_dont,	/* complain_on_overflow */
274 	 glob15_reloc,			/* special_function */
275 	 "PPN15W",			/* name */
276 	 TRUE,				/* partial_inplace */
277 	 0x1ffc0,			/* src_mask */
278 	 0x1ffc0,			/* dst_mask */
279 	 FALSE),			/* pcrel_offset */
280 
281   HOWTO (R_PPN15H,			/* type */
282 	 1,				/* rightshift */
283 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
284 	 15,				/* bitsize */
285 	 FALSE,				/* pc_relative */
286 	 6,				/* bitpos */
287 	 complain_overflow_dont,	/* complain_on_overflow */
288 	 glob15_reloc,			/* special_function */
289 	 "PPN15H",			/* name */
290 	 TRUE,				/* partial_inplace */
291 	 0x1ffc0,			/* src_mask */
292 	 0x1ffc0,			/* dst_mask */
293 	 FALSE),			/* pcrel_offset */
294 
295   HOWTO (R_PPN16B,			/* type */
296 	 0,				/* rightshift */
297 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
298 	 16,				/* bitsize */
299 	 FALSE,				/* pc_relative */
300 	 6,				/* bitpos */
301 	 complain_overflow_dont,	/* complain_on_overflow */
302 	 glob16_reloc,			/* special_function */
303 	 "PPN16B",			/* name */
304 	 TRUE,				/* partial_inplace */
305 	 0x3ffc0,			/* src_mask */
306 	 0x3ffc0,			/* dst_mask */
307 	 FALSE),			/* pcrel_offset */
308 
309   HOWTO (R_PPLN15,			/* type */
310 	 0,				/* rightshift */
311 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
312 	 15,				/* bitsize */
313 	 FALSE,				/* pc_relative */
314 	 0,				/* bitpos */
315 	 complain_overflow_dont,	/* complain_on_overflow */
316 	 NULL,				/* special_function */
317 	 "PPLN15",			/* name */
318 	 TRUE,				/* partial_inplace */
319 	 0x7fff,			/* src_mask */
320 	 0x7fff,			/* dst_mask */
321 	 FALSE),			/* pcrel_offset */
322 
323   HOWTO (R_PPLN15W,			/* type */
324 	 2,				/* rightshift */
325 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
326 	 15,				/* bitsize */
327 	 FALSE,				/* pc_relative */
328 	 0,				/* bitpos */
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 */
336 
337   HOWTO (R_PPLN15H,			/* type */
338 	 1,				/* rightshift */
339 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
340 	 15,				/* bitsize */
341 	 FALSE,				/* pc_relative */
342 	 0,				/* bitpos */
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 */
350 
351   HOWTO (R_PPLN16B,			/* type */
352 	 0,				/* rightshift */
353 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
354 	 15,				/* bitsize */
355 	 FALSE,				/* pc_relative */
356 	 0,				/* bitpos */
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 */
364 };
365 
366 /* Special relocation functions, used when the output file is not
367    itself a COFF TIc80 file.  */
368 
369 /* This special function is used for the base address type
370    relocations.  */
371 
372 static bfd_reloc_status_type
373 ppbase_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
374 	      error_message)
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;
382 {
383   /* FIXME.  */
384   abort ();
385 }
386 
387 /* This special function is used for the global 15 bit relocations.  */
388 
389 static bfd_reloc_status_type
390 glob15_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
391 	      error_message)
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;
399 {
400   /* FIXME.  */
401   abort ();
402 }
403 
404 /* This special function is used for the global 16 bit relocations.  */
405 
406 static bfd_reloc_status_type
407 glob16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
408 	      error_message)
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;
416 {
417   /* FIXME.  */
418   abort ();
419 }
420 
421 /* This special function is used for the local 16 bit relocations.  */
422 
423 static bfd_reloc_status_type
424 local16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
425 	      error_message)
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;
433 {
434   /* FIXME.  */
435   abort ();
436 }
437 
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.  */
441 
442 static void
443 rtype2howto (cache_ptr, dst)
444      arelent *cache_ptr;
445      struct internal_reloc *dst;
446 {
447   unsigned int i;
448 
449   for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
450     {
451       if (tic80_howto_table[i].type == dst->r_type)
452 	{
453 	  cache_ptr->howto = tic80_howto_table + i;
454 	  return;
455 	}
456     }
457 
458   (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
459 			 (unsigned int) dst->r_type);
460   cache_ptr->howto = tic80_howto_table + 0;
461 }
462 
463 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
464 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
465 
466 static reloc_howto_type *
467 coff_tic80_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
468      bfd *abfd ATTRIBUTE_UNUSED;
469      asection *sec;
470      struct internal_reloc *rel;
471      struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
472      struct internal_syment *sym ATTRIBUTE_UNUSED;
473      bfd_vma *addendp;
474 {
475   arelent genrel;
476 
477   if (rel -> r_symndx == -1 && addendp != NULL)
478     {
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;
483     }
484   RTYPE2HOWTO (&genrel, rel);
485   return genrel.howto;
486 }
487 
488 #ifndef BADMAG
489 #define BADMAG(x) TIC80BADMAG(x)
490 #endif
491 
492 #define coff_relocate_section coff_tic80_relocate_section
493 
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.  */
496 
497 static bfd_boolean
498 coff_tic80_relocate_section (output_bfd, info, input_bfd,
499 			     input_section, contents, relocs, syms,
500 			     sections)
501      bfd *output_bfd;
502      struct bfd_link_info *info;
503      bfd *input_bfd;
504      asection *input_section;
505      bfd_byte *contents;
506      struct internal_reloc *relocs;
507      struct internal_syment *syms;
508      asection **sections;
509 {
510   struct internal_reloc *rel;
511   struct internal_reloc *relend;
512 
513   rel = relocs;
514   relend = rel + input_section->reloc_count;
515   for (; rel < relend; rel++)
516     {
517       long symndx;
518       struct coff_link_hash_entry *h;
519       struct internal_syment *sym;
520       bfd_vma addend;
521       bfd_vma val;
522       reloc_howto_type *howto;
523       bfd_reloc_status_type rstat;
524       bfd_vma addr;
525 
526       symndx = rel->r_symndx;
527 
528       if (symndx == -1)
529 	{
530 	  h = NULL;
531 	  sym = NULL;
532 	}
533       else
534 	{
535 	  h = obj_coff_sym_hashes (input_bfd)[symndx];
536 	  sym = syms + symndx;
537 	}
538 
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.  */
543 
544       if (sym != NULL && sym->n_scnum != 0)
545 	addend = - sym->n_value;
546       else
547 	addend = 0;
548 
549       howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
550 				       sym, &addend);
551       if (howto == NULL)
552 	return FALSE;
553 
554       val = 0;
555 
556       if (h == NULL)
557 	{
558 	  asection *sec;
559 
560 	  if (symndx == -1)
561 	    {
562 	      sec = bfd_abs_section_ptr;
563 	      val = 0;
564 	    }
565 	  else
566 	    {
567 	      sec = sections[symndx];
568               val = (sec->output_section->vma
569 		     + sec->output_offset
570 		     + sym->n_value);
571 	      if (! obj_pe (output_bfd))
572 		val -= sec->vma;
573 	    }
574 	}
575       else
576 	{
577 	  if (h->root.type == bfd_link_hash_defined
578 	      || h->root.type == bfd_link_hash_defweak)
579 	    {
580 	      asection *sec;
581 
582 	      sec = h->root.u.def.section;
583 	      val = (h->root.u.def.value
584 		     + sec->output_section->vma
585 		     + sec->output_offset);
586 	      }
587 
588 	  else if (! info->relocatable)
589 	    {
590 	      if (! ((*info->callbacks->undefined_symbol)
591 		     (info, h->root.root.string, input_bfd, input_section,
592 		      rel->r_vaddr - input_section->vma, TRUE)))
593 		return FALSE;
594 	    }
595 	}
596 
597       addr = rel->r_vaddr - input_section->vma;
598 
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.  */
602       switch (howto->type)
603 	{
604 	default:
605 	case R_ABS:
606 	case R_RELLONGX:
607 	case R_PPL15:
608 	case R_PPL15W:
609 	case R_PPL15H:
610 	case R_PPLN15:
611 	case R_PPLN15W:
612 	case R_PPLN15H:
613 	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
614 					    contents, addr, val, addend);
615 	  break;
616 
617 	case R_PP15:
618 	case R_PP15W:
619 	case R_PP15H:
620 	case R_PPN15:
621 	case R_PPN15W:
622 	case R_PPN15H:
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);
626 	  break;
627 
628 	case R_PP16B:
629 	case R_PPN16B:
630 	  {
631 	    /* The most significant bit is stored in bit 6.  */
632 	    bfd_byte hold;
633 
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,
638 					      contents + 2, addr,
639 					      val, addend);
640 	    contents[addr] &=~ 0x40;
641 	    contents[addr] |= (contents[addr + 4] << 1) & 0x40;
642 	    contents[addr + 4] &=~ 0x20;
643 	    contents[addr + 4] |= hold & 0x20;
644 	    break;
645 	  }
646 
647 	case R_PPL16B:
648 	case R_PPLN16B:
649 	  {
650 	    /* The most significant bit is stored in bit 28.  */
651 	    bfd_byte hold;
652 
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,
657 					      contents, addr,
658 					      val, addend);
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;
663 	    break;
664 	  }
665 
666 	case R_PPBASE:
667 	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
668 	  contents[addr] &=~ 0x3;
669 	  if (val >= 0x1000000 && val < 0x1000800)
670 	    contents[addr] |= 0x3;
671 	  else
672 	    contents[addr] |= 0x2;
673 	  rstat = bfd_reloc_ok;
674 	  break;
675 
676 	case R_PPLBASE:
677 	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
678 	  contents[addr + 2] &= ~0xc0;
679 	  if (val >= 0x1000000 && val < 0x1000800)
680 	    contents[addr + 2] |= 0xc0;
681 	  else
682 	    contents[addr + 2] |= 0x80;
683 	  rstat = bfd_reloc_ok;
684 	  break;
685 	}
686 
687       switch (rstat)
688 	{
689 	default:
690 	  abort ();
691 	case bfd_reloc_ok:
692 	  break;
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);
697 	  return FALSE;
698 	case bfd_reloc_overflow:
699 	  {
700 	    const char *name;
701 	    char buf[SYMNMLEN + 1];
702 
703 	    if (symndx == -1)
704 	      name = "*ABS*";
705 	    else if (h != NULL)
706 	      name = NULL;
707 	    else
708 	      {
709 		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
710 		if (name == NULL)
711 		  return FALSE;
712 	      }
713 
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)))
718 	      return FALSE;
719 	  }
720 	}
721     }
722   return TRUE;
723 }
724 
725 /* Clear the r_reserved field in relocs.  */
726 #define SWAP_OUT_RELOC_EXTRA(abfd,src,dst) \
727   do \
728     { \
729       dst->r_reserved[0] = 0; \
730       dst->r_reserved[1] = 0; \
731     } \
732   while (0)
733 
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"
738 
739 CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
740