1 /* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2    Copyright (C) 1996-2016 Free Software Foundation, Inc.
3 
4    Written by Fred Fish (fnf@cygnus.com)
5 
6    There is nothing new under the sun. This file draws a lot on other
7    coff files.
8 
9    This file is part of BFD, the Binary File Descriptor library.
10 
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 3 of the License, or
14    (at your option) any later version.
15 
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.
20 
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, 51 Franklin Street - Fifth Floor,
24    Boston, MA 02110-1301, USA.  */
25 
26 #include "sysdep.h"
27 #include "bfd.h"
28 #include "bfdlink.h"
29 #include "libbfd.h"
30 #ifdef _CONST
31 /* Newlib-based hosts define _CONST as a STDC-safe alias for const,
32   but to the tic80 toolchain it means something altogether different.
33   Since sysdep.h will have pulled in stdio.h and hence _ansi.h which
34   contains this definition, we must undef it before including the
35   tic80-specific definition. */
36 #undef _CONST
37 #endif /* _CONST */
38 #include "coff/tic80.h"
39 #include "coff/internal.h"
40 #include "libcoff.h"
41 
42 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
43 #define COFF_ALIGN_IN_SECTION_HEADER 1
44 #define COFF_ALIGN_IN_SFLAGS 1
45 
46 #define GET_SCNHDR_FLAGS H_GET_16
47 #define PUT_SCNHDR_FLAGS H_PUT_16
48 
49 static bfd_reloc_status_type ppbase_reloc
50   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
51 static bfd_reloc_status_type glob15_reloc
52   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
53 static bfd_reloc_status_type glob16_reloc
54   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55 static bfd_reloc_status_type local16_reloc
56   (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
57 
58 
59 static reloc_howto_type tic80_howto_table[] =
60 {
61 
62   HOWTO (R_RELLONG,			/* type */
63 	 0,				/* rightshift */
64 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
65 	 32,				/* bitsize */
66 	 FALSE,				/* pc_relative */
67 	 0,				/* bitpos */
68 	 complain_overflow_bitfield,	/* complain_on_overflow */
69 	 NULL,				/* special_function */
70 	 "RELLONG",			/* name */
71 	 TRUE,				/* partial_inplace */
72 	 0xffffffff,			/* src_mask */
73 	 0xffffffff,			/* dst_mask */
74 	 FALSE),			/* pcrel_offset */
75 
76   HOWTO (R_MPPCR,			/* type */
77 	 2,				/* rightshift */
78 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
79 	 32,				/* bitsize */
80 	 TRUE,				/* pc_relative */
81 	 0,				/* bitpos */
82 	 complain_overflow_signed,	/* complain_on_overflow */
83 	 NULL,				/* special_function */
84 	 "MPPCR",			/* name */
85 	 TRUE,				/* partial_inplace */
86 	 0xffffffff,			/* src_mask */
87 	 0xffffffff,			/* dst_mask */
88 	 TRUE),				/* pcrel_offset */
89 
90   HOWTO (R_ABS,				/* type */
91 	 0,				/* rightshift */
92 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
93 	 32,				/* bitsize */
94 	 FALSE,				/* pc_relative */
95 	 0,				/* bitpos */
96 	 complain_overflow_bitfield,	/* complain_on_overflow */
97 	 NULL,				/* special_function */
98 	 "ABS",				/* name */
99 	 TRUE,				/* partial_inplace */
100 	 0xffffffff,			/* src_mask */
101 	 0xffffffff,			/* dst_mask */
102 	 FALSE),				/* pcrel_offset */
103 
104   HOWTO (R_PPBASE,			/* type */
105 	 0,				/* rightshift */
106 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
107 	 32,				/* bitsize */
108 	 FALSE,				/* pc_relative */
109 	 0,				/* bitpos */
110 	 complain_overflow_dont,	/* complain_on_overflow */
111 	 ppbase_reloc,			/* special_function */
112 	 "PPBASE",			/* name */
113 	 TRUE,				/* partial_inplace */
114 	 0xffffffff,			/* src_mask */
115 	 0xffffffff,			/* dst_mask */
116 	 FALSE),			/* pcrel_offset */
117 
118   HOWTO (R_PPLBASE,			/* type */
119 	 0,				/* rightshift */
120 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
121 	 32,				/* bitsize */
122 	 FALSE,				/* pc_relative */
123 	 0,				/* bitpos */
124 	 complain_overflow_dont,	/* complain_on_overflow */
125 	 ppbase_reloc,			/* special_function */
126 	 "PPLBASE",			/* name */
127 	 TRUE,				/* partial_inplace */
128 	 0xffffffff,			/* src_mask */
129 	 0xffffffff,			/* dst_mask */
130 	 FALSE),			/* pcrel_offset */
131 
132   HOWTO (R_PP15,			/* type */
133 	 0,				/* rightshift */
134 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
135 	 15,				/* bitsize */
136 	 FALSE,				/* pc_relative */
137 	 6,				/* bitpos */
138 	 complain_overflow_dont,	/* complain_on_overflow */
139 	 glob15_reloc,			/* special_function */
140 	 "PP15",			/* name */
141 	 TRUE,				/* partial_inplace */
142 	 0x1ffc0,			/* src_mask */
143 	 0x1ffc0,			/* dst_mask */
144 	 FALSE),			/* pcrel_offset */
145 
146   HOWTO (R_PP15W,			/* type */
147 	 2,				/* rightshift */
148 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
149 	 15,				/* bitsize */
150 	 FALSE,				/* pc_relative */
151 	 6,				/* bitpos */
152 	 complain_overflow_dont,	/* complain_on_overflow */
153 	 glob15_reloc,			/* special_function */
154 	 "PP15W",			/* name */
155 	 TRUE,				/* partial_inplace */
156 	 0x1ffc0,			/* src_mask */
157 	 0x1ffc0,			/* dst_mask */
158 	 FALSE),			/* pcrel_offset */
159 
160   HOWTO (R_PP15H,			/* type */
161 	 1,				/* rightshift */
162 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
163 	 15,				/* bitsize */
164 	 FALSE,				/* pc_relative */
165 	 6,				/* bitpos */
166 	 complain_overflow_dont,	/* complain_on_overflow */
167 	 glob15_reloc,			/* special_function */
168 	 "PP15H",			/* name */
169 	 TRUE,				/* partial_inplace */
170 	 0x1ffc0,			/* src_mask */
171 	 0x1ffc0,			/* dst_mask */
172 	 FALSE),			/* pcrel_offset */
173 
174   HOWTO (R_PP16B,			/* type */
175 	 0,				/* rightshift */
176 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
177 	 16,				/* bitsize */
178 	 FALSE,				/* pc_relative */
179 	 6,				/* bitpos */
180 	 complain_overflow_dont,	/* complain_on_overflow */
181 	 glob16_reloc,			/* special_function */
182 	 "PP16B",			/* name */
183 	 TRUE,				/* partial_inplace */
184 	 0x3ffc0,			/* src_mask */
185 	 0x3ffc0,			/* dst_mask */
186 	 FALSE),			/* pcrel_offset */
187 
188   HOWTO (R_PPL15,			/* type */
189 	 0,				/* rightshift */
190 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
191 	 15,				/* bitsize */
192 	 FALSE,				/* pc_relative */
193 	 0,				/* bitpos */
194 	 complain_overflow_dont,	/* complain_on_overflow */
195 	 NULL,				/* special_function */
196 	 "PPL15",			/* name */
197 	 TRUE,				/* partial_inplace */
198 	 0x7fff,			/* src_mask */
199 	 0x7fff,			/* dst_mask */
200 	 FALSE),			/* pcrel_offset */
201 
202   HOWTO (R_PPL15W,			/* type */
203 	 2,				/* rightshift */
204 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
205 	 15,				/* bitsize */
206 	 FALSE,				/* pc_relative */
207 	 0,				/* bitpos */
208 	 complain_overflow_dont,	/* complain_on_overflow */
209 	 NULL,				/* special_function */
210 	 "PPL15W",			/* name */
211 	 TRUE,				/* partial_inplace */
212 	 0x7fff,			/* src_mask */
213 	 0x7fff,			/* dst_mask */
214 	 FALSE),			/* pcrel_offset */
215 
216   HOWTO (R_PPL15H,			/* type */
217 	 1,				/* rightshift */
218 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
219 	 15,				/* bitsize */
220 	 FALSE,				/* pc_relative */
221 	 0,				/* bitpos */
222 	 complain_overflow_dont,	/* complain_on_overflow */
223 	 NULL,				/* special_function */
224 	 "PPL15H",			/* name */
225 	 TRUE,				/* partial_inplace */
226 	 0x7fff,			/* src_mask */
227 	 0x7fff,			/* dst_mask */
228 	 FALSE),			/* pcrel_offset */
229 
230   HOWTO (R_PPL16B,			/* type */
231 	 0,				/* rightshift */
232 	 2,				/* size (0 = byte, 1 = short, 2 = long) */
233 	 16,				/* bitsize */
234 	 FALSE,				/* pc_relative */
235 	 0,				/* bitpos */
236 	 complain_overflow_dont,	/* complain_on_overflow */
237 	 local16_reloc,			/* special_function */
238 	 "PPL16B",			/* name */
239 	 TRUE,				/* partial_inplace */
240 	 0xffff,			/* src_mask */
241 	 0xffff,			/* dst_mask */
242 	 FALSE),			/* pcrel_offset */
243 
244   HOWTO (R_PPN15,			/* type */
245 	 0,				/* rightshift */
246 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
247 	 15,				/* bitsize */
248 	 FALSE,				/* pc_relative */
249 	 6,				/* bitpos */
250 	 complain_overflow_dont,	/* complain_on_overflow */
251 	 glob15_reloc,			/* special_function */
252 	 "PPN15",			/* name */
253 	 TRUE,				/* partial_inplace */
254 	 0x1ffc0,			/* src_mask */
255 	 0x1ffc0,			/* dst_mask */
256 	 FALSE),			/* pcrel_offset */
257 
258   HOWTO (R_PPN15W,			/* type */
259 	 2,				/* rightshift */
260 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
261 	 15,				/* bitsize */
262 	 FALSE,				/* pc_relative */
263 	 6,				/* bitpos */
264 	 complain_overflow_dont,	/* complain_on_overflow */
265 	 glob15_reloc,			/* special_function */
266 	 "PPN15W",			/* name */
267 	 TRUE,				/* partial_inplace */
268 	 0x1ffc0,			/* src_mask */
269 	 0x1ffc0,			/* dst_mask */
270 	 FALSE),			/* pcrel_offset */
271 
272   HOWTO (R_PPN15H,			/* type */
273 	 1,				/* rightshift */
274 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
275 	 15,				/* bitsize */
276 	 FALSE,				/* pc_relative */
277 	 6,				/* bitpos */
278 	 complain_overflow_dont,	/* complain_on_overflow */
279 	 glob15_reloc,			/* special_function */
280 	 "PPN15H",			/* name */
281 	 TRUE,				/* partial_inplace */
282 	 0x1ffc0,			/* src_mask */
283 	 0x1ffc0,			/* dst_mask */
284 	 FALSE),			/* pcrel_offset */
285 
286   HOWTO (R_PPN16B,			/* type */
287 	 0,				/* rightshift */
288 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
289 	 16,				/* bitsize */
290 	 FALSE,				/* pc_relative */
291 	 6,				/* bitpos */
292 	 complain_overflow_dont,	/* complain_on_overflow */
293 	 glob16_reloc,			/* special_function */
294 	 "PPN16B",			/* name */
295 	 TRUE,				/* partial_inplace */
296 	 0x3ffc0,			/* src_mask */
297 	 0x3ffc0,			/* dst_mask */
298 	 FALSE),			/* pcrel_offset */
299 
300   HOWTO (R_PPLN15,			/* type */
301 	 0,				/* rightshift */
302 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
303 	 15,				/* bitsize */
304 	 FALSE,				/* pc_relative */
305 	 0,				/* bitpos */
306 	 complain_overflow_dont,	/* complain_on_overflow */
307 	 NULL,				/* special_function */
308 	 "PPLN15",			/* name */
309 	 TRUE,				/* partial_inplace */
310 	 0x7fff,			/* src_mask */
311 	 0x7fff,			/* dst_mask */
312 	 FALSE),			/* pcrel_offset */
313 
314   HOWTO (R_PPLN15W,			/* type */
315 	 2,				/* rightshift */
316 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
317 	 15,				/* bitsize */
318 	 FALSE,				/* pc_relative */
319 	 0,				/* bitpos */
320 	 complain_overflow_dont,	/* complain_on_overflow */
321 	 NULL,				/* special_function */
322 	 "PPLN15W",			/* name */
323 	 TRUE,				/* partial_inplace */
324 	 0x7fff,			/* src_mask */
325 	 0x7fff,			/* dst_mask */
326 	 FALSE),			/* pcrel_offset */
327 
328   HOWTO (R_PPLN15H,			/* type */
329 	 1,				/* rightshift */
330 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
331 	 15,				/* bitsize */
332 	 FALSE,				/* pc_relative */
333 	 0,				/* bitpos */
334 	 complain_overflow_dont,	/* complain_on_overflow */
335 	 NULL,				/* special_function */
336 	 "PPLN15H",			/* name */
337 	 TRUE,				/* partial_inplace */
338 	 0x7fff,			/* src_mask */
339 	 0x7fff,			/* dst_mask */
340 	 FALSE),			/* pcrel_offset */
341 
342   HOWTO (R_PPLN16B,			/* type */
343 	 0,				/* rightshift */
344 	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
345 	 15,				/* bitsize */
346 	 FALSE,				/* pc_relative */
347 	 0,				/* bitpos */
348 	 complain_overflow_dont,	/* complain_on_overflow */
349 	 local16_reloc,			/* special_function */
350 	 "PPLN16B",			/* name */
351 	 TRUE,				/* partial_inplace */
352 	 0xffff,			/* src_mask */
353 	 0xffff,			/* dst_mask */
354 	 FALSE)				/* pcrel_offset */
355 };
356 
357 /* Special relocation functions, used when the output file is not
358    itself a COFF TIc80 file.  */
359 
360 /* This special function is used for the base address type
361    relocations.  */
362 
363 static bfd_reloc_status_type
ppbase_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol_in ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)364 ppbase_reloc (bfd *abfd ATTRIBUTE_UNUSED,
365 	      arelent *reloc_entry ATTRIBUTE_UNUSED,
366 	      asymbol *symbol_in ATTRIBUTE_UNUSED,
367 	      void * data ATTRIBUTE_UNUSED,
368 	      asection *input_section ATTRIBUTE_UNUSED,
369 	      bfd *output_bfd ATTRIBUTE_UNUSED,
370 	      char **error_message ATTRIBUTE_UNUSED)
371 {
372   /* FIXME.  */
373   abort ();
374 }
375 
376 /* This special function is used for the global 15 bit relocations.  */
377 
378 static bfd_reloc_status_type
glob15_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol_in ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)379 glob15_reloc (bfd *abfd ATTRIBUTE_UNUSED,
380 	      arelent *reloc_entry ATTRIBUTE_UNUSED,
381 	      asymbol *symbol_in ATTRIBUTE_UNUSED,
382 	      void * data ATTRIBUTE_UNUSED,
383 	      asection *input_section ATTRIBUTE_UNUSED,
384 	      bfd *output_bfd ATTRIBUTE_UNUSED,
385 	      char **error_message ATTRIBUTE_UNUSED)
386 {
387   /* FIXME.  */
388   abort ();
389 }
390 
391 /* This special function is used for the global 16 bit relocations.  */
392 
393 static bfd_reloc_status_type
glob16_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol_in ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)394 glob16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
395 	      arelent *reloc_entry ATTRIBUTE_UNUSED,
396 	      asymbol *symbol_in ATTRIBUTE_UNUSED,
397 	      void * data ATTRIBUTE_UNUSED,
398 	      asection *input_section ATTRIBUTE_UNUSED,
399 	      bfd *output_bfd ATTRIBUTE_UNUSED,
400 	      char **error_message ATTRIBUTE_UNUSED)
401 {
402   /* FIXME.  */
403   abort ();
404 }
405 
406 /* This special function is used for the local 16 bit relocations.  */
407 
408 static bfd_reloc_status_type
local16_reloc(bfd * abfd ATTRIBUTE_UNUSED,arelent * reloc_entry ATTRIBUTE_UNUSED,asymbol * symbol_in ATTRIBUTE_UNUSED,void * data ATTRIBUTE_UNUSED,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)409 local16_reloc (bfd *abfd ATTRIBUTE_UNUSED,
410 	       arelent *reloc_entry ATTRIBUTE_UNUSED,
411 	       asymbol *symbol_in ATTRIBUTE_UNUSED,
412 	       void * 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 /* Code to turn an external r_type into a pointer to an entry in the howto_table.
422    If passed an r_type we don't recognize the abort rather than silently failing
423    to generate an output file.  */
424 
425 static void
rtype2howto(arelent * cache_ptr,struct internal_reloc * dst)426 rtype2howto (arelent *cache_ptr, struct internal_reloc *dst)
427 {
428   unsigned int i;
429 
430   for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
431     {
432       if (tic80_howto_table[i].type == dst->r_type)
433 	{
434 	  cache_ptr->howto = tic80_howto_table + i;
435 	  return;
436 	}
437     }
438 
439   (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
440 			 (unsigned int) dst->r_type);
441   cache_ptr->howto = tic80_howto_table + 0;
442 }
443 
444 #define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
445 #define coff_rtype_to_howto coff_tic80_rtype_to_howto
446 
447 static reloc_howto_type *
coff_tic80_rtype_to_howto(bfd * abfd ATTRIBUTE_UNUSED,asection * sec,struct internal_reloc * rel,struct coff_link_hash_entry * h ATTRIBUTE_UNUSED,struct internal_syment * sym ATTRIBUTE_UNUSED,bfd_vma * addendp)448 coff_tic80_rtype_to_howto (bfd *abfd ATTRIBUTE_UNUSED,
449 			   asection *sec,
450 			   struct internal_reloc *rel,
451 			   struct coff_link_hash_entry *h ATTRIBUTE_UNUSED,
452 			   struct internal_syment *sym ATTRIBUTE_UNUSED,
453 			   bfd_vma *addendp)
454 {
455   arelent genrel;
456 
457   if (rel -> r_symndx == -1 && addendp != NULL)
458     {
459       /* This is a TI "internal relocation", which means that the relocation
460 	 amount is the amount by which the current section is being relocated
461 	 in the output section.  */
462       *addendp = (sec -> output_section -> vma + sec -> output_offset) - sec -> vma;
463     }
464   RTYPE2HOWTO (&genrel, rel);
465   return genrel.howto;
466 }
467 
468 #ifndef BADMAG
469 #define BADMAG(x) TIC80BADMAG(x)
470 #endif
471 
472 #define coff_relocate_section coff_tic80_relocate_section
473 
474 /* We need a special relocation routine to handle the PP relocs.  Most
475    of this is a copy of _bfd_coff_generic_relocate_section.  */
476 
477 static bfd_boolean
coff_tic80_relocate_section(bfd * output_bfd,struct bfd_link_info * info,bfd * input_bfd,asection * input_section,bfd_byte * contents,struct internal_reloc * relocs,struct internal_syment * syms,asection ** sections)478 coff_tic80_relocate_section (bfd *output_bfd,
479 			     struct bfd_link_info *info,
480 			     bfd *input_bfd,
481 			     asection *input_section,
482 			     bfd_byte *contents,
483 			     struct internal_reloc *relocs,
484 			     struct internal_syment *syms,
485 			     asection **sections)
486 {
487   struct internal_reloc *rel;
488   struct internal_reloc *relend;
489 
490   rel = relocs;
491   relend = rel + input_section->reloc_count;
492   for (; rel < relend; rel++)
493     {
494       long symndx;
495       struct coff_link_hash_entry *h;
496       struct internal_syment *sym;
497       bfd_vma addend;
498       bfd_vma val;
499       reloc_howto_type *howto;
500       bfd_reloc_status_type rstat;
501       bfd_vma addr;
502 
503       symndx = rel->r_symndx;
504 
505       if (symndx == -1)
506 	{
507 	  h = NULL;
508 	  sym = NULL;
509 	}
510       else
511 	{
512 	  h = obj_coff_sym_hashes (input_bfd)[symndx];
513 	  sym = syms + symndx;
514 	}
515 
516       /* COFF treats common symbols in one of two ways.  Either the
517          size of the symbol is included in the section contents, or it
518          is not.  We assume that the size is not included, and force
519          the rtype_to_howto function to adjust the addend as needed.  */
520 
521       if (sym != NULL && sym->n_scnum != 0)
522 	addend = - sym->n_value;
523       else
524 	addend = 0;
525 
526       howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
527 				       sym, &addend);
528       if (howto == NULL)
529 	return FALSE;
530 
531       val = 0;
532 
533       if (h == NULL)
534 	{
535 	  asection *sec;
536 
537 	  if (symndx == -1)
538 	    {
539 	      sec = bfd_abs_section_ptr;
540 	      val = 0;
541 	    }
542 	  else
543 	    {
544 	      sec = sections[symndx];
545               val = (sec->output_section->vma
546 		     + sec->output_offset
547 		     + sym->n_value);
548 	      if (! obj_pe (output_bfd))
549 		val -= sec->vma;
550 	    }
551 	}
552       else
553 	{
554 	  if (h->root.type == bfd_link_hash_defined
555 	      || h->root.type == bfd_link_hash_defweak)
556 	    {
557 	      asection *sec;
558 
559 	      sec = h->root.u.def.section;
560 	      val = (h->root.u.def.value
561 		     + sec->output_section->vma
562 		     + sec->output_offset);
563 	      }
564 
565 	  else if (! bfd_link_relocatable (info))
566 	    (*info->callbacks->undefined_symbol)
567 	      (info, h->root.root.string, input_bfd, input_section,
568 	       rel->r_vaddr - input_section->vma, TRUE);
569 	}
570 
571       addr = rel->r_vaddr - input_section->vma;
572 
573       /* FIXME: This code assumes little endian, but the PP can
574          apparently be bi-endian.  I don't know if the bi-endianness
575          applies to the instruction set or just to the data.  */
576       switch (howto->type)
577 	{
578 	default:
579 	case R_ABS:
580 	case R_RELLONGX:
581 	case R_PPL15:
582 	case R_PPL15W:
583 	case R_PPL15H:
584 	case R_PPLN15:
585 	case R_PPLN15W:
586 	case R_PPLN15H:
587 	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
588 					    contents, addr, val, addend);
589 	  break;
590 
591 	case R_PP15:
592 	case R_PP15W:
593 	case R_PP15H:
594 	case R_PPN15:
595 	case R_PPN15W:
596 	case R_PPN15H:
597 	  /* Offset the address so that we can use 4 byte relocations.  */
598 	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
599 					    contents + 2, addr, val, addend);
600 	  break;
601 
602 	case R_PP16B:
603 	case R_PPN16B:
604 	  {
605 	    /* The most significant bit is stored in bit 6.  */
606 	    bfd_byte hold;
607 
608 	    hold = contents[addr + 4];
609 	    contents[addr + 4] &=~ 0x20;
610 	    contents[addr + 4] |= (contents[addr] >> 1) & 0x20;
611 	    rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
612 					      contents + 2, addr,
613 					      val, addend);
614 	    contents[addr] &=~ 0x40;
615 	    contents[addr] |= (contents[addr + 4] << 1) & 0x40;
616 	    contents[addr + 4] &=~ 0x20;
617 	    contents[addr + 4] |= hold & 0x20;
618 	    break;
619 	  }
620 
621 	case R_PPL16B:
622 	case R_PPLN16B:
623 	  {
624 	    /* The most significant bit is stored in bit 28.  */
625 	    bfd_byte hold;
626 
627 	    hold = contents[addr + 1];
628 	    contents[addr + 1] &=~ 0x80;
629 	    contents[addr + 1] |= (contents[addr + 3] << 3) & 0x80;
630 	    rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
631 					      contents, addr,
632 					      val, addend);
633 	    contents[addr + 3] &= ~0x10;
634 	    contents[addr + 3] |= (contents[addr + 1] >> 3) & 0x10;
635 	    contents[addr + 1] &=~ 0x80;
636 	    contents[addr + 1] |= hold & 0x80;
637 	    break;
638 	  }
639 
640 	case R_PPBASE:
641 	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
642 	  contents[addr] &=~ 0x3;
643 	  if (val >= 0x1000000 && val < 0x1000800)
644 	    contents[addr] |= 0x3;
645 	  else
646 	    contents[addr] |= 0x2;
647 	  rstat = bfd_reloc_ok;
648 	  break;
649 
650 	case R_PPLBASE:
651 	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
652 	  contents[addr + 2] &= ~0xc0;
653 	  if (val >= 0x1000000 && val < 0x1000800)
654 	    contents[addr + 2] |= 0xc0;
655 	  else
656 	    contents[addr + 2] |= 0x80;
657 	  rstat = bfd_reloc_ok;
658 	  break;
659 	}
660 
661       switch (rstat)
662 	{
663 	default:
664 	  abort ();
665 	case bfd_reloc_ok:
666 	  break;
667 	case bfd_reloc_outofrange:
668 	  (*_bfd_error_handler)
669 	    (_("%B: bad reloc address 0x%lx in section `%A'"),
670 	     input_bfd, input_section, (unsigned long) rel->r_vaddr);
671 	  return FALSE;
672 	case bfd_reloc_overflow:
673 	  {
674 	    const char *name;
675 	    char buf[SYMNMLEN + 1];
676 
677 	    if (symndx == -1)
678 	      name = "*ABS*";
679 	    else if (h != NULL)
680 	      name = NULL;
681 	    else
682 	      {
683 		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
684 		if (name == NULL)
685 		  return FALSE;
686 	      }
687 
688 	    (*info->callbacks->reloc_overflow)
689 	      (info, (h ? &h->root : NULL), name, howto->name,
690 	       (bfd_vma) 0, input_bfd, input_section,
691 	       rel->r_vaddr - input_section->vma);
692 	  }
693 	}
694     }
695   return TRUE;
696 }
697 
698 #define TIC80COFF 1		/* Customize coffcode.h */
699 #undef C_AUTOARG		/* Clashes with TIc80's C_UEXT */
700 #undef C_LASTENT		/* Clashes with TIc80's C_STATLAB */
701 
702 #ifndef bfd_pe_print_pdata
703 #define bfd_pe_print_pdata	NULL
704 #endif
705 
706 #include "coffcode.h"
707 
708 CREATE_LITTLE_COFF_TARGET_VEC (tic80_coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
709