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