xref: /netbsd-src/external/gpl3/gdb/dist/bfd/elf32-fr30.c (revision 16dce51364ebe8aeafbae46bc5aa167b8115bc45)
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.  */
28 static bfd_reloc_status_type
29 fr30_elf_i20_reloc (bfd *, arelent *, asymbol *, void * data,
30 		    asection *, bfd *, char **error_message);
31 static bfd_reloc_status_type
32 fr30_elf_i32_reloc (bfd *, arelent *, asymbol *, void *,
33 		    asection *, bfd *, char **);
34 
35 static 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 
234 static bfd_reloc_status_type
235 fr30_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 
278 static bfd_reloc_status_type
279 fr30_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 
316 struct fr30_reloc_map
317 {
318   bfd_reloc_code_real_type bfd_reloc_val;
319   unsigned int fr30_reloc_val;
320 };
321 
322 static 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 
339 static reloc_howto_type *
340 fr30_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 
353 static reloc_howto_type *
354 fr30_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 
370 static void
371 fr30_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 
390 static bfd_reloc_status_type
391 fr30_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 
497 static bfd_boolean
498 fr30_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 
619 static asection *
620 fr30_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 
641 static bfd_boolean
642 fr30_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