1/* FR30-specific support for 32-bit ELF.
2   Copyright (C) 1998-2017 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 void
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 (_("%B: invalid FR30 reloc number: %d"), abfd, r_type);
382      r_type = 0;
383    }
384  cache_ptr->howto = & fr30_elf_howto_table [r_type];
385}
386
387/* Perform a single relocation.  By default we use the standard BFD
388   routines, but a few relocs, we have to do them ourselves.  */
389
390static bfd_reloc_status_type
391fr30_final_link_relocate (reloc_howto_type *howto,
392			  bfd *input_bfd,
393			  asection *input_section,
394			  bfd_byte *contents,
395			  Elf_Internal_Rela *rel,
396			  bfd_vma relocation)
397{
398  bfd_reloc_status_type r = bfd_reloc_ok;
399  bfd_vma x;
400  bfd_signed_vma srel;
401
402  switch (howto->type)
403    {
404    case R_FR30_20:
405      contents   += rel->r_offset;
406      relocation += rel->r_addend;
407
408      if (relocation > ((1 << 20) - 1))
409	return bfd_reloc_overflow;
410
411      x = bfd_get_32 (input_bfd, contents);
412      x = (x & 0xff0f0000) | (relocation & 0x0000ffff) | ((relocation & 0x000f0000) << 4);
413      bfd_put_32 (input_bfd, x, contents);
414      break;
415
416    case R_FR30_48:
417      contents   += rel->r_offset + 2;
418      relocation += rel->r_addend;
419      bfd_put_32 (input_bfd, relocation, contents);
420      break;
421
422    case R_FR30_9_PCREL:
423      contents   += rel->r_offset + 1;
424      srel = (bfd_signed_vma) relocation;
425      srel += rel->r_addend;
426      srel -= rel->r_offset;
427      srel -= 2;  /* Branch instructions add 2 to the PC...  */
428      srel -= (input_section->output_section->vma +
429		     input_section->output_offset);
430
431      if (srel & 1)
432	return bfd_reloc_outofrange;
433      if (srel > ((1 << 8) - 1) || (srel < - (1 << 8)))
434	return bfd_reloc_overflow;
435
436      bfd_put_8 (input_bfd, srel >> 1, contents);
437      break;
438
439    case R_FR30_12_PCREL:
440      contents   += rel->r_offset;
441      srel = (bfd_signed_vma) relocation;
442      srel += rel->r_addend;
443      srel -= rel->r_offset;
444      srel -= 2; /* Branch instructions add 2 to the PC...  */
445      srel -= (input_section->output_section->vma +
446		     input_section->output_offset);
447
448      if (srel & 1)
449	return bfd_reloc_outofrange;
450      if (srel > ((1 << 11) - 1) || (srel < - (1 << 11)))
451	  return bfd_reloc_overflow;
452
453      x = bfd_get_16 (input_bfd, contents);
454      x = (x & 0xf800) | ((srel >> 1) & 0x7ff);
455      bfd_put_16 (input_bfd, x, contents);
456      break;
457
458    default:
459      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
460				    contents, rel->r_offset,
461				    relocation, rel->r_addend);
462    }
463
464  return r;
465}
466
467/* Relocate an FR30 ELF section.
468
469   The RELOCATE_SECTION function is called by the new ELF backend linker
470   to handle the relocations for a section.
471
472   The relocs are always passed as Rela structures; if the section
473   actually uses Rel structures, the r_addend field will always be
474   zero.
475
476   This function is responsible for adjusting the section contents as
477   necessary, and (if using Rela relocs and generating a relocatable
478   output file) adjusting the reloc addend as necessary.
479
480   This function does not have to worry about setting the reloc
481   address or the reloc symbol index.
482
483   LOCAL_SYMS is a pointer to the swapped in local symbols.
484
485   LOCAL_SECTIONS is an array giving the section in the input file
486   corresponding to the st_shndx field of each local symbol.
487
488   The global hash table entry for the global symbols can be found
489   via elf_sym_hashes (input_bfd).
490
491   When generating relocatable output, this function must handle
492   STB_LOCAL/STT_SECTION symbols specially.  The output symbol is
493   going to be the section symbol corresponding to the output
494   section, which means that the addend must be adjusted
495   accordingly.  */
496
497static bfd_boolean
498fr30_elf_relocate_section (bfd *output_bfd,
499			   struct bfd_link_info *info,
500			   bfd *input_bfd,
501			   asection *input_section,
502			   bfd_byte *contents,
503			   Elf_Internal_Rela *relocs,
504			   Elf_Internal_Sym *local_syms,
505			   asection **local_sections)
506{
507  Elf_Internal_Shdr *symtab_hdr;
508  struct elf_link_hash_entry **sym_hashes;
509  Elf_Internal_Rela *rel;
510  Elf_Internal_Rela *relend;
511
512  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
513  sym_hashes = elf_sym_hashes (input_bfd);
514  relend     = relocs + input_section->reloc_count;
515
516  for (rel = relocs; rel < relend; rel ++)
517    {
518      reloc_howto_type *howto;
519      unsigned long r_symndx;
520      Elf_Internal_Sym *sym;
521      asection *sec;
522      struct elf_link_hash_entry *h;
523      bfd_vma relocation;
524      bfd_reloc_status_type r;
525      const char *name;
526      int r_type;
527
528      r_type = ELF32_R_TYPE (rel->r_info);
529
530      if (   r_type == R_FR30_GNU_VTINHERIT
531	  || r_type == R_FR30_GNU_VTENTRY)
532	continue;
533
534      r_symndx = ELF32_R_SYM (rel->r_info);
535
536      howto  = fr30_elf_howto_table + ELF32_R_TYPE (rel->r_info);
537      h      = NULL;
538      sym    = NULL;
539      sec    = NULL;
540
541      if (r_symndx < symtab_hdr->sh_info)
542	{
543	  sym = local_syms + r_symndx;
544	  sec = local_sections [r_symndx];
545	  relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
546
547	  name = bfd_elf_string_from_elf_section
548	    (input_bfd, symtab_hdr->sh_link, sym->st_name);
549	  name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name;
550	}
551      else
552	{
553	  bfd_boolean unresolved_reloc, warned, ignored;
554
555	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
556				   r_symndx, symtab_hdr, sym_hashes,
557				   h, sec, relocation,
558				   unresolved_reloc, warned, ignored);
559
560	  name = h->root.root.string;
561	}
562
563      if (sec != NULL && discarded_section (sec))
564	RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section,
565					 rel, 1, relend, howto, 0, contents);
566
567      if (bfd_link_relocatable (info))
568	continue;
569
570      r = fr30_final_link_relocate (howto, input_bfd, input_section,
571				     contents, rel, relocation);
572
573      if (r != bfd_reloc_ok)
574	{
575	  const char * msg = (const char *) NULL;
576
577	  switch (r)
578	    {
579	    case bfd_reloc_overflow:
580	      (*info->callbacks->reloc_overflow)
581		(info, (h ? &h->root : NULL), name, howto->name,
582		 (bfd_vma) 0, input_bfd, input_section, rel->r_offset);
583	      break;
584
585	    case bfd_reloc_undefined:
586	      (*info->callbacks->undefined_symbol)
587		(info, name, input_bfd, input_section, rel->r_offset, TRUE);
588	      break;
589
590	    case bfd_reloc_outofrange:
591	      msg = _("internal error: out of range error");
592	      break;
593
594	    case bfd_reloc_notsupported:
595	      msg = _("internal error: unsupported relocation error");
596	      break;
597
598	    case bfd_reloc_dangerous:
599	      msg = _("internal error: dangerous relocation");
600	      break;
601
602	    default:
603	      msg = _("internal error: unknown error");
604	      break;
605	    }
606
607	  if (msg)
608	    (*info->callbacks->warning) (info, msg, name, input_bfd,
609					 input_section, rel->r_offset);
610	}
611    }
612
613  return TRUE;
614}
615
616/* Return the section that should be marked against GC for a given
617   relocation.  */
618
619static asection *
620fr30_elf_gc_mark_hook (asection *sec,
621		       struct bfd_link_info *info,
622		       Elf_Internal_Rela *rel,
623		       struct elf_link_hash_entry *h,
624		       Elf_Internal_Sym *sym)
625{
626  if (h != NULL)
627    switch (ELF32_R_TYPE (rel->r_info))
628      {
629      case R_FR30_GNU_VTINHERIT:
630      case R_FR30_GNU_VTENTRY:
631	return NULL;
632      }
633
634  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
635}
636
637/* Look through the relocs for a section during the first phase.
638   Since we don't do .gots or .plts, we just need to consider the
639   virtual table relocs for gc.  */
640
641static bfd_boolean
642fr30_elf_check_relocs (bfd *abfd,
643		       struct bfd_link_info *info,
644		       asection *sec,
645		       const Elf_Internal_Rela *relocs)
646{
647  Elf_Internal_Shdr *symtab_hdr;
648  struct elf_link_hash_entry **sym_hashes;
649  const Elf_Internal_Rela *rel;
650  const Elf_Internal_Rela *rel_end;
651
652  if (bfd_link_relocatable (info))
653    return TRUE;
654
655  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
656  sym_hashes = elf_sym_hashes (abfd);
657
658  rel_end = relocs + sec->reloc_count;
659  for (rel = relocs; rel < rel_end; rel++)
660    {
661      struct elf_link_hash_entry *h;
662      unsigned long r_symndx;
663
664      r_symndx = ELF32_R_SYM (rel->r_info);
665      if (r_symndx < symtab_hdr->sh_info)
666        h = NULL;
667      else
668	{
669	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
670	  while (h->root.type == bfd_link_hash_indirect
671		 || h->root.type == bfd_link_hash_warning)
672	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
673
674	  /* PR15323, ref flags aren't set for references in the same
675	     object.  */
676	  h->root.non_ir_ref = 1;
677	}
678
679      switch (ELF32_R_TYPE (rel->r_info))
680        {
681        /* This relocation describes the C++ object vtable hierarchy.
682           Reconstruct it for later use during GC.  */
683        case R_FR30_GNU_VTINHERIT:
684          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
685            return FALSE;
686          break;
687
688        /* This relocation describes which C++ vtable entries are actually
689           used.  Record for later use during GC.  */
690        case R_FR30_GNU_VTENTRY:
691          BFD_ASSERT (h != NULL);
692          if (h != NULL
693              && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
694            return FALSE;
695          break;
696        }
697    }
698
699  return TRUE;
700}
701
702#define ELF_ARCH		bfd_arch_fr30
703#define ELF_MACHINE_CODE	EM_FR30
704#define ELF_MACHINE_ALT1	EM_CYGNUS_FR30
705#define ELF_MAXPAGESIZE		0x1000
706
707#define TARGET_BIG_SYM          fr30_elf32_vec
708#define TARGET_BIG_NAME		"elf32-fr30"
709
710#define elf_info_to_howto_rel			NULL
711#define elf_info_to_howto			fr30_info_to_howto_rela
712#define elf_backend_relocate_section		fr30_elf_relocate_section
713#define elf_backend_gc_mark_hook		fr30_elf_gc_mark_hook
714#define elf_backend_check_relocs                fr30_elf_check_relocs
715
716#define elf_backend_can_gc_sections		1
717#define elf_backend_rela_normal			1
718
719#define bfd_elf32_bfd_reloc_type_lookup		fr30_reloc_type_lookup
720#define bfd_elf32_bfd_reloc_name_lookup	fr30_reloc_name_lookup
721
722#include "elf32-target.h"
723