1/* Visium-specific support for 32-bit ELF.
2
3   Copyright (C) 2003-2024 Free Software Foundation, Inc.
4
5   This file is part of BFD, the Binary File Descriptor library.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor,
20   Boston, MA 02110-1301, USA.  */
21
22#include "sysdep.h"
23#include "bfd.h"
24#include "sysdep.h"
25#include "libbfd.h"
26#include "elf-bfd.h"
27#include "elf/visium.h"
28#include "libiberty.h"
29
30static bfd_reloc_status_type visium_elf_howto_parity_reloc
31  (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
32
33static reloc_howto_type visium_elf_howto_table[] = {
34  /* This reloc does nothing.  */
35  HOWTO (R_VISIUM_NONE,		/* type */
36	 0,			/* rightshift */
37	 0,			/* size */
38	 0,			/* bitsize */
39	 false,			/* pc_relative */
40	 0,			/* bitpos */
41	 complain_overflow_dont,	/* complain_on_overflow */
42	 bfd_elf_generic_reloc,	/* special_function */
43	 "R_VISIUM_NONE",	/* name */
44	 false,			/* partial_inplace */
45	 0,			/* src_mask */
46	 0,			/* dst_mask */
47	 false),		/* pcrel_offset */
48
49  /* A 8 bit absolute relocation.  */
50  HOWTO (R_VISIUM_8,		/* type */
51	 0,			/* rightshift */
52	 1,			/* size */
53	 8,			/* bitsize */
54	 false,			/* pc_relative */
55	 0,			/* bitpos */
56	 complain_overflow_bitfield,	/* complain_on_overflow */
57	 bfd_elf_generic_reloc,	/* special_function */
58	 "R_VISIUM_8",		/* name */
59	 false,			/* partial_inplace */
60	 0x00,			/* src_mask */
61	 0xff,			/* dst_mask */
62	 false),		/* pcrel_offset */
63
64  /* A 16 bit absolute relocation.  */
65  HOWTO (R_VISIUM_16,		/* type */
66	 0,			/* rightshift */
67	 2,			/* size */
68	 16,			/* bitsize */
69	 false,			/* pc_relative */
70	 0,			/* bitpos */
71	 complain_overflow_bitfield,	/* complain_on_overflow */
72	 bfd_elf_generic_reloc,	/* special_function */
73	 "R_VISIUM_16",		/* name */
74	 false,			/* partial_inplace */
75	 0x0000,		/* src_mask */
76	 0xffff,		/* dst_mask */
77	 false),		/* pcrel_offset */
78
79  /* A 32 bit absolute relocation.  */
80  HOWTO (R_VISIUM_32,		/* type */
81	 0,			/* rightshift */
82	 4,			/* size */
83	 32,			/* bitsize */
84	 false,			/* pc_relative */
85	 0,			/* bitpos */
86	 complain_overflow_bitfield,	/* complain_on_overflow */
87	 bfd_elf_generic_reloc,	/* special_function */
88	 "R_VISIUM_32",		/* name */
89	 false,			/* partial_inplace */
90	 0x00000000,		/* src_mask */
91	 0xffffffff,		/* dst_mask */
92	 false),		/* pcrel_offset */
93
94
95  /* A 8 bit PC relative relocation.  */
96  HOWTO (R_VISIUM_8_PCREL,		/* type */
97	 0,			/* rightshift */
98	 1,			/* size */
99	 8,			/* bitsize */
100	 true,			/* pc_relative */
101	 0,			/* bitpos */
102	 complain_overflow_bitfield,	/* complain_on_overflow */
103	 bfd_elf_generic_reloc,	/* special_function */
104	 "R_VISIUM_8_PCREL",	/* name */
105	 false,			/* partial_inplace */
106	 0x00,			/* src_mask */
107	 0xff,			/* dst_mask */
108	 true),			/* pcrel_offset */
109
110  /* A 16 bit PC relative relocation.  */
111  HOWTO (R_VISIUM_16_PCREL,	/* type */
112	 0,			/* rightshift */
113	 2,			/* size */
114	 16,			/* bitsize */
115	 true,			/* pc_relative */
116	 0,			/* bitpos */
117	 complain_overflow_bitfield,	/* complain_on_overflow */
118	 bfd_elf_generic_reloc,	/* special_function */
119	 "R_VISIUM_16_PCREL",	/* name */
120	 false,			/* partial inplace */
121	 0x0000,		/* src_mask */
122	 0xffff,		/* dst_mask */
123	 true),			/* pcrel_offset */
124
125  /* A 32-bit PC relative relocation.  */
126  HOWTO (R_VISIUM_32_PCREL,	/* type */
127	 0,			/* rightshift */
128	 4,			/* size */
129	 32,			/* bitsize */
130	 true,			/* pc_relative */
131	 0,			/* bitpos */
132	 complain_overflow_bitfield,	/* complain_on_overflow */
133	 bfd_elf_generic_reloc,	/* special_function */
134	 "R_VISIUM_32_PCREL",	/* name */
135	 false,			/* partial_inplace */
136	 0,			/* src_mask */
137	 0xffffffff,		/* dst_mask */
138	 true),			/* pcrel_offset */
139
140  /* A 16-bit PC word relative offset, relative to start of instruction
141     and always in the second half of the instruction.  */
142  HOWTO (R_VISIUM_PC16,		/* type */
143	 2,			/* rightshift */
144	 4,			/* size */
145	 16,			/* bitsize */
146	 true,			/* pc_relative */
147	 0,			/* bitpos */
148	 complain_overflow_signed,	/* complain_on_overflow */
149	 visium_elf_howto_parity_reloc,	/* special_function */
150	 "R_VISIUM_PC16",	/* name */
151	 false,			/* partial_inplace */
152	 0x00000000,		/* src_mask */
153	 0x0000ffff,		/* dst_mask */
154	 true),			/* pcrel_offset */
155
156  /* The high 16 bits of symbol value.  */
157  HOWTO (R_VISIUM_HI16,		/* type */
158	 16,			/* rightshift */
159	 4,			/* size */
160	 16,			/* bitsize */
161	 false,			/* pc_relative */
162	 0,			/* bitpos */
163	 complain_overflow_dont,	/* complain_on_overflow */
164	 visium_elf_howto_parity_reloc,	/* special_function */
165	 "R_VISIUM_HI16",	/* name */
166	 false,			/* partial_inplace */
167	 0x00000000,		/* src_mask */
168	 0x0000ffff,		/* dst_mask */
169	 false),		/* pcrel_offset */
170
171  /* The low 16 bits of symbol value.  */
172  HOWTO (R_VISIUM_LO16,		/* type */
173	 0,			/* rightshift */
174	 4,			/* size */
175	 16,			/* bitsize */
176	 false,			/* pc_relative */
177	 0,			/* bitpos */
178	 complain_overflow_dont,	/* complain_on_overflow */
179	 visium_elf_howto_parity_reloc,	/* special_function */
180	 "R_VISIUM_LO16",	/* name */
181	 false,			/* partial_inplace */
182	 0x00000000,		/* src_mask */
183	 0x0000ffff,		/* dst_mask */
184	 false),		/* pcrel_offset */
185
186  /* A 16 bit immediate value.  */
187  HOWTO (R_VISIUM_IM16,		/* type */
188	 0,			/* rightshift */
189	 4,			/* size */
190	 16,			/* bitsize */
191	 false,			/* pc_relative */
192	 0,			/* bitpos */
193	 complain_overflow_unsigned,	/* complain_on_overflow */
194	 visium_elf_howto_parity_reloc,	/* special_function */
195	 "R_VISIUM_IM16",	/* name */
196	 false,			/* partial_inplace */
197	 0x0000000,		/* src_mask */
198	 0x000ffff,		/* dst_mask */
199	 false),		/* pcrel_offset */
200
201  /* The high 16 bits of symbol value, pc relative.  */
202  HOWTO (R_VISIUM_HI16_PCREL,	/* type */
203	 16,			/* rightshift */
204	 4,			/* size */
205	 16,			/* bitsize */
206	 true,			/* pc_relative */
207	 0,			/* bitpos */
208	 complain_overflow_dont,	/* complain_on_overflow */
209	 visium_elf_howto_parity_reloc,	/* special_function */
210	 "R_VISIUM_HI16_PCREL",	/* name */
211	 false,			/* partial_inplace */
212	 0x00000000,		/* src_mask */
213	 0x0000ffff,		/* dst_mask */
214	 true),			/* pcrel_offset */
215
216  /* The low 16 bits of symbol value, pc relative.  */
217  HOWTO (R_VISIUM_LO16_PCREL,	/* type */
218	 0,			/* rightshift */
219	 4,			/* size */
220	 16,			/* bitsize */
221	 true,			/* pc_relative */
222	 0,			/* bitpos */
223	 complain_overflow_dont,	/* complain_on_overflow */
224	 visium_elf_howto_parity_reloc,	/* special_function */
225	 "R_VISIUM_LO16_PCREL",	/* name */
226	 false,			/* partial_inplace */
227	 0x00000000,		/* src_mask */
228	 0x0000ffff,		/* dst_mask */
229	 true),			/* pcrel_offset */
230
231  /* A 16 bit immediate value, pc relative.  */
232  HOWTO (R_VISIUM_IM16_PCREL,	/* type */
233	 0,			/* rightshift */
234	 4,			/* size */
235	 16,			/* bitsize */
236	 true,			/* pc_relative */
237	 0,			/* bitpos */
238	 complain_overflow_unsigned,	/* complain_on_overflow */
239	 visium_elf_howto_parity_reloc,	/* special_function */
240	 "R_VISIUM_IM16_PCREL",	/* name */
241	 false,			/* partial_inplace */
242	 0x0000000,		/* src_mask */
243	 0x000ffff,		/* dst_mask */
244	 true),			/* pcrel_offset */
245
246};
247
248/* GNU extension to record C++ vtable hierarchy.  */
249static reloc_howto_type visium_elf_vtinherit_howto =
250  HOWTO (R_VISIUM_GNU_VTINHERIT,      /* type */
251	 0,			   /* rightshift */
252	 4,			   /* size */
253	 0,			   /* bitsize */
254	 false,			   /* pc_relative */
255	 0,			   /* bitpos */
256	 complain_overflow_dont,   /* complain_on_overflow */
257	 NULL,			   /* special_function */
258	 "R_VISIUM_GNU_VTINHERIT", /* name */
259	 false,			   /* partial_inplace */
260	 0,			   /* src_mask */
261	 0,			   /* dst_mask */
262	 false);		   /* pcrel_offset */
263
264/* GNU extension to record C++ vtable member usage.  */
265static reloc_howto_type visium_elf_vtentry_howto =
266  HOWTO (R_VISIUM_GNU_VTENTRY,	   /* type */
267	 0,			   /* rightshift */
268	 4,			   /* size */
269	 0,			   /* bitsize */
270	 false,			   /* pc_relative */
271	 0,			   /* bitpos */
272	 complain_overflow_dont,   /* complain_on_overflow */
273	 NULL,			   /* special_function */
274	 "R_VISIUM_GNU_VTENTRY",   /* name */
275	 false,			   /* partial_inplace */
276	 0,			   /* src_mask */
277	 0,			   /* dst_mask */
278	 false);		   /* pcrel_offset */
279
280/* Return the parity bit for INSN shifted to its final position.  */
281
282static bfd_vma
283visium_parity_bit (bfd_vma insn)
284{
285  bfd_vma p = 0;
286  int i;
287
288  for (i = 0; i < 31; i++)
289    {
290      p ^= (insn & 1);
291      insn >>= 1;
292    }
293
294  return p << 31;
295}
296
297/* This "special function" will only be used when the input and
298   output files have different formats ie. when generating S-records
299   directly using "--oformat srec". Otherwise we use
300   _bfd_final_link_relocate which uses a howto structure, but does
301   not use the special_function field.
302
303   It sets instruction parity to even.  This cannot be done by a howto.  */
304
305static bfd_reloc_status_type
306visium_elf_howto_parity_reloc (bfd * input_bfd, arelent *reloc_entry,
307			       asymbol *symbol, void *data,
308			       asection *input_section, bfd *output_bfd,
309			       char **error_message ATTRIBUTE_UNUSED)
310{
311  bfd_reloc_status_type ret;
312  bfd_vma relocation;
313  bfd_byte *inplace_address;
314  bfd_vma insn;
315
316  /* This part is from bfd_elf_generic_reloc.
317     If we're relocating, and this an external symbol, we don't want
318     to change anything.  */
319  if (output_bfd != (bfd *) NULL && (symbol->flags & BSF_SECTION_SYM) == 0)
320    {
321      reloc_entry->address += input_section->output_offset;
322      return bfd_reloc_ok;
323    }
324
325  /* Now do the reloc in the usual way.  */
326
327  /* Sanity check the address (offset in section).  */
328  if (reloc_entry->address > bfd_get_section_limit (input_bfd, input_section))
329    return bfd_reloc_outofrange;
330
331  ret = bfd_reloc_ok;
332  if (bfd_is_und_section (symbol->section) && output_bfd == (bfd *) NULL)
333    ret = bfd_reloc_undefined;
334
335  if (bfd_is_com_section (symbol->section) || output_bfd != (bfd *) NULL)
336    relocation = 0;
337  else
338    relocation = symbol->value;
339
340  /* Only do this for a final link.  */
341  if (output_bfd == (bfd *) NULL)
342    {
343      relocation += symbol->section->output_section->vma;
344      relocation += symbol->section->output_offset;
345    }
346
347  relocation += reloc_entry->addend;
348  inplace_address = (bfd_byte *) data + reloc_entry->address;
349  insn = bfd_get_32 (input_bfd, inplace_address);
350
351  if (reloc_entry->howto->pc_relative)
352    {
353      relocation -= input_section->output_section->vma;
354      relocation -= input_section->output_offset;
355      relocation -= reloc_entry->address;
356    }
357
358  switch (reloc_entry->howto->type)
359    {
360    case R_VISIUM_PC16:
361      if (ret == bfd_reloc_ok
362	  && ((bfd_signed_vma) relocation < -0x20000
363	      || (bfd_signed_vma) relocation > 0x1ffff))
364	ret = bfd_reloc_overflow;
365      relocation = (relocation >> 2) & 0xffff;
366      break;
367    case R_VISIUM_HI16:
368    case R_VISIUM_HI16_PCREL:
369      relocation = (relocation >> 16) & 0xffff;
370      break;
371    case R_VISIUM_LO16:
372    case R_VISIUM_LO16_PCREL:
373      relocation &= 0xffff;
374      break;
375    case R_VISIUM_IM16:
376    case R_VISIUM_IM16_PCREL:
377      if (ret == bfd_reloc_ok && (relocation & 0xffff0000) != 0)
378	ret = bfd_reloc_overflow;
379      relocation &= 0xffff;
380      break;
381    }
382  insn = (insn & 0x7fff0000) | relocation;
383  insn |= visium_parity_bit (insn);
384  bfd_put_32 (input_bfd, insn, inplace_address);
385
386  if (output_bfd != (bfd *) NULL)
387    reloc_entry->address += input_section->output_offset;
388
389  return ret;
390}
391
392static reloc_howto_type *
393visium_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
394			  bfd_reloc_code_real_type code)
395{
396  /* Note that the visium_elf_howto_table is indexed by the R_
397     constants. Thus, the order that the howto records appear in the
398     table *must* match the order of the relocation types defined in
399     include/elf/visium.h.  */
400  switch (code)
401    {
402    case BFD_RELOC_NONE:
403      return &visium_elf_howto_table[(int) R_VISIUM_NONE];
404    case BFD_RELOC_8:
405      return &visium_elf_howto_table[(int) R_VISIUM_8];
406    case BFD_RELOC_16:
407      return &visium_elf_howto_table[(int) R_VISIUM_16];
408    case BFD_RELOC_32:
409      return &visium_elf_howto_table[(int) R_VISIUM_32];
410    case BFD_RELOC_8_PCREL:
411      return &visium_elf_howto_table[(int) R_VISIUM_8_PCREL];
412    case BFD_RELOC_16_PCREL:
413      return &visium_elf_howto_table[(int) R_VISIUM_16_PCREL];
414    case BFD_RELOC_32_PCREL:
415      return &visium_elf_howto_table[(int) R_VISIUM_32_PCREL];
416    case BFD_RELOC_VISIUM_REL16:
417      return &visium_elf_howto_table[(int) R_VISIUM_PC16];
418    case BFD_RELOC_VISIUM_HI16:
419      return &visium_elf_howto_table[(int) R_VISIUM_HI16];
420    case BFD_RELOC_VISIUM_LO16:
421      return &visium_elf_howto_table[(int) R_VISIUM_LO16];
422    case BFD_RELOC_VISIUM_IM16:
423      return &visium_elf_howto_table[(int) R_VISIUM_IM16];
424    case BFD_RELOC_VISIUM_HI16_PCREL:
425      return &visium_elf_howto_table[(int) R_VISIUM_HI16_PCREL];
426    case BFD_RELOC_VISIUM_LO16_PCREL:
427      return &visium_elf_howto_table[(int) R_VISIUM_LO16_PCREL];
428    case BFD_RELOC_VISIUM_IM16_PCREL:
429      return &visium_elf_howto_table[(int) R_VISIUM_IM16_PCREL];
430    case BFD_RELOC_VTABLE_INHERIT:
431      return &visium_elf_vtinherit_howto;
432    case BFD_RELOC_VTABLE_ENTRY:
433      return &visium_elf_vtentry_howto;
434    default:
435      return NULL;
436    }
437}
438
439static reloc_howto_type *
440visium_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
441{
442  unsigned int i;
443
444  for (i = 0;
445       i < (sizeof (visium_elf_howto_table)
446	    / sizeof (visium_elf_howto_table[0])); i++)
447    if (visium_elf_howto_table[i].name != NULL
448	&& strcasecmp (visium_elf_howto_table[i].name, r_name) == 0)
449      return &visium_elf_howto_table[i];
450
451  if (strcasecmp (visium_elf_vtinherit_howto.name, r_name) == 0)
452    return &visium_elf_vtinherit_howto;
453  if (strcasecmp (visium_elf_vtentry_howto.name, r_name) == 0)
454    return &visium_elf_vtentry_howto;
455
456  return NULL;
457}
458
459/* Set the howto pointer for a VISIUM ELF reloc.  */
460
461static bool
462visium_info_to_howto_rela (bfd *abfd, arelent *cache_ptr,
463			   Elf_Internal_Rela *dst)
464{
465  unsigned int r_type = ELF32_R_TYPE (dst->r_info);
466
467  switch (r_type)
468    {
469    case R_VISIUM_GNU_VTINHERIT:
470      cache_ptr->howto = &visium_elf_vtinherit_howto;
471      break;
472
473    case R_VISIUM_GNU_VTENTRY:
474      cache_ptr->howto = &visium_elf_vtentry_howto;
475      break;
476
477    default:
478      if (r_type >= ARRAY_SIZE (visium_elf_howto_table))
479	{
480	  /* xgettext:c-format */
481	  _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
482			      abfd, r_type);
483	  bfd_set_error (bfd_error_bad_value);
484	  return false;
485	}
486      cache_ptr->howto = &visium_elf_howto_table[r_type];
487      break;
488    }
489  return true;
490}
491
492/* Look through the relocs for a section during the first phase.
493   Since we don't do .gots or .plts, we just need to consider the
494   virtual table relocs for gc.  */
495
496static bool
497visium_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
498			 asection *sec, const Elf_Internal_Rela *relocs)
499{
500  Elf_Internal_Shdr *symtab_hdr;
501  struct elf_link_hash_entry **sym_hashes;
502  const Elf_Internal_Rela *rel;
503  const Elf_Internal_Rela *rel_end;
504
505  if (bfd_link_relocatable (info))
506    return true;
507
508  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
509  sym_hashes = elf_sym_hashes (abfd);
510
511  rel_end = relocs + sec->reloc_count;
512  for (rel = relocs; rel < rel_end; rel++)
513    {
514      struct elf_link_hash_entry *h;
515      unsigned long r_symndx;
516
517      r_symndx = ELF32_R_SYM (rel->r_info);
518      if (r_symndx < symtab_hdr->sh_info)
519	h = NULL;
520      else
521	{
522	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
523	  while (h->root.type == bfd_link_hash_indirect
524		 || h->root.type == bfd_link_hash_warning)
525	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
526	}
527
528      switch (ELF32_R_TYPE (rel->r_info))
529	{
530	  /* This relocation describes the C++ object vtable hierarchy.
531	     Reconstruct it for later use during GC.  */
532	case R_VISIUM_GNU_VTINHERIT:
533	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
534	    return false;
535	  break;
536
537	  /* This relocation describes which C++ vtable entries are actually
538	     used.  Record for later use during GC.  */
539	case R_VISIUM_GNU_VTENTRY:
540	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
541	    return false;
542	  break;
543	}
544    }
545
546  return true;
547}
548
549/* Relocate a VISIUM ELF section.  */
550
551static int
552visium_elf_relocate_section (bfd *output_bfd,
553			     struct bfd_link_info *info, bfd *input_bfd,
554			     asection *input_section, bfd_byte *contents,
555			     Elf_Internal_Rela *relocs,
556			     Elf_Internal_Sym *local_syms,
557			     asection **local_sections)
558{
559  Elf_Internal_Shdr *symtab_hdr;
560  struct elf_link_hash_entry **sym_hashes;
561  Elf_Internal_Rela *rel;
562  Elf_Internal_Rela *relend;
563
564  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
565  sym_hashes = elf_sym_hashes (input_bfd);
566  relend = relocs + input_section->reloc_count;
567
568  for (rel = relocs; rel < relend; rel++)
569    {
570      reloc_howto_type *howto;
571      unsigned long r_symndx;
572      Elf_Internal_Sym *sym;
573      asection *sec;
574      struct elf_link_hash_entry *h;
575      bfd_vma relocation;
576      bfd_reloc_status_type r;
577      const char *name = NULL;
578      int r_type;
579      bfd_vma insn;
580
581      r_type = ELF32_R_TYPE (rel->r_info);
582
583      if (r_type == R_VISIUM_GNU_VTINHERIT || r_type == R_VISIUM_GNU_VTENTRY)
584	continue;
585
586      r_symndx = ELF32_R_SYM (rel->r_info);
587
588      howto = visium_elf_howto_table + ELF32_R_TYPE (rel->r_info);
589      h = NULL;
590      sym = NULL;
591      sec = NULL;
592
593      if (r_symndx < symtab_hdr->sh_info)
594	{
595	  /* This is a local symbol.  */
596	  sym = local_syms + r_symndx;
597	  sec = local_sections[r_symndx];
598	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
599
600	  name = bfd_elf_string_from_elf_section
601	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
602	  name = name == NULL ? bfd_section_name (sec) : name;
603	}
604      else
605	{
606	  bool unresolved_reloc;
607	  bool warned, ignored;
608
609	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
610				   r_symndx, symtab_hdr, sym_hashes,
611				   h, sec, relocation,
612				   unresolved_reloc, warned, ignored);
613
614	  name = h->root.root.string;
615	}
616
617      if (sec != NULL && discarded_section (sec))
618	{
619	  /* For relocs against symbols from removed linkonce sections,
620	     or sections discarded by a linker script, we just want the
621	     section contents zeroed.  Avoid any special processing.  */
622	  _bfd_clear_contents (howto, input_bfd, input_section,
623			       contents, rel->r_offset);
624
625	  rel->r_info = 0;
626	  rel->r_addend = 0;
627	  continue;
628	}
629
630      if (bfd_link_relocatable (info))
631	continue;
632
633      switch (r_type)
634	{
635	case R_VISIUM_PC16:
636	case R_VISIUM_HI16:
637	case R_VISIUM_LO16:
638	case R_VISIUM_IM16:
639	case R_VISIUM_HI16_PCREL:
640	case R_VISIUM_LO16_PCREL:
641	case R_VISIUM_IM16_PCREL:
642	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
643					contents, rel->r_offset,
644					relocation, rel->r_addend);
645
646	  /* For instruction relocations, the parity needs correcting.  */
647	  if (r == bfd_reloc_ok)
648	    {
649	      insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
650	      insn = (insn & 0x7fffffff) | visium_parity_bit (insn);
651	      bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
652	    }
653	  break;
654
655	default:
656	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
657					contents, rel->r_offset,
658					relocation, rel->r_addend);
659	  break;
660	}
661
662      if (r != bfd_reloc_ok)
663	{
664	  const char *msg = (const char *) NULL;
665
666	  switch (r)
667	    {
668	    case bfd_reloc_overflow:
669	      (*info->callbacks->reloc_overflow)
670		(info, (h ? &h->root : NULL), name, howto->name, (bfd_vma) 0,
671		 input_bfd, input_section, rel->r_offset);
672	      break;
673
674	    case bfd_reloc_undefined:
675	      (*info->callbacks->undefined_symbol)
676		(info, name, input_bfd, input_section, rel->r_offset, true);
677	      break;
678
679	    case bfd_reloc_outofrange:
680	      msg = _("internal error: out of range error");
681	      break;
682
683	    case bfd_reloc_notsupported:
684	      msg = _("internal error: unsupported relocation error");
685	      break;
686
687	    case bfd_reloc_dangerous:
688	      msg = _("internal error: dangerous relocation");
689	      break;
690
691	    default:
692	      msg = _("internal error: unknown error");
693	      break;
694	    }
695
696	  if (msg)
697	    (*info->callbacks->warning) (info, msg, name, input_bfd,
698					 input_section, rel->r_offset);
699	}
700    }
701
702  return true;
703}
704
705/* This function is called during section gc to discover the section a
706   to which a particular relocation refers.  Return the section that
707   should be marked against GC for a given relocation.  */
708
709static asection *
710visium_elf_gc_mark_hook (asection *sec, struct bfd_link_info *info,
711			 Elf_Internal_Rela *rel, struct elf_link_hash_entry *h,
712			 Elf_Internal_Sym *sym)
713{
714  if (h != NULL)
715    switch (ELF32_R_TYPE (rel->r_info))
716      {
717      case R_VISIUM_GNU_VTINHERIT:
718      case R_VISIUM_GNU_VTENTRY:
719	return NULL;
720      }
721
722  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
723}
724
725static bool
726visium_elf_init_file_header (bfd *abfd, struct bfd_link_info *info)
727{
728  Elf_Internal_Ehdr *i_ehdrp;
729
730  if (!_bfd_elf_init_file_header (abfd, info))
731    return false;
732
733  i_ehdrp = elf_elfheader (abfd);
734  i_ehdrp->e_ident[EI_ABIVERSION] = 1;
735  return true;
736}
737
738/* Function to set the ELF flag bits.  */
739
740static bool
741visium_elf_set_private_flags (bfd *abfd, flagword flags)
742{
743  elf_elfheader (abfd)->e_flags = flags;
744  elf_flags_init (abfd) = true;
745  return true;
746}
747
748/* Copy backend specific data from one object module to another.  */
749
750static bool
751visium_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
752{
753  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
754      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
755    return true;
756
757  BFD_ASSERT (!elf_flags_init (obfd)
758	      || elf_elfheader (obfd)->e_flags ==
759	      elf_elfheader (ibfd)->e_flags);
760
761  elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
762  elf_flags_init (obfd) = true;
763
764  /* Copy object attributes.  */
765  _bfd_elf_copy_obj_attributes (ibfd, obfd);
766
767  return true;
768}
769
770/* Merge backend specific data from an object
771   file to the output object file when linking.  */
772
773static bool
774visium_elf_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)
775{
776  bfd *obfd = info->output_bfd;
777  flagword old_flags;
778  flagword new_flags;
779  flagword mismatch;
780  const char *opt_arch = NULL;
781  const char *new_opt_with = NULL;
782  const char *old_opt_with = NULL;
783  const char *with = "with";
784  const char *without = "without";
785  const char *mcm = "mcm";
786  const char *mcm24 = "mcm24";
787  const char *gr6 = "gr6";
788
789  new_flags = elf_elfheader (ibfd)->e_flags;
790  old_flags = elf_elfheader (obfd)->e_flags;
791
792  if (!elf_flags_init (obfd))
793    {
794      /* First call, no flags set.  */
795      elf_flags_init (obfd) = true;
796      elf_elfheader (obfd)->e_flags = new_flags;
797    }
798  else
799    {
800      mismatch = (new_flags ^ old_flags)
801	& (EF_VISIUM_ARCH_MCM | EF_VISIUM_ARCH_MCM24 | EF_VISIUM_ARCH_GR6);
802      if (mismatch & EF_VISIUM_ARCH_GR6)
803	{
804	  opt_arch = gr6;
805	  new_opt_with = new_flags & EF_VISIUM_ARCH_GR6 ? with : without;
806	  old_opt_with = old_flags & EF_VISIUM_ARCH_GR6 ? with : without;
807	}
808      else if (mismatch & EF_VISIUM_ARCH_MCM)
809	{
810	  opt_arch = mcm;
811	  new_opt_with = new_flags & EF_VISIUM_ARCH_MCM ? with : without;
812	  old_opt_with = old_flags & EF_VISIUM_ARCH_MCM ? with : without;
813	}
814      else if (mismatch & EF_VISIUM_ARCH_MCM24)
815	{
816	  opt_arch = mcm24;
817	  new_opt_with = new_flags & EF_VISIUM_ARCH_MCM24 ? with : without;
818	  old_opt_with = old_flags & EF_VISIUM_ARCH_MCM24 ? with : without;
819	}
820
821      if (mismatch)
822	_bfd_error_handler
823	  /* xgettext:c-format */
824	  (_("%pB: compiled %s -mtune=%s and linked with modules"
825	     " compiled %s -mtune=%s"),
826	   ibfd, new_opt_with, opt_arch, old_opt_with, opt_arch);
827    }
828
829  return true;
830}
831
832static bool
833visium_elf_print_private_bfd_data (bfd *abfd, void *ptr)
834{
835  FILE *file = (FILE *) ptr;
836  flagword flags;
837
838  BFD_ASSERT (abfd != NULL && ptr != NULL);
839
840  /* Print normal ELF private data.  */
841  _bfd_elf_print_private_bfd_data (abfd, ptr);
842
843  flags = elf_elfheader (abfd)->e_flags;
844  fprintf (file, _("private flags = 0x%lx:"), (long) flags);
845
846  if (flags & EF_VISIUM_ARCH_GR6)
847    fprintf (file, " -mtune=gr6");
848  else if (flags & EF_VISIUM_ARCH_MCM)
849    fprintf (file, " -mtune=mcm");
850  else if (flags & EF_VISIUM_ARCH_MCM24)
851    fprintf (file, " -mtune=mcm24");
852
853  fputc ('\n', file);
854  return true;
855}
856
857#define ELF_ARCH		bfd_arch_visium
858#define ELF_MACHINE_CODE	EM_VISIUM
859#define ELF_OSABI		ELFOSABI_STANDALONE
860#define ELF_MAXPAGESIZE		1
861
862#define TARGET_BIG_SYM		visium_elf32_vec
863#define TARGET_BIG_NAME		"elf32-visium"
864
865#define elf_info_to_howto_rel			NULL
866#define elf_info_to_howto			visium_info_to_howto_rela
867#define elf_backend_relocate_section		visium_elf_relocate_section
868#define elf_backend_gc_mark_hook		visium_elf_gc_mark_hook
869#define elf_backend_check_relocs		visium_elf_check_relocs
870#define elf_backend_rela_normal			1
871
872#define elf_backend_can_gc_sections		1
873
874#define bfd_elf32_bfd_reloc_type_lookup		visium_reloc_type_lookup
875#define bfd_elf32_bfd_reloc_name_lookup		visium_reloc_name_lookup
876
877#define bfd_elf32_bfd_set_private_flags		visium_elf_set_private_flags
878#define bfd_elf32_bfd_copy_private_bfd_data	visium_elf_copy_private_bfd_data
879#define bfd_elf32_bfd_merge_private_bfd_data	visium_elf_merge_private_bfd_data
880#define bfd_elf32_bfd_print_private_bfd_data	visium_elf_print_private_bfd_data
881#define elf_backend_init_file_header		visium_elf_init_file_header
882
883#include "elf32-target.h"
884