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