1/* BFD back-end for Texas Instruments TMS320C80 Multimedia Video Processor (MVP).
2   Copyright (C) 1996-2017 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
49static bfd_reloc_status_type ppbase_reloc
50  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
51static bfd_reloc_status_type glob15_reloc
52  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
53static bfd_reloc_status_type glob16_reloc
54  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
55static bfd_reloc_status_type local16_reloc
56  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
57
58
59static 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
363static bfd_reloc_status_type
364ppbase_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
378static bfd_reloc_status_type
379glob15_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
393static bfd_reloc_status_type
394glob16_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
408static bfd_reloc_status_type
409local16_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
425static void
426rtype2howto (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
447static reloc_howto_type *
448coff_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
477static bfd_boolean
478coff_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	    /* xgettext: c-format */
670	    (_("%B: bad reloc address 0x%lx in section `%A'"),
671	     input_bfd, input_section, (unsigned long) rel->r_vaddr);
672	  return FALSE;
673	case bfd_reloc_overflow:
674	  {
675	    const char *name;
676	    char buf[SYMNMLEN + 1];
677
678	    if (symndx == -1)
679	      name = "*ABS*";
680	    else if (h != NULL)
681	      name = NULL;
682	    else
683	      {
684		name = _bfd_coff_internal_syment_name (input_bfd, sym, buf);
685		if (name == NULL)
686		  return FALSE;
687	      }
688
689	    (*info->callbacks->reloc_overflow)
690	      (info, (h ? &h->root : NULL), name, howto->name,
691	       (bfd_vma) 0, input_bfd, input_section,
692	       rel->r_vaddr - input_section->vma);
693	  }
694	}
695    }
696  return TRUE;
697}
698
699#define TIC80COFF 1		/* Customize coffcode.h */
700#undef C_AUTOARG		/* Clashes with TIc80's C_UEXT */
701#undef C_LASTENT		/* Clashes with TIc80's C_STATLAB */
702
703#ifndef bfd_pe_print_pdata
704#define bfd_pe_print_pdata	NULL
705#endif
706
707#include "coffcode.h"
708
709CREATE_LITTLE_COFF_TARGET_VEC (tic80_coff_vec, "coff-tic80", D_PAGED, 0, '_', NULL, COFF_SWAP_TABLE)
710