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.
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
10This file is part of BFD, the Binary File Descriptor library.
11
12This program is free software; you can redistribute it and/or modify
13it under the terms of the GNU General Public License as published by
14the Free Software Foundation; either version 2 of the License, or
15(at your option) any later version.
16
17This program is distributed in the hope that it will be useful,
18but WITHOUT ANY WARRANTY; without even the implied warranty of
19MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, 59 Temple Place - Suite 330,
25Boston, MA 02111-1307, USA.  */
26
27#include "bfd.h"
28#include "bfdlink.h"
29#include "sysdep.h"
30#include "libbfd.h"
31#include "coff/tic80.h"
32#include "coff/internal.h"
33#include "libcoff.h"
34
35#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
36#define COFF_ALIGN_IN_SECTION_HEADER 1
37#define COFF_ALIGN_IN_SFLAGS 1
38
39#define GET_SCNHDR_FLAGS H_GET_16
40#define PUT_SCNHDR_FLAGS H_PUT_16
41
42static void rtype2howto
43  PARAMS ((arelent *cache_ptr, struct internal_reloc *dst));
44static bfd_reloc_status_type ppbase_reloc
45  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
46static bfd_reloc_status_type glob15_reloc
47  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
48static bfd_reloc_status_type glob16_reloc
49  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
50static bfd_reloc_status_type local16_reloc
51  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
52static 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 **));
55static reloc_howto_type * coff_tic80_rtype_to_howto
56  PARAMS ((bfd *, asection *, struct internal_reloc *,
57	   struct coff_link_hash_entry *, struct internal_syment *,
58	   bfd_vma *));
59
60static reloc_howto_type tic80_howto_table[] =
61{
62
63  HOWTO (R_RELLONG,			/* type */
64	 0,				/* rightshift */
65	 2,				/* size (0 = byte, 1 = short, 2 = long) */
66	 32,				/* bitsize */
67	 FALSE,				/* pc_relative */
68	 0,				/* bitpos */
69	 complain_overflow_bitfield,	/* complain_on_overflow */
70	 NULL,				/* special_function */
71	 "RELLONG",			/* name */
72	 TRUE,				/* partial_inplace */
73	 0xffffffff,			/* src_mask */
74	 0xffffffff,			/* dst_mask */
75	 FALSE),			/* pcrel_offset */
76
77  HOWTO (R_MPPCR,			/* type */
78	 2,				/* rightshift */
79	 2,				/* size (0 = byte, 1 = short, 2 = long) */
80	 32,				/* bitsize */
81	 TRUE,				/* pc_relative */
82	 0,				/* bitpos */
83	 complain_overflow_signed,	/* complain_on_overflow */
84	 NULL,				/* special_function */
85	 "MPPCR",			/* name */
86	 TRUE,				/* partial_inplace */
87	 0xffffffff,			/* src_mask */
88	 0xffffffff,			/* dst_mask */
89	 TRUE),				/* pcrel_offset */
90
91  HOWTO (R_ABS,				/* type */
92	 0,				/* rightshift */
93	 2,				/* size (0 = byte, 1 = short, 2 = long) */
94	 32,				/* bitsize */
95	 FALSE,				/* pc_relative */
96	 0,				/* bitpos */
97	 complain_overflow_bitfield,	/* complain_on_overflow */
98	 NULL,				/* special_function */
99	 "ABS",				/* name */
100	 TRUE,				/* partial_inplace */
101	 0xffffffff,			/* src_mask */
102	 0xffffffff,			/* dst_mask */
103	 FALSE),				/* pcrel_offset */
104
105  HOWTO (R_PPBASE,			/* type */
106	 0,				/* rightshift */
107	 2,				/* size (0 = byte, 1 = short, 2 = long) */
108	 32,				/* bitsize */
109	 FALSE,				/* pc_relative */
110	 0,				/* bitpos */
111	 complain_overflow_dont,	/* complain_on_overflow */
112	 ppbase_reloc,			/* special_function */
113	 "PPBASE",			/* name */
114	 TRUE,				/* partial_inplace */
115	 0xffffffff,			/* src_mask */
116	 0xffffffff,			/* dst_mask */
117	 FALSE),			/* pcrel_offset */
118
119  HOWTO (R_PPLBASE,			/* type */
120	 0,				/* rightshift */
121	 2,				/* size (0 = byte, 1 = short, 2 = long) */
122	 32,				/* bitsize */
123	 FALSE,				/* pc_relative */
124	 0,				/* bitpos */
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 */
132
133  HOWTO (R_PP15,			/* type */
134	 0,				/* rightshift */
135	 2,				/* size (0 = byte, 1 = short, 2 = long) */
136	 15,				/* bitsize */
137	 FALSE,				/* pc_relative */
138	 6,				/* bitpos */
139	 complain_overflow_dont,	/* complain_on_overflow */
140	 glob15_reloc,			/* special_function */
141	 "PP15",			/* name */
142	 TRUE,				/* partial_inplace */
143	 0x1ffc0,			/* src_mask */
144	 0x1ffc0,			/* dst_mask */
145	 FALSE),			/* pcrel_offset */
146
147  HOWTO (R_PP15W,			/* type */
148	 2,				/* rightshift */
149	 2,				/* size (0 = byte, 1 = short, 2 = long) */
150	 15,				/* bitsize */
151	 FALSE,				/* pc_relative */
152	 6,				/* bitpos */
153	 complain_overflow_dont,	/* complain_on_overflow */
154	 glob15_reloc,			/* special_function */
155	 "PP15W",			/* name */
156	 TRUE,				/* partial_inplace */
157	 0x1ffc0,			/* src_mask */
158	 0x1ffc0,			/* dst_mask */
159	 FALSE),			/* pcrel_offset */
160
161  HOWTO (R_PP15H,			/* type */
162	 1,				/* rightshift */
163	 2,				/* size (0 = byte, 1 = short, 2 = long) */
164	 15,				/* bitsize */
165	 FALSE,				/* pc_relative */
166	 6,				/* bitpos */
167	 complain_overflow_dont,	/* complain_on_overflow */
168	 glob15_reloc,			/* special_function */
169	 "PP15H",			/* name */
170	 TRUE,				/* partial_inplace */
171	 0x1ffc0,			/* src_mask */
172	 0x1ffc0,			/* dst_mask */
173	 FALSE),			/* pcrel_offset */
174
175  HOWTO (R_PP16B,			/* type */
176	 0,				/* rightshift */
177	 2,				/* size (0 = byte, 1 = short, 2 = long) */
178	 16,				/* bitsize */
179	 FALSE,				/* pc_relative */
180	 6,				/* bitpos */
181	 complain_overflow_dont,	/* complain_on_overflow */
182	 glob16_reloc,			/* special_function */
183	 "PP16B",			/* name */
184	 TRUE,				/* partial_inplace */
185	 0x3ffc0,			/* src_mask */
186	 0x3ffc0,			/* dst_mask */
187	 FALSE),			/* pcrel_offset */
188
189  HOWTO (R_PPL15,			/* type */
190	 0,				/* rightshift */
191	 2,				/* size (0 = byte, 1 = short, 2 = long) */
192	 15,				/* bitsize */
193	 FALSE,				/* pc_relative */
194	 0,				/* bitpos */
195	 complain_overflow_dont,	/* complain_on_overflow */
196	 NULL,				/* special_function */
197	 "PPL15",			/* name */
198	 TRUE,				/* partial_inplace */
199	 0x7fff,			/* src_mask */
200	 0x7fff,			/* dst_mask */
201	 FALSE),			/* pcrel_offset */
202
203  HOWTO (R_PPL15W,			/* type */
204	 2,				/* rightshift */
205	 2,				/* size (0 = byte, 1 = short, 2 = long) */
206	 15,				/* bitsize */
207	 FALSE,				/* pc_relative */
208	 0,				/* bitpos */
209	 complain_overflow_dont,	/* complain_on_overflow */
210	 NULL,				/* special_function */
211	 "PPL15W",			/* name */
212	 TRUE,				/* partial_inplace */
213	 0x7fff,			/* src_mask */
214	 0x7fff,			/* dst_mask */
215	 FALSE),			/* pcrel_offset */
216
217  HOWTO (R_PPL15H,			/* type */
218	 1,				/* rightshift */
219	 2,				/* size (0 = byte, 1 = short, 2 = long) */
220	 15,				/* bitsize */
221	 FALSE,				/* pc_relative */
222	 0,				/* bitpos */
223	 complain_overflow_dont,	/* complain_on_overflow */
224	 NULL,				/* special_function */
225	 "PPL15H",			/* name */
226	 TRUE,				/* partial_inplace */
227	 0x7fff,			/* src_mask */
228	 0x7fff,			/* dst_mask */
229	 FALSE),			/* pcrel_offset */
230
231  HOWTO (R_PPL16B,			/* type */
232	 0,				/* rightshift */
233	 2,				/* size (0 = byte, 1 = short, 2 = long) */
234	 16,				/* bitsize */
235	 FALSE,				/* pc_relative */
236	 0,				/* bitpos */
237	 complain_overflow_dont,	/* complain_on_overflow */
238	 local16_reloc,			/* special_function */
239	 "PPL16B",			/* name */
240	 TRUE,				/* partial_inplace */
241	 0xffff,			/* src_mask */
242	 0xffff,			/* dst_mask */
243	 FALSE),			/* pcrel_offset */
244
245  HOWTO (R_PPN15,			/* type */
246	 0,				/* rightshift */
247	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
248	 15,				/* bitsize */
249	 FALSE,				/* pc_relative */
250	 6,				/* bitpos */
251	 complain_overflow_dont,	/* complain_on_overflow */
252	 glob15_reloc,			/* special_function */
253	 "PPN15",			/* name */
254	 TRUE,				/* partial_inplace */
255	 0x1ffc0,			/* src_mask */
256	 0x1ffc0,			/* dst_mask */
257	 FALSE),			/* pcrel_offset */
258
259  HOWTO (R_PPN15W,			/* type */
260	 2,				/* rightshift */
261	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
262	 15,				/* bitsize */
263	 FALSE,				/* pc_relative */
264	 6,				/* bitpos */
265	 complain_overflow_dont,	/* complain_on_overflow */
266	 glob15_reloc,			/* special_function */
267	 "PPN15W",			/* name */
268	 TRUE,				/* partial_inplace */
269	 0x1ffc0,			/* src_mask */
270	 0x1ffc0,			/* dst_mask */
271	 FALSE),			/* pcrel_offset */
272
273  HOWTO (R_PPN15H,			/* type */
274	 1,				/* rightshift */
275	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
276	 15,				/* bitsize */
277	 FALSE,				/* pc_relative */
278	 6,				/* bitpos */
279	 complain_overflow_dont,	/* complain_on_overflow */
280	 glob15_reloc,			/* special_function */
281	 "PPN15H",			/* name */
282	 TRUE,				/* partial_inplace */
283	 0x1ffc0,			/* src_mask */
284	 0x1ffc0,			/* dst_mask */
285	 FALSE),			/* pcrel_offset */
286
287  HOWTO (R_PPN16B,			/* type */
288	 0,				/* rightshift */
289	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
290	 16,				/* bitsize */
291	 FALSE,				/* pc_relative */
292	 6,				/* bitpos */
293	 complain_overflow_dont,	/* complain_on_overflow */
294	 glob16_reloc,			/* special_function */
295	 "PPN16B",			/* name */
296	 TRUE,				/* partial_inplace */
297	 0x3ffc0,			/* src_mask */
298	 0x3ffc0,			/* dst_mask */
299	 FALSE),			/* pcrel_offset */
300
301  HOWTO (R_PPLN15,			/* type */
302	 0,				/* rightshift */
303	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
304	 15,				/* bitsize */
305	 FALSE,				/* pc_relative */
306	 0,				/* bitpos */
307	 complain_overflow_dont,	/* complain_on_overflow */
308	 NULL,				/* special_function */
309	 "PPLN15",			/* name */
310	 TRUE,				/* partial_inplace */
311	 0x7fff,			/* src_mask */
312	 0x7fff,			/* dst_mask */
313	 FALSE),			/* pcrel_offset */
314
315  HOWTO (R_PPLN15W,			/* type */
316	 2,				/* rightshift */
317	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
318	 15,				/* bitsize */
319	 FALSE,				/* pc_relative */
320	 0,				/* bitpos */
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 */
328
329  HOWTO (R_PPLN15H,			/* type */
330	 1,				/* rightshift */
331	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
332	 15,				/* bitsize */
333	 FALSE,				/* pc_relative */
334	 0,				/* bitpos */
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 */
342
343  HOWTO (R_PPLN16B,			/* type */
344	 0,				/* rightshift */
345	 -2,				/* size (0 = byte, 1 = short, 2 = long) */
346	 15,				/* bitsize */
347	 FALSE,				/* pc_relative */
348	 0,				/* bitpos */
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 */
356};
357
358/* Special relocation functions, used when the output file is not
359   itself a COFF TIc80 file.  */
360
361/* This special function is used for the base address type
362   relocations.  */
363
364static bfd_reloc_status_type
365ppbase_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
366	      error_message)
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;
374{
375  /* FIXME.  */
376  abort ();
377}
378
379/* This special function is used for the global 15 bit relocations.  */
380
381static bfd_reloc_status_type
382glob15_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
383	      error_message)
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;
391{
392  /* FIXME.  */
393  abort ();
394}
395
396/* This special function is used for the global 16 bit relocations.  */
397
398static bfd_reloc_status_type
399glob16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
400	      error_message)
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;
408{
409  /* FIXME.  */
410  abort ();
411}
412
413/* This special function is used for the local 16 bit relocations.  */
414
415static bfd_reloc_status_type
416local16_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
417	      error_message)
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;
425{
426  /* FIXME.  */
427  abort ();
428}
429
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.  */
433
434static void
435rtype2howto (cache_ptr, dst)
436     arelent *cache_ptr;
437     struct internal_reloc *dst;
438{
439  unsigned int i;
440
441  for (i = 0; i < sizeof tic80_howto_table / sizeof tic80_howto_table[0]; i++)
442    {
443      if (tic80_howto_table[i].type == dst->r_type)
444	{
445	  cache_ptr->howto = tic80_howto_table + i;
446	  return;
447	}
448    }
449
450  (*_bfd_error_handler) (_("Unrecognized reloc type 0x%x"),
451			 (unsigned int) dst->r_type);
452  cache_ptr->howto = tic80_howto_table + 0;
453}
454
455#define RTYPE2HOWTO(cache_ptr, dst) rtype2howto (cache_ptr, dst)
456#define coff_rtype_to_howto coff_tic80_rtype_to_howto
457
458static reloc_howto_type *
459coff_tic80_rtype_to_howto (abfd, sec, rel, h, sym, addendp)
460     bfd *abfd ATTRIBUTE_UNUSED;
461     asection *sec;
462     struct internal_reloc *rel;
463     struct coff_link_hash_entry *h ATTRIBUTE_UNUSED;
464     struct internal_syment *sym ATTRIBUTE_UNUSED;
465     bfd_vma *addendp;
466{
467  arelent genrel;
468
469  if (rel -> r_symndx == -1 && addendp != NULL)
470    {
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;
475    }
476  RTYPE2HOWTO (&genrel, rel);
477  return genrel.howto;
478}
479
480#ifndef BADMAG
481#define BADMAG(x) TIC80BADMAG(x)
482#endif
483
484#define coff_relocate_section coff_tic80_relocate_section
485
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.  */
488
489static bfd_boolean
490coff_tic80_relocate_section (output_bfd, info, input_bfd,
491			     input_section, contents, relocs, syms,
492			     sections)
493     bfd *output_bfd;
494     struct bfd_link_info *info;
495     bfd *input_bfd;
496     asection *input_section;
497     bfd_byte *contents;
498     struct internal_reloc *relocs;
499     struct internal_syment *syms;
500     asection **sections;
501{
502  struct internal_reloc *rel;
503  struct internal_reloc *relend;
504
505  rel = relocs;
506  relend = rel + input_section->reloc_count;
507  for (; rel < relend; rel++)
508    {
509      long symndx;
510      struct coff_link_hash_entry *h;
511      struct internal_syment *sym;
512      bfd_vma addend;
513      bfd_vma val;
514      reloc_howto_type *howto;
515      bfd_reloc_status_type rstat;
516      bfd_vma addr;
517
518      symndx = rel->r_symndx;
519
520      if (symndx == -1)
521	{
522	  h = NULL;
523	  sym = NULL;
524	}
525      else
526	{
527	  h = obj_coff_sym_hashes (input_bfd)[symndx];
528	  sym = syms + symndx;
529	}
530
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.  */
535
536      if (sym != NULL && sym->n_scnum != 0)
537	addend = - sym->n_value;
538      else
539	addend = 0;
540
541      howto = bfd_coff_rtype_to_howto (input_bfd, input_section, rel, h,
542				       sym, &addend);
543      if (howto == NULL)
544	return FALSE;
545
546      val = 0;
547
548      if (h == NULL)
549	{
550	  asection *sec;
551
552	  if (symndx == -1)
553	    {
554	      sec = bfd_abs_section_ptr;
555	      val = 0;
556	    }
557	  else
558	    {
559	      sec = sections[symndx];
560              val = (sec->output_section->vma
561		     + sec->output_offset
562		     + sym->n_value);
563	      if (! obj_pe (output_bfd))
564		val -= sec->vma;
565	    }
566	}
567      else
568	{
569	  if (h->root.type == bfd_link_hash_defined
570	      || h->root.type == bfd_link_hash_defweak)
571	    {
572	      asection *sec;
573
574	      sec = h->root.u.def.section;
575	      val = (h->root.u.def.value
576		     + sec->output_section->vma
577		     + sec->output_offset);
578	      }
579
580	  else if (! info->relocatable)
581	    {
582	      if (! ((*info->callbacks->undefined_symbol)
583		     (info, h->root.root.string, input_bfd, input_section,
584		      rel->r_vaddr - input_section->vma, TRUE)))
585		return FALSE;
586	    }
587	}
588
589      addr = rel->r_vaddr - input_section->vma;
590
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.  */
594      switch (howto->type)
595	{
596	default:
597	case R_ABS:
598	case R_RELLONGX:
599	case R_PPL15:
600	case R_PPL15W:
601	case R_PPL15H:
602	case R_PPLN15:
603	case R_PPLN15W:
604	case R_PPLN15H:
605	  rstat = _bfd_final_link_relocate (howto, input_bfd, input_section,
606					    contents, addr, val, addend);
607	  break;
608
609	case R_PP15:
610	case R_PP15W:
611	case R_PP15H:
612	case R_PPN15:
613	case R_PPN15W:
614	case R_PPN15H:
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);
618	  break;
619
620	case R_PP16B:
621	case R_PPN16B:
622	  {
623	    /* The most significant bit is stored in bit 6.  */
624	    bfd_byte hold;
625
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,
630					      contents + 2, addr,
631					      val, addend);
632	    contents[addr] &=~ 0x40;
633	    contents[addr] |= (contents[addr + 4] << 1) & 0x40;
634	    contents[addr + 4] &=~ 0x20;
635	    contents[addr + 4] |= hold & 0x20;
636	    break;
637	  }
638
639	case R_PPL16B:
640	case R_PPLN16B:
641	  {
642	    /* The most significant bit is stored in bit 28.  */
643	    bfd_byte hold;
644
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,
649					      contents, addr,
650					      val, addend);
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;
655	    break;
656	  }
657
658	case R_PPBASE:
659	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
660	  contents[addr] &=~ 0x3;
661	  if (val >= 0x1000000 && val < 0x1000800)
662	    contents[addr] |= 0x3;
663	  else
664	    contents[addr] |= 0x2;
665	  rstat = bfd_reloc_ok;
666	  break;
667
668	case R_PPLBASE:
669	  /* Parameter RAM is from 0x1000000 to 0x1000800.  */
670	  contents[addr + 2] &= ~0xc0;
671	  if (val >= 0x1000000 && val < 0x1000800)
672	    contents[addr + 2] |= 0xc0;
673	  else
674	    contents[addr + 2] |= 0x80;
675	  rstat = bfd_reloc_ok;
676	  break;
677	}
678
679      switch (rstat)
680	{
681	default:
682	  abort ();
683	case bfd_reloc_ok:
684	  break;
685	case bfd_reloc_outofrange:
686	  (*_bfd_error_handler)
687	    (_("%B: bad reloc address 0x%lx in section `%A'"),
688	     input_bfd, input_section, (unsigned long) rel->r_vaddr);
689	  return FALSE;
690	case bfd_reloc_overflow:
691	  {
692	    const char *name;
693	    char buf[SYMNMLEN + 1];
694
695	    if (symndx == -1)
696	      name = "*ABS*";
697	    else if (h != NULL)
698	      name = h->root.root.string;
699	    else
700	      {
701		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
702		if (name == NULL)
703		  return FALSE;
704	      }
705
706	    if (! ((*info->callbacks->reloc_overflow)
707		   (info, name, howto->name, (bfd_vma) 0, input_bfd,
708		    input_section, rel->r_vaddr - input_section->vma)))
709	      return FALSE;
710	  }
711	}
712    }
713  return TRUE;
714}
715
716#define TIC80COFF 1		/* Customize coffcode.h */
717#undef C_AUTOARG		/* Clashes with TIc80's C_UEXT */
718#undef C_LASTENT		/* Clashes with TIc80's C_STATLAB */
719#include "coffcode.h"
720
721CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
722