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
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, 51 Franklin Street - Fifth Floor,
25Boston, 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
50static void rtype2howto
51  PARAMS ((arelent *cache_ptr, struct internal_reloc *dst));
52static bfd_reloc_status_type ppbase_reloc
53  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
54static bfd_reloc_status_type glob15_reloc
55  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
56static bfd_reloc_status_type glob16_reloc
57  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
58static bfd_reloc_status_type local16_reloc
59  PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
60static 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 **));
63static 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
68static 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
372static bfd_reloc_status_type
373ppbase_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
389static bfd_reloc_status_type
390glob15_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
406static bfd_reloc_status_type
407glob16_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
423static bfd_reloc_status_type
424local16_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
442static void
443rtype2howto (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
466static reloc_howto_type *
467coff_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
497static bfd_boolean
498coff_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
739CREATE_LITTLE_COFF_TARGET_VEC (tic80coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
740