1/* FR30-specific support for 32-bit ELF.
2   Copyright (C) 1998-2020 Free Software Foundation, Inc.
3
4   This file is part of BFD, the Binary File Descriptor library.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "sysdep.h"
22#include "bfd.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25#include "elf/fr30.h"
26
27/* Forward declarations.  */
28static bfd_reloc_status_type
29fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
30		    asection *, bfd *, char **error_message);
31static bfd_reloc_status_type
32fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
33		    asection *, bfd *, char **);
34
35static reloc_howto_type fr30_elf_howto_table [] =
36{
37  /* This reloc does nothing.  */
38  HOWTO (R_FR30_NONE,		/* type */
39	 0,			/* rightshift */
40	 3,			/* size (0 = byte, 1 = short, 2 = long) */
41	 0,			/* bitsize */
42	 FALSE,			/* pc_relative */
43	 0,			/* bitpos */
44	 complain_overflow_dont, /* complain_on_overflow */
45	 bfd_elf_generic_reloc,	/* special_function */
46	 "R_FR30_NONE",		/* name */
47	 FALSE,			/* partial_inplace */
48	 0,			/* src_mask */
49	 0,			/* dst_mask */
50	 FALSE),		/* pcrel_offset */
51
52  /* An 8 bit absolute relocation.  */
53  HOWTO (R_FR30_8,		/* type */
54	 0,			/* rightshift */
55	 1,			/* size (0 = byte, 1 = short, 2 = long) */
56	 8,			/* bitsize */
57	 FALSE,			/* pc_relative */
58	 4,			/* bitpos */
59	 complain_overflow_bitfield, /* complain_on_overflow */
60	 bfd_elf_generic_reloc,	/* special_function */
61	 "R_FR30_8",		/* name */
62	 FALSE,			/* partial_inplace */
63	 0x0000,		/* src_mask */
64	 0x0ff0,		/* dst_mask */
65	 FALSE),		/* pcrel_offset */
66
67  /* A 20 bit absolute relocation.  */
68  HOWTO (R_FR30_20,		/* type */
69	 0,			/* rightshift */
70	 2,			/* size (0 = byte, 1 = short, 2 = long) */
71	 20,			/* bitsize */
72	 FALSE,			/* pc_relative */
73	 0,			/* bitpos */
74	 complain_overflow_bitfield, /* complain_on_overflow */
75	 fr30_elf_i20_reloc,	/* special_function */
76	 "R_FR30_20",		/* name */
77	 FALSE,			/* partial_inplace */
78	 0x00000000,		/* src_mask */
79	 0x00f0ffff,		/* dst_mask */
80	 FALSE),		/* pcrel_offset */
81
82  /* A 32 bit absolute relocation.  */
83  HOWTO (R_FR30_32,		/* type */
84	 0,			/* rightshift */
85	 2,			/* size (0 = byte, 1 = short, 2 = long) */
86	 32,			/* bitsize */
87	 FALSE,			/* pc_relative */
88	 0,			/* bitpos */
89	 complain_overflow_bitfield, /* complain_on_overflow */
90	 bfd_elf_generic_reloc,	/* special_function */
91	 "R_FR30_32",		/* name */
92	 FALSE,			/* partial_inplace */
93	 0x00000000,		/* src_mask */
94	 0xffffffff,		/* dst_mask */
95	 FALSE),		/* pcrel_offset */
96
97  /* A 32 bit into 48 bits absolute relocation.  */
98  HOWTO (R_FR30_48,		/* type */
99	 0,			/* rightshift */
100	 2,			/* size (0 = byte, 1 = short, 2 = long) */
101	 32,			/* bitsize */
102	 FALSE,			/* pc_relative */
103	 0,			/* bitpos */
104	 complain_overflow_bitfield, /* complain_on_overflow */
105	 fr30_elf_i32_reloc,	/* special_function */
106	 "R_FR30_48",		/* name */
107	 FALSE,			/* partial_inplace */
108	 0x00000000,		/* src_mask */
109	 0xffffffff,		/* dst_mask */
110	 FALSE),		/* pcrel_offset */
111
112  /* A 6 bit absolute relocation.  */
113  HOWTO (R_FR30_6_IN_4,		/* type */
114	 2,			/* rightshift */
115	 1,			/* size (0 = byte, 1 = short, 2 = long) */
116	 6,			/* bitsize */
117	 FALSE,			/* pc_relative */
118	 4,			/* bitpos */
119	 complain_overflow_unsigned, /* complain_on_overflow */
120	 bfd_elf_generic_reloc,	/* special_function */
121	 "R_FR30_6_IN_4",	/* name */
122	 FALSE,			/* partial_inplace */
123	 0x0000,		/* src_mask */
124	 0x00f0,		/* dst_mask */
125	 FALSE),		/* pcrel_offset */
126
127  /* An 8 bit absolute relocation.  */
128  HOWTO (R_FR30_8_IN_8,		/* type */
129	 0,			/* rightshift */
130	 1,			/* size (0 = byte, 1 = short, 2 = long) */
131	 8,			/* bitsize */
132	 FALSE,			/* pc_relative */
133	 4,			/* bitpos */
134	 complain_overflow_signed, /* complain_on_overflow */
135	 bfd_elf_generic_reloc,/* special_function */
136	 "R_FR30_8_IN_8",	/* name */
137	 FALSE,			/* partial_inplace */
138	 0x0000,		/* src_mask */
139	 0x0ff0,		/* dst_mask */
140	 FALSE),		/* pcrel_offset */
141
142  /* A 9 bit absolute relocation.  */
143  HOWTO (R_FR30_9_IN_8,		/* type */
144	 1,			/* rightshift */
145	 1,			/* size (0 = byte, 1 = short, 2 = long) */
146	 9,			/* bitsize */
147	 FALSE,			/* pc_relative */
148	 4,			/* bitpos */
149	 complain_overflow_signed, /* complain_on_overflow */
150	 bfd_elf_generic_reloc,/* special_function */
151	 "R_FR30_9_IN_8",	/* name */
152	 FALSE,			/* partial_inplace */
153	 0x0000,		/* src_mask */
154	 0x0ff0,		/* dst_mask */
155	 FALSE),		/* pcrel_offset */
156
157  /* A 10 bit absolute relocation.  */
158  HOWTO (R_FR30_10_IN_8,	/* type */
159	 2,			/* rightshift */
160	 1,			/* size (0 = byte, 1 = short, 2 = long) */
161	 10,			/* bitsize */
162	 FALSE,			/* pc_relative */
163	 4,			/* bitpos */
164	 complain_overflow_signed, /* complain_on_overflow */
165	 bfd_elf_generic_reloc,/* special_function */
166	 "R_FR30_10_IN_8",	/* name */
167	 FALSE,			/* partial_inplace */
168	 0x0000,		/* src_mask */
169	 0x0ff0,		/* dst_mask */
170	 FALSE),		/* pcrel_offset */
171
172  /* A PC relative 9 bit relocation, right shifted by 1.  */
173  HOWTO (R_FR30_9_PCREL,	/* type */
174	 1,			/* rightshift */
175	 1,			/* size (0 = byte, 1 = short, 2 = long) */
176	 9,			/* bitsize */
177	 TRUE,			/* pc_relative */
178	 0,			/* bitpos */
179	 complain_overflow_signed, /* complain_on_overflow */
180	 bfd_elf_generic_reloc, /* special_function */
181	 "R_FR30_9_PCREL",	/* name */
182	 FALSE,			/* partial_inplace */
183	 0x0000,		/* src_mask */
184	 0x00ff,		/* dst_mask */
185	 FALSE),		/* pcrel_offset */
186
187  /* A PC relative 12 bit relocation, right shifted by 1.  */
188  HOWTO (R_FR30_12_PCREL,	/* type */
189	 1,			/* rightshift */
190	 1,			/* size (0 = byte, 1 = short, 2 = long) */
191	 12,			/* bitsize */
192	 TRUE,			/* pc_relative */
193	 0,			/* bitpos */
194	 complain_overflow_signed, /* complain_on_overflow */
195	 bfd_elf_generic_reloc, /* special_function */
196	 "R_FR30_12_PCREL",	/* name */
197	 FALSE,			/* partial_inplace */
198	 0x0000,		/* src_mask */
199	 0x07ff,		/* dst_mask */
200	 FALSE),		/* pcrel_offset */
201  /* GNU extension to record C++ vtable hierarchy */
202  HOWTO (R_FR30_GNU_VTINHERIT, /* type */
203	 0,			/* rightshift */
204	 2,			/* size (0 = byte, 1 = short, 2 = long) */
205	 0,			/* bitsize */
206	 FALSE,			/* pc_relative */
207	 0,			/* bitpos */
208	 complain_overflow_dont, /* complain_on_overflow */
209	 NULL,			/* special_function */
210	 "R_FR30_GNU_VTINHERIT", /* name */
211	 FALSE,			/* partial_inplace */
212	 0,			/* src_mask */
213	 0,			/* dst_mask */
214	 FALSE),		/* pcrel_offset */
215
216  /* GNU extension to record C++ vtable member usage */
217  HOWTO (R_FR30_GNU_VTENTRY,	 /* type */
218	 0,			/* rightshift */
219	 2,			/* size (0 = byte, 1 = short, 2 = long) */
220	 0,			/* bitsize */
221	 FALSE,			/* pc_relative */
222	 0,			/* bitpos */
223	 complain_overflow_dont, /* complain_on_overflow */
224	 _bfd_elf_rel_vtable_reloc_fn,	/* special_function */
225	 "R_FR30_GNU_VTENTRY",	 /* name */
226	 FALSE,			/* partial_inplace */
227	 0,			/* src_mask */
228	 0,			/* dst_mask */
229	 FALSE),		/* pcrel_offset */
230};
231
232/* Utility to actually perform an R_FR30_20 reloc.  */
233
234static bfd_reloc_status_type
235fr30_elf_i20_reloc (bfd *abfd,
236		    arelent *reloc_entry,
237		    asymbol *symbol,
238		    void * data,
239		    asection *input_section,
240		    bfd *output_bfd,
241		    char **error_message ATTRIBUTE_UNUSED)
242{
243  bfd_vma relocation;
244  unsigned long x;
245
246  /* This part is from bfd_elf_generic_reloc.  */
247  if (output_bfd != (bfd *) NULL
248      && (symbol->flags & BSF_SECTION_SYM) == 0
249      && (! reloc_entry->howto->partial_inplace
250	  || reloc_entry->addend == 0))
251    {
252      reloc_entry->address += input_section->output_offset;
253      return bfd_reloc_ok;
254    }
255
256  if (output_bfd != NULL)
257    /* FIXME: See bfd_perform_relocation.  Is this right?  */
258    return bfd_reloc_ok;
259
260  relocation =
261    symbol->value
262    + symbol->section->output_section->vma
263    + symbol->section->output_offset
264    + reloc_entry->addend;
265
266  if (relocation > (((bfd_vma) 1 << 20) - 1))
267    return bfd_reloc_overflow;
268
269  x = bfd_get_32 (abfd, (char *) data + reloc_entry->address);
270  x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
271  bfd_put_32 (abfd, (bfd_vma) x, (char *) data + reloc_entry->address);
272
273  return bfd_reloc_ok;
274}
275
276/* Utility to actually perform a R_FR30_48 reloc.  */
277
278static bfd_reloc_status_type
279fr30_elf_i32_reloc (bfd *abfd,
280		    arelent *reloc_entry,
281		    asymbol *symbol,
282		    void * data,
283		    asection *input_section,
284		    bfd *output_bfd,
285		    char **error_message ATTRIBUTE_UNUSED)
286{
287  bfd_vma relocation;
288
289  /* This part is from bfd_elf_generic_reloc.  */
290  if (output_bfd != (bfd *) NULL
291      && (symbol->flags & BSF_SECTION_SYM) == 0
292      && (! reloc_entry->howto->partial_inplace
293	  || reloc_entry->addend == 0))
294    {
295      reloc_entry->address += input_section->output_offset;
296      return bfd_reloc_ok;
297    }
298
299  if (output_bfd != NULL)
300    /* FIXME: See bfd_perform_relocation.  Is this right?  */
301    return bfd_reloc_ok;
302
303  relocation =
304    symbol->value
305    + symbol->section->output_section->vma
306    + symbol->section->output_offset
307    + reloc_entry->addend;
308
309  bfd_put_32 (abfd, relocation, (char *) data + reloc_entry->address + 2);
310
311  return bfd_reloc_ok;
312}
313
314/* Map BFD reloc types to FR30 ELF reloc types.  */
315
316struct fr30_reloc_map
317{
318  bfd_reloc_code_real_type bfd_reloc_val;
319  unsigned int fr30_reloc_val;
320};
321
322static const struct fr30_reloc_map fr30_reloc_map [] =
323{
324  { BFD_RELOC_NONE,	      R_FR30_NONE },
325  { BFD_RELOC_8,	      R_FR30_8 },
326  { BFD_RELOC_FR30_20,	      R_FR30_20 },
327  { BFD_RELOC_32,	      R_FR30_32 },
328  { BFD_RELOC_FR30_48,	      R_FR30_48 },
329  { BFD_RELOC_FR30_6_IN_4,    R_FR30_6_IN_4 },
330  { BFD_RELOC_FR30_8_IN_8,    R_FR30_8_IN_8 },
331  { BFD_RELOC_FR30_9_IN_8,    R_FR30_9_IN_8 },
332  { BFD_RELOC_FR30_10_IN_8,   R_FR30_10_IN_8 },
333  { BFD_RELOC_FR30_9_PCREL,   R_FR30_9_PCREL },
334  { BFD_RELOC_FR30_12_PCREL,  R_FR30_12_PCREL },
335  { BFD_RELOC_VTABLE_INHERIT, R_FR30_GNU_VTINHERIT },
336  { BFD_RELOC_VTABLE_ENTRY,   R_FR30_GNU_VTENTRY },
337};
338
339static reloc_howto_type *
340fr30_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
341			bfd_reloc_code_real_type code)
342{
343  unsigned int i;
344
345  for (i = sizeof (fr30_reloc_map) / sizeof (fr30_reloc_map[0]);
346       i--;)
347    if (fr30_reloc_map [i].bfd_reloc_val == code)
348      return & fr30_elf_howto_table [fr30_reloc_map[i].fr30_reloc_val];
349
350  return NULL;
351}
352
353static reloc_howto_type *
354fr30_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
355{
356  unsigned int i;
357
358  for (i = 0;
359       i < sizeof (fr30_elf_howto_table) / sizeof (fr30_elf_howto_table[0]);
360       i++)
361    if (fr30_elf_howto_table[i].name != NULL
362	&& strcasecmp (fr30_elf_howto_table[i].name, r_name) == 0)
363      return &fr30_elf_howto_table[i];
364
365  return NULL;
366}
367
368/* Set the howto pointer for an FR30 ELF reloc.  */
369
370static bfd_boolean
371fr30_info_to_howto_rela (bfd *abfd ATTRIBUTE_UNUSED,
372			 arelent *cache_ptr,
373			 Elf_Internal_Rela *dst)
374{
375  unsigned int r_type;
376
377  r_type = ELF32_R_TYPE (dst->r_info);
378  if (r_type >= (unsigned int) R_FR30_max)
379    {
380      /* xgettext:c-format */
381      _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
382			  abfd, r_type);
383      bfd_set_error (bfd_error_bad_value);
384      return FALSE;
385    }
386  cache_ptr->howto = & fr30_elf_howto_table [r_type];
387  return TRUE;
388}
389
390/* Perform a single relocation.  By default we use the standard BFD
391   routines, but a few relocs, we have to do them ourselves.  */
392
393static bfd_reloc_status_type
394fr30_final_link_relocate (reloc_howto_type *howto,
395			  bfd *input_bfd,
396			  asection *input_section,
397			  bfd_byte *contents,
398			  Elf_Internal_Rela *rel,
399			  bfd_vma relocation)
400{
401  bfd_reloc_status_type r = bfd_reloc_ok;
402  bfd_vma x;
403  bfd_signed_vma srel;
404
405  switch (howto->type)
406    {
407    case R_FR30_20:
408      contents   += rel->r_offset;
409      relocation += rel->r_addend;
410
411      if (relocation > ((1 << 20) - 1))
412	return bfd_reloc_overflow;
413
414      x = bfd_get_32 (input_bfd, contents);
415      x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
416      bfd_put_32 (input_bfd, x, contents);
417      break;
418
419    case R_FR30_48:
420      contents   += rel->r_offset + 2;
421      relocation += rel->r_addend;
422      bfd_put_32 (input_bfd, relocation, contents);
423      break;
424
425    case R_FR30_9_PCREL:
426      contents   += rel->r_offset + 1;
427      srel = (bfd_signed_vma) relocation;
428      srel += rel->r_addend;
429      srel -= rel->r_offset;
430      srel -= 2;  /* Branch instructions add 2 to the PC...  */
431      srel -= (input_section->output_section->vma +
432		     input_section->output_offset);
433
434      if (srel & 1)
435	return bfd_reloc_outofrange;
436      if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
437	return bfd_reloc_overflow;
438
439      bfd_put_8 (input_bfd, srel >> 1, contents);
440      break;
441
442    case R_FR30_12_PCREL:
443      contents   += rel->r_offset;
444      srel = (bfd_signed_vma) relocation;
445      srel += rel->r_addend;
446      srel -= rel->r_offset;
447      srel -= 2; /* Branch instructions add 2 to the PC...  */
448      srel -= (input_section->output_section->vma +
449		     input_section->output_offset);
450
451      if (srel & 1)
452	return bfd_reloc_outofrange;
453      if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
454	  return bfd_reloc_overflow;
455
456      x = bfd_get_16 (input_bfd, contents);
457      x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
458      bfd_put_16 (input_bfd, x, contents);
459      break;
460
461    default:
462      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
463				    contents, rel->r_offset,
464				    relocation, rel->r_addend);
465    }
466
467  return r;
468}
469
470/* Relocate an FR30 ELF section.
471
472   The RELOCATE_SECTION function is called by the new ELF backend linker
473   to handle the relocations for a section.
474
475   The relocs are always passed as Rela structures; if the section
476   actually uses Rel structures, the r_addend field will always be
477   zero.
478
479   This function is responsible for adjusting the section contents as
480   necessary, and (if using Rela relocs and generating a relocatable
481   output file) adjusting the reloc addend as necessary.
482
483   This function does not have to worry about setting the reloc
484   address or the reloc symbol index.
485
486   LOCAL_SYMS is a pointer to the swapped in local symbols.
487
488   LOCAL_SECTIONS is an array giving the section in the input file
489   corresponding to the st_shndx field of each local symbol.
490
491   The global hash table entry for the global symbols can be found
492   via elf_sym_hashes (input_bfd).
493
494   When generating relocatable output, this function must handle
495   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
496   going to be the section symbol corresponding to the output
497   section, which means that the addend must be adjusted
498   accordingly.  */
499
500static bfd_boolean
501fr30_elf_relocate_section (bfd *output_bfd,
502			   struct bfd_link_info *info,
503			   bfd *input_bfd,
504			   asection *input_section,
505			   bfd_byte *contents,
506			   Elf_Internal_Rela *relocs,
507			   Elf_Internal_Sym *local_syms,
508			   asection **local_sections)
509{
510  Elf_Internal_Shdr *symtab_hdr;
511  struct elf_link_hash_entry **sym_hashes;
512  Elf_Internal_Rela *rel;
513  Elf_Internal_Rela *relend;
514
515  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
516  sym_hashes = elf_sym_hashes (input_bfd);
517  relend     = relocs + input_section->reloc_count;
518
519  for (rel = relocs; rel < relend; rel ++)
520    {
521      reloc_howto_type *howto;
522      unsigned long r_symndx;
523      Elf_Internal_Sym *sym;
524      asection *sec;
525      struct elf_link_hash_entry *h;
526      bfd_vma relocation;
527      bfd_reloc_status_type r;
528      const char *name;
529      int r_type;
530
531      r_type = ELF32_R_TYPE (rel->r_info);
532
533      if (   r_type == R_FR30_GNU_VTINHERIT
534	  || r_type == R_FR30_GNU_VTENTRY)
535	continue;
536
537      r_symndx = ELF32_R_SYM (rel->r_info);
538
539      howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
540      h      = NULL;
541      sym    = NULL;
542      sec    = NULL;
543
544      if (r_symndx < symtab_hdr->sh_info)
545	{
546	  sym = local_syms + r_symndx;
547	  sec = local_sections [r_symndx];
548	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
549
550	  name = bfd_elf_string_from_elf_section
551	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
552	  name = name == NULL ? bfd_section_name (sec) : name;
553	}
554      else
555	{
556	  bfd_boolean unresolved_reloc, warned, ignored;
557
558	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
559				   r_symndx, symtab_hdr, sym_hashes,
560				   h, sec, relocation,
561				   unresolved_reloc, warned, ignored);
562
563	  name = h->root.root.string;
564	}
565
566      if (sec != NULL && discarded_section (sec))
567	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
568					 rel, 1, relend, howto, 0, contents);
569
570      if (bfd_link_relocatable (info))
571	continue;
572
573      r = fr30_final_link_relocate (howto, input_bfd, input_section,
574				     contents, rel, relocation);
575
576      if (r != bfd_reloc_ok)
577	{
578	  const char * msg = (const char *) NULL;
579
580	  switch (r)
581	    {
582	    case bfd_reloc_overflow:
583	      (*info->callbacks->reloc_overflow)
584		(info, (h ? &h->root : NULL), name, howto->name,
585		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
586	      break;
587
588	    case bfd_reloc_undefined:
589	      (*info->callbacks->undefined_symbol)
590		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
591	      break;
592
593	    case bfd_reloc_outofrange:
594	      msg = _("internal error: out of range error");
595	      break;
596
597	    case bfd_reloc_notsupported:
598	      msg = _("internal error: unsupported relocation error");
599	      break;
600
601	    case bfd_reloc_dangerous:
602	      msg = _("internal error: dangerous relocation");
603	      break;
604
605	    default:
606	      msg = _("internal error: unknown error");
607	      break;
608	    }
609
610	  if (msg)
611	    (*info->callbacks->warning) (info, msg, name, input_bfd,
612					 input_section, rel->r_offset);
613	}
614    }
615
616  return TRUE;
617}
618
619/* Return the section that should be marked against GC for a given
620   relocation.  */
621
622static asection *
623fr30_elf_gc_mark_hook (asection *sec,
624		       struct bfd_link_info *info,
625		       Elf_Internal_Rela *rel,
626		       struct elf_link_hash_entry *h,
627		       Elf_Internal_Sym *sym)
628{
629  if (h != NULL)
630    switch (ELF32_R_TYPE (rel->r_info))
631      {
632      case R_FR30_GNU_VTINHERIT:
633      case R_FR30_GNU_VTENTRY:
634	return NULL;
635      }
636
637  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
638}
639
640/* Look through the relocs for a section during the first phase.
641   Since we don't do .gots or .plts, we just need to consider the
642   virtual table relocs for gc.  */
643
644static bfd_boolean
645fr30_elf_check_relocs (bfd *abfd,
646		       struct bfd_link_info *info,
647		       asection *sec,
648		       const Elf_Internal_Rela *relocs)
649{
650  Elf_Internal_Shdr *symtab_hdr;
651  struct elf_link_hash_entry **sym_hashes;
652  const Elf_Internal_Rela *rel;
653  const Elf_Internal_Rela *rel_end;
654
655  if (bfd_link_relocatable (info))
656    return TRUE;
657
658  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
659  sym_hashes = elf_sym_hashes (abfd);
660
661  rel_end = relocs + sec->reloc_count;
662  for (rel = relocs; rel < rel_end; rel++)
663    {
664      struct elf_link_hash_entry *h;
665      unsigned long r_symndx;
666
667      r_symndx = ELF32_R_SYM (rel->r_info);
668      if (r_symndx < symtab_hdr->sh_info)
669	h = NULL;
670      else
671	{
672	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
673	  while (h->root.type == bfd_link_hash_indirect
674		 || h->root.type == bfd_link_hash_warning)
675	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
676	}
677
678      switch (ELF32_R_TYPE (rel->r_info))
679	{
680	/* This relocation describes the C++ object vtable hierarchy.
681	   Reconstruct it for later use during GC.  */
682	case R_FR30_GNU_VTINHERIT:
683	  if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
684	    return FALSE;
685	  break;
686
687	/* This relocation describes which C++ vtable entries are actually
688	   used.  Record for later use during GC.  */
689	case R_FR30_GNU_VTENTRY:
690	  if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
691	    return FALSE;
692	  break;
693	}
694    }
695
696  return TRUE;
697}
698
699#define ELF_ARCH		bfd_arch_fr30
700#define ELF_MACHINE_CODE	EM_FR30
701#define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
702#define ELF_MAXPAGESIZE		0x1000
703
704#define TARGET_BIG_SYM		fr30_elf32_vec
705#define TARGET_BIG_NAME		"elf32-fr30"
706
707#define elf_info_to_howto_rel			NULL
708#define elf_info_to_howto			fr30_info_to_howto_rela
709#define elf_backend_relocate_section		fr30_elf_relocate_section
710#define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
711#define elf_backend_check_relocs		fr30_elf_check_relocs
712
713#define elf_backend_can_gc_sections		1
714#define elf_backend_rela_normal			1
715
716#define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
717#define bfd_elf32_bfd_reloc_name_lookup		fr30_reloc_name_lookup
718
719#include "elf32-target.h"
720